@wrongstack/core 0.297.0 → 0.298.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chronicle/index.js +126 -22
- package/dist/chronicle/project-server-client.d.ts +12 -0
- package/dist/chronicle/project-server-protocol.d.ts +22 -0
- package/dist/chronicle/project-server.js +238 -157
- package/dist/coordination/agents/index.js +136 -1
- package/dist/coordination/agents/role-skills.d.ts +3 -2
- package/dist/coordination/brain-trace.d.ts +2 -1
- package/dist/coordination/director/director-task-registry.d.ts +12 -0
- package/dist/coordination/fleet-supervisor.d.ts +21 -0
- package/dist/coordination/index.d.ts +23 -21
- package/dist/coordination/index.js +16493 -16068
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-credential-store.d.ts +22 -2
- package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
- package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
- package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
- package/dist/coordination/mailbox-project-server.js +508 -253
- package/dist/coordination/provider-status-tracker.d.ts +2 -0
- package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
- package/dist/coordination/remote-mailbox.d.ts +8 -4
- package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
- package/dist/core/fallback-profile-manager.d.ts +14 -0
- package/dist/core/index.js +451 -137
- package/dist/core/instruction-bundle.d.ts +12 -0
- package/dist/core/system-prompt-builder.d.ts +14 -0
- package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
- package/dist/core/system-prompt-skill-text.d.ts +1 -2
- package/dist/defaults/index.js +2191 -1208
- package/dist/design/index.js +47 -8
- package/dist/execution/design-materialize.d.ts +22 -0
- package/dist/execution/index.js +495 -248
- package/dist/execution/skill-loader.d.ts +10 -1
- package/dist/execution/tool-error-taxonomy.d.ts +31 -0
- package/dist/execution/tool-executor.d.ts +1 -0
- package/dist/goal/index.js +3 -1
- package/dist/hooks/index.js +5 -0
- package/dist/hq/auth-audit.d.ts +6 -0
- package/dist/hq/auth-store.d.ts +59 -3
- package/dist/hq/index.js +401 -101
- package/dist/hq/kanban-store.d.ts +3 -0
- package/dist/hq/protocol/core.d.ts +3 -15
- package/dist/hq/protocol/envelope.d.ts +29 -0
- package/dist/hq/protocol/governance.d.ts +34 -0
- package/dist/hq/protocol/project.d.ts +3 -0
- package/dist/hq/protocol/resume.d.ts +1 -1
- package/dist/hq/protocol.d.ts +9 -8
- package/dist/hq/protocol.js +675 -0
- package/dist/index.js +9012 -6916
- package/dist/infrastructure/index.js +199 -102
- package/dist/kernel/events/session-events.d.ts +3 -0
- package/dist/kernel/events/tool-events.d.ts +3 -1
- package/dist/models/index.js +1 -1
- package/dist/observability/index.js +27 -0
- package/dist/observability/prometheus.d.ts +11 -0
- package/dist/plugin/index.d.ts +5 -1
- package/dist/plugin/index.js +988 -558
- package/dist/plugins/auto-review-plugin.d.ts +1 -11
- package/dist/plugins/review-store-maintenance.d.ts +26 -0
- package/dist/plugins/review-types.d.ts +6 -0
- package/dist/security/auto-approve-policy.d.ts +37 -0
- package/dist/security/capabilities.d.ts +45 -1
- package/dist/security/error-sanitize.d.ts +49 -0
- package/dist/security/file-permissions.d.ts +41 -0
- package/dist/security/index.d.ts +9 -6
- package/dist/security/index.js +3008 -2029
- package/dist/security/permission-helpers.d.ts +93 -0
- package/dist/security/permission-policy.d.ts +37 -35
- package/dist/security/secret-vault.d.ts +17 -0
- package/dist/security/totp.d.ts +86 -0
- package/dist/skills/frontmatter.d.ts +12 -1
- package/dist/skills/github-fetcher.d.ts +48 -0
- package/dist/skills/index.js +137 -26
- package/dist/skills/limits.d.ts +19 -0
- package/dist/skills/skill-installer.d.ts +13 -0
- package/dist/storage/index.js +929 -733
- package/dist/storage/provider-config-watcher.d.ts +1 -0
- package/dist/storage/session-helpers.d.ts +1 -0
- package/dist/storage/session-store.d.ts +9 -2
- package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
- package/dist/tools/fallback-manage-tools.d.ts +6 -0
- package/dist/tools/index.js +287 -131
- package/dist/tools/mcp-use.d.ts +1 -1
- package/dist/types/blocks.d.ts +7 -0
- package/dist/types/config/autonomy.d.ts +15 -7
- package/dist/types/config/mcp-features.d.ts +9 -1
- package/dist/types/config/root.d.ts +10 -4
- package/dist/types/context-window.d.ts +15 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/secret-vault.d.ts +8 -0
- package/dist/types/session.d.ts +2 -0
- package/dist/types/skill.d.ts +56 -0
- package/dist/types/tool-executor.d.ts +2 -0
- package/dist/utils/env-typed.d.ts +64 -0
- package/dist/utils/glob-match.d.ts +21 -1
- package/dist/utils/heap-watchdog.js +1 -1
- package/dist/utils/incoming-images.d.ts +19 -0
- package/dist/utils/index.d.ts +16 -12
- package/dist/utils/index.js +3128 -2800
- package/dist/utils/path-segment.d.ts +29 -0
- package/dist/utils/sage-output-block.js +48 -0
- package/dist/utils/win32-cmd.d.ts +25 -0
- package/dist/worktree/index.js +5 -0
- package/instructions/llm/chimera-review.md +4 -6
- package/package.json +13 -4
- package/skills/auto-review/SKILL.md +11 -76
- package/skills/chimera/SKILL.md +31 -49
- package/skills/data-governance/SKILL.md +92 -0
- package/skills/wrongstack-kanban/SKILL.md +125 -64
- package/dist/agent-status-helpers.d.ts.map +0 -1
- package/dist/agent-status-tracker.d.ts.map +0 -1
- package/dist/boot.d.ts.map +0 -1
- package/dist/chronicle/context.d.ts.map +0 -1
- package/dist/chronicle/decision-adapter.d.ts.map +0 -1
- package/dist/chronicle/domain-adapter.d.ts.map +0 -1
- package/dist/chronicle/event-hash.d.ts.map +0 -1
- package/dist/chronicle/file-observer.d.ts.map +0 -1
- package/dist/chronicle/health-monitor.d.ts.map +0 -1
- package/dist/chronicle/identity.d.ts.map +0 -1
- package/dist/chronicle/index.d.ts.map +0 -1
- package/dist/chronicle/index.js.map +0 -7
- package/dist/chronicle/journal.d.ts.map +0 -1
- package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
- package/dist/chronicle/metrics-store.d.ts.map +0 -1
- package/dist/chronicle/partition-filename.d.ts.map +0 -1
- package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
- package/dist/chronicle/process-adapter.d.ts.map +0 -1
- package/dist/chronicle/project-access.d.ts.map +0 -1
- package/dist/chronicle/project-server-client.d.ts.map +0 -1
- package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
- package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
- package/dist/chronicle/project-server.d.ts.map +0 -1
- package/dist/chronicle/project-server.js.map +0 -7
- package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
- package/dist/chronicle/provider-adapter.d.ts.map +0 -1
- package/dist/chronicle/query.d.ts.map +0 -1
- package/dist/chronicle/review-adapter.d.ts.map +0 -1
- package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
- package/dist/chronicle/sink.d.ts.map +0 -1
- package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
- package/dist/chronicle/sqlite-query.d.ts.map +0 -1
- package/dist/chronicle/stream-adapter.d.ts.map +0 -1
- package/dist/chronicle/tool-adapter.d.ts.map +0 -1
- package/dist/chronicle/types.d.ts.map +0 -1
- package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
- package/dist/coordination/agent-bridge.d.ts.map +0 -1
- package/dist/coordination/agent-monitor.d.ts.map +0 -1
- package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
- package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
- package/dist/coordination/agents/index.d.ts.map +0 -1
- package/dist/coordination/agents/index.js.map +0 -7
- package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
- package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
- package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
- package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
- package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
- package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
- package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
- package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
- package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
- package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
- package/dist/coordination/agents/role-skills.d.ts.map +0 -1
- package/dist/coordination/agents/types.d.ts.map +0 -1
- package/dist/coordination/agents.d.ts.map +0 -1
- package/dist/coordination/auto-extend.d.ts.map +0 -1
- package/dist/coordination/autonomous-brain.d.ts.map +0 -1
- package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
- package/dist/coordination/brain-cache.d.ts.map +0 -1
- package/dist/coordination/brain-heuristics.d.ts.map +0 -1
- package/dist/coordination/brain-ledger.d.ts.map +0 -1
- package/dist/coordination/brain-monitor.d.ts.map +0 -1
- package/dist/coordination/brain-rules.d.ts.map +0 -1
- package/dist/coordination/brain-telemetry.d.ts.map +0 -1
- package/dist/coordination/brain-trace.d.ts.map +0 -1
- package/dist/coordination/brain.d.ts.map +0 -1
- package/dist/coordination/change-manager.d.ts.map +0 -1
- package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
- package/dist/coordination/collab-bus.d.ts.map +0 -1
- package/dist/coordination/collab-debug-types.d.ts.map +0 -1
- package/dist/coordination/collab-debug.d.ts.map +0 -1
- package/dist/coordination/collab-director-host.d.ts.map +0 -1
- package/dist/coordination/commit-safety.d.ts.map +0 -1
- package/dist/coordination/consensus-protocol.d.ts.map +0 -1
- package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
- package/dist/coordination/delegate-tool.d.ts.map +0 -1
- package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
- package/dist/coordination/dep-watcher.d.ts.map +0 -1
- package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
- package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
- package/dist/coordination/director/director-collab.d.ts.map +0 -1
- package/dist/coordination/director/director-errors.d.ts.map +0 -1
- package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
- package/dist/coordination/director/director-toolset.d.ts.map +0 -1
- package/dist/coordination/director-basic-tools.d.ts.map +0 -1
- package/dist/coordination/director-collab-tools.d.ts.map +0 -1
- package/dist/coordination/director-host-contracts.d.ts.map +0 -1
- package/dist/coordination/director-input-helpers.d.ts.map +0 -1
- package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
- package/dist/coordination/director-options.d.ts.map +0 -1
- package/dist/coordination/director-prompts.d.ts.map +0 -1
- package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
- package/dist/coordination/director-session.d.ts.map +0 -1
- package/dist/coordination/director-spawn-model.d.ts.map +0 -1
- package/dist/coordination/director-tools.d.ts.map +0 -1
- package/dist/coordination/director.d.ts.map +0 -1
- package/dist/coordination/dispatcher.d.ts.map +0 -1
- package/dist/coordination/file-author-tracker.d.ts.map +0 -1
- package/dist/coordination/fleet-bus.d.ts.map +0 -1
- package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
- package/dist/coordination/fleet-manager.d.ts.map +0 -1
- package/dist/coordination/fleet-spawn.d.ts.map +0 -1
- package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
- package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
- package/dist/coordination/fleet.d.ts.map +0 -1
- package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
- package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
- package/dist/coordination/icoordinator.d.ts.map +0 -1
- package/dist/coordination/ifleet-manager.d.ts.map +0 -1
- package/dist/coordination/in-memory-transport.d.ts.map +0 -1
- package/dist/coordination/index.d.ts.map +0 -1
- package/dist/coordination/index.js.map +0 -7
- package/dist/coordination/knowledge-graph.d.ts.map +0 -1
- package/dist/coordination/large-answer-store.d.ts.map +0 -1
- package/dist/coordination/mail-tools.d.ts.map +0 -1
- package/dist/coordination/mailbox-actions.d.ts.map +0 -1
- package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
- package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
- package/dist/coordination/mailbox-constants.d.ts.map +0 -1
- package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
- package/dist/coordination/mailbox-events.d.ts.map +0 -1
- package/dist/coordination/mailbox-health.d.ts.map +0 -1
- package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
- package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
- package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server.js.map +0 -7
- package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
- package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
- package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
- package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
- package/dist/coordination/mailbox-tool.d.ts.map +0 -1
- package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
- package/dist/coordination/mailbox-types.d.ts.map +0 -1
- package/dist/coordination/model-matrix.d.ts.map +0 -1
- package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
- package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
- package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
- package/dist/coordination/package-author-tracker.d.ts.map +0 -1
- package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
- package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
- package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
- package/dist/coordination/remote-mailbox.d.ts.map +0 -1
- package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
- package/dist/coordination/spawn-budget.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
- package/dist/coordination/subagent-budget.d.ts.map +0 -1
- package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
- package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
- package/dist/coordination/task-auctioneer.d.ts.map +0 -1
- package/dist/coordination/task-dag.d.ts.map +0 -1
- package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
- package/dist/coordination/transport.d.ts.map +0 -1
- package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
- package/dist/core/agent-internals.d.ts.map +0 -1
- package/dist/core/agent-loop.d.ts.map +0 -1
- package/dist/core/agent-response.d.ts.map +0 -1
- package/dist/core/agent-tools.d.ts.map +0 -1
- package/dist/core/agent-types.d.ts.map +0 -1
- package/dist/core/agent.d.ts.map +0 -1
- package/dist/core/btw.d.ts.map +0 -1
- package/dist/core/context.d.ts.map +0 -1
- package/dist/core/continue-intent.d.ts.map +0 -1
- package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
- package/dist/core/conversation-state.d.ts.map +0 -1
- package/dist/core/fallback-model.d.ts.map +0 -1
- package/dist/core/fallback-profile-manager.d.ts.map +0 -1
- package/dist/core/fleet-pulse.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -7
- package/dist/core/input-builder.d.ts.map +0 -1
- package/dist/core/instruction-bundle.d.ts.map +0 -1
- package/dist/core/iteration-limit.d.ts.map +0 -1
- package/dist/core/mailbox-loop.d.ts.map +0 -1
- package/dist/core/model-availability-calendar.d.ts.map +0 -1
- package/dist/core/model-ref.d.ts.map +0 -1
- package/dist/core/model-ref.js.map +0 -7
- package/dist/core/modes/brief.d.ts.map +0 -1
- package/dist/core/modes/default.d.ts.map +0 -1
- package/dist/core/modes/teach.d.ts.map +0 -1
- package/dist/core/provider-runner.d.ts.map +0 -1
- package/dist/core/queued-messages.d.ts.map +0 -1
- package/dist/core/request-provider-binding.d.ts.map +0 -1
- package/dist/core/run-env.d.ts.map +0 -1
- package/dist/core/streaming-response-builder.d.ts.map +0 -1
- package/dist/core/system-prompt-blocks.d.ts.map +0 -1
- package/dist/core/system-prompt-builder.d.ts.map +0 -1
- package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
- package/dist/core/system-prompt-environment.d.ts.map +0 -1
- package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
- package/dist/core/system-prompt-plan.d.ts.map +0 -1
- package/dist/core/system-prompt-shell.d.ts.map +0 -1
- package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
- package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
- package/dist/defaults/index.d.ts.map +0 -1
- package/dist/defaults/index.js.map +0 -7
- package/dist/design/index.d.ts.map +0 -1
- package/dist/design/index.js.map +0 -7
- package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
- package/dist/execution/autonomous-runner.d.ts.map +0 -1
- package/dist/execution/autonomy-brain.d.ts.map +0 -1
- package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
- package/dist/execution/brain-chain.d.ts.map +0 -1
- package/dist/execution/brain-circuit.d.ts.map +0 -1
- package/dist/execution/brain-evaluation.d.ts.map +0 -1
- package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
- package/dist/execution/brain-runtime.d.ts.map +0 -1
- package/dist/execution/compaction-core.d.ts.map +0 -1
- package/dist/execution/compaction-scoring.d.ts.map +0 -1
- package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
- package/dist/execution/compactor.d.ts.map +0 -1
- package/dist/execution/council-brain.d.ts.map +0 -1
- package/dist/execution/council-orchestrator.d.ts.map +0 -1
- package/dist/execution/council-personas.d.ts.map +0 -1
- package/dist/execution/council-profiles.d.ts.map +0 -1
- package/dist/execution/council-prompts.d.ts.map +0 -1
- package/dist/execution/council-resolution.d.ts.map +0 -1
- package/dist/execution/design-color.d.ts.map +0 -1
- package/dist/execution/design-detect.d.ts.map +0 -1
- package/dist/execution/design-kit-loader.d.ts.map +0 -1
- package/dist/execution/design-materialize.d.ts.map +0 -1
- package/dist/execution/design-project-store.d.ts.map +0 -1
- package/dist/execution/design-tune.d.ts.map +0 -1
- package/dist/execution/design-verify.d.ts.map +0 -1
- package/dist/execution/enhance-recovery.d.ts.map +0 -1
- package/dist/execution/error-handler.d.ts.map +0 -1
- package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
- package/dist/execution/eternal-autonomy.d.ts.map +0 -1
- package/dist/execution/goal-preamble.d.ts.map +0 -1
- package/dist/execution/index.d.ts.map +0 -1
- package/dist/execution/index.js.map +0 -7
- package/dist/execution/intelligent-compactor.d.ts.map +0 -1
- package/dist/execution/model-runtime.d.ts.map +0 -1
- package/dist/execution/one-shot-llm.d.ts.map +0 -1
- package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
- package/dist/execution/prompt-enhancer.d.ts.map +0 -1
- package/dist/execution/prompt-enhancer.js.map +0 -7
- package/dist/execution/prompt-loader.d.ts.map +0 -1
- package/dist/execution/provider-runner-impl.d.ts.map +0 -1
- package/dist/execution/regex-patterns.d.ts.map +0 -1
- package/dist/execution/retry-policy.d.ts.map +0 -1
- package/dist/execution/selective-compactor.d.ts.map +0 -1
- package/dist/execution/skill-loader.d.ts.map +0 -1
- package/dist/execution/strategy-compactor.d.ts.map +0 -1
- package/dist/execution/subagent-compaction.d.ts.map +0 -1
- package/dist/execution/tool-executor-logging.d.ts.map +0 -1
- package/dist/execution/tool-executor-results.d.ts.map +0 -1
- package/dist/execution/tool-executor-stream.d.ts.map +0 -1
- package/dist/execution/tool-executor-support.d.ts.map +0 -1
- package/dist/execution/tool-executor.d.ts.map +0 -1
- package/dist/extension/extension-points.d.ts.map +0 -1
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js.map +0 -7
- package/dist/extension/registry.d.ts.map +0 -1
- package/dist/fleet-notifier.d.ts.map +0 -1
- package/dist/goal/checkpoint.d.ts.map +0 -1
- package/dist/goal/goal-assessor.d.ts.map +0 -1
- package/dist/goal/goal-planner.d.ts.map +0 -1
- package/dist/goal/goal-runner.d.ts.map +0 -1
- package/dist/goal/index.d.ts.map +0 -1
- package/dist/goal/index.js.map +0 -7
- package/dist/goal/phase-board-mutations.d.ts.map +0 -1
- package/dist/goal/phase-graph-builder.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator.d.ts.map +0 -1
- package/dist/goal/phase-store.d.ts.map +0 -1
- package/dist/goal/types.d.ts.map +0 -1
- package/dist/hooks/http-executor.d.ts.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -7
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/runner.d.ts.map +0 -1
- package/dist/hooks/shell-executor.d.ts.map +0 -1
- package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
- package/dist/hq/alerts.d.ts.map +0 -1
- package/dist/hq/auth-audit.d.ts.map +0 -1
- package/dist/hq/auth-store.d.ts.map +0 -1
- package/dist/hq/bootstrap-store.d.ts.map +0 -1
- package/dist/hq/brain-bridge.d.ts.map +0 -1
- package/dist/hq/bridge-context.d.ts.map +0 -1
- package/dist/hq/commands.d.ts.map +0 -1
- package/dist/hq/cost-bridge.d.ts.map +0 -1
- package/dist/hq/exposure.d.ts.map +0 -1
- package/dist/hq/factory.d.ts.map +0 -1
- package/dist/hq/fleet-bridge.d.ts.map +0 -1
- package/dist/hq/index.d.ts.map +0 -1
- package/dist/hq/index.js.map +0 -7
- package/dist/hq/kanban-store.d.ts.map +0 -1
- package/dist/hq/mailbox-mapper.d.ts.map +0 -1
- package/dist/hq/persistence/event-log.d.ts.map +0 -1
- package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
- package/dist/hq/persistence/simple-log.d.ts.map +0 -1
- package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
- package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
- package/dist/hq/persistence.d.ts.map +0 -1
- package/dist/hq/protocol/brain.d.ts.map +0 -1
- package/dist/hq/protocol/browser.d.ts.map +0 -1
- package/dist/hq/protocol/client.d.ts.map +0 -1
- package/dist/hq/protocol/core.d.ts.map +0 -1
- package/dist/hq/protocol/fleet.d.ts.map +0 -1
- package/dist/hq/protocol/kanban.d.ts.map +0 -1
- package/dist/hq/protocol/mailbox.d.ts.map +0 -1
- package/dist/hq/protocol/mcp.d.ts.map +0 -1
- package/dist/hq/protocol/peer.d.ts.map +0 -1
- package/dist/hq/protocol/project.d.ts.map +0 -1
- package/dist/hq/protocol/resume.d.ts.map +0 -1
- package/dist/hq/protocol/session.d.ts.map +0 -1
- package/dist/hq/protocol/tool.d.ts.map +0 -1
- package/dist/hq/protocol.d.ts.map +0 -1
- package/dist/hq/publisher.d.ts.map +0 -1
- package/dist/hq/redaction.d.ts.map +0 -1
- package/dist/hq/session-bridge.d.ts.map +0 -1
- package/dist/hq/tool-bridge.d.ts.map +0 -1
- package/dist/hq/transcript-mapper.d.ts.map +0 -1
- package/dist/hq/worktree-bridge.d.ts.map +0 -1
- package/dist/hq/write-queues.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/infrastructure/context-manager.d.ts.map +0 -1
- package/dist/infrastructure/index.d.ts.map +0 -1
- package/dist/infrastructure/index.js.map +0 -7
- package/dist/infrastructure/logger.d.ts.map +0 -1
- package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
- package/dist/infrastructure/path-resolver.d.ts.map +0 -1
- package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
- package/dist/infrastructure/token-counter.d.ts.map +0 -1
- package/dist/kernel/container.d.ts.map +0 -1
- package/dist/kernel/events/agent-events.d.ts.map +0 -1
- package/dist/kernel/events/brain-events.d.ts.map +0 -1
- package/dist/kernel/events/file-events.d.ts.map +0 -1
- package/dist/kernel/events/fleet-events.d.ts.map +0 -1
- package/dist/kernel/events/memory-events.d.ts.map +0 -1
- package/dist/kernel/events/network-events.d.ts.map +0 -1
- package/dist/kernel/events/process-events.d.ts.map +0 -1
- package/dist/kernel/events/provider-events.d.ts.map +0 -1
- package/dist/kernel/events/sdd-events.d.ts.map +0 -1
- package/dist/kernel/events/session-events.d.ts.map +0 -1
- package/dist/kernel/events/tool-events.d.ts.map +0 -1
- package/dist/kernel/events/worktree-events.d.ts.map +0 -1
- package/dist/kernel/events.d.ts.map +0 -1
- package/dist/kernel/index.d.ts.map +0 -1
- package/dist/kernel/index.js.map +0 -7
- package/dist/kernel/pipeline.d.ts.map +0 -1
- package/dist/kernel/run-controller.d.ts.map +0 -1
- package/dist/kernel/tokens.d.ts.map +0 -1
- package/dist/mailbox-attach.d.ts.map +0 -1
- package/dist/middleware/collab-pause.d.ts.map +0 -1
- package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
- package/dist/models/codex-catalog.d.ts.map +0 -1
- package/dist/models/index.d.ts.map +0 -1
- package/dist/models/index.js.map +0 -7
- package/dist/models/llm-selector.d.ts.map +0 -1
- package/dist/models/mode-store.d.ts.map +0 -1
- package/dist/models/model-intelligence.d.ts.map +0 -1
- package/dist/models/model-router.d.ts.map +0 -1
- package/dist/models/models-registry.d.ts.map +0 -1
- package/dist/models/provider-model-resolve.d.ts.map +0 -1
- package/dist/notifications/index.d.ts.map +0 -1
- package/dist/notifications/index.js.map +0 -7
- package/dist/notifications/notifier-impl.d.ts.map +0 -1
- package/dist/notifications/notifier.d.ts.map +0 -1
- package/dist/notifications/types.d.ts.map +0 -1
- package/dist/observability/event-bridge.d.ts.map +0 -1
- package/dist/observability/health.d.ts.map +0 -1
- package/dist/observability/index.d.ts.map +0 -1
- package/dist/observability/index.js.map +0 -7
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/network-telemetry.d.ts.map +0 -1
- package/dist/observability/otel-tracer.d.ts.map +0 -1
- package/dist/observability/otlp-metrics.d.ts.map +0 -1
- package/dist/observability/otlp-traces.d.ts.map +0 -1
- package/dist/observability/process-telemetry.d.ts.map +0 -1
- package/dist/observability/prometheus.d.ts.map +0 -1
- package/dist/observability/redact-command.d.ts.map +0 -1
- package/dist/observability/tracer.d.ts.map +0 -1
- package/dist/plugin/api.d.ts.map +0 -1
- package/dist/plugin/config.d.ts.map +0 -1
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/index.js.map +0 -7
- package/dist/plugin/loader.d.ts.map +0 -1
- package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
- package/dist/plugins/chimera-plugin.d.ts.map +0 -1
- package/dist/plugins/prompts-plugin.d.ts.map +0 -1
- package/dist/plugins/review-claim-registry.d.ts.map +0 -1
- package/dist/plugins/review-context-builder.d.ts.map +0 -1
- package/dist/plugins/review-finding-commands.d.ts.map +0 -1
- package/dist/plugins/review-finding-integration.d.ts.map +0 -1
- package/dist/plugins/review-finding-parser.d.ts.map +0 -1
- package/dist/plugins/review-finding-store.d.ts.map +0 -1
- package/dist/plugins/review-finding-types.d.ts.map +0 -1
- package/dist/plugins/review-report-integration.d.ts.map +0 -1
- package/dist/plugins/review-report-store.d.ts.map +0 -1
- package/dist/plugins/review-report-types.d.ts.map +0 -1
- package/dist/plugins/review-types.d.ts.map +0 -1
- package/dist/plugins/skills-plugin.d.ts.map +0 -1
- package/dist/plugins/sync-plugin.d.ts.map +0 -1
- package/dist/prompts/index.d.ts.map +0 -1
- package/dist/prompts/prompt-installer.d.ts.map +0 -1
- package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
- package/dist/registry/index.d.ts.map +0 -1
- package/dist/registry/index.js.map +0 -7
- package/dist/registry/provider-registry.d.ts.map +0 -1
- package/dist/registry/slash-command-registry.d.ts.map +0 -1
- package/dist/registry/tool-registry.d.ts.map +0 -1
- package/dist/replay/hash.d.ts.map +0 -1
- package/dist/replay/index.d.ts.map +0 -1
- package/dist/replay/index.js.map +0 -7
- package/dist/replay/replay-provider-runner.d.ts.map +0 -1
- package/dist/security/capabilities.d.ts.map +0 -1
- package/dist/security/config-secrets.d.ts.map +0 -1
- package/dist/security/directory-permission-policy.d.ts.map +0 -1
- package/dist/security/directory-policy-schema.d.ts.map +0 -1
- package/dist/security/index.d.ts.map +0 -1
- package/dist/security/index.js.map +0 -7
- package/dist/security/kanban-boundary.d.ts.map +0 -1
- package/dist/security/permission-policy-schema.d.ts.map +0 -1
- package/dist/security/permission-policy.d.ts.map +0 -1
- package/dist/security/readonly-permission-policy.d.ts.map +0 -1
- package/dist/security/secret-scrubber.d.ts.map +0 -1
- package/dist/security/secret-vault.d.ts.map +0 -1
- package/dist/security/trust-boundary.d.ts.map +0 -1
- package/dist/security/yolo-risk.d.ts.map +0 -1
- package/dist/session-registry-atomic-file.d.ts.map +0 -1
- package/dist/session-registry-types.d.ts.map +0 -1
- package/dist/session-registry.d.ts.map +0 -1
- package/dist/skills/foreign-sources.d.ts.map +0 -1
- package/dist/skills/frontmatter.d.ts.map +0 -1
- package/dist/skills/github-fetcher.d.ts.map +0 -1
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js.map +0 -7
- package/dist/skills/limits.d.ts.map +0 -1
- package/dist/skills/manifest-store.d.ts.map +0 -1
- package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
- package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
- package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
- package/dist/skills/skill-generator.d.ts.map +0 -1
- package/dist/skills/skill-installer.d.ts.map +0 -1
- package/dist/storage/annotations-store.d.ts.map +0 -1
- package/dist/storage/attachment-store.d.ts.map +0 -1
- package/dist/storage/cloud-sync.d.ts.map +0 -1
- package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
- package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
- package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
- package/dist/storage/config-loader/defaults.d.ts.map +0 -1
- package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
- package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
- package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
- package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
- package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
- package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
- package/dist/storage/config-loader/types.d.ts.map +0 -1
- package/dist/storage/config-loader/validation.d.ts.map +0 -1
- package/dist/storage/config-loader.d.ts.map +0 -1
- package/dist/storage/config-migration.d.ts.map +0 -1
- package/dist/storage/config-store.d.ts.map +0 -1
- package/dist/storage/director-state.d.ts.map +0 -1
- package/dist/storage/file-session-writer.d.ts.map +0 -1
- package/dist/storage/goal-coordination.d.ts.map +0 -1
- package/dist/storage/goal-kanban.d.ts.map +0 -1
- package/dist/storage/goal-store.d.ts.map +0 -1
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js.map +0 -7
- package/dist/storage/input-history-store.d.ts.map +0 -1
- package/dist/storage/memory-backend.d.ts.map +0 -1
- package/dist/storage/memory-consolidator.d.ts.map +0 -1
- package/dist/storage/memory-graph-backend.d.ts.map +0 -1
- package/dist/storage/plan-store.d.ts.map +0 -1
- package/dist/storage/plan-templates.d.ts.map +0 -1
- package/dist/storage/prompt-store.d.ts.map +0 -1
- package/dist/storage/prompt-usage-store.d.ts.map +0 -1
- package/dist/storage/provider-config-watcher.d.ts.map +0 -1
- package/dist/storage/queue-store.d.ts.map +0 -1
- package/dist/storage/recovery-lock.d.ts.map +0 -1
- package/dist/storage/replay-log-store.d.ts.map +0 -1
- package/dist/storage/session-analyzer.d.ts.map +0 -1
- package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
- package/dist/storage/session-event-bridge.d.ts.map +0 -1
- package/dist/storage/session-helpers.d.ts.map +0 -1
- package/dist/storage/session-id-resolver.d.ts.map +0 -1
- package/dist/storage/session-id.d.ts.map +0 -1
- package/dist/storage/session-read-scrubber.d.ts.map +0 -1
- package/dist/storage/session-reader.d.ts.map +0 -1
- package/dist/storage/session-recovery.d.ts.map +0 -1
- package/dist/storage/session-resume-validation.d.ts.map +0 -1
- package/dist/storage/session-rewind-apply.d.ts.map +0 -1
- package/dist/storage/session-rewinder.d.ts.map +0 -1
- package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
- package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
- package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
- package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
- package/dist/storage/session-store/events.d.ts.map +0 -1
- package/dist/storage/session-store/fork-session.d.ts.map +0 -1
- package/dist/storage/session-store/index-reader.d.ts.map +0 -1
- package/dist/storage/session-store/load-cache.d.ts.map +0 -1
- package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
- package/dist/storage/session-store/paths.d.ts.map +0 -1
- package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
- package/dist/storage/session-store/replay.d.ts.map +0 -1
- package/dist/storage/session-store/search-events.d.ts.map +0 -1
- package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
- package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
- package/dist/storage/session-store/summary-header.d.ts.map +0 -1
- package/dist/storage/session-store/types.d.ts.map +0 -1
- package/dist/storage/session-store.d.ts.map +0 -1
- package/dist/storage/session-summary.d.ts.map +0 -1
- package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
- package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
- package/dist/storage/session-writer-truncate.d.ts.map +0 -1
- package/dist/storage/storage-concurrency.d.ts.map +0 -1
- package/dist/storage/task-store.d.ts.map +0 -1
- package/dist/storage/todos-checkpoint.d.ts.map +0 -1
- package/dist/storage/tool-audit-log.d.ts.map +0 -1
- package/dist/tasking/index.d.ts.map +0 -1
- package/dist/tasking/index.js.map +0 -7
- package/dist/tasking/task-store.d.ts.map +0 -1
- package/dist/tasking/task-tracker.d.ts.map +0 -1
- package/dist/tools/council-tool.d.ts.map +0 -1
- package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
- package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
- package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
- package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
- package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
- package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
- package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
- package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -7
- package/dist/tools/mcp-control.d.ts.map +0 -1
- package/dist/tools/mcp-use.d.ts.map +0 -1
- package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
- package/dist/tools/plugin-manager.d.ts.map +0 -1
- package/dist/types/agent-bridge.d.ts.map +0 -1
- package/dist/types/attachment.d.ts.map +0 -1
- package/dist/types/autonomy.d.ts.map +0 -1
- package/dist/types/blocks.d.ts.map +0 -1
- package/dist/types/compactor.d.ts.map +0 -1
- package/dist/types/config/autonomy.d.ts.map +0 -1
- package/dist/types/config/context.d.ts.map +0 -1
- package/dist/types/config/fleet-chat.d.ts.map +0 -1
- package/dist/types/config/mcp-features.d.ts.map +0 -1
- package/dist/types/config/providers.d.ts.map +0 -1
- package/dist/types/config/root.d.ts.map +0 -1
- package/dist/types/config/runtime.d.ts.map +0 -1
- package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
- package/dist/types/config/tools.d.ts.map +0 -1
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/context-evidence.d.ts.map +0 -1
- package/dist/types/context-window.d.ts.map +0 -1
- package/dist/types/council.d.ts.map +0 -1
- package/dist/types/default-config.d.ts.map +0 -1
- package/dist/types/design-kit.d.ts.map +0 -1
- package/dist/types/error-handler.d.ts.map +0 -1
- package/dist/types/errors.d.ts.map +0 -1
- package/dist/types/file-event-record.d.ts.map +0 -1
- package/dist/types/hooks.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -7
- package/dist/types/input-reader.d.ts.map +0 -1
- package/dist/types/logger.d.ts.map +0 -1
- package/dist/types/memory.d.ts.map +0 -1
- package/dist/types/messages.d.ts.map +0 -1
- package/dist/types/mode-prompts.d.ts.map +0 -1
- package/dist/types/mode.d.ts.map +0 -1
- package/dist/types/models-registry.d.ts.map +0 -1
- package/dist/types/multi-agent.d.ts.map +0 -1
- package/dist/types/observability.d.ts.map +0 -1
- package/dist/types/one-shot-llm.d.ts.map +0 -1
- package/dist/types/path-resolver.d.ts.map +0 -1
- package/dist/types/permission.d.ts.map +0 -1
- package/dist/types/plugin.d.ts.map +0 -1
- package/dist/types/prompt-registry.d.ts.map +0 -1
- package/dist/types/prompt.d.ts.map +0 -1
- package/dist/types/provider-runner.d.ts.map +0 -1
- package/dist/types/provider.d.ts.map +0 -1
- package/dist/types/quota-regex.d.ts.map +0 -1
- package/dist/types/renderer.d.ts.map +0 -1
- package/dist/types/retry-policy.d.ts.map +0 -1
- package/dist/types/secret-scrubber.d.ts.map +0 -1
- package/dist/types/secret-vault.d.ts.map +0 -1
- package/dist/types/selector.d.ts.map +0 -1
- package/dist/types/session-markers.d.ts.map +0 -1
- package/dist/types/session-markers.js.map +0 -7
- package/dist/types/session-reader.d.ts.map +0 -1
- package/dist/types/session-rewinder.d.ts.map +0 -1
- package/dist/types/session.d.ts.map +0 -1
- package/dist/types/side-effect.d.ts.map +0 -1
- package/dist/types/skill.d.ts.map +0 -1
- package/dist/types/slash-command.d.ts.map +0 -1
- package/dist/types/spec.d.ts.map +0 -1
- package/dist/types/system-prompt-contributor.d.ts.map +0 -1
- package/dist/types/system-prompt.d.ts.map +0 -1
- package/dist/types/task-graph.d.ts.map +0 -1
- package/dist/types/token-counter.d.ts.map +0 -1
- package/dist/types/tool-executor.d.ts.map +0 -1
- package/dist/types/tool-markers.d.ts.map +0 -1
- package/dist/types/tool.d.ts.map +0 -1
- package/dist/types/utility-types.d.ts.map +0 -1
- package/dist/utils/assert-never.d.ts.map +0 -1
- package/dist/utils/atomic-write.d.ts.map +0 -1
- package/dist/utils/cache-key.d.ts.map +0 -1
- package/dist/utils/child-env.d.ts.map +0 -1
- package/dist/utils/color.d.ts.map +0 -1
- package/dist/utils/compaction-preview.d.ts.map +0 -1
- package/dist/utils/config-backup.d.ts.map +0 -1
- package/dist/utils/config-json.d.ts.map +0 -1
- package/dist/utils/connectivity.d.ts.map +0 -1
- package/dist/utils/context-breakdown.d.ts.map +0 -1
- package/dist/utils/context-evidence.d.ts.map +0 -1
- package/dist/utils/continuous-memory-profiler.d.ts.map +0 -1
- package/dist/utils/crash-shield.d.ts.map +0 -1
- package/dist/utils/deep-merge.d.ts.map +0 -1
- package/dist/utils/diff.d.ts.map +0 -1
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -7
- package/dist/utils/expect-defined.d.ts.map +0 -1
- package/dist/utils/expect-defined.js.map +0 -7
- package/dist/utils/glob-expand.d.ts.map +0 -1
- package/dist/utils/glob-match.d.ts.map +0 -1
- package/dist/utils/heap-watchdog-types.d.ts.map +0 -1
- package/dist/utils/heap-watchdog.d.ts.map +0 -1
- package/dist/utils/heap-watchdog.js.map +0 -7
- package/dist/utils/incoming-images.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -7
- package/dist/utils/instruction-file.d.ts.map +0 -1
- package/dist/utils/ip-guard.d.ts.map +0 -1
- package/dist/utils/json-repair.d.ts.map +0 -1
- package/dist/utils/json-schema-validate.d.ts.map +0 -1
- package/dist/utils/lru-cache.d.ts.map +0 -1
- package/dist/utils/memory-flight-recorder.d.ts.map +0 -1
- package/dist/utils/merge-custom-models.d.ts.map +0 -1
- package/dist/utils/merge-models-payload.d.ts.map +0 -1
- package/dist/utils/message-invariants.d.ts.map +0 -1
- package/dist/utils/newline-normalize.d.ts.map +0 -1
- package/dist/utils/perf-profile.d.ts.map +0 -1
- package/dist/utils/pid.d.ts.map +0 -1
- package/dist/utils/project-identity.d.ts.map +0 -1
- package/dist/utils/project-watch.d.ts.map +0 -1
- package/dist/utils/regex-guard.d.ts.map +0 -1
- package/dist/utils/safe-json.d.ts.map +0 -1
- package/dist/utils/sage-output-block.d.ts.map +0 -1
- package/dist/utils/session-scoped-path.d.ts.map +0 -1
- package/dist/utils/sleep.d.ts.map +0 -1
- package/dist/utils/slug.d.ts.map +0 -1
- package/dist/utils/socket-path.d.ts.map +0 -1
- package/dist/utils/sqlite-warning.d.ts.map +0 -1
- package/dist/utils/string.d.ts.map +0 -1
- package/dist/utils/task-format.d.ts.map +0 -1
- package/dist/utils/term.d.ts.map +0 -1
- package/dist/utils/todos-format.d.ts.map +0 -1
- package/dist/utils/token-estimate.d.ts.map +0 -1
- package/dist/utils/tool-description-mode.d.ts.map +0 -1
- package/dist/utils/tool-name.d.ts.map +0 -1
- package/dist/utils/tool-output-serializer.d.ts.map +0 -1
- package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
- package/dist/utils/tool-subject.d.ts.map +0 -1
- package/dist/utils/tool-wire-compact.d.ts.map +0 -1
- package/dist/utils/tree-kill.d.ts.map +0 -1
- package/dist/utils/tree-kill.js.map +0 -7
- package/dist/utils/ulid.d.ts.map +0 -1
- package/dist/utils/walk-ignore.d.ts.map +0 -1
- package/dist/utils/wstack-paths.d.ts.map +0 -1
- package/dist/worktree/index.d.ts.map +0 -1
- package/dist/worktree/index.js.map +0 -7
- package/dist/worktree/worktree-git.d.ts.map +0 -1
- package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
- package/dist/worktree/worktree-manager.d.ts.map +0 -1
- package/dist/worktree/worktree-types.d.ts.map +0 -1
package/dist/hq/index.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/hq/protocol/tool.ts", "../../src/hq/protocol/kanban.ts", "../../src/hq/protocol/peer.ts", "../../src/hq/protocol/resume.ts", "../../src/hq/protocol/core.ts", "../../src/hq/publisher.ts", "../../src/coordination/mailbox-types.ts", "../../src/security/secret-scrubber.ts", "../../src/hq/redaction.ts", "../../src/hq/mailbox-mapper.ts", "../../src/hq/factory.ts", "../../src/utils/project-identity.ts", "../../src/utils/atomic-write.ts", "../../src/types/errors.ts", "../../src/utils/ulid.ts", "../../src/hq/auth-store.ts", "../../src/utils/wstack-paths.ts", "../../src/hq/auth-audit.ts", "../../src/hq/session-bridge.ts", "../../src/utils/session-scoped-path.ts", "../../src/types/session-markers.ts", "../../src/hq/transcript-mapper.ts", "../../src/hq/bridge-context.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/kanban-store.ts", "../../src/hq/write-queues.ts", "../../src/hq/persistence/event-log.ts", "../../src/hq/persistence/jsonl-io.ts", "../../src/hq/persistence/simple-log.ts", "../../src/hq/persistence/snapshot-store.ts", "../../src/hq/persistence/timeseries-store.ts", "../../src/hq/persistence.ts", "../../src/hq/commands.ts", "../../src/hq/alerts.ts", "../../src/hq/bootstrap-store.ts", "../../src/hq/exposure.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", "const HQ_KANBAN_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;\nconst MAX_HQ_KANBAN_BOARDS = 250;\nconst MAX_HQ_KANBAN_BOARD_BYTES = 750_000;\n\nexport interface HqKanbanBoardRecord {\n boardId: string;\n revision: number;\n updatedAt: string;\n /** Opaque KanbanBoard JSON. Kept in core so @wrongstack/kanban remains standalone. */\n board: Record<string, unknown>;\n}\n\nexport interface HqKanbanTombstone {\n boardId: string;\n revision: number;\n deletedAt: string;\n}\n\n/** Complete project state emitted by one client. Missing boards are not deletions. */\nexport interface HqKanbanSnapshotPayload {\n projectId: string;\n generatedAt: string;\n boards: HqKanbanBoardRecord[];\n tombstones: HqKanbanTombstone[];\n}\n\n/** Server-to-client snapshot after HQ has merged all known project writers. */\nexport interface HqServerKanbanSnapshotMessage {\n type: 'hq.kanban_snapshot';\n payload: HqKanbanSnapshotPayload;\n}\n\nexport function isHqKanbanSnapshotPayload(value: unknown): value is HqKanbanSnapshotPayload {\n if (typeof value !== 'object' || value === null) return false;\n const payload = value as Record<string, unknown>;\n if (\n typeof payload.projectId !== 'string' ||\n payload.projectId.length === 0 ||\n typeof payload.generatedAt !== 'string' ||\n !Number.isFinite(Date.parse(payload.generatedAt)) ||\n !Array.isArray(payload.boards) ||\n !Array.isArray(payload.tombstones) ||\n payload.boards.length > MAX_HQ_KANBAN_BOARDS ||\n payload.tombstones.length > MAX_HQ_KANBAN_BOARDS\n ) {\n return false;\n }\n\n const seen = new Set<string>();\n for (const item of payload.boards) {\n if (!isBoardRecord(item) || seen.has(item.boardId)) return false;\n seen.add(item.boardId);\n }\n for (const item of payload.tombstones) {\n if (!isTombstone(item) || seen.has(item.boardId)) return false;\n seen.add(item.boardId);\n }\n return true;\n}\n\nfunction isBoardRecord(value: unknown): value is HqKanbanBoardRecord {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Record<string, unknown>;\n if (\n typeof record.boardId !== 'string' ||\n !HQ_KANBAN_ID_PATTERN.test(record.boardId) ||\n typeof record.revision !== 'number' ||\n !Number.isSafeInteger(record.revision) ||\n record.revision < 0 ||\n typeof record.updatedAt !== 'string' ||\n !Number.isFinite(Date.parse(record.updatedAt)) ||\n typeof record.board !== 'object' ||\n record.board === null ||\n Array.isArray(record.board)\n ) {\n return false;\n }\n const board = record.board as Record<string, unknown>;\n if (board.id !== record.boardId) return false;\n try {\n return new TextEncoder().encode(JSON.stringify(board)).byteLength <= MAX_HQ_KANBAN_BOARD_BYTES;\n } catch {\n return false;\n }\n}\n\nfunction isTombstone(value: unknown): value is HqKanbanTombstone {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Record<string, unknown>;\n return (\n typeof record.boardId === 'string' &&\n HQ_KANBAN_ID_PATTERN.test(record.boardId) &&\n typeof record.revision === 'number' &&\n Number.isSafeInteger(record.revision) &&\n record.revision >= 0 &&\n typeof record.deletedAt === 'string' &&\n Number.isFinite(Date.parse(record.deletedAt))\n );\n}\n", "/**\n * Peer lifecycle envelopes \u2014 broadcast from the HQ server to surviving clients\n * when a project's leader session terminates. Carries no runnable command by\n * default; the broadcast is informational. The envelope is piggybacked on\n * the existing client WS channel via `client.command_poll` (per\n * `docs/plans/hq-evolution-2026-08.md` \u00A710.1).\n *\n * Two event types:\n * - `peer.rehydrate` \u2014 the project lost its leader AND has at least one\n * surviving client. Envelope carries project id, machine id, leader\n * client id, reason, and an opaque `rehydrateHint` (\u2264 280 chars).\n * - `peer.lost` \u2014 the project lost its leader AND has no surviving clients.\n * Envelope is informational; the server still emits it so the cockpit and\n * any future reconnecting client can see the leader is gone.\n *\n * Both events are v1-protocol additive (no `protocolVersion: 2` bump required).\n *\n * @module hq/protocol/peer\n */\n\nexport type HqPeerRehydrateReason =\n | 'graceful'\n | 'crash'\n | 'heartbeat-timeout'\n | 'auth-revoked';\n\nexport const HQ_PEER_REHYDRATE_REASONS = new Set<HqPeerRehydrateReason>([\n 'graceful',\n 'crash',\n 'heartbeat-timeout',\n 'auth-revoked',\n]);\n\n/** Maximum length of the opaque `rehydrateHint` field. */\nexport const HQ_PEER_REHYDRATE_HINT_MAX_CHARS = 280;\n\n/**\n * Synthetic `clientId` the HQ server uses on `peer.rehydrate` / `peer.lost`\n * envelopes. It is *not* a real publisher identity \u2014 it identifies the\n * browser-side cursor bucket the dashboard uses to dedupe / replay peer\n * lifecycle envelopes across reconnects. Both the server (`hq-server/ws.ts`)\n * and the browser (`webui-hq`) must agree on this literal; hoisting it here\n * keeps a single source of truth.\n */\nexport const HQ_BROWSER_PEER_RESUME_CLIENT_ID = '__hq_peer__';\n\nexport interface HqPeerRehydratePayload {\n projectId: string;\n machineId: string;\n leaderClientId: string;\n previousLeaderHandle: string;\n reason: HqPeerRehydrateReason;\n detectedAt: string;\n /** Opaque, project-specific. Client decides what to do with it. */\n rehydrateHint?: string;\n /** Optional, only if the previous leader explicitly registered a command. */\n rehydrateCommandId?: string;\n}\n\nexport interface HqPeerLostPayload {\n projectId: string;\n machineId: string;\n leaderClientId: string;\n previousLeaderHandle: string;\n reason: HqPeerRehydrateReason;\n detectedAt: string;\n}\n\nfunction isStringOrUndefined(x: unknown): x is string | undefined {\n return x === undefined || typeof x === 'string';\n}\n\nexport function isHqPeerRehydratePayload(x: unknown): x is HqPeerRehydratePayload {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.projectId !== 'string' || v.projectId.length === 0) return false;\n if (typeof v.machineId !== 'string' || v.machineId.length === 0) return false;\n if (typeof v.leaderClientId !== 'string' || v.leaderClientId.length === 0) return false;\n if (typeof v.previousLeaderHandle !== 'string' || v.previousLeaderHandle.length === 0) return false;\n if (typeof v.reason !== 'string' || !HQ_PEER_REHYDRATE_REASONS.has(v.reason as HqPeerRehydrateReason)) return false;\n if (typeof v.detectedAt !== 'string' || !Number.isFinite(Date.parse(v.detectedAt))) return false;\n if (!isStringOrUndefined(v.rehydrateHint)) return false;\n if (v.rehydrateHint !== undefined && v.rehydrateHint.length > HQ_PEER_REHYDRATE_HINT_MAX_CHARS) return false;\n if (!isStringOrUndefined(v.rehydrateCommandId)) return false;\n return true;\n}\n\nexport function isHqPeerLostPayload(x: unknown): x is HqPeerLostPayload {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.projectId !== 'string' || v.projectId.length === 0) return false;\n if (typeof v.machineId !== 'string' || v.machineId.length === 0) return false;\n if (typeof v.leaderClientId !== 'string' || v.leaderClientId.length === 0) return false;\n if (typeof v.previousLeaderHandle !== 'string' || v.previousLeaderHandle.length === 0) return false;\n if (typeof v.reason !== 'string' || !HQ_PEER_REHYDRATE_REASONS.has(v.reason as HqPeerRehydrateReason)) return false;\n if (typeof v.detectedAt !== 'string' || !Number.isFinite(Date.parse(v.detectedAt))) return false;\n return true;\n}\n", "/**\n * Sync ladder \u2014 server \u2192 client resume envelopes.\n *\n * Triggered when a client reconnects after a network interruption and sends\n * `client.resume { lastSeqSeen }`. The server replies with one of:\n * - `hq.resume_gap` \u2014 bounded list of missed envelopes from the event log.\n * - `hq.snapshot` \u2014 full snapshot when the gap is too large (>1000 envelopes\n * or >24 h stale) or when the event log cannot serve the gap.\n *\n * The envelope is additively v1; existing v1 clients ignore unknown types.\n *\n * See `docs/plans/hq-evolution-2026-08.md` \u00A72.5 and \u00A77.\n *\n * @module hq/protocol/resume\n */\n\nimport type { HqEventEnvelope } from './core.js';\n\n/** Maximum envelopes per `hq.resume_gap` reply. */\nexport const HQ_RESUME_GAP_MAX_ENVELOPES = 1000;\n\n/** Maximum bytes per `hq.resume_gap` reply (sum of `JSON.stringify(envelope).byteLength`). */\nexport const HQ_RESUME_GAP_MAX_BYTES = 1_048_576; // 1 MiB;\n\n/** Maximum age of `lastSeqSeen` for which the gap-fill route is acceptable. */\nexport const HQ_RESUME_GAP_MAX_STALE_MS = 24 * 60 * 60 * 1000; // 24 h.\n\n/**\n * Server-to-client gap-fill envelope. The server reads the unbounded\n * `HqEventLog` for envelopes with `(clientId, seq) > lastSeqSeen` and\n * returns them capped at `{HQ_RESUME_GAP_MAX_ENVELOPES}` items and\n * `{HQ_RESUME_GAP_MAX_BYTES}` bytes. The client is expected to dedupe\n * on `envelope.id` (already in the `HqEventEnvelope` shape).\n */\nexport interface HqResumeGapMessage {\n type: 'hq.resume_gap';\n /** The `lastSeqSeen` the client reported on `client.resume`. */\n lastSeqSeen: number;\n /** Envelopes the client missed. Bounded by the limits above. */\n envelopes: readonly HqEventEnvelope[];\n /** True when the response was capped; the client should request a snapshot. */\n truncated: boolean;\n}\n\n/**\n * Server-to-client resume indicator. The server uses this to tell the\n * client why the gap-fill could not be served (e.g. snapshotted instead).\n */\nexport interface HqResumeRejectMessage {\n type: 'hq.resume_reject';\n reason: 'gap_too_large' | 'last_seen_too_old' | 'log_unavailable';\n /** ISO timestamp the server received the resume. */\n detectedAt: string;\n}\n\nexport type HqResumeMessage = HqResumeGapMessage | HqResumeRejectMessage;\n\n/**\n * Returns `true` if `envelope` is a `HqResumeGapMessage` with valid shape.\n * Defensive against malformed payloads from misbehaving servers.\n */\nexport function isHqResumeGapMessage(x: unknown): x is HqResumeGapMessage {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n if (v.type !== 'hq.resume_gap') return false;\n if (!Number.isSafeInteger(v.lastSeqSeen) || (v.lastSeqSeen as number) < 0) return false;\n if (!Array.isArray(v.envelopes)) return false;\n if (v.envelopes.length > HQ_RESUME_GAP_MAX_ENVELOPES) return false;\n if (typeof v.truncated !== 'boolean') return false;\n return true;\n}\n\nexport function isHqResumeRejectMessage(x: unknown): x is HqResumeRejectMessage {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n if (v.type !== 'hq.resume_reject') return false;\n if (\n v.reason !== 'gap_too_large' &&\n v.reason !== 'last_seen_too_old' &&\n v.reason !== 'log_unavailable'\n ) {\n return false;\n }\n if (typeof v.detectedAt !== 'string' || !Number.isFinite(Date.parse(v.detectedAt))) return false;\n return true;\n}\n", "import type {\n HqClientCapability,\n HqClientCommandAckMessage,\n HqClientCommandPollMessage,\n HqClientHelloPayload,\n HqClientHeartbeatPayload,\n HqClientIdentity,\n HqClientKind,\n HqClientMessage,\n HqClientResumeMessage,\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 { isHqKanbanSnapshotPayload, type HqServerKanbanSnapshotMessage } from './kanban.js';\nimport { isHqPeerLostPayload, isHqPeerRehydratePayload } from './peer.js';\nimport type { HqResumeMessage } from './resume.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 | 'kanban.snapshot'\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 | 'peer.rehydrate'\n | 'peer.lost';\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 =\n | HqServerCommandBatchMessage\n | HqServerKanbanSnapshotMessage\n | HqWelcomePayload\n | HqResumeMessage;\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 'client.resume',\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\nfunction isHqClientResumeMessage(x: unknown): x is HqClientResumeMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.type === 'string' &&\n v.type === 'client.resume' &&\n Number.isSafeInteger(v.lastSeqSeen) &&\n (v.lastSeqSeen as number) >= 0 &&\n (v.clientId === undefined || typeof v.clientId === 'string') &&\n (v.projectId === undefined || typeof v.projectId === '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 case 'client.resume':\n if (!isHqClientResumeMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.resume',\n lastSeqSeen: obj.lastSeqSeen,\n ...(typeof obj.clientId === 'string' ? { clientId: obj.clientId } : {}),\n ...(typeof obj.projectId === 'string' ? { projectId: obj.projectId } : {}),\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 'kanban.snapshot',\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 'peer.rehydrate',\n 'peer.lost',\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 'kanban.snapshot':\n return isHqKanbanSnapshotPayload(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 case 'peer.rehydrate':\n return isHqPeerRehydratePayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'peer.lost':\n return isHqPeerLostPayload(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 { randomUUID } from 'node:crypto';\nimport * as v8 from 'node:v8';\nimport type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport type { Logger } from '../types/logger.js';\nimport {\n createMailboxEventPayload,\n createMailboxSnapshotPayloadFromMailbox,\n type HqMailboxEventAction,\n type HqMailboxSnapshotOptions,\n} from './mailbox-mapper.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 HqKanbanSnapshotPayload,\n type HqMailboxEventPayload,\n type HqMailboxSnapshotPayload,\n type HqProjectIdentity,\n type HqQueuedCommand,\n type HqRedactionPolicy,\n type HqServerCommandBatchMessage,\n type HqServerKanbanSnapshotMessage,\n type HqSessionEndedPayload,\n type HqSessionSnapshotPayload,\n type HqTranscriptAppendPayload,\n} from './protocol.js';\nimport { redactHqEvent, resolveHqRedactionPolicy } from './redaction.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 /** Hard byte cap on the outbound queue (prevents RAM blow-up when HQ is\n * offline). Older frames are dropped oldest-first when exceeded. The default\n * is heap-relative: `min(16 MiB, heap_limit * 0.10)` \u2014 see `DEFAULT_MAX_QUEUED_BYTES`. */\n maxQueuedBytes?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n commandPollIntervalMs?: number;\n commandPollLimit?: number;\n onCommand?: HqPublisherCommandHandler;\n /** Called whenever HQ sends the merged Kanban state for this project. */\n onKanbanSnapshot?: (snapshot: HqKanbanSnapshotPayload) => void | Promise<void>;\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/**\n * Hard byte cap on the enqueue to prevent unbounded RAM growth when HQ is offline.\n *\n * Heap-relative: `min(16 MiB, heap_limit * 0.10)`. The lower bound keeps the cap\n * small in typical V8 configurations (e.g. ~512 MiB limit \u2192 16 MiB cap), while\n * the upper bound prevents the cap from exceeding 10 % of the V8 heap limit in\n * small-container or `--max-old-space-size` scenarios. Operators can override\n * via the `maxQueuedBytes` option \u2014 the override takes precedence over this\n * default and is the right escape hatch for long offline periods.\n */\nconst DEFAULT_MAX_QUEUED_BYTES = Math.min(\n 16 * 1024 * 1024,\n Math.floor(v8.getHeapStatistics().heap_size_limit * 0.1),\n);\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\ninterface QueuedFrame {\n serialized: string;\n bytes: number;\n /**\n * State snapshots are rollups: while offline, only the newest snapshot for\n * a scope has value. Event/transcript frames intentionally have no key and\n * retain FIFO semantics.\n */\n coalesceKey?: string | undefined;\n}\n\nfunction queuedFrameCoalesceKey(\n frame:\n | HqClientHelloMessage\n | HqClientEventMessage\n | HqClientCommandPollMessage\n | HqClientCommandAckMessage,\n): string | undefined {\n if (frame.type !== 'client.event' || !frame.event.type.endsWith('.snapshot')) {\n return undefined;\n }\n return [frame.event.type, frame.event.sessionId ?? '', frame.event.runId ?? ''].join('|');\n}\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 maxQueuedBytes: 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: QueuedFrame[] = [];\n private queueBytes = 0;\n /**\n * Cumulative count of frames dropped by the bounded outbound queue when the\n * count/byte cap is exceeded while HQ is unreachable. Lifetime statistic \u2014\n * intentionally NOT reset on close()/reconnect, so it reflects total\n * telemetry loss to overflow for this publisher instance.\n */\n private droppedFrames = 0;\n /** Cumulative UTF-8 bytes of frames dropped on overflow (see droppedFrames). */\n private droppedBytes = 0;\n /** Obsolete state snapshots replaced in-place while HQ was unreachable. */\n private coalescedFrames = 0;\n /** UTF-8 bytes released by snapshot coalescing. */\n private coalescedBytes = 0;\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.maxQueuedBytes = options.maxQueuedBytes ?? DEFAULT_MAX_QUEUED_BYTES;\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 // HQ traffic is best-effort telemetry: a failed message (e.g. transient\n // Windows EPERM while a kanban board is being renamed under a reader)\n // must degrade to a warning, never an unhandled rejection that kills\n // the host process.\n this.handleServerMessage(event).catch((error: unknown) => {\n const message = `WrongStack HQ publisher: server message handling failed: ${\n error instanceof Error ? error.message : String(error)\n }`;\n if (this.logger) {\n this.logger.warn(message, { event: 'hq.publisher.message_failed' });\n return;\n }\n process.emitWarning(message, { code: 'WRONGSTACK_HQ_MESSAGE_FAILED' });\n });\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 this.queueBytes = 0;\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 /** Current outbound queue pressure \u2014 useful for flow control in telemetry bridges. */\n getQueueStats(): {\n entries: number;\n bytes: number;\n maxBytes: number;\n droppedFrames: number;\n droppedBytes: number;\n coalescedFrames: number;\n coalescedBytes: number;\n } {\n return {\n entries: this.queue.length,\n bytes: this.queueBytes,\n maxBytes: this.maxQueuedBytes,\n droppedFrames: this.droppedFrames,\n droppedBytes: this.droppedBytes,\n coalescedFrames: this.coalescedFrames,\n coalescedBytes: this.coalescedBytes,\n };\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, queuedFrameCoalesceKey(frame));\n this.connect();\n }\n\n private enqueue(serialized: string, coalesceKey?: string): void {\n const bytes = Buffer.byteLength(serialized, 'utf8');\n // A single pathological snapshot must not bypass the total byte cap just\n // because the queue is empty. It is telemetry, so fail closed and let the\n // next (usually smaller) rollup supersede it.\n if (bytes > this.maxQueuedBytes) {\n this.droppedFrames += 1;\n this.droppedBytes += bytes;\n return;\n }\n\n if (coalesceKey !== undefined) {\n let existingIndex = -1;\n for (let index = this.queue.length - 1; index >= 0; index -= 1) {\n if (this.queue[index]?.coalesceKey === coalesceKey) {\n existingIndex = index;\n break;\n }\n }\n if (existingIndex !== -1) {\n const [obsolete] = this.queue.splice(existingIndex, 1);\n if (obsolete !== undefined) {\n this.queueBytes -= obsolete.bytes;\n this.coalescedFrames += 1;\n this.coalescedBytes += obsolete.bytes;\n }\n }\n }\n\n // Drop oldest frames when either the count cap or the byte cap is\n // exceeded. The byte cap prevents unbounded RAM growth during extended\n // HQ outages while the count cap limits per-frame overhead.\n while (\n (this.queue.length >= this.maxQueuedMessages ||\n this.queueBytes + bytes > this.maxQueuedBytes) &&\n this.queue.length > 0\n ) {\n const dropped = this.queue.shift();\n if (dropped !== undefined) {\n this.queueBytes -= dropped.bytes;\n this.droppedFrames += 1;\n this.droppedBytes += dropped.bytes;\n }\n }\n this.queue.push({ serialized, bytes, coalesceKey });\n this.queueBytes += bytes;\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) {\n socket.send(frame.serialized);\n this.queueBytes -= frame.bytes;\n }\n this.queueBytes = Math.max(0, this.queueBytes);\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') {\n await this.handleCommandBatch(message);\n return;\n }\n if (message?.type === 'hq.kanban_snapshot') {\n await this.options.onKanbanSnapshot?.(message.payload);\n }\n }\n\n private parseServerMessage(\n event: unknown,\n ): HqServerCommandBatchMessage | HqServerKanbanSnapshotMessage | null {\n const data = this.extractMessageData(event);\n if (data === null) return null;\n try {\n const parsed = JSON.parse(data) as\n | Partial<HqServerCommandBatchMessage>\n | Partial<HqServerKanbanSnapshotMessage>;\n if (parsed.type === 'hq.command_batch' && Array.isArray(parsed.commands)) {\n return parsed as HqServerCommandBatchMessage;\n }\n if (parsed.type === 'hq.kanban_snapshot') {\n const payload = (parsed as Partial<HqServerKanbanSnapshotMessage>).payload;\n if (\n payload !== undefined &&\n typeof payload === 'object' &&\n typeof payload.projectId === 'string' &&\n payload.projectId === this.options.project.projectId &&\n Array.isArray(payload.boards) &&\n Array.isArray(payload.tombstones)\n ) {\n return parsed as HqServerKanbanSnapshotMessage;\n }\n }\n return null;\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 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 // Advance the poll cursor only AFTER the command is handled and acked.\n // Advancing it before `await handler` meant a socket flap mid-handler\n // left the next command_poll asking for commands AFTER this one \u2014 so an\n // operator command (steer/abort/broadcast) that never ran was silently\n // skipped and never re-fetched. At-least-once (a possible duplicate on\n // reconnect, which these commands tolerate) beats losing one outright.\n this.lastCommandId = command.commandId;\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", "/**\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.sqlite`, owned by one detached\n * project server and reached over IPC),\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\nimport {\n MAILBOX_TYPE_PROPERTIES,\n type MailboxMessageType,\n} from './mailbox-type-properties.js';\nexport {\n MAILBOX_TYPE_PROPERTIES,\n type MailboxMessageType,\n type MailboxTypeCategory,\n} from './mailbox-type-properties.js';\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). `Mailbox.getAgentStatuses()` derives\n * a registry snapshot from `status`-type messages as a fallback when no\n * shared registry file exists.\n * 8. **Request-scoped context**: delivered raw mailbox blocks are removed\n * after one successful provider evaluation. Durable assistant/tool/task\n * consequences remain; routine mail does not occupy later requests.\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\n/**\n * Which class of agent may consume a mailbox message.\n *\n * `leaders` is a delivery boundary, not merely a UI hint: agent-loop and\n * inbox readers must exclude these messages for subagents. The optional\n * persisted field keeps older JSONL records backwards-compatible (`all`).\n */\nexport type MailboxAudience = 'all' | 'leaders';\n\n/** Return the stable base portion of a session-qualified mailbox identity. */\nexport function mailboxIdentityBase(agentId: string): string {\n return agentId.split(/[@#]/, 1)[0]!.trim().toLowerCase();\n}\n\n/** Whether a mailbox identity belongs to the session's main/leader agent. */\nexport function isMailboxLeader(agentId: string, role?: string): boolean {\n return mailboxIdentityBase(agentId) === 'leader' || role?.trim().toLowerCase() === 'leader';\n}\n\n/** Whether a message may be consumed by the supplied agent identity. */\nexport function isMailboxMessageVisibleTo(\n message: Pick<MailboxMessage, 'audience'>,\n agentId: string,\n role?: string,\n): boolean {\n return message.audience !== 'leaders' || isMailboxLeader(agentId, role);\n}\n\n/** Category + expectsReply are provided by MAILBOX_TYPE_PROPERTIES directly. */\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 /** Delivery audience. Omitted legacy values mean `all`. */\n audience?: MailboxAudience | undefined;\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 Mailbox.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 /** Trusted caller role used with `unreadBy` for audience filtering. */\n readerRole?: string | undefined;\n /** Only incomplete messages. */\n incompleteOnly?: boolean | undefined;\n /**\n * Internal trusted-read option: retain folded per-actor receipt state so a\n * boundary can derive an actor-safe projection. Untrusted query codecs must\n * never accept this field from request payloads.\n */\n includeReceiptState?: 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 * Filter by replyTo parent message id (UUID). When set, only messages\n * whose `replyTo` exactly matches this value are returned. An empty\n * string matches nothing \u2014 empty strings are technically allowed by\n * `send()` (it passes through `MailboxSendInput.replyTo` directly with\n * no normalization), but are never produced by chimera/execution callers.\n * The query filter is exact-match.\n * Useful for polling the response to a specific `ask` message.\n */\n replyTo?: string | 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 /** Restrict consumption to main/leader agents. Default: `all`. */\n audience?: MailboxAudience | undefined;\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 * Per-message-type TTL overrides, consulted before `defaultTtlMs` for\n * messages with no explicit `expiresAt`. Keyed by `MailboxMessageType`.\n * Default: {@link AUTO_COMPACT_TYPE_TTL_MS} (transient `status` chatter\n * expires in 30 minutes instead of 24 hours).\n */\n typeTtlMs?: Readonly<Record<string, 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\nexport {\n expandMailboxCapabilities,\n hasMailboxCapability,\n MAILBOX_CAPABILITY_IMPLICATIONS,\n type MailboxActorContext,\n type MailboxAuthMode,\n type MailboxCapability,\n type MailboxPrincipalKind,\n} from './mailbox-auth-types.js';\n\n// \u2500\u2500 Recipient-scoped receipt state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 delivery/action state for a single message.\n *\n * Keyed by actor ID. Each entry tracks when the actor read, completed,\n * or otherwise interacted with the message \u2014 independently of other actors.\n */\nexport interface MailboxRecipientState {\n /** Actor ID this state belongs to. */\n actorId: string;\n /** ISO8601 \u2014 when this actor first read the message. */\n readAt?: string | undefined;\n /** ISO8601 \u2014 when this actor completed the message. */\n completedAt?: string | undefined;\n /** Who recorded the completion (usually same as actorId). */\n completedBy?: string | undefined;\n /** Optional outcome summary recorded by this actor. */\n outcome?: string | undefined;\n}\n\n/**\n * V2 JSONL receipt record. Appended alongside messages and v1 ack records.\n *\n * Has an explicit `__mailboxReceipt: 2` discriminator so:\n * 1. The v2 reader folds these into per-actor `MailboxRecipientState`.\n * 2. A v1 reader ignores the unknown JSON line (no `__ack` field).\n *\n * Fold algebra (applied during materialization):\n * - Keyed by `(messageId, actorId)`.\n * - `read`: first-write-wins (earliest read timestamp is preserved).\n * - `completed`: monotonic upward (once `true`, cannot revert unless an\n * explicit reopen record with `completed: false` is appended).\n * - `outcome`: last-write-wins.\n * - Duplicate records (same messageId, actorId, timestamp): idempotent no-ops.\n */\nexport interface MailboxReceiptRecordV2 {\n /** Discriminator \u2014 always `2` to distinguish from messages and v1 acks. */\n __mailboxReceipt: 2;\n /** Target message this receipt applies to. */\n messageId: string;\n /** Actor this receipt belongs to. */\n actorId: string;\n /** ISO8601 \u2014 when the receipt event occurred. */\n timestamp: string;\n /** Was the message read by this actor? */\n read?: boolean | undefined;\n /** Was the message completed by this actor? */\n completed?: boolean | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n}\n\n/**\n * Check if a parsed JSONL value is a v2 receipt record.\n * Validates the discriminator AND required structural fields.\n */\nexport function isMailboxReceiptRecordV2(value: unknown): value is MailboxReceiptRecordV2 {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const v = value as Record<string, unknown>;\n if (v['__mailboxReceipt'] !== 2) return false;\n if (typeof v['messageId'] !== 'string' || v['messageId'].length === 0) return false;\n if (typeof v['actorId'] !== 'string' || v['actorId'].length === 0) return false;\n if (typeof v['timestamp'] !== 'string' || v['timestamp'].length === 0) return false;\n // Validate optional fields when present \u2014 prevents malformed JSONL records\n // from entering typed receipt-folding code (e.g. completed:\"false\" truthy string).\n if ('read' in v && typeof v['read'] !== 'boolean') return false;\n if ('completed' in v && typeof v['completed'] !== 'boolean') return false;\n if ('outcome' in v && v['outcome'] !== undefined && typeof v['outcome'] !== 'string') return false;\n return true;\n}\n\n// \u2500\u2500 Message projections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Materialized message with per-actor recipient state.\n *\n * This is the internal representation after folding all v1 acks and v2\n * receipt records. It carries both the legacy fields (for backward\n * compatibility) and the new actor-specific state map.\n *\n * `legacyGlobalCompletion` is set ONLY for historical v1 fan-out messages\n * that were globally completed. It is never set for new v2 writes.\n */\nexport interface MailboxMessageProjection extends MailboxMessage {\n /** Per-actor delivery/action state, keyed by actorId. */\n recipientState: Readonly<Record<string, MailboxRecipientState>>;\n /**\n * True ONLY for historical v1 fan-out messages that were globally completed\n * (completed before the v2 migration). These remain globally suppressed to\n * prevent upgrade re-delivery. New v2 writes NEVER set this.\n */\n legacyGlobalCompletion?: boolean | undefined;\n}\n\n/**\n * Self-facing message \u2014 what a specific actor sees.\n *\n * This does NOT extend `MailboxMessage` because self-facing responses must NOT\n * contain aggregate receipt metadata (`readBy`, `completedBy`, `completedAt`,\n * `outcome`) that would leak other actors' activity. Only actor-specific\n * derived fields are added on top of the non-sensitive message fields.\n */\nexport interface ActorMailboxMessage\n extends Omit<MailboxMessage, 'readBy' | 'completed' | 'completedBy' | 'completedAt' | 'outcome'> {\n /** Has this actor read the message? */\n readByMe: boolean;\n /** Has this actor completed the message? */\n completedByMe: boolean;\n /** Does this message require action from this actor? */\n actionRequiredForMe: boolean;\n /** This actor's outcome, if any. */\n myOutcome?: string | undefined;\n /**\n * True for historical v1 fan-out messages that were globally completed.\n * Lets the UI distinguish \"completed by me\" from \"completed globally\n * before migration.\"\n */\n legacyGlobalCompletion?: boolean | undefined;\n}\n\n/**\n * Derive `actionRequiredForMe` from the canonical type properties and actor state.\n *\n * Defined as:\n * `MAILBOX_TYPE_PROPERTIES[type].requiresAction && visible && !completedByMe && !deleted && !legacyGlobalCompletion`\n *\n * For historical legacy-global messages, `actionRequiredForMe` is always false\n * because the message is suppressed and should not re-enter any actor's flow.\n */\nexport function isActionRequiredForActor(\n message: Pick<MailboxMessage, 'type' | 'deletedAt' | 'completed'>,\n projection: Pick<ActorMailboxMessage, 'completedByMe' | 'legacyGlobalCompletion'>,\n): boolean {\n if (projection.legacyGlobalCompletion) return false;\n if (message.deletedAt !== undefined) return false;\n if (projection.completedByMe) return false;\n return MAILBOX_TYPE_PROPERTIES[message.type]?.requiresAction === true;\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\n// Kanban records are an explicitly configured project-state synchronization\n// channel, not telemetry summaries. Their user-authored fields must round-trip\n// intact; sensitive-key and secret-pattern scrubbing still applies recursively.\nconst HQ_PROJECT_STATE_EVENT_TYPES = new Set(['kanban.snapshot']);\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 preserveRawContentKeys?: boolean;\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 (\n !options.preserveRawContentKeys &&\n !options.policy.rawContent &&\n key !== undefined &&\n isRawContentKey(key)\n ) {\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\nfunction redactHqValueInternal<T>(\n value: T,\n options: HqRedactOptions,\n preserveRawContentKeys: boolean,\n): 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 preserveRawContentKeys,\n seen: new WeakSet<object>(),\n });\n return { value: result.value as T, redacted: result.redacted };\n}\n\nexport function redactHqValue<T>(\n value: T,\n options: HqRedactOptions = {},\n): HqRedactionResult<T> {\n return redactHqValueInternal(value, options, false);\n}\n\nexport function redactHqEvent<TPayload>(\n event: HqEventEnvelope<TPayload>,\n options: HqRedactOptions = {},\n): HqRedactionResult<HqEventEnvelope<TPayload>> {\n const payload = redactHqValueInternal(\n event.payload,\n options,\n HQ_PROJECT_STATE_EVENT_TYPES.has(event.type),\n );\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 { 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 ...(message.audience !== undefined ? { audience: message.audience } : {}),\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 { createHash, randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { hostname } from 'node:os';\nimport { basename } from 'node:path';\nimport { readProjectIdentitySync } from '../utils/project-identity.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 {\n HqPublisher,\n type HqPublisherCommandHandler,\n type HqPublisherOptions,\n type HqSocketFactory,\n} 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\nexport function deriveHqProjectId(projectRoot: string, projectAlias?: string): string {\n const projectIdentity = readProjectIdentitySync(projectRoot);\n if (projectIdentity) return projectIdentity.projectId;\n const alias = projectAlias?.trim();\n if (!alias && projectRoot.startsWith('alias:')) {\n throw new Error('projectRoot must not use the reserved \"alias:\" HQ identity prefix');\n }\n const identity = alias ? `alias:${alias}` : projectRoot;\n return createHash('sha256').update(identity).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 /** Bound offline telemetry retained by this client. */\n maxQueuedMessages?: number;\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n onCommand?: HqPublisherCommandHandler;\n /** Receives the latest merged Kanban snapshot from HQ. */\n onKanbanSnapshot?: HqPublisherOptions['onKanbanSnapshot'];\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 projectAlias = config.projectAlias?.trim() || undefined;\n const projectName = projectAlias ?? options.projectName ?? (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: deriveHqProjectId(options.projectRoot, projectAlias),\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.maxQueuedMessages !== undefined\n ? { maxQueuedMessages: options.maxQueuedMessages }\n : {}),\n ...(options.onCommand !== undefined ? { onCommand: options.onCommand } : {}),\n ...(options.onKanbanSnapshot !== undefined\n ? { onKanbanSnapshot: options.onKanbanSnapshot }\n : {}),\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", "import * as fs from 'node:fs';\nimport * as fsPromises from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from './atomic-write.js';\nimport { isUlid, ulid } from './ulid.js';\n\nexport const PROJECT_IDENTITY_VERSION = 1 as const;\nexport const PROJECT_ID_PREFIX = 'proj_';\nexport const PROJECT_IDENTITY_RELATIVE_PATH = path.join('.wrongstack', 'project.json');\n\nexport interface ProjectIdentityFile {\n version: typeof PROJECT_IDENTITY_VERSION;\n projectId: string;\n}\n\nexport interface EnsureProjectIdentityResult {\n identity: ProjectIdentityFile;\n created: boolean;\n}\n\nexport interface RekeyProjectIdentityResult {\n previous?: ProjectIdentityFile | undefined;\n identity: ProjectIdentityFile;\n}\n\nconst PROJECT_GITIGNORE_RULES = [\n '.wrongstack/',\n '!/.wrongstack/',\n '/.wrongstack/*',\n '!/.wrongstack/project.json',\n] as const;\n\nexport function projectIdentityPath(projectRoot: string): string {\n return path.join(projectRoot, PROJECT_IDENTITY_RELATIVE_PATH);\n}\n\nexport function createProjectId(seedTime: number = Date.now()): string {\n return `${PROJECT_ID_PREFIX}${ulid(seedTime)}`;\n}\n\nexport function isProjectId(value: string): boolean {\n return value.startsWith(PROJECT_ID_PREFIX) && isUlid(value.slice(PROJECT_ID_PREFIX.length));\n}\n\nexport function readProjectIdentitySync(projectRoot: string): ProjectIdentityFile | undefined {\n const filePath = projectIdentityPath(projectRoot);\n try {\n return parseProjectIdentity(fs.readFileSync(filePath, 'utf8'), filePath);\n } catch (error) {\n if (isMissingFileError(error)) return undefined;\n throw error;\n }\n}\n\nexport async function readProjectIdentity(\n projectRoot: string,\n): Promise<ProjectIdentityFile | undefined> {\n const filePath = projectIdentityPath(projectRoot);\n try {\n return parseProjectIdentity(await fsPromises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if (isMissingFileError(error)) return undefined;\n throw error;\n }\n}\n\nexport async function ensureProjectIdentity(\n projectRoot: string,\n idFactory: () => string = createProjectId,\n): Promise<EnsureProjectIdentityResult> {\n const existing = await readProjectIdentity(projectRoot);\n if (existing) return { identity: existing, created: false };\n\n const filePath = projectIdentityPath(projectRoot);\n const identity = makeIdentity(idFactory());\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n\n try {\n await fsPromises.writeFile(filePath, serializeProjectIdentity(identity), {\n encoding: 'utf8',\n flag: 'wx',\n });\n return { identity, created: true };\n } catch (error) {\n if (!isAlreadyExistsError(error)) throw error;\n const winner = await readProjectIdentity(projectRoot);\n if (!winner) throw error;\n return { identity: winner, created: false };\n }\n}\n\nexport async function rekeyProjectIdentity(\n projectRoot: string,\n idFactory: () => string = createProjectId,\n): Promise<RekeyProjectIdentityResult> {\n const previous = await readProjectIdentity(projectRoot);\n const identity = makeIdentity(idFactory());\n const filePath = projectIdentityPath(projectRoot);\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n await atomicWrite(filePath, serializeProjectIdentity(identity));\n return { previous, identity };\n}\n\n/**\n * Keep runtime state ignored while allowing the small, explicitly shared\n * WrongStack project contract to travel with the repository.\n */\nexport async function ensureProjectGitignore(projectRoot: string): Promise<void> {\n const filePath = path.join(projectRoot, '.gitignore');\n let content = '';\n try {\n content = await fsPromises.readFile(filePath, 'utf8');\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n }\n\n const hadTrailingNewline = content.endsWith('\\n');\n const lines = content.length === 0 ? [] : content.split(/\\r?\\n/);\n if (hadTrailingNewline) lines.pop();\n\n let changed = false;\n for (let index = 0; index < lines.length; index++) {\n if (lines[index]?.trim() === '.wrongstack/*') {\n lines[index] = '.wrongstack/';\n changed = true;\n }\n }\n\n for (const entry of PROJECT_GITIGNORE_RULES) {\n if (!lines.some((line) => line.trim() === entry)) {\n if (entry === '.wrongstack/' && lines.length > 0 && lines.at(-1) !== '') lines.push('');\n lines.push(entry);\n changed = true;\n }\n }\n\n if (!changed) return;\n await fsPromises.writeFile(filePath, `${lines.join('\\n')}\\n`, 'utf8');\n}\n\nfunction makeIdentity(projectId: string): ProjectIdentityFile {\n if (!isProjectId(projectId)) {\n throw new Error(`Invalid WrongStack project id: ${projectId}`);\n }\n return { version: PROJECT_IDENTITY_VERSION, projectId };\n}\n\nfunction parseProjectIdentity(raw: string, filePath: string): ProjectIdentityFile {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in WrongStack project identity file: ${filePath}`);\n }\n if (typeof value !== 'object' || value === null) {\n throw new Error(`Invalid WrongStack project identity file: ${filePath}`);\n }\n const record = value as Record<string, unknown>;\n if (record['version'] !== PROJECT_IDENTITY_VERSION) {\n throw new Error(`Unsupported WrongStack project identity version in ${filePath}`);\n }\n if (typeof record['projectId'] !== 'string' || !isProjectId(record['projectId'])) {\n throw new Error(`Invalid projectId in WrongStack project identity file: ${filePath}`);\n }\n return { version: PROJECT_IDENTITY_VERSION, projectId: record['projectId'] };\n}\n\nfunction serializeProjectIdentity(identity: ProjectIdentityFile): string {\n return `${JSON.stringify(identity, null, 2)}\\n`;\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT';\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === 'EEXIST';\n}\n", "import type { FileHandle } from 'node:fs/promises';\nimport {\n type AtomicWriteOptions,\n createPersistencePrimitives,\n type FileLockOptions,\n} from '@wrongstack/persistence';\nimport { FsError } from '../types/errors.js';\n\nexport type { AtomicWriteOptions, FileLockOptions } from '@wrongstack/persistence';\n\nconst primitives = createPersistencePrimitives({\n createLockTimeoutError: ({ targetPath, timeoutMs }) =>\n 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\nexport const atomicWrite: (\n targetPath: string,\n content: string | Uint8Array,\n opts?: AtomicWriteOptions,\n) => Promise<void> = primitives.atomicWrite;\n/**\n * Atomic replace that streams its new contents instead of taking them as one\n * buffer. Use when the replacement is large enough that materializing it would\n * itself be the memory problem (log rotation, tail compaction).\n */\nexport const atomicReplaceWithWriter: <T>(\n targetPath: string,\n write: (handle: FileHandle) => Promise<T>,\n opts?: AtomicWriteOptions,\n) => Promise<T> = primitives.atomicReplaceWithWriter;\nexport const ensureDir: (dir: string) => Promise<void> = primitives.ensureDir;\nexport const withFileLock: <T>(\n targetPath: string,\n fn: () => Promise<T>,\n opts?: FileLockOptions,\n) => Promise<T> = primitives.withFileLock;\n", "import { toErrorMessage } from '../utils/error.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", "import { randomBytes } from 'node:crypto';\n\n/**\n * Crockford base32 alphabet (excludes I, L, O, U to avoid ambiguity).\n */\nconst ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\nconst ENCODING_LEN = ENCODING.length;\nconst TIME_LEN = 10;\nconst RANDOM_LEN = 16;\n\nfunction encodeTime(now: number, len: number): string {\n let mod: number;\n let str = '';\n for (let i = len - 1; i >= 0; i--) {\n mod = now % ENCODING_LEN;\n str = ENCODING[mod] + str;\n now = (now - mod) / ENCODING_LEN;\n }\n return str;\n}\n\nfunction encodeRandom(len: number): string {\n const bytes = randomBytes(len);\n let str = '';\n for (let i = 0; i < len; i++) {\n str += ENCODING[(bytes[i] as number) % ENCODING_LEN];\n }\n return str;\n}\n\n/**\n * Generate a ULID \u2014 a 26-char Crockford-base32 identifier whose first 10 chars\n * encode the millisecond timestamp (so IDs sort lexicographically by creation\n * time) followed by 16 chars of randomness. Zero runtime dependencies.\n *\n * The codebase convention is \"IDs are ULIDs\"; use this for any new store key.\n */\nexport function ulid(seedTime: number = Date.now()): string {\n return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN);\n}\n\n/** True for a well-formed 26-char Crockford-base32 ULID. */\nexport function isUlid(value: string): boolean {\n if (value.length !== TIME_LEN + RANDOM_LEN) return false;\n for (const ch of value) {\n if (!ENCODING.includes(ch)) return false;\n }\n return true;\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 { createHash, 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 { logHqAuthAudit } from './auth-audit.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 * Optional ISO timestamp after which the token is refused. When absent\n * (the pre-TTL default), the token never expires. The HQ server rejects\n * an expired token at both the HTTP and the WS-upgrade auth boundary,\n * so TTL rotation is enforced even for long-lived browser sessions.\n *\n * The timestamp is wall-clock (`new Date().toISOString()`). Clock skew\n * between the issuing HQ and the client is handled by passing a\n * `clockSkewMs` tolerance to {@link isTokenExpired} and\n * {@link tokenHasCapability} \u2014 callers that fetch tokens from a remote\n * HQ should use the server's clock (e.g. `Date.parse(expiresAt)`)\n * rather than the local wall clock.\n */\n expiresAt?: string;\n}\n\n/**\n * True when a token has a wall-clock expiry that has already passed.\n * Returns `false` when `expiresAt` is absent (the pre-TTL default).\n *\n * The check is fail-open for malformed values: an unparseable timestamp\n * is treated as \"no expiry\" rather than \"already expired\", because the\n * latter would lock the operator out of their own HQ on a bad file edit.\n * Use {@link tokenHasCapability} at the auth boundary to also deny\n * capabilities for expired tokens.\n *\n * @param at - epoch milliseconds; defaults to `Date.now()`. Exposed so\n * tests can inject a fixed clock.\n * @param clockSkewMs - tolerance in milliseconds for clock skew between\n * the issuing node and the verifying node. When set, a token that has\n * technically expired by up to `clockSkewMs` is still accepted, so a\n * verifier whose clock is slightly ahead of the issuer does not\n * prematurely reject valid tokens. Defaults to 0 (no tolerance).\n */\nexport function isTokenExpired(\n token: Pick<HqToken, 'expiresAt'> | undefined,\n at: number = Date.now(),\n clockSkewMs: number = 0,\n): boolean {\n if (token === undefined) return false;\n const expiresAt = token.expiresAt;\n if (expiresAt === undefined) return false;\n const parsed = Date.parse(expiresAt);\n if (!Number.isFinite(parsed)) return false;\n return at >= parsed - Math.max(0, clockSkewMs);\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. **Expired tokens are refused regardless of capability**\n * \u2014 call this at the auth boundary so TTL rotation is enforced uniformly.\n *\n * @param clockSkewMs - passed through to {@link isTokenExpired}. When set, a\n * token that has expired by up to `clockSkewMs` is still accepted. Defaults\n * to 0.\n */\nexport function tokenHasCapability(\n token: HqToken | undefined,\n capability: string,\n clockSkewMs: number = 0,\n): boolean {\n if (token === undefined) return false;\n if (isTokenExpired(token, Date.now(), clockSkewMs)) 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/**\n * Sentinel value `hqAuthContentHash` substitutes for every raw secret\n * (`HqToken.token`, `HqAuthFile.passwordHash`, `HqAuthFile.cookieSecret`)\n * before hashing. Exported so downstream consumers of the audit log can\n * recognize the redaction shape without hardcoding the literal \u2014 e.g. a\n * forensic tool that re-derives a `contentHash` from a known on-disk\n * `auth.json` can substitute this same sentinel and compare.\n */\nexport const HQ_AUTH_CONTENT_HASH_REDACTED = '<redacted>';\n\n/**\n * Compute a SHA-256 content hash over a *redacted* projection of an\n * `HqAuthFile`. The projection replaces every raw token string, the\n * `passwordHash`, and the `cookieSecret` with constant sentinels, so:\n *\n * - the audit log never holds derivable token material (a hash of a\n * redacted projection can't be reversed to recover the originals),\n * - two files that differ only in their secrets hash identically\n * (reissuing a token without changing its id/label/expiry does not\n * change the hash), and\n * - the hash still flips whenever the structural state the operator\n * cares about (version, token ids/labels/capabilities/expiries,\n * alert rules, redaction policy) changes.\n *\n * Returns `undefined` when hashing or serialization throws (e.g. a\n * future schema addition that isn't JSON-serializable) \u2014 callers\n * should pass that through as an absent `contentHash` field rather\n * than failing the audit append, matching the audit module's\n * best-effort contract.\n */\nexport function hqAuthContentHash(file: HqAuthFile): string | undefined {\n const REDACTED = HQ_AUTH_CONTENT_HASH_REDACTED;\n const redactToken = (t: HqToken): HqToken => ({ ...t, token: REDACTED });\n try {\n // `exactOptionalPropertyTypes: true` means optional fields can't be\n // assigned `undefined` explicitly \u2014 preserve absence via conditional\n // spreads so the projection stays a valid `HqAuthFile`.\n const projection: HqAuthFile = {\n version: file.version,\n updatedAt: file.updatedAt,\n ...(file.redactionPolicy !== undefined ? { redactionPolicy: file.redactionPolicy } : {}),\n ...(file.browserTokens !== undefined\n ? { browserTokens: file.browserTokens.map(redactToken) }\n : {}),\n ...(file.clientTokens !== undefined\n ? { clientTokens: file.clientTokens.map(redactToken) }\n : {}),\n ...(file.passwordHash !== undefined ? { passwordHash: REDACTED } : {}),\n ...(file.cookieSecret !== undefined ? { cookieSecret: REDACTED } : {}),\n ...(file.alertRules !== undefined ? { alertRules: file.alertRules } : {}),\n };\n // Stable key ordering \u2014 the projection above has a fixed key order, so\n // the serialized form is deterministic across runs for the same\n // structural state.\n const payload = JSON.stringify(projection);\n return createHash('sha256').update(payload).digest('hex');\n } catch {\n return undefined;\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 * Optional time-to-live (milliseconds) stamped on the first-run browser\n * and client tokens. When set, both tokens carry an `expiresAt` and the\n * HQ server will refuse them once it passes. Default: no expiry.\n *\n * Only affects tokens minted by THIS call (the first run). Tokens added\n * later via `wstack hq token create` choose their own TTL.\n */\n tokenTtlMs?: number | undefined;\n /**\n * Optional `actor` string recorded in `auth-audit.jsonl` for the two\n * `first-run` entries this function emits (one per minted token). The\n * CLI fills this with `user@host`; when omitted the entry carries no\n * `actor` field. Never contains the token string.\n */\n actor?: string | undefined;\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 *\n * Caller surface: the sole production caller is `startHqServer` in\n * `packages/cli/src/hq-server.ts`, which threads `actor: resolveAuditActor()`\n * so both first-run audit entries carry `user@host`. Test callers live under\n * `packages/core/tests/hq/` (token-ttl, first-run-audit, auth-store). Any\n * new production caller MUST pass `actor` for the audit log to carry\n * forensic identity \u2014 see `EnsureHqFirstRunAuthOptions.actor`.\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 // Re-read so the hash reflects exactly what landed on disk \u2014\n // `writeHqAuthFile` re-stamps `updatedAt` internally, so hashing\n // the in-memory `authFile` would diverge from the persisted state\n // an operator can independently inspect.\n const persisted = await readHqAuthFile(dataDir, opts);\n const hash = hqAuthContentHash(persisted);\n const actorField = opts.actor ? { actor: opts.actor } : {};\n logHqAuthAudit(\n dataDir,\n {\n kind: 'password-rotate',\n scope: 'browser',\n tokenId: '(password-rotation)',\n ...(hash !== undefined ? { contentHash: hash } : {}),\n ...actorField,\n },\n {\n onError: (err) =>\n opts.warn?.(`HQ password-rotate audit write failed: ${(err as Error).message}`),\n },\n );\n return { authFile: persisted, 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 = {\n ...mintHqToken({ label: 'first-run browser', ttlMs: opts.tokenTtlMs }),\n capabilities: ['control.enqueue'],\n };\n const clientToken = {\n ...mintHqToken({ label: 'first-run client', ttlMs: opts.tokenTtlMs }),\n capabilities: ['telemetry.publish'],\n };\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\n // Re-read so the audit hash + the returned `authFile` reflect exactly\n // what landed on disk. `writeHqAuthFile` re-stamps `updatedAt` (and\n // could normalize other fields in the future); hashing the in-memory\n // `authFile` would diverge from the persisted state an operator can\n // independently inspect, defeating the forensic-tie-back purpose.\n const persisted = await readHqAuthFile(dataDir, opts);\n\n // Record both first-run mints in auth-audit.jsonl. Best-effort: a failed\n // append must never roll back the fresh auth.json we just wrote. The two\n // entries use the same `kind: 'first-run'` discriminator the audit\n // schema reserves for this bootstrap path. Both carry the content hash of\n // the persisted file so an operator reviewing the log can tie them back\n // to the exact on-disk state without the log holding secrets.\n const hash = hqAuthContentHash(persisted);\n const hashField = hash !== undefined ? { contentHash: hash } : {};\n const actorField = opts.actor ? { actor: opts.actor } : {};\n for (const [scope, token] of [\n ['browser', browserToken],\n ['client', clientToken],\n ] as const) {\n logHqAuthAudit(\n dataDir,\n {\n kind: 'first-run',\n scope,\n tokenId: token.id,\n ...hashField,\n ...(token.label ? { label: token.label } : {}),\n capabilities: token.capabilities,\n ...(token.expiresAt ? { expiresAt: token.expiresAt } : {}),\n ...actorField,\n },\n {\n onError: (err) =>\n opts.warn?.(`HQ first-run audit write failed: ${(err as Error).message}`),\n },\n );\n }\n\n return { authFile: persisted, 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 * Options for {@link mintHqToken}.\n *\n * - `label` \u2014 human-readable identifier persisted alongside the token.\n * - `ttlMs` \u2014 when set, the token is stamped with `expiresAt = now + ttlMs`.\n * Absent (the default) means the token never expires, preserving the\n * pre-TTL contract.\n * - `now` \u2014 epoch milliseconds override for deterministic tests.\n */\nexport interface MintHqTokenOptions {\n label?: string | undefined;\n ttlMs?: number | undefined;\n now?: number | undefined;\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 *\n * Pass an options object to stamp an `expiresAt`; the bare-string overload\n * (`mintHqToken('my-label')`) is preserved for backward-compat.\n */\nexport function mintHqToken(labelOrOptions?: string | MintHqTokenOptions): HqToken {\n const opts: MintHqTokenOptions =\n typeof labelOrOptions === 'string' ? { label: labelOrOptions } : (labelOrOptions ?? {});\n const at = opts.now ?? Date.now();\n const createdAtIso = new Date(at).toISOString();\n return {\n id: randomUUID(),\n token: randomUUID().replace(/-/g, '') + randomUUID().replace(/-/g, ''),\n createdAt: createdAtIso,\n ...(opts.label ? { label: opts.label } : {}),\n ...(opts.ttlMs !== undefined && Number.isFinite(opts.ttlMs) && opts.ttlMs > 0\n ? { expiresAt: new Date(at + opts.ttlMs).toISOString() }\n : {}),\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 // Without a listener an FSWatcher 'error' event is an uncaught exception\n // (Windows emits transient EPERMs on dir churn). Degrade to \"no watcher\" \u2014\n // same as the creation-failure path above.\n watcher.on('error', (err: Error) => {\n opts.warn?.(`HQ auth watcher error: ${err.message}`);\n try {\n watcher.close();\n } catch {\n /* already closed */\n }\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", "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 /** Active profile name resolved from the bootstrap config. */\n profileName: string;\n /** ~/.wrongstack/profiles/<activeProfile> \u2014 active user-profile root. */\n profileDir: 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/profiles/<activeProfile> \u2014 directory for profile-scoped\n * user state (mode.json, statusline.json, custom-context-modes.json, \u2026).\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 /** Resolve ~/.wrongstack/profiles/<name>/statusline.json */\n profileStatuslineConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/mode.json */\n profileModeConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/provider-status.json */\n profileProviderStatus: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/update-cache.json */\n profileUpdateCache: (name: string) => string;\n /** ~/.wrongstack/.key \u2014 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/profiles/<activeProfile>/memory.md \u2014 profile memory. */\n globalMemory: string;\n /** ~/.wrongstack/profiles/<activeProfile>/skills \u2014 profile 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/profiles/<activeProfile>/design-kits \u2014 profile Design Studio kits. */\n globalDesignKits: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompts \u2014 profile prompt library. */\n globalPrompts: string;\n /** ~/.wrongstack/profiles/<activeProfile>/instructions \u2014 profile instruction overrides. */\n globalInstructions: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompt-usage.json \u2014 prompt usage. */\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/profiles/<activeProfile>/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/profiles/<activeProfile>/sync.json \u2014 CloudSync configuration */\n syncConfig: string;\n /** ~/.wrongstack/config-history \u2014 timestamped backups on every config write */\n configHistoryDir: 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 /** Explicit profile override. Otherwise read from the root bootstrap config. */\n profileName?: string | undefined;\n}\n\n/** Make an untrusted profile name safe for use as one path segment. */\nexport function safeProfileName(name: string | undefined): string {\n const safe = (name ?? '').replace(/[/\\\\:]/g, '_').replace(/\\.\\./g, '_').trim();\n return safe || 'default';\n}\n\n/**\n * Resolve the selected profile from ~/.wrongstack/config.json. The root file\n * is bootstrap metadata only; a missing/corrupt bootstrap selects `default`.\n */\nexport function activeProfileName(globalRoot: string): string {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, 'config.json'), 'utf8')) as {\n activeProfile?: unknown;\n };\n return safeProfileName(typeof parsed.activeProfile === 'string' ? parsed.activeProfile : undefined);\n } catch {\n return 'default';\n }\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 profileName = safeProfileName(opts.profileName ?? activeProfileName(globalRoot));\n const profileDir = path.join(globalRoot, 'profiles', profileName);\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 profileName,\n profileDir,\n projectRoot: opts.projectRoot,\n homeDir,\n configDir: profileDir,\n globalConfig: path.join(globalRoot, 'config.json'),\n profilesDir: path.join(globalRoot, 'profiles'),\n profileConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'config.json');\n },\n profileStatuslineConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'statusline.json');\n },\n profileModeConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'mode.json');\n },\n profileProviderStatus: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'provider-status.json');\n },\n profileUpdateCache: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'update-cache.json');\n },\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(profileDir, 'memory.md'),\n globalSkills: path.join(profileDir, 'skills'),\n globalClaudeSkills: path.join(homeDir, '.claude', 'skills'),\n globalDesignKits: path.join(profileDir, 'design-kits'),\n globalPrompts: path.join(profileDir, 'prompts'),\n globalInstructions: path.join(profileDir, 'instructions'),\n promptUsage: path.join(profileDir, '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(profileDir, '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(profileDir, 'sync.json'),\n configHistoryDir: path.join(globalRoot, 'config-history'),\n projectStatus: (projectHash: string) => path.join(globalRoot, 'projects', projectHash, 'status.json'),\n };\n}\n", "/**\n * HQ auth audit log \u2014 append-only JSONL record of token lifecycle events.\n *\n * Stored at `<dataDir>/auth-audit.jsonl`. One entry per token create /\n * revoke / first-run mint / live-reload-driven expiry sweep. Never holds\n * raw token strings \u2014 only the token id, label, scope, and actor.\n *\n * Design:\n * - **Append-only.** Nothing ever rewrites or deletes lines. Rotation is\n * a separate operator concern (the file is bounded only by disk).\n * - **Synchronous append** via `appendFileSync` so a power loss between\n * the CLI's mutate call and the audit write loses at most the audit\n * entry, never the auth state. Errors are swallowed (best-effort).\n * - **Ring in memory** is intentionally NOT kept \u2014 this log is for\n * long-term forensic review, not for live UI rendering. The HQ server\n * doesn't load it; only the CLI mutators write to it.\n * - **No PII.** `actor` is a free-form string the caller fills with\n * whatever identity context it has (CLI user, env var, machine id).\n * The token `id` is a UUID \u2014 safe to log. The token `token` string\n * is NEVER recorded.\n *\n * @module hq/auth-audit\n */\n\nimport { appendFileSync, mkdirSync } from 'node:fs';\nimport * as path from 'node:path';\n\n/** Scope of the token the event is about. */\nexport type HqAuthAuditScope = 'browser' | 'client';\n\n/** Kind of event recorded. */\nexport type HqAuthAuditKind =\n /** Token created via `wstack hq token create` (or first-run mint). */\n | 'create'\n /** Token revoked via `wstack hq token revoke`. */\n | 'revoke'\n /**\n * First-run bootstrap \u2014 both browser and client tokens minted by\n * `ensureHqFirstRunAuthFile`. Recorded once per fresh data dir;\n * subsequent calls (existing auth.json) do not log.\n */\n | 'first-run'\n /**\n * Operator edited `auth.json` directly and the HQ server's\n * live-reload watcher pruned one or more tokens whose `expiresAt`\n * had already passed. The entry records how many were pruned.\n */\n | 'expired-prune'\n /**\n * Password rotation \u2014 the operator changed the browser password, which\n * also rotated the cookie secret (invalidating all active sessions).\n * Recorded by `ensureHqFirstRunAuthFile` for the password-change path.\n */\n | 'password-rotate';\n\nexport interface HqAuthAuditEntry {\n /** Epoch milliseconds when the event was recorded. */\n at: number;\n kind: HqAuthAuditKind;\n scope: HqAuthAuditScope;\n /** Token id (UUID) \u2014 safe to log. Never the token string. */\n tokenId: string;\n /** Human-readable label, when the token carried one. */\n label?: string;\n /** Capabilities granted to the token, when known. */\n capabilities?: readonly string[];\n /** Optional expiresAt timestamp on the token (ISO). */\n expiresAt?: string;\n /**\n * Who performed the action. Free-form string \u2014 the CLI fills this with\n * the OS user + hostname when available. Never contains the token string.\n */\n actor?: string;\n /**\n * For `expired-prune`: how many tokens were filtered out by the\n * live-reload watcher in this reload. For other kinds: undefined.\n */\n prunedCount?: number;\n /**\n * SHA-256 hash (hex) of the redacted `auth.json` contents at the\n * moment of the event \u2014 lets an operator reviewing the audit log tie\n * an entry back to the exact on-disk state that produced it without\n * the log ever holding derivable token material. Computed by\n * `hqAuthContentHash` over a projection of the `HqAuthFile` with the\n * raw token strings, `passwordHash`, and `cookieSecret` replaced by\n * the constant sentinel `HQ_AUTH_CONTENT_HASH_REDACTED` (exported\n * from `@wrongstack/core`) \u2014 so two files that differ only in secrets\n * hash identically. Absent on entries emitted before the hash landed\n * and when the file is unreadable at emit time. Re-derivable from the\n * current `auth.json` via `hqAuthContentHash(await readHqAuthFile(dir))`.\n */\n contentHash?: string;\n}\n\n/** Path to `auth-audit.jsonl` under the given data dir. */\nexport function hqAuthAuditPath(dataDir: string): string {\n return path.join(dataDir, 'auth-audit.jsonl');\n}\n\n/**\n * Append a single audit entry to `<dataDir>/auth-audit.jsonl`.\n *\n * Best-effort: errors are swallowed and the optional `onError` callback\n * is invoked instead. The caller's mutation (auth.json write, token\n * mint, etc.) has already succeeded by the time this is called, so a\n * failed audit append must never roll it back.\n *\n * The data dir is created if missing. The file is opened in append mode\n * so concurrent writers (e.g. two CLI invocations) do not clobber each\n * other \u2014 JSONL append is the safe granularity.\n */\nexport function appendHqAuthAudit(\n dataDir: string,\n entry: HqAuthAuditEntry,\n options?: { onError?: (err: Error) => void },\n): void {\n try {\n mkdirSync(dataDir, { recursive: true });\n const line = `${JSON.stringify(entry)}\\n`;\n appendFileSync(hqAuthAuditPath(dataDir), line, { encoding: 'utf8', flag: 'a' });\n } catch (err) {\n options?.onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n}\n\n/**\n * Convenience: build an entry with a sensible default `at` (now) and\n * append it. The `at` field can still be overridden via the partial.\n */\nexport function logHqAuthAudit(\n dataDir: string,\n partial: Omit<HqAuthAuditEntry, 'at'> & { at?: number },\n options?: { onError?: (err: Error) => void; now?: () => number },\n): void {\n const at = partial.at ?? (options?.now?.() ?? Date.now());\n const { at: _omit, ...rest } = partial;\n void _omit;\n appendHqAuthAudit(dataDir, { at, ...rest } as HqAuthAuditEntry, options);\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';\nimport type { SessionEvent, SessionWriter } from '../types/session.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 /**\n * Transcript tail poll interval. Default 500ms. Passing this explicitly\n * pins the poll to a fixed cadence; with the default, the poll relaxes to\n * {@link transcriptFallbackIntervalMs} while the per-file watcher is live\n * (the watcher streams changes within milliseconds \u2014 the poll is only a\n * safety net, and a 500ms stat loop per bridged session adds up).\n */\n transcriptIntervalMs?: number | undefined;\n /** Poll interval while the transcript fs.watch is healthy. Default 5000ms. */\n transcriptFallbackIntervalMs?: number | undefined;\n now?: (() => string) | undefined;\n /**\n * Optional session writer. When provided, the bridge subscribes to\n * the writer's `onAppend` callback to receive events directly, avoiding\n * a disk read-back of the session JSONL file. When absent, the bridge\n * falls back to polling the file via `tail()`.\n */\n writer?: SessionWriter | 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 // Captured so the disposer can restore it instead of permanently clearing.\n let prevOnAppend: ((event: SessionEvent) => void) | undefined;\n\n // \u2500\u2500 Direct event subscription (avoids disk read-back) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // When a session writer is available, subscribe to its onAppend callbacks to\n // receive events directly as they're written, instead of polling the JSONL\n // file from disk. The tail fallback is suppressed when the writer path is\n // active \u2014 the synchronous callback delivers every event before it enters\n // the write buffer, so tail() would duplicate them.\n // Subscribe directly only when the writer implements setOnAppend \u2014\n // otherwise the optional-chained call silently no-ops and the tail\n // fallback below would also be suppressed (it's gated on the same\n // condition), producing zero transcript streaming.\n if (opts.writer?.setOnAppend) {\n // Capture any pre-existing callback (e.g. from SessionStoreOptions) so\n // the disposer can restore it instead of permanently clearing.\n prevOnAppend = opts.writer.onAppend;\n\n // Subscribe to onAppend which fires for both single append() calls and\n // individual events inside appendBatch(). The batch-specific callback\n // is NOT used here \u2014 subscribing to both would cause duplicate publishing\n // since appendBatch() now also triggers onAppend per-event.\n opts.writer.setOnAppend((event: SessionEvent) => {\n if (disposed) return;\n // Also invoke the previous callback if one exists \u2014 preserves the\n // call chain for any other subscriber wired at the store level.\n try { prevOnAppend?.(event); } catch { /* best-effort */ }\n try {\n const entries = mapSessionEventToEntries(event as unknown as Record<string, unknown>);\n if (entries.length > 0) {\n publishTranscriptEntries(entries);\n lastActivityAt = now();\n }\n } catch {\n /* best-effort \u2014 never let the callback break the write path */\n }\n });\n }\n\n // seqEmitted is used by publishTranscriptEntries \u2014 must be hoisted above\n // the tail guard so the callback path can use it.\n let seqEmitted = 0;\n\n // Declared outside the tail guard so the disposer can reference them even\n // when the tail path is skipped (writer subscription active).\n let watcher: fs.FSWatcher | null = null;\n let tailTimer: ReturnType<typeof setTimeout> | null = null;\n const snapshotTimer = setInterval(() => publishSnapshot(true), opts.snapshotIntervalMs ?? 2500);\n snapshotTimer.unref?.();\n\n // \u2500\u2500 Transcript tail (only when no direct writer subscription) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Without a writer, fall back to polling the JSONL file via stat + read.\n // With a writer, tail() is suppressed to avoid duplicate publishing.\n if (!opts.writer?.setOnAppend) {\n let offset = 0;\n let partial = '';\n let tailing = false;\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 const { bytesRead } = await fd.read(buf, 0, len, offset);\n const actualBuf = bytesRead < len ? buf.subarray(0, bytesRead) : buf;\n offset += bytesRead;\n partial += actualBuf.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 fastTailMs = opts.transcriptIntervalMs ?? 500;\n const relaxedTailMs =\n opts.transcriptFallbackIntervalMs ??\n (opts.transcriptIntervalMs !== undefined ? opts.transcriptIntervalMs : 5_000);\n function scheduleTail(): void {\n if (disposed) return;\n tailTimer = setTimeout(\n () => {\n void tail().finally(scheduleTail);\n },\n watcher ? relaxedTailMs : fastTailMs,\n );\n tailTimer.unref?.();\n }\n void tail().finally(scheduleTail);\n }\n\n return () => {\n if (disposed) return;\n disposed = true;\n // Unsubscribe the direct event callback, restoring any that was\n // captured from the writer before the bridge subscribed.\n if (opts.writer?.setOnAppend) {\n try { opts.writer.setOnAppend(prevOnAppend); } catch { /* best-effort */ }\n }\n offAgents?.();\n if (watcher) {\n try {\n watcher.close();\n } catch {\n /* ignore */\n }\n watcher = null;\n }\n clearInterval(snapshotTimer);\n if (tailTimer) {\n clearTimeout(tailTimer);\n tailTimer = null;\n }\n try {\n publisher.publishSessionEnded({ sessionId: opts.sessionId, endedAt: now() });\n } catch {\n /* best-effort */\n }\n };\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", "/**\n * Session marker projection \u2014 the single source of truth for how audit events\n * are rendered as human-readable timeline entries.\n *\n * A session JSONL carries two interleaved streams: the conversation itself\n * (user/assistant/tool turns, reconstructed by `DefaultSessionStore.load`) and\n * an audit stream of things that happened *around* the conversation \u2014\n * compaction, mode switches, skill activation, subagent lifecycle, provider\n * retries, truncation. During a live run every surface renders those audit\n * events as they arrive. On resume/reconnect they must render identically, or\n * the same session looks different before and after a reload.\n *\n * This module owns the event \u2192 text mapping so TUI, WebUI, SimpleUI and HQ\n * cannot drift. Each surface still decides *presentation* (icon, colour, chat\n * bubble vs. dimmed line) from {@link SessionMarker.source} and\n * {@link SessionMarker.level}; only the wording lives here.\n *\n * Pure and dependency-free: safe to call from a WebSocket payload builder, a\n * React render path, or a Node stream mapper alike.\n */\nimport type { SessionEvent } from './session.js';\n\nexport type SessionMarkerLevel = 'info' | 'warn' | 'error';\n\n/** One rendered audit-timeline entry. */\nexport interface SessionMarker {\n ts: string;\n /**\n * The event type this marker was projected from. Surfaces switch on it for\n * presentation (e.g. the TUI picks a different icon for `agent_spawned` vs\n * `agent_stopped`, both of which are `level: 'info'`).\n */\n source: SessionEvent['type'];\n level: SessionMarkerLevel;\n text: string;\n /** Set only for the `agent_*` sources. */\n agentId?: string | undefined;\n}\n\n/**\n * Every event type that projects to a marker. Conversation-bearing events\n * (`user_input`, `llm_response`, `tool_*`) are deliberately excluded \u2014 those\n * come from the reconstructed message list so legacy logs and the modern\n * `message_appended` journal replay identically.\n */\nexport const SESSION_MARKER_EVENT_TYPES: ReadonlySet<SessionEvent['type']> = new Set([\n 'mode_changed',\n 'compaction',\n 'checkpoint',\n 'skill_activated',\n 'skill_deactivated',\n 'agent_spawned',\n 'agent_stopped',\n 'agent_error',\n 'error',\n 'provider_retry',\n 'provider_error',\n 'message_truncated',\n]);\n\n/**\n * The subset chat-shaped surfaces (WebUI, SimpleUI, HQ Live Console) render.\n *\n * `checkpoint` is excluded: one is written per user prompt\n * (`agent-loop.ts` \u2192 `writeCheckpoint`), so in a chat transcript it would be a\n * line restating the user message immediately next to it. Dense timeline\n * surfaces like the TUI use {@link SESSION_MARKER_EVENT_TYPES} instead, where\n * the checkpoint marker doubles as a `/rewind` target hint.\n */\nexport const CHAT_MARKER_SOURCES: ReadonlySet<SessionEvent['type']> = new Set(\n [...SESSION_MARKER_EVENT_TYPES].filter((type) => type !== 'checkpoint'),\n);\n\n/**\n * Project one session event to a marker, or `null` when the event carries no\n * timeline meaning (conversation turns, lifecycle bookkeeping, unknown types).\n */\nexport function sessionEventToMarker(ev: SessionEvent): SessionMarker | null {\n switch (ev.type) {\n case 'compaction': {\n const before = (ev.before / 1000).toFixed(0);\n const after = (ev.after / 1000).toFixed(0);\n const level = ev.level ? ` (${ev.level})` : '';\n const reductions =\n ev.reductions && ev.reductions.length > 0\n ? ` [${ev.reductions.map((r) => `${r.phase}: \u2212${r.saved}`).join(', ')}]`\n : '';\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: `\u27F2 context compacted${level}: ${before}K \u2192 ${after}K tokens${reductions}`,\n };\n }\n\n case 'error':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'error',\n text: ev.phase ? `[${ev.phase}] ${ev.message}` : ev.message,\n };\n\n case 'provider_retry': {\n const secs = (ev.delayMs / 1000).toFixed(ev.delayMs >= 1000 ? 1 : 2);\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'warn',\n text: ev.status\n ? `\u27F3 retry ${ev.attempt} (HTTP ${ev.status}) after ${secs}s \u2014 ${ev.description}`\n : `\u27F3 retry ${ev.attempt} after ${secs}s \u2014 ${ev.description}`,\n };\n }\n\n case 'provider_error':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'error',\n text: ev.status\n ? `provider error (HTTP ${ev.status}, ${ev.retryable ? 'retryable' : 'fatal'}): ${ev.description}`\n : `provider error (${ev.retryable ? 'retryable' : 'fatal'}): ${ev.description}`,\n };\n\n case 'checkpoint':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: `\u2713 checkpoint #${ev.promptIndex}: \"${ev.promptPreview.slice(0, 60)}\"`,\n };\n\n case 'agent_spawned':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: `spawned as ${ev.role}`,\n agentId: ev.agentId,\n };\n\n case 'agent_stopped':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: 'stopped',\n agentId: ev.agentId,\n };\n\n case 'agent_error':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'error',\n text: `error: ${ev.error.slice(0, 80)}`,\n agentId: ev.agentId,\n };\n\n case 'mode_changed':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: `mode: ${ev.from} \u2192 ${ev.to}`,\n };\n\n case 'skill_activated':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: `skill activated: ${ev.skillName}`,\n };\n\n case 'skill_deactivated':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'info',\n text: `skill deactivated: ${ev.skillName}`,\n };\n\n case 'message_truncated':\n return {\n ts: ev.ts,\n source: ev.type,\n level: 'warn',\n text:\n ev.after < ev.before\n ? `message truncated: ${ev.before} \u2192 ${ev.after} tokens`\n : `message truncated at ${ev.after} tokens`,\n };\n\n default:\n return null;\n }\n}\n\n/**\n * Project an event stream to its markers, in JSONL order.\n *\n * `sources` restricts which event types are projected \u2014 pass\n * {@link CHAT_MARKER_SOURCES} for chat-shaped surfaces. Defaults to the full\n * {@link SESSION_MARKER_EVENT_TYPES}.\n */\nexport function projectSessionMarkers(\n events: readonly SessionEvent[],\n sources: ReadonlySet<SessionEvent['type']> = SESSION_MARKER_EVENT_TYPES,\n): SessionMarker[] {\n const markers: SessionMarker[] = [];\n for (const ev of events) {\n if (!sources.has(ev.type)) continue;\n const marker = sessionEventToMarker(ev);\n if (marker) markers.push(marker);\n }\n return markers;\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 { CHAT_MARKER_SOURCES, sessionEventToMarker } from '../types/session-markers.js';\nimport type { SessionEvent } from '../types/session.js';\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 '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 // Audit markers (compaction, mode/skill switches, subagent lifecycle,\n // provider retries/errors, truncation) share their wording with every\n // other surface. This one branch covers both HQ planes: the disk replay\n // behind `/api/sessions/:id/events` and the live `session.transcript`\n // stream, since both funnel through this mapper.\n if (!CHAT_MARKER_SOURCES.has(ev['type'] as SessionEvent['type'])) return [];\n const marker = sessionEventToMarker(ev as unknown as SessionEvent);\n if (!marker) return [];\n // HqTranscriptRole has no 'warn'; warn-level markers keep their leading\n // glyph (\u27F3 / truncation wording) to stay distinguishable as 'system'.\n return [\n make(marker.level === 'error' ? 'error' : 'system', marker.text, {\n ...(marker.level === 'error' ? { isError: true } : {}),\n ...(marker.agentId !== undefined ? { agentId: marker.agentId } : {}),\n }),\n ];\n }\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 * Shared context for HQ telemetry bridges.\n *\n * Every bridge (`cost-bridge`, `brain-bridge`, `worktree-bridge`,\n * `fleet-bridge`, `tool-bridge`) repeats the same four pieces of\n * boilerplate:\n *\n * 1. Resolve `now` from options or fall back to `new Date().toISOString()`.\n * 2. Conditionally spread `{ sessionId }` into every `publishEvent` call.\n * 3. Wrap every publish in `try / catch` (best-effort) so a transient\n * publisher failure never breaks the host's event loop.\n * 4. Collect unsubscribe handles and return a single disposer.\n *\n * This module collapses those four into one factory so each bridge shrinks\n * to its event-mapping logic.\n *\n * @module hq/bridge-context\n */\n\nimport type { HqPublisher, HqPublishEventOptions } from './publisher.js';\n\n// \u2500\u2500 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BridgeContextOptions {\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Override `now()` for deterministic tests. */\n now?: (() => string) | undefined;\n /** Optional sessionId to tag envelopes with when the event has none. */\n sessionId?: string | undefined;\n}\n\nexport interface BridgeContext {\n /** Resolved timestamp function (never undefined). */\n readonly now: () => string;\n /**\n * Build the `{ sessionId } | {}` spread for a `publishEvent` call.\n * The event-level sessionId (from the event payload) takes precedence\n * over the bridge-level sessionId (from options).\n */\n readonly sessionIdTag: (eventSessionId?: string) => { sessionId?: string };\n /**\n * Wrap a publish in try/catch so a transient publisher failure never\n * breaks the host. Returns the envelope on success, `undefined` on\n * failure.\n */\n readonly safePublish: (options: HqPublishEventOptions) => void;\n /** Track an unsubscribe handle for the disposer. */\n readonly track: (off: () => void) => void;\n /** Call every tracked unsubscribe handle. */\n readonly dispose: () => void;\n}\n\n// \u2500\u2500 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Create a {@link BridgeContext} from the common bridge options.\n *\n * Usage in a bridge:\n *\n * ```ts\n * export function startSomethingBridge(opts: SomethingBridgeOptions): () => void {\n * const { events, publisher } = opts;\n * const ctx = createBridgeContext(opts);\n *\n * ctx.track(events.on('something.happened', (p) => {\n * ctx.safePublish({\n * type: 'something.event',\n * payload: { ... },\n * ...ctx.sessionIdTag(p.sessionId),\n * timestamp: ctx.now(),\n * });\n * }));\n *\n * return ctx.dispose;\n * }\n * ```\n */\nexport function createBridgeContext(options: BridgeContextOptions): BridgeContext {\n const publisher = options.publisher;\n const now = options.now ?? (() => new Date().toISOString());\n const bridgeSessionId = options.sessionId;\n const offs: Array<() => void> = [];\n\n function sessionIdTag(eventSessionId?: string): { sessionId?: string } {\n const tag = eventSessionId ?? bridgeSessionId;\n return tag !== undefined && tag.length > 0 ? { sessionId: tag } : {};\n }\n\n function safePublish(publishOptions: HqPublishEventOptions): void {\n try {\n publisher.publishEvent(publishOptions);\n } catch {\n /* best-effort \u2014 HQ telemetry must never break the host */\n }\n }\n\n function track(off: () => void): void {\n offs.push(off);\n }\n\n function dispose(): void {\n for (const off of offs) {\n try {\n off();\n } catch {\n /* best-effort */\n }\n }\n offs.length = 0;\n }\n\n return { now, sessionIdTag, safePublish, track, dispose };\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 { createBridgeContext, type BridgeContextOptions } from './bridge-context.js';\n\nexport interface FleetTelemetryBridgeOptions extends BridgeContextOptions {\n /** Local EventBus emitting `coordinator.stats` (host EventBus after the FleetBus hop). */\n events: EventBus;\n /** Coordinator run id \u2014 identifies this fleet instance. Falls back to a stable per-session id. */\n runId: 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 ctx = createBridgeContext(opts);\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 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 try {\n publisher.publishFleetSnapshot(payload, {\n ...ctx.sessionIdTag(),\n timestamp: ctx.now(),\n });\n } catch {\n /* best-effort \u2014 HQ telemetry must never break the host */\n }\n });\n\n ctx.track(off);\n return ctx.dispose;\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 { createBridgeContext, type BridgeContextOptions } from './bridge-context.js';\n\nexport interface BrainTelemetryBridgeOptions extends BridgeContextOptions {\n /** Local EventBus emitting `brain.*` events. */\n events: EventBus;\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 } = opts;\n const ctx = createBridgeContext(opts);\n\n function publish(\n kind: HqBrainEventKind,\n payload: Partial<HqBrainEventPayload>,\n at: number,\n ): void {\n ctx.safePublish({\n type: 'brain.event',\n payload: { kind, at, ...payload } as HqBrainEventPayload,\n ...ctx.sessionIdTag(),\n timestamp: ctx.now(),\n });\n }\n\n ctx.track(\n events.on('brain.decision_requested', (p) => {\n publish('decision_requested', extractRequestFields(p.request), p.at);\n }),\n );\n ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.dispose;\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 { createBridgeContext, type BridgeContextOptions } from './bridge-context.js';\n\nexport interface WorktreeTelemetryBridgeOptions extends BridgeContextOptions {\n /** Local EventBus emitting `worktree.*` events. */\n events: EventBus;\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 } = opts;\n const ctx = createBridgeContext(opts);\n\n function publish(payload: HqWorktreeEventPayload, eventSessionId?: string): void {\n ctx.safePublish({\n type: 'worktree.event',\n payload,\n ...ctx.sessionIdTag(eventSessionId),\n timestamp: ctx.now(),\n });\n }\n\n ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.track(\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 ctx.dispose;\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 { createBridgeContext, type BridgeContextOptions } from './bridge-context.js';\n\nexport interface ToolTelemetryBridgeOptions extends BridgeContextOptions {\n /** Local EventBus emitting `tool.started` and `tool.executed` events. */\n events: EventBus;\n /** Project root for path redaction in tool input summaries. */\n projectRoot?: 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 ctx = createBridgeContext(opts);\n const inFlight = new Map<string, InFlightTool>();\n\n const offStarted = events.on('tool.started', (p: ToolStartedEvent) => {\n inFlight.set(p.id, { name: p.name, startedAt: Date.now() });\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 ctx.safePublish({\n type: 'tool.started',\n payload,\n ...ctx.sessionIdTag(p.sessionId),\n timestamp: ctx.now(),\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 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 ctx.safePublish({\n type: 'tool.completed',\n payload,\n ...ctx.sessionIdTag(p.sessionId),\n timestamp: ctx.now(),\n });\n });\n\n ctx.track(offStarted);\n ctx.track(offExecuted);\n return () => {\n ctx.dispose();\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\n * HQ 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 { createBridgeContext, type BridgeContextOptions } from './bridge-context.js';\n\nexport interface CostTelemetryBridgeOptions extends BridgeContextOptions {\n /** Local EventBus emitting `token.accounted`. */\n events: EventBus;\n}\n\ninterface TokenAccountedEvent {\n sessionId?: string | undefined;\n usage: Usage;\n deltaUsage?: Usage | undefined;\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 } = opts;\n const ctx = createBridgeContext(opts);\n\n const off = events.on('token.accounted', (p: TokenAccountedEvent) => {\n const usage = p.deltaUsage ?? p.usage;\n const payload: HqUsagePayload = {\n inputTokens: usage.input,\n outputTokens: usage.output,\n totalTokens: usage.input + 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 (usage.cacheRead !== undefined) payload.cacheRead = usage.cacheRead;\n if (usage.cacheWrite !== undefined) payload.cacheWrite = usage.cacheWrite;\n const sessionId = opts.sessionId ?? p.sessionId;\n ctx.safePublish({\n type: 'session.usage',\n payload,\n ...(sessionId !== undefined ? { sessionId } : {}),\n timestamp: ctx.now(),\n });\n });\n\n ctx.track(off);\n return ctx.dispose;\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from '../utils/atomic-write.js';\nimport { type HqKanbanSnapshotPayload, isHqKanbanSnapshotPayload } from './protocol.js';\nimport { BestEffortLatestQueue } from './write-queues.js';\n\nexport class HqKanbanStore {\n private readonly dirPath: string;\n private readonly cache = new Map<string, HqKanbanSnapshotPayload>();\n private readonly writers = new Map<string, BestEffortLatestQueue<HqKanbanSnapshotPayload>>();\n private readonly mergeChains = new Map<string, Promise<HqKanbanSnapshotPayload>>();\n\n constructor(dataDir: string) {\n this.dirPath = path.join(dataDir, 'kanban');\n }\n\n async load(projectId: string): Promise<HqKanbanSnapshotPayload> {\n const cached = this.cache.get(projectId);\n if (cached !== undefined) return structuredClone(cached);\n try {\n const content = await fs.readFile(this.filePath(projectId), 'utf8');\n const snapshot: unknown = JSON.parse(content);\n if (!isHqKanbanSnapshotPayload(snapshot) || snapshot.projectId !== projectId) {\n return emptyKanbanSnapshot(projectId);\n }\n this.cache.set(projectId, snapshot);\n return structuredClone(snapshot);\n } catch {\n return emptyKanbanSnapshot(projectId);\n }\n }\n\n /** Merge by revision, then timestamp. HQ never lets a stale writer win. */\n merge(incoming: HqKanbanSnapshotPayload): Promise<HqKanbanSnapshotPayload> {\n const previous =\n this.mergeChains.get(incoming.projectId) ??\n Promise.resolve(emptyKanbanSnapshot(incoming.projectId));\n const next = previous\n .catch(() => emptyKanbanSnapshot(incoming.projectId))\n .then(() => this.mergeNow(incoming));\n this.mergeChains.set(incoming.projectId, next);\n void next.then(\n () => {\n if (this.mergeChains.get(incoming.projectId) === next) {\n this.mergeChains.delete(incoming.projectId);\n }\n },\n () => {\n if (this.mergeChains.get(incoming.projectId) === next) {\n this.mergeChains.delete(incoming.projectId);\n }\n },\n );\n return next;\n }\n\n private async mergeNow(incoming: HqKanbanSnapshotPayload): Promise<HqKanbanSnapshotPayload> {\n const current = await this.load(incoming.projectId);\n const records = new Map<\n string,\n HqKanbanSnapshotPayload['boards'][number] | HqKanbanSnapshotPayload['tombstones'][number]\n >();\n for (const record of [...current.boards, ...current.tombstones]) records.set(record.boardId, record);\n for (const record of [...incoming.boards, ...incoming.tombstones]) {\n const existing = records.get(record.boardId);\n if (existing === undefined || compareKanbanRecord(record, existing) > 0) {\n records.set(record.boardId, record);\n }\n }\n const merged: HqKanbanSnapshotPayload = {\n projectId: incoming.projectId,\n generatedAt: new Date().toISOString(),\n boards: [],\n tombstones: [],\n };\n for (const record of records.values()) {\n if ('board' in record) merged.boards.push(record);\n else merged.tombstones.push(record);\n }\n merged.boards.sort((a, b) => a.boardId.localeCompare(b.boardId));\n merged.tombstones.sort((a, b) => a.boardId.localeCompare(b.boardId));\n this.cache.set(incoming.projectId, merged);\n this.writer(incoming.projectId).enqueue(merged);\n return structuredClone(merged);\n }\n\n async drain(): Promise<void> {\n await Promise.allSettled(this.mergeChains.values());\n await Promise.all([...this.writers.values()].map((writer) => writer.drain()));\n }\n\n private writer(projectId: string): BestEffortLatestQueue<HqKanbanSnapshotPayload> {\n let writer = this.writers.get(projectId);\n if (writer === undefined) {\n writer = new BestEffortLatestQueue(async (snapshot) => {\n await fs.mkdir(this.dirPath, { recursive: true });\n await atomicWrite(this.filePath(projectId), JSON.stringify(snapshot), { mode: 0o600 });\n });\n this.writers.set(projectId, writer);\n }\n return writer;\n }\n\n private filePath(projectId: string): string {\n const safe = createHash('sha256').update(projectId).digest('hex');\n return path.join(this.dirPath, `${safe}.json`);\n }\n}\n\nfunction emptyKanbanSnapshot(projectId: string): HqKanbanSnapshotPayload {\n return { projectId, generatedAt: new Date(0).toISOString(), boards: [], tombstones: [] };\n}\n\nfunction compareKanbanRecord(\n a: HqKanbanSnapshotPayload['boards'][number] | HqKanbanSnapshotPayload['tombstones'][number],\n b: HqKanbanSnapshotPayload['boards'][number] | HqKanbanSnapshotPayload['tombstones'][number],\n): number {\n if (a.revision !== b.revision) return a.revision - b.revision;\n const aTime = 'board' in a ? a.updatedAt : a.deletedAt;\n const bTime = 'board' in b ? b.updatedAt : b.deletedAt;\n if (aTime !== bTime) return aTime.localeCompare(bTime);\n if ('board' in a === 'board' in b) return 0;\n return 'board' in a ? -1 : 1;\n}\n", "/**\n * Collect fire-and-forget writes issued in the same event-loop turn and send\n * them to storage as one batch. The FIFO promise still serializes batches,\n * while drain() observes batches queued during an in-flight write as well.\n */\nexport class BestEffortBatchQueue<T> {\n private readonly pending: T[] = [];\n private activeWrite: Promise<void> | null = null;\n private drainScheduled = false;\n private static readonly MAX_PENDING = 10_000;\n\n constructor(private readonly writeBatch: (items: T[]) => Promise<void>) {}\n\n enqueue(item: T): void {\n if (this.pending.length >= BestEffortBatchQueue.MAX_PENDING) this.pending.shift();\n this.pending.push(item);\n if (this.drainScheduled) return;\n this.drainScheduled = true;\n queueMicrotask(() => this.flushPending());\n }\n\n async drain(): Promise<void> {\n for (;;) {\n this.flushPending();\n const observed = this.activeWrite;\n if (observed) await observed;\n if (!this.activeWrite && this.pending.length === 0) return;\n }\n }\n\n private flushPending(): void {\n this.drainScheduled = false;\n if (this.activeWrite || this.pending.length === 0) return;\n const batch = this.pending.splice(0);\n const active = this.writeBatch(batch)\n .catch((err: unknown) => {\n /* best-effort: a failed batch must not break the write chain, but\n * surface the error to stderr so a silent write death is observable.\n * Programmer errors (TypeError, etc.) should not go unnoticed. */\n console.error(\n `[BestEffortBatchQueue] failed to write batch of ${batch.length} item(s):`,\n err,\n );\n })\n .finally(() => {\n if (this.activeWrite === active) this.activeWrite = null;\n if (this.pending.length > 0) this.flushPending();\n });\n this.activeWrite = active;\n }\n}\n\n/** Coalesce queued checkpoints so only the newest not-yet-started value writes. */\nexport class BestEffortLatestQueue<T> {\n private pending: T | undefined;\n private activeWrite: Promise<void> | null = null;\n private drainScheduled = false;\n\n constructor(private readonly writeLatest: (value: T) => Promise<void>) {}\n\n enqueue(value: T): void {\n this.pending = value;\n if (this.drainScheduled) return;\n this.drainScheduled = true;\n queueMicrotask(() => this.flushPending());\n }\n\n async drain(): Promise<void> {\n for (;;) {\n this.flushPending();\n const observed = this.activeWrite;\n if (observed) await observed;\n if (!this.activeWrite && this.pending === undefined) return;\n }\n }\n\n private flushPending(): void {\n this.drainScheduled = false;\n if (this.activeWrite || this.pending === undefined) return;\n const latest = this.pending;\n this.pending = undefined;\n const active = this.writeLatest(latest)\n .catch((err: unknown) => {\n /* best-effort: a failed write must not break the write chain, but\n * surface the error to stderr so a silent write death is observable.\n * Programmer errors (TypeError, etc.) should not go unnoticed. */\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.persistence_latest_write_failed',\n message: err instanceof Error ? err.message : String(err),\n timestamp: new Date().toISOString(),\n }),\n );\n })\n .finally(() => {\n if (this.activeWrite === active) this.activeWrite = null;\n if (this.pending !== undefined) this.flushPending();\n });\n this.activeWrite = active;\n }\n}\n", "/**\n * Append-only JSONL log of every HQ event envelope, with tail-first reads.\n *\n * Split out of `hq/persistence.ts`; see that module for the shared design\n * constraints (file-lock + atomic writes, best-effort semantics, FIFO write\n * chain).\n *\n * @module hq/persistence/event-log\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicReplaceWithWriter, withFileLock } from '../../utils/atomic-write.js';\nimport type { HqEventEnvelope } from '../protocol.js';\nimport { BestEffortBatchQueue } from '../write-queues.js';\nimport {\n copyTailToHandle,\n findTailStartOffset,\n LINE_COUNT_CHUNK_BYTES,\n RECENT_READ_CHUNK_BYTES,\n} from './jsonl-io.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 * Maximum event-log *bytes* before rotation, and how many bytes to retain.\n *\n * A line cap alone does not bound this file: envelope size varies by three\n * orders of magnitude across event types, so 50k lines has meant anywhere from\n * a few MB to ~700 MB in practice (measured: 429 MB at 30,809 lines, average\n * line 14.5 KB \u2014 the line cap had never once fired). Rotation now triggers on\n * whichever cap binds first, and the retained tail is bounded the same way.\n *\n * Defaults per HQ Evolution 2026-08 \u00A710.3: cap lowered from 64 MB to 32 MB\n * to keep on-disk footprint bounded for VPS deployments; still safely above\n * the 1 MB tail-scan threshold. Both numbers remain configurable per HQ\n * instance via {@link HqEventLogOptions}.\n */\nconst DEFAULT_EVENT_LOG_MAX_BYTES = 32 * 1024 * 1024;\nconst DEFAULT_EVENT_LOG_ROTATE_KEEP_BYTES = 16 * 1024 * 1024;\n/** Switch to one bulk prefix read when a selective filter requires a deep scan. */\nconst RECENT_TAIL_SCAN_BYTES = 1024 * 1024;\nconst FILTERED_RECENT_TAIL_SCAN_BYTES = 256 * 1024;\n/**\n * Cap on the bulk prefix read used when a tail scan cannot satisfy `limit`.\n * Without a cap, a multi-GB event log would allocate one giant buffer per\n * `recent()` call. 8 MiB keeps the worst-case allocation bounded while still\n * scanning deep enough for practical filtered queries; older events beyond\n * the cap are simply not returned in that one call.\n */\nconst BULK_PREFIX_READ_CAP = 8 * 1024 * 1024;\n\nexport interface HqEventLogOptions {\n dataDir: string;\n maxLines?: number;\n rotateKeep?: number;\n maxBytes?: number;\n rotateKeepBytes?: number;\n}\n\n/**\n * Named presets for the byte cap. The default (no preset) is the 32 MB cap\n * per HQ Evolution 2026-08 \u00A710.3. Pick a preset when you want to make\n * the override path explicit in code review.\n *\n * - `'vps8'` \u2014 8 MB cap, 2 MB retained. Tightest cap for memory-constrained\n * VPS deployments.\n * - `'vps32'` \u2014 32 MB cap, 16 MB retained. Same as the default.\n * - `'desktop'` \u2014 64 MB cap, 24 MB retained. The pre-\u00A710.3 default; for\n * workstations with disk to spare.\n */\nexport type HqEventLogPreset = 'vps8' | 'vps32' | 'desktop';\n\nexport const HQ_EVENT_LOG_PRESETS: Readonly<Record<HqEventLogPreset, {\n maxBytes: number;\n rotateKeepBytes: number;\n}>> = Object.freeze({\n vps8: { maxBytes: 8 * 1024 * 1024, rotateKeepBytes: 2 * 1024 * 1024 },\n vps32: { maxBytes: 32 * 1024 * 1024, rotateKeepBytes: 16 * 1024 * 1024 },\n desktop: { maxBytes: 64 * 1024 * 1024, rotateKeepBytes: 24 * 1024 * 1024 },\n});\n\n/**\n * Return the byte-cap fields for a named preset. Throws on unknown preset\n * names so callers get a clear error at construction time rather than\n * silently falling back to the default.\n */\nexport function hqEventLogPresetFields(preset: HqEventLogPreset): {\n maxBytes: number;\n rotateKeepBytes: number;\n} {\n const fields = HQ_EVENT_LOG_PRESETS[preset];\n if (fields === undefined) {\n throw new Error(\n `Unknown HqEventLogPreset: ${String(preset)}. Allowed: ${Object.keys(HQ_EVENT_LOG_PRESETS).join(', ')}.`,\n );\n }\n return fields;\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 readonly writer: BestEffortBatchQueue<HqEventEnvelope>;\n private readonly maxBytes: number;\n private readonly rotateKeepBytes: number;\n private lineCount = 0;\n private byteCount = 0;\n private counted = false;\n private hydration: Promise<void> | undefined;\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 this.maxBytes = opts.maxBytes ?? DEFAULT_EVENT_LOG_MAX_BYTES;\n this.rotateKeepBytes = opts.rotateKeepBytes ?? DEFAULT_EVENT_LOG_ROTATE_KEEP_BYTES;\n this.writer = new BestEffortBatchQueue((events) => this.appendInternal(events));\n }\n\n /** Append an event envelope as one JSON line. Best-effort, never rejects. */\n append(event: HqEventEnvelope): void {\n this.writer.enqueue(event);\n }\n\n /** Resolves once all queued appends have settled. For tests. */\n async drain(): Promise<void> {\n await this.writer.drain();\n }\n\n private async appendInternal(events: HqEventEnvelope[]): Promise<void> {\n await this.ensureLineCount();\n const lines = events.map((event) => JSON.stringify(event)).join('\\n') + '\\n';\n await fs.appendFile(this.filePath, lines, { encoding: 'utf8' });\n this.lineCount += events.length;\n this.byteCount += Buffer.byteLength(lines, 'utf8');\n if (this.lineCount >= this.maxLines || this.byteCount >= this.maxBytes) {\n await this.rotate();\n }\n }\n\n /**\n * Compact the log down to its most recent lines.\n *\n * Streams the retained tail straight from the old file into the replacement\n * rather than materializing it. The previous implementation read the tail\n * into a `string[]`, `join`ed it, and handed the result to `atomicWrite` \u2014\n * at the observed 14.5 KB average line that is ~277 MB of UTF-8 inflated to\n * ~555 MB of JS strings, plus another ~555 MB for the join, all allocated\n * inside the file lock. Rotation is now O(one chunk) no matter how much is\n * retained, so the operation that exists to *reclaim* space stops being the\n * largest allocation the process ever makes.\n */\n private async rotate(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n try {\n const retainCount = Math.max(0, Math.floor(this.rotateKeep));\n const { offset, size } = await findTailStartOffset(\n this.filePath,\n retainCount,\n this.rotateKeepBytes,\n );\n // offset 0 means the file is already at or under the keep-count and\n // within the byte budget \u2014 nothing to reclaim. Re-sync the counters\n // (another process may have rotated underneath us) and stop.\n if (offset === 0) {\n this.byteCount = size;\n this.lineCount = await this.countLines();\n return;\n }\n const copied = await atomicReplaceWithWriter(this.filePath, (handle) =>\n copyTailToHandle(this.filePath, offset, handle),\n );\n this.lineCount = copied.lines;\n this.byteCount = copied.bytes;\n } catch {\n /* best-effort */\n }\n });\n }\n\n private async countLines(): Promise<number> {\n let handle: fs.FileHandle;\n try {\n handle = await fs.open(this.filePath, 'r');\n } catch {\n return 0;\n }\n try {\n const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);\n let count = 0;\n let position = 0;\n let lineHasBytes = false;\n // `lineHasBytes` is the \"the current open line has at least one\n // non-newline byte\" flag \u2014 it survives chunk boundaries by design.\n // Invariants:\n // - Reset to `false` after every newline we encounter inside the chunk.\n // - Set to `true` if we see a non-newline byte in the chunk's trailing\n // bytes (everything after the last `\\n` of the chunk).\n // - Carried across `handle.read()` boundaries so a multi-chunk line\n // that spans a partial read is counted exactly once. Without this\n // carry, a 200 KB line straddling two 256 KB reads would either be\n // double-counted (both halves look like non-empty trailing bytes)\n // or under-counted (neither half clears the flag).\n // - After the loop, `true` means \"the last line in the file had no\n // trailing newline\", which contributes one final line.\n // The trailing-bytes special case below mirrors `split('\\n').filter(Boolean)`\n // exactly: a chunk that ends with `\\n` (or a run of newlines) must not\n // yield an extra empty line.\n for (;;) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);\n if (bytesRead === 0) break;\n position += bytesRead;\n let start = 0;\n for (;;) {\n const newline = buffer.indexOf(0x0a, start);\n if (newline < 0 || newline >= bytesRead) {\n // Trailing bytes after the last newline in this chunk. Mark the\n // partial line as \"has content\" only when at least one non-newline\n // byte remains \u2014 a chunk that ends with `\\n` (or a run of newlines)\n // contributes no extra line, matching `split('\\n').filter(Boolean)`.\n for (let index = start; index < bytesRead; index++) {\n if (buffer[index] !== 0x0a) {\n lineHasBytes = true;\n break;\n }\n }\n break;\n }\n if (lineHasBytes || newline > start) count++;\n lineHasBytes = false;\n start = newline + 1;\n }\n }\n return count + (lineHasBytes ? 1 : 0);\n } catch {\n return 0;\n } finally {\n await handle.close().catch(() => {});\n }\n }\n\n private async ensureLineCount(): Promise<void> {\n if (this.counted) return;\n // Seed the byte counter alongside the line counter, otherwise a process\n // that restarts against an already-oversized log would count up from zero\n // and never trip the byte cap.\n this.hydration ??= Promise.all([\n this.countLines(),\n fs.stat(this.filePath).then(\n (stat) => stat.size,\n () => 0,\n ),\n ]).then(([count, size]) => {\n this.lineCount = count;\n this.byteCount = size;\n this.counted = true;\n });\n try {\n await this.hydration;\n } catch {\n // Defensive: countLines currently swallows IO errors, but a future\n // change could let one reject. Reset the cache so the next call\n // retries instead of re-throwing a cached rejection forever.\n this.hydration = undefined;\n throw new Error('ensureLineCount hydration rejected; cache cleared');\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 * Reads are best-effort against a concurrent appender: the file size is\n * sampled once at entry and may return one duplicate or miss one tail\n * line if another process appends during the scan. When a `typeFilter`\n * is set and matches are sparse, the scan walks the whole file in\n * bounded windows but is still guaranteed to reach every line.\n */\n async recent(limit: number, typeFilter?: string): Promise<HqEventEnvelope[]> {\n return readRecentEvents(this.filePath, limit, typeFilter);\n }\n\n /** Initialize the line count cache from disk (call once at boot). */\n async hydrate(): Promise<void> {\n await this.ensureLineCount();\n }\n}\n\nexport async function readRecentEvents(\n filePath: string,\n limit: number,\n typeFilter?: string,\n): Promise<HqEventEnvelope[]> {\n if (!(limit > 0)) return [];\n let handle: fs.FileHandle;\n try {\n handle = await fs.open(filePath, 'r');\n } catch {\n return [];\n }\n\n const out: HqEventEnvelope[] = [];\n const acceptText = (raw: string): boolean => {\n const line = raw.trim();\n if (!line) return false;\n try {\n const event = JSON.parse(line) as HqEventEnvelope;\n if (typeFilter === undefined || event.type === typeFilter) out.push(event);\n } catch {\n /* skip malformed lines */\n }\n return out.length >= limit;\n };\n const acceptLine = (parts: Buffer[]): boolean =>\n acceptText(Buffer.concat(parts).toString('utf8'));\n\n try {\n let position = (await handle.stat()).size;\n // Byte slices are retained until a complete line is found. Splitting on\n // the ASCII newline byte before UTF-8 decoding keeps multibyte characters\n // valid even when a block boundary lands in the middle of one.\n let carry: Buffer[] = [];\n let tailBytesRead = 0;\n const tailScanLimit =\n typeFilter === undefined ? RECENT_TAIL_SCAN_BYTES : FILTERED_RECENT_TAIL_SCAN_BYTES;\n while (position > 0) {\n const length = Math.min(RECENT_READ_CHUNK_BYTES, position);\n position -= length;\n const buffer = Buffer.allocUnsafe(length);\n const { bytesRead } = await handle.read(buffer, 0, length, position);\n if (bytesRead === 0) break;\n tailBytesRead += bytesRead;\n const chunk = bytesRead === length ? buffer : buffer.subarray(0, bytesRead);\n let lineEnd = chunk.length;\n for (let index = chunk.length - 1; index >= 0; index--) {\n if (chunk[index] !== 0x0a) continue;\n if (acceptLine([chunk.subarray(index + 1, lineEnd), ...carry])) return out;\n carry = [];\n lineEnd = index;\n }\n if (lineEnd > 0) carry.unshift(chunk.subarray(0, lineEnd));\n if (position > 0 && tailBytesRead >= tailScanLimit) {\n // A rare type filter can require most of the file. One bulk read and\n // native UTF-8 split is faster than hundreds of small reads and a\n // JavaScript byte walk, while common tail hits retain the bounded\n // 64 KiB fast path above. We slice the remaining prefix into\n // `BULK_PREFIX_READ_CAP`-sized windows (newest first) so a multi-GB\n // event log still yields up to `limit` matches without one allocation\n // spanning the whole file.\n let sliceEnd = position;\n // The first iteration's seam line is the line bridging `carry` (head\n // bytes from the tail scan) and `prefixRead`; it has not been\n // accepted before. On subsequent iterations, `carry` already holds\n // the FULL bytes of that same seam line, and re-decoding +\n // re-accepting it would count it twice. We track the seam string so\n // we can skip the duplicate acceptText on iteration 1+.\n let priorSeam = '';\n while (sliceEnd > 0) {\n const readLen = Math.min(sliceEnd, BULK_PREFIX_READ_CAP);\n const readOffset = sliceEnd - readLen;\n const prefix = Buffer.allocUnsafe(readLen);\n let offset = 0;\n while (offset < readLen) {\n const result = await handle.read(prefix, offset, readLen - offset, readOffset + offset);\n if (result.bytesRead === 0) break;\n offset += result.bytesRead;\n }\n const prefixRead = offset === prefix.length ? prefix : prefix.subarray(0, offset);\n // The boundary between `prefixRead` and `carry` may split a multibyte\n // UTF-8 character; joining at the buffer level keeps that character\n // intact across the seam. Stitch the oldest line of THIS slice with\n // the carry from the previous (newer) slice so the window-boundary\n // line is decoded once. All subsequent lines in the slice are\n // processed standalone.\n const text = Buffer.concat([prefixRead, ...carry]).toString('utf8');\n carry = [];\n const lines = text.split('\\n');\n for (let index = lines.length - 1; index >= 1; index--) {\n const line = lines[index];\n if (line === undefined) continue;\n if (acceptText(line)) return out;\n }\n // Stitch the oldest line of this slice with the carry from the\n // previous iteration (already in `text` via the concat above) so\n // the window-boundary line is decoded exactly once. lines[0] has\n // already been combined with carry at the buffer level.\n // On iteration 1+ the same seam line reappears (carry holds its\n // full bytes); skip re-accepting because `priorSeam` matches.\n const boundary = lines[0] ?? '';\n if (boundary !== priorSeam && acceptText(boundary)) return out;\n if (readOffset === 0) break;\n // Save the boundary line text in its buffer form so the next slice\n // can stitch with it at the byte level (preserving any multibyte\n // UTF-8 split character at the new seam).\n carry = [Buffer.from(boundary, 'utf8')];\n priorSeam = boundary;\n sliceEnd = readOffset;\n }\n return out;\n }\n }\n if (carry.length > 0) acceptLine(carry);\n return out;\n } catch {\n return [];\n } finally {\n await handle.close().catch(() => {});\n }\n}\n", "/**\n * Shared JSONL read primitives for the HQ persistence stores.\n *\n * Every HQ store is backed by an append-only JSONL file, so they all need the\n * same three reads: \"give me the last N non-empty lines\", \"stream me every\n * line without holding the file\", and \"how many non-empty lines are there\".\n * They live here so {@link module:hq/persistence} stays a facade.\n *\n * All three speak `fs/promises` FileHandles and chunked reads rather than\n * streams: peak memory stays at one chunk plus the longest single line, and\n * there is no stream teardown to get wrong on the error path.\n *\n * @module hq/persistence/jsonl-io\n */\nimport * as fs from 'node:fs/promises';\nimport { StringDecoder } from 'node:string_decoder';\n\n/** Read recent JSONL records from the tail without loading the whole log. */\nexport const RECENT_READ_CHUNK_BYTES = 64 * 1024;\nexport const LINE_COUNT_CHUNK_BYTES = 256 * 1024;\n\nexport async function readTailNonEmptyLines(\n filePath: string,\n limit: number,\n estimatedLineCount: number,\n): Promise<string[]> {\n if (!(limit > 0)) return [];\n const handle = await fs.open(filePath, 'r');\n try {\n const size = (await handle.stat()).size;\n let position = size;\n const chunks: Buffer[] = [];\n // Track the accumulated newline count across chunks without doing a full\n // concat+decode+split on every iteration. We only pay the O(N) decode\n // cost once \u2014 when we have enough lines (or hit the start of file).\n let totalNewlines = 0;\n // The in-memory line count lets rotation jump directly to the likely tail\n // boundary in one read. Keep 10% headroom plus one block for variable-size\n // records; if the estimate is short, expand backwards geometrically.\n let nextReadBytes = Math.min(\n size,\n Math.max(\n RECENT_READ_CHUNK_BYTES,\n estimatedLineCount > 0\n ? Math.ceil((size * limit * 1.1) / estimatedLineCount) + RECENT_READ_CHUNK_BYTES\n : Math.ceil(limit * 512) + RECENT_READ_CHUNK_BYTES,\n ),\n );\n while (position > 0) {\n const length = Math.min(nextReadBytes, position);\n position -= length;\n const buffer = Buffer.allocUnsafe(length);\n let bytesRead = 0;\n while (bytesRead < length) {\n const result = await handle.read(\n buffer,\n bytesRead,\n length - bytesRead,\n position + bytesRead,\n );\n if (result.bytesRead === 0) break;\n bytesRead += result.bytesRead;\n }\n if (bytesRead === 0) break;\n const chunk = bytesRead === length ? buffer : buffer.subarray(0, bytesRead);\n chunks.unshift(chunk);\n // Byte-scan the newest chunk only \u2014 totalNewlines is an overcount of\n // non-empty lines (consecutive newlines don't add a line) so when it\n // crosses `limit` we are guaranteed to have enough to return.\n for (let index = 0; index < chunk.length; index++) {\n if (chunk[index] === 0x0a) totalNewlines++;\n }\n if (position === 0 || totalNewlines >= limit) {\n const lines = Buffer.concat(chunks)\n .toString('utf8')\n .split('\\n')\n .filter((line) => line.length > 0);\n return lines.slice(-limit).reverse();\n }\n nextReadBytes = Math.min(position, nextReadBytes * 2);\n }\n return [];\n } finally {\n await handle.close().catch(() => {});\n }\n}\n\n/**\n * Byte offset at which the retained tail of a JSONL file begins.\n *\n * The counterpart to {@link readTailNonEmptyLines} for callers that want to\n * *keep* a tail rather than read it: this returns a line-aligned offset and\n * never materializes the tail itself. Peak memory is one chunk, regardless of\n * how large the retained region is \u2014 the whole point, since the tail of a\n * rotation-sized log is exactly what must not be buffered.\n *\n * The retained region is bounded by both `keepLines` and `maxBytes`; whichever\n * binds first wins. A single line longer than `maxBytes` is still retained\n * whole rather than dropped, so rotation can never empty the file outright.\n *\n * Returns `offset === 0` when the file has fewer than `keepLines` lines (no\n * rotation needed) and the file's size, sampled once, for the caller.\n */\nexport async function findTailStartOffset(\n filePath: string,\n keepLines: number,\n maxBytes: number,\n): Promise<{ offset: number; size: number }> {\n const handle = await fs.open(filePath, 'r');\n try {\n const size = (await handle.stat()).size;\n if (size === 0) return { offset: 0, size };\n\n // A trailing newline terminates the last line; without one, the last\n // newline in the file *opens* the final line. That shifts which newline\n // from the end marks the start of the retained region by exactly one.\n const tailByte = Buffer.allocUnsafe(1);\n await handle.read(tailByte, 0, 1, size - 1);\n const target = keepLines + (tailByte[0] === 0x0a ? 1 : 0);\n if (target <= 0) return { offset: size, size };\n\n const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);\n let position = size;\n let seen = 0;\n // Best line-aligned boundary found so far. Walks backwards from \"retain\n // nothing\" as newlines are discovered.\n let boundary = size;\n while (position > 0) {\n const length = Math.min(LINE_COUNT_CHUNK_BYTES, position);\n position -= length;\n let read = 0;\n while (read < length) {\n const result = await handle.read(buffer, read, length - read, position + read);\n if (result.bytesRead === 0) break;\n read += result.bytesRead;\n }\n if (read === 0) break;\n for (let index = read - 1; index >= 0; index--) {\n if (buffer[index] !== 0x0a) continue;\n const candidate = position + index + 1;\n if (size - candidate > maxBytes) {\n // Past the byte budget. Keep the last boundary that fit \u2014 or this\n // one when nothing has fit yet, so an oversized final line survives.\n return { offset: boundary < size ? boundary : candidate, size };\n }\n boundary = candidate;\n seen++;\n if (seen >= target) return { offset: boundary, size };\n }\n }\n // Fewer lines than requested: the whole file is already the tail.\n return { offset: 0, size };\n } finally {\n await handle.close().catch(() => {});\n }\n}\n\n/**\n * Copy `sourcePath` from `offset` to EOF into an open destination handle,\n * chunk by chunk. Peak memory is one chunk. Returns the bytes copied and the\n * number of newlines seen, so a caller rotating a log can reset its counters\n * without a second pass.\n */\nexport async function copyTailToHandle(\n sourcePath: string,\n offset: number,\n destination: fs.FileHandle,\n): Promise<{ bytes: number; lines: number }> {\n const handle = await fs.open(sourcePath, 'r');\n try {\n const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);\n let position = offset;\n let bytes = 0;\n let lines = 0;\n let lineHasBytes = false;\n for (;;) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);\n if (bytesRead === 0) break;\n position += bytesRead;\n const chunk = buffer.subarray(0, bytesRead);\n for (let index = 0; index < bytesRead; index++) {\n if (chunk[index] === 0x0a) {\n if (lineHasBytes) lines++;\n lineHasBytes = false;\n } else {\n lineHasBytes = true;\n }\n }\n await destination.write(chunk);\n bytes += bytesRead;\n }\n return { bytes, lines: lines + (lineHasBytes ? 1 : 0) };\n } finally {\n await handle.close().catch(() => {});\n }\n}\n\n/**\n * Yield non-empty lines of a JSONL file without ever holding the whole file.\n *\n * Deliberately not `readline`/`createReadStream`: this module already speaks\n * `fs/promises` FileHandles (see {@link countNonEmptyLines}) and a chunked read\n * keeps the peak at one chunk plus the longest single line, with no stream\n * teardown to get wrong on the error path. Callers get a plain async iterable\n * they can `break` out of; the handle is closed either way.\n *\n * `StringDecoder` \u2014 not `buffer.toString('utf8')` \u2014 because a chunk boundary\n * lands mid-character sooner or later, and a bare decode turns that character\n * into U+FFFD before any carry logic could rescue it. The decoder holds the\n * incomplete byte sequence until the next chunk completes it.\n *\n * Throws only if the file cannot be opened \u2014 malformed content is the caller's\n * problem, one line at a time.\n */\nexport async function* readJsonlLines(filePath: string): AsyncGenerator<string> {\n const handle = await fs.open(filePath, 'r');\n try {\n const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);\n const decoder = new StringDecoder('utf8');\n let position = 0;\n let carry = '';\n for (;;) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);\n if (bytesRead === 0) break;\n position += bytesRead;\n const text = carry + decoder.write(buffer.subarray(0, bytesRead));\n let start = 0;\n for (;;) {\n const newline = text.indexOf('\\n', start);\n if (newline === -1) break;\n const line = text.slice(start, newline).trim();\n start = newline + 1;\n if (line) yield line;\n }\n carry = text.slice(start);\n }\n const last = (carry + decoder.end()).trim();\n if (last) yield last;\n } finally {\n await handle.close();\n }\n}\n\nexport async function countNonEmptyLines(filePath: string): Promise<number> {\n let handle: fs.FileHandle;\n try {\n handle = await fs.open(filePath, 'r');\n } catch {\n return 0;\n }\n try {\n const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);\n let count = 0;\n let position = 0;\n let lineHasBytes = false;\n for (;;) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);\n if (bytesRead === 0) break;\n position += bytesRead;\n let start = 0;\n for (;;) {\n const newline = buffer.indexOf(0x0a, start);\n if (newline < 0 || newline >= bytesRead) {\n if (start < bytesRead) lineHasBytes = true;\n break;\n }\n if (lineHasBytes || newline > start) count++;\n lineHasBytes = false;\n start = newline + 1;\n }\n }\n return count + (lineHasBytes ? 1 : 0);\n } finally {\n await handle.close().catch(() => {});\n }\n}\n", "/**\n * Generic append-only JSONL log for HQ audit/alert records.\n *\n * Split out of `hq/persistence.ts`; see that module for the shared design\n * constraints.\n *\n * @module hq/persistence/simple-log\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../../utils/atomic-write.js';\nimport { BestEffortBatchQueue } from '../write-queues.js';\nimport { countNonEmptyLines, readTailNonEmptyLines } from './jsonl-io.js';\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 HqSimpleLog.readAll}\n * parses them oldest-first. Best-effort: a rejected append resolves (never\n * rejects) so the HQ server hot path is never broken.\n */\nexport interface HqSimpleLogOptions {\n dataDir: string;\n filename: string;\n maxLines?: number;\n rotateKeep?: number;\n readLimit?: number;\n}\n\nexport class HqSimpleLog<T> {\n private readonly filePath: string;\n private readonly maxLines: number;\n private readonly rotateKeep: number;\n private readonly readLimit: number;\n private readonly writer: BestEffortBatchQueue<T>;\n private lineCount = 0;\n private counted = false;\n private hydration: Promise<void> | undefined;\n\n constructor(opts: HqSimpleLogOptions) {\n this.filePath = path.join(opts.dataDir, opts.filename);\n this.maxLines = opts.maxLines ?? Infinity;\n this.rotateKeep = opts.rotateKeep ?? this.maxLines;\n this.readLimit = opts.readLimit ?? Infinity;\n this.writer = new BestEffortBatchQueue((records) => this.appendInternal(records));\n }\n\n /** Append one record as a JSON line. Best-effort, never rejects. */\n append(record: T): void {\n this.writer.enqueue(record);\n }\n\n /** Resolves once all queued appends have settled. For tests. */\n async drain(): Promise<void> {\n await this.writer.drain();\n }\n\n private async appendInternal(records: T[]): Promise<void> {\n if (Number.isFinite(this.maxLines)) await this.ensureLineCount();\n await fs.appendFile(\n this.filePath,\n records.map((record) => JSON.stringify(record)).join('\\n') + '\\n',\n { encoding: 'utf8' },\n );\n this.lineCount += records.length;\n if (this.lineCount < this.maxLines) return;\n await withFileLock(this.filePath, async () => {\n const retainCount = Math.max(0, Math.floor(this.rotateKeep));\n const newest = await readTailNonEmptyLines(this.filePath, retainCount + 1, this.lineCount);\n if (newest.length <= retainCount) {\n this.lineCount = newest.length;\n return;\n }\n const kept = newest.slice(0, retainCount).reverse();\n await atomicWrite(this.filePath, kept.join('\\n') + '\\n', { mode: 0o600 });\n this.lineCount = kept.length;\n });\n }\n\n private async ensureLineCount(): Promise<void> {\n if (this.counted) return;\n this.hydration ??= countNonEmptyLines(this.filePath)\n .catch(() => 0)\n .then((count) => {\n this.lineCount = count;\n this.counted = true;\n });\n await this.hydration;\n }\n\n /** Read all records oldest-first. Returns `[]` if the file doesn't exist. */\n async readAll(): Promise<T[]> {\n let lines: string[];\n try {\n lines = (\n await readTailNonEmptyLines(\n this.filePath,\n this.readLimit,\n this.counted ? this.lineCount : 0,\n )\n ).reverse();\n } catch {\n return [];\n }\n const out: T[] = [];\n for (const line of lines) {\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 * Atomic checkpoint of the latest HQ snapshot.\n *\n * Split out of `hq/persistence.ts`; see that module for the shared design\n * constraints.\n *\n * @module hq/persistence/snapshot-store\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from '../../utils/atomic-write.js';\nimport type { HqSnapshot } from '../protocol.js';\nimport { BestEffortLatestQueue } from '../write-queues.js';\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 readonly writer: BestEffortLatestQueue<HqSnapshot>;\n\n constructor(opts: HqSnapshotStoreOptions) {\n this.filePath = path.join(opts.dataDir, 'snapshot.json');\n this.writer = new BestEffortLatestQueue((snapshot) =>\n atomicWrite(this.filePath, JSON.stringify(snapshot), { mode: 0o600 }),\n );\n }\n\n /** Persist a snapshot. Best-effort, never rejects. */\n save(snapshot: HqSnapshot): void {\n this.writer.enqueue(snapshot);\n }\n\n /** Resolves once all queued saves have settled. For tests. */\n async drain(): Promise<void> {\n await this.writer.drain();\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 * Time-bucketed cost + activity samples for HQ trend charts.\n *\n * Split out of `hq/persistence.ts`; see that module for the shared design\n * constraints.\n *\n * @module hq/persistence/timeseries-store\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../../utils/atomic-write.js';\nimport { BestEffortLatestQueue } from '../write-queues.js';\nimport { countNonEmptyLines, readJsonlLines } from './jsonl-io.js';\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 readonly dirtyVersions = new Map<number, number>();\n private readonly writer: BestEffortLatestQueue<{\n samples: HqTimeseriesSample[];\n versions: Map<number, number>;\n }>;\n private nextDirtyVersion = 0;\n private diskLineCount: number | undefined;\n private loaded = false;\n private loadPromise: Promise<void> | undefined;\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 this.writer = new BestEffortLatestQueue((snapshot) => this.flushInternal(snapshot));\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 this.dirtyVersions.set(start, ++this.nextDirtyVersion);\n // Prune in-memory buckets beyond retention so a long-lived HQ doesn't\n // accumulate unbounded history. Keep the most-recent maxBuckets.\n this.pruneBuckets({ dropDirty: true });\n }\n\n /**\n * Drop the oldest buckets beyond `maxBuckets`.\n *\n * `dropDirty` also forgets the pending flush version for an evicted bucket \u2014\n * correct when the eviction happens on the record path (the bucket is gone,\n * so there is nothing left to write). The load path leaves `dirtyVersions`\n * alone because it has not produced any.\n */\n private pruneBuckets(opts: { dropDirty?: boolean } = {}): void {\n if (this.buckets.size <= this.maxBuckets) return;\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 if (opts.dropDirty) this.dirtyVersions.delete(oldest);\n }\n }\n\n /**\n * Persist accumulated buckets to disk (append under lock), prune to maxBuckets.\n *\n * Note: this dispatcher coalesces \u2014 if `flush()` is called multiple times\n * before the previous flush settles, only the most-recent snapshot is\n * written. The dropped snapshots came from the same in-memory `buckets`\n * map, so their data is folded into the surviving snapshot rather than\n * lost. Callers that need every intermediate window on disk should use a\n * BestEffortBatchQueue instead of BestEffortLatestQueue here.\n */\n flush(): void {\n if (this.dirtyVersions.size === 0) return;\n const versions = new Map(this.dirtyVersions);\n for (const [timestamp, version] of versions) {\n if (this.buckets.has(timestamp)) continue;\n versions.delete(timestamp);\n if (this.dirtyVersions.get(timestamp) === version) this.dirtyVersions.delete(timestamp);\n }\n const samples = Array.from(versions.keys())\n .map((timestamp) => this.buckets.get(timestamp))\n .filter((sample): sample is HqTimeseriesSample => sample !== undefined)\n .map(cloneTimeseriesSample)\n .sort((a, b) => a.ts - b.ts);\n if (samples.length === 0) return;\n this.writer.enqueue({ samples, versions });\n }\n\n /** Resolves once all queued flushes have settled. For tests. */\n async drain(): Promise<void> {\n await this.writer.drain();\n }\n\n private async flushInternal(snapshot: {\n samples: HqTimeseriesSample[];\n versions: Map<number, number>;\n }): Promise<void> {\n const lines = snapshot.samples.map((bucket) => JSON.stringify(bucket)).join('\\n') + '\\n';\n await withFileLock(this.filePath, async () => {\n this.diskLineCount ??= await countNonEmptyLines(this.filePath);\n await fs.appendFile(this.filePath, lines, { encoding: 'utf8' });\n this.diskLineCount += snapshot.samples.length;\n const compactAt = Math.max(this.maxBuckets + 1, this.maxBuckets * 4);\n if (this.diskLineCount >= compactAt) {\n const retained = Array.from(this.buckets.values())\n .map(cloneTimeseriesSample)\n .sort((a, b) => a.ts - b.ts);\n await atomicWrite(\n this.filePath,\n retained.map((bucket) => JSON.stringify(bucket)).join('\\n') + '\\n',\n { mode: 0o600 },\n );\n this.diskLineCount = retained.length;\n }\n });\n for (const [timestamp, version] of snapshot.versions) {\n if (this.dirtyVersions.get(timestamp) === version) this.dirtyVersions.delete(timestamp);\n }\n // Prune in-memory buckets beyond retention.\n this.pruneBuckets();\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.loaded && 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 if (this.loaded) return;\n this.loadPromise ??= this.loadInternal();\n await this.loadPromise;\n }\n\n private async loadInternal(): Promise<void> {\n // Streamed, not `readFile(\u2026, 'utf8')`. Two reasons, and the second one bit:\n // 1. The whole file would be resident as one string plus its split parts,\n // for a store that only ever keeps `maxBuckets` samples.\n // 2. Node caps a single string at ~512 MB. This file had grown past that,\n // so the read threw ERR_STRING_TOO_LONG \u2014 which the catch below turned\n // into `diskLineCount = 0`, and compaction only fires once\n // `diskLineCount` crosses a threshold. Too big to read meant too big to\n // compact, so it grew forever and HQ silently lost all trend history on\n // every restart. Streaming removes the ceiling that started it.\n let lineCount = 0;\n try {\n for await (const line of readJsonlLines(this.filePath)) {\n lineCount++;\n try {\n const sample = JSON.parse(line) 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 // Bound the working set during the scan itself: an oversized file must\n // not cost more than a healthy one just because it is being read.\n if (this.buckets.size > this.maxBuckets * 2) this.pruneBuckets();\n }\n } catch {\n // Missing/unreadable file. `lineCount` reflects whatever was consumed, so\n // a partial read still leaves compaction armed rather than disabled.\n this.diskLineCount = lineCount;\n this.loaded = true;\n return;\n }\n this.diskLineCount = lineCount;\n this.loaded = true;\n // Prune to retention.\n this.pruneBuckets();\n }\n}\n\nfunction cloneTimeseriesSample(sample: HqTimeseriesSample): HqTimeseriesSample {\n return {\n ...sample,\n ...(sample.byModel\n ? {\n byModel: Object.fromEntries(\n Object.entries(sample.byModel).map(([key, value]) => [key, { ...value }]),\n ),\n }\n : {}),\n ...(sample.byProvider\n ? {\n byProvider: Object.fromEntries(\n Object.entries(sample.byProvider).map(([key, value]) => [key, { ...value }]),\n ),\n }\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 * 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 * Each store lives in its own module under `persistence/`; this file is the\n * facade that re-exports them and composes {@link createHqPersistence}. The\n * shared JSONL read primitives are in `persistence/jsonl-io.ts`.\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 { HqKanbanStore } from './kanban-store.js';\nimport { HqEventLog } from './persistence/event-log.js';\nimport { HqSimpleLog } from './persistence/simple-log.js';\nimport { HqSnapshotStore } from './persistence/snapshot-store.js';\nimport { HqTimeseriesStore } from './persistence/timeseries-store.js';\n\nexport { HqKanbanStore } from './kanban-store.js';\nexport {\n HqEventLog,\n HQ_EVENT_LOG_PRESETS,\n hqEventLogPresetFields,\n type HqEventLogOptions,\n type HqEventLogPreset,\n} from './persistence/event-log.js';\nexport { HqSimpleLog, type HqSimpleLogOptions } from './persistence/simple-log.js';\nexport { HqSnapshotStore, type HqSnapshotStoreOptions } from './persistence/snapshot-store.js';\nexport {\n type HqTimeseriesBreakdownEntry,\n type HqTimeseriesSample,\n HqTimeseriesStore,\n type HqTimeseriesStoreOptions,\n} from './persistence/timeseries-store.js';\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 kanban: HqKanbanStore;\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 kanban: new HqKanbanStore(dataDir),\n commandLog: new HqSimpleLog({\n dataDir,\n filename: 'commands.jsonl',\n maxLines: 8_000,\n rotateKeep: 4_000,\n readLimit: 4_000,\n }),\n alertLog: new HqSimpleLog({\n dataDir,\n filename: 'alerts.jsonl',\n maxLines: 2_000,\n rotateKeep: 1_000,\n readLimit: 1_000,\n }),\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 * Hours before expiry at which the `token-expiry-imminent` warning fires.\n * Default 24. Set to 0 to disable the warning entirely (expired-only alert remains).\n */\n tokenExpiryWarningHours?: number;\n}\n\n/** The fully-resolved config passed to rule.evaluate (no optional fields). */\ntype ResolvedAlertConfig = Required<Pick<HqAlertRuleConfig, 'costThresholdUsd' | 'staleMachineSeconds' | 'maxAgents' | 'tokenExpiryWarningHours'>>;\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 tokenExpiryWarningHours: 24,\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 id: 'token-expired-present',\n severity: 'error',\n evaluate: (snapshot) => {\n if (snapshot === null) return null;\n const stats = snapshot.totals.tokenStats;\n if (stats === undefined || stats.expired <= 0) return null;\n return `${stats.expired} expired token(s) filtered from live auth \u2014 rotate or revoke them`;\n },\n },\n {\n id: 'token-expiry-imminent',\n severity: 'warn',\n evaluate: (snapshot, config) => {\n if (snapshot === null) return null;\n if (config.tokenExpiryWarningHours <= 0) return null;\n const stats = snapshot.totals.tokenStats;\n if (stats === undefined || stats.expiringSoon <= 0) return null;\n return `${stats.expiringSoon} token(s) expire within ${config.tokenExpiryWarningHours}h \u2014 mint replacements before they lapse`;\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", "/**\n * One-time bootstrap code store for HQ browser authentication.\n *\n * Replaces the practice of placing a reusable browser token in the startup\n * URL. Instead, a short-lived, single-use code is minted at startup and\n * carried in the URL fragment (`#bootstrap=\u2026`). The browser SPA extracts\n * it from the fragment (fragments never reach HTTP access logs or Referer\n * headers), POSTs it to `/api/auth/bootstrap`, and receives only an\n * HttpOnly session cookie. The code itself is atomically consumed on\n * first exchange and can never be replayed.\n *\n * Each code carries the ID and capabilities of the originating browser\n * token so the cookie session preserves the token's privilege scope.\n */\n\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\n\n/** Maximum number of un-exchanged codes retained at once (FIFO eviction). */\nconst MAX_PENDING_CODES = 32;\n\n/** How long a code remains exchangeable after minting. */\nconst BOOTSTRAP_CODE_TTL_MS = 120_000; // 2 minutes\n\nexport interface HqBootstrapEntry {\n /** The opaque code string carried in the URL fragment. */\n readonly code: string;\n /** Epoch-ms deadline after which the code is refused. */\n readonly expiresAt: number;\n /** ID of the browser token this code was derived from. */\n readonly tokenId: string;\n /** Capability scope inherited from the source token (absent = unrestricted). */\n readonly capabilities?: string[] | undefined;\n}\n\n/**\n * Bounded, in-memory, single-use bootstrap code store.\n *\n * `issue()` mints a 256-bit code and stores its entry. `consume()` does a\n * constant-time comparison and atomically deletes the entry on match, so a\n * second exchange with the same code always fails. Expired entries are\n * swept on every `issue`/`consume` call, and the store is capped at\n * {@link MAX_PENDING_CODES} entries (oldest evicted first).\n */\nexport class HqBootstrapCodeStore {\n private readonly entries = new Map<string, HqBootstrapEntry>();\n\n /** Mint a new one-time bootstrap code for the given token. */\n issue(source: { tokenId: string; capabilities?: string[] }): string {\n this.sweepExpired();\n // Evict oldest if at capacity (Map iteration is insertion-ordered).\n while (this.entries.size >= MAX_PENDING_CODES) {\n const oldest = this.entries.keys().next().value;\n if (oldest === undefined) break;\n this.entries.delete(oldest);\n }\n const code = randomBytes(32).toString('base64url');\n this.entries.set(code, {\n code,\n expiresAt: Date.now() + BOOTSTRAP_CODE_TTL_MS,\n tokenId: source.tokenId,\n ...(source.capabilities !== undefined ? { capabilities: source.capabilities } : {}),\n });\n return code;\n }\n\n /**\n * Atomically consume a code. Returns the entry on match (and deletes it\n * so it can never be reused), or `undefined` if the code is unknown,\n * already consumed, or expired.\n */\n consume(supplied: string): HqBootstrapEntry | undefined {\n this.sweepExpired();\n // Constant-time lookup: iterate rather than Map.has to avoid timing\n // leakage of code length/prefix via hash-table probe timing.\n for (const [key, entry] of this.entries) {\n const a = Buffer.from(key);\n const b = Buffer.from(supplied);\n if (a.length === b.length && timingSafeEqual(a, b)) {\n this.entries.delete(key);\n return Date.now() < entry.expiresAt ? entry : undefined;\n }\n }\n return undefined;\n }\n\n /** Remove all codes (called on server shutdown). */\n clear(): void {\n this.entries.clear();\n }\n\n /** Current number of pending (not-yet-consumed) codes. */\n get size(): number {\n return this.entries.size;\n }\n\n private sweepExpired(): void {\n const now = Date.now();\n for (const [key, entry] of this.entries) {\n if (now >= entry.expiresAt) this.entries.delete(key);\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"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["redacted", "out", "createHash", "randomUUID", "fs", "basename", "createHash", "randomUUID", "fs", "path", "fs", "path", "projectHash", "path", "createHash", "authFile", "persisted", "hash", "actorField", "resolve", "randomUUID", "createHash", "basename", "randomUUID", "fs", "path", "setupWatcher", "scheduleTail", "stat", "createHash", "fs", "path", "createHash", "fs", "path", "fs", "stat", "fs", "path", "fs", "path", "fs", "path", "randomBytes", "timingSafeEqual"]
|
|
7
|
-
}
|