lattice-orchestrator 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +58 -0
- package/config/logrotate.conf +15 -0
- package/dist/cli-parser.d.ts +11 -0
- package/dist/cli-parser.d.ts.map +1 -0
- package/dist/cli-parser.js +48 -0
- package/dist/cli-parser.js.map +1 -0
- package/dist/lattice-server.d.ts +70 -0
- package/dist/lattice-server.d.ts.map +1 -0
- package/dist/lattice-server.js +969 -0
- package/dist/lattice-server.js.map +1 -0
- package/dist/mcp-server/index.d.ts +3 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +190 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/mcp-server/lattice-tools.d.ts +15 -0
- package/dist/mcp-server/lattice-tools.d.ts.map +1 -0
- package/dist/mcp-server/lattice-tools.js +366 -0
- package/dist/mcp-server/lattice-tools.js.map +1 -0
- package/dist/middleware/cors-setup.d.ts +7 -0
- package/dist/middleware/cors-setup.d.ts.map +1 -0
- package/dist/middleware/cors-setup.js +8 -0
- package/dist/middleware/cors-setup.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +4 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +27 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/query-parser.d.ts +11 -0
- package/dist/middleware/query-parser.d.ts.map +1 -0
- package/dist/middleware/query-parser.js +68 -0
- package/dist/middleware/query-parser.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +4 -0
- package/dist/middleware/request-logger.d.ts.map +1 -0
- package/dist/middleware/request-logger.js +6 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/process-daemon/index.d.ts +14 -0
- package/dist/process-daemon/index.d.ts.map +1 -0
- package/dist/process-daemon/index.js +51 -0
- package/dist/process-daemon/index.js.map +1 -0
- package/dist/process-daemon/process-daemon.d.ts +101 -0
- package/dist/process-daemon/process-daemon.d.ts.map +1 -0
- package/dist/process-daemon/process-daemon.js +846 -0
- package/dist/process-daemon/process-daemon.js.map +1 -0
- package/dist/process-daemon/process-manager-client.d.ts +123 -0
- package/dist/process-daemon/process-manager-client.d.ts.map +1 -0
- package/dist/process-daemon/process-manager-client.js +329 -0
- package/dist/process-daemon/process-manager-client.js.map +1 -0
- package/dist/process-daemon/process-manager-interface.d.ts +61 -0
- package/dist/process-daemon/process-manager-interface.d.ts.map +1 -0
- package/dist/process-daemon/process-manager-interface.js +8 -0
- package/dist/process-daemon/process-manager-interface.js.map +1 -0
- package/dist/process-daemon/test-daemon.d.ts +12 -0
- package/dist/process-daemon/test-daemon.d.ts.map +1 -0
- package/dist/process-daemon/test-daemon.js +81 -0
- package/dist/process-daemon/test-daemon.js.map +1 -0
- package/dist/process-daemon/types.d.ts +97 -0
- package/dist/process-daemon/types.d.ts.map +1 -0
- package/dist/process-daemon/types.js +8 -0
- package/dist/process-daemon/types.js.map +1 -0
- package/dist/routes/analysis.routes.d.ts +13 -0
- package/dist/routes/analysis.routes.d.ts.map +1 -0
- package/dist/routes/analysis.routes.js +520 -0
- package/dist/routes/analysis.routes.js.map +1 -0
- package/dist/routes/config.routes.d.ts +4 -0
- package/dist/routes/config.routes.d.ts.map +1 -0
- package/dist/routes/config.routes.js +27 -0
- package/dist/routes/config.routes.js.map +1 -0
- package/dist/routes/conversation.routes.d.ts +43 -0
- package/dist/routes/conversation.routes.d.ts.map +1 -0
- package/dist/routes/conversation.routes.js +79 -0
- package/dist/routes/conversation.routes.js.map +1 -0
- package/dist/routes/filesystem.routes.d.ts +4 -0
- package/dist/routes/filesystem.routes.d.ts.map +1 -0
- package/dist/routes/filesystem.routes.js +86 -0
- package/dist/routes/filesystem.routes.js.map +1 -0
- package/dist/routes/insights.routes.d.ts +17 -0
- package/dist/routes/insights.routes.d.ts.map +1 -0
- package/dist/routes/insights.routes.js +633 -0
- package/dist/routes/insights.routes.js.map +1 -0
- package/dist/routes/lattice.routes.d.ts +10 -0
- package/dist/routes/lattice.routes.d.ts.map +1 -0
- package/dist/routes/lattice.routes.js +123 -0
- package/dist/routes/lattice.routes.js.map +1 -0
- package/dist/routes/license.routes.d.ts +3 -0
- package/dist/routes/license.routes.d.ts.map +1 -0
- package/dist/routes/license.routes.js +95 -0
- package/dist/routes/license.routes.js.map +1 -0
- package/dist/routes/log.routes.d.ts +3 -0
- package/dist/routes/log.routes.d.ts.map +1 -0
- package/dist/routes/log.routes.js +184 -0
- package/dist/routes/log.routes.js.map +1 -0
- package/dist/routes/pending-question.routes.d.ts +9 -0
- package/dist/routes/pending-question.routes.d.ts.map +1 -0
- package/dist/routes/pending-question.routes.js +162 -0
- package/dist/routes/pending-question.routes.js.map +1 -0
- package/dist/routes/permission.routes.d.ts +18 -0
- package/dist/routes/permission.routes.d.ts.map +1 -0
- package/dist/routes/permission.routes.js +370 -0
- package/dist/routes/permission.routes.js.map +1 -0
- package/dist/routes/process-events.routes.d.ts +9 -0
- package/dist/routes/process-events.routes.d.ts.map +1 -0
- package/dist/routes/process-events.routes.js +141 -0
- package/dist/routes/process-events.routes.js.map +1 -0
- package/dist/routes/prototype.routes.d.ts +9 -0
- package/dist/routes/prototype.routes.d.ts.map +1 -0
- package/dist/routes/prototype.routes.js +757 -0
- package/dist/routes/prototype.routes.js.map +1 -0
- package/dist/routes/question.routes.d.ts +8 -0
- package/dist/routes/question.routes.d.ts.map +1 -0
- package/dist/routes/question.routes.js +83 -0
- package/dist/routes/question.routes.js.map +1 -0
- package/dist/routes/session-control.routes.d.ts +29 -0
- package/dist/routes/session-control.routes.d.ts.map +1 -0
- package/dist/routes/session-control.routes.js +455 -0
- package/dist/routes/session-control.routes.js.map +1 -0
- package/dist/routes/session-lifecycle.routes.d.ts +21 -0
- package/dist/routes/session-lifecycle.routes.d.ts.map +1 -0
- package/dist/routes/session-lifecycle.routes.js +256 -0
- package/dist/routes/session-lifecycle.routes.js.map +1 -0
- package/dist/routes/session-query.routes.d.ts +25 -0
- package/dist/routes/session-query.routes.d.ts.map +1 -0
- package/dist/routes/session-query.routes.js +363 -0
- package/dist/routes/session-query.routes.js.map +1 -0
- package/dist/routes/session-stream.routes.d.ts +21 -0
- package/dist/routes/session-stream.routes.d.ts.map +1 -0
- package/dist/routes/session-stream.routes.js +235 -0
- package/dist/routes/session-stream.routes.js.map +1 -0
- package/dist/routes/streaming.routes.d.ts +4 -0
- package/dist/routes/streaming.routes.d.ts.map +1 -0
- package/dist/routes/streaming.routes.js +33 -0
- package/dist/routes/streaming.routes.js.map +1 -0
- package/dist/routes/system.routes.d.ts +7 -0
- package/dist/routes/system.routes.d.ts.map +1 -0
- package/dist/routes/system.routes.js +214 -0
- package/dist/routes/system.routes.js.map +1 -0
- package/dist/routes/walkthrough.routes.d.ts +19 -0
- package/dist/routes/walkthrough.routes.d.ts.map +1 -0
- package/dist/routes/walkthrough.routes.js +688 -0
- package/dist/routes/walkthrough.routes.js.map +1 -0
- package/dist/routes/working-directories.routes.d.ts +4 -0
- package/dist/routes/working-directories.routes.d.ts.map +1 -0
- package/dist/routes/working-directories.routes.js +25 -0
- package/dist/routes/working-directories.routes.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +34 -0
- package/dist/server.js.map +1 -0
- package/dist/services/ToolMetricsService.d.ts +53 -0
- package/dist/services/ToolMetricsService.d.ts.map +1 -0
- package/dist/services/ToolMetricsService.js +230 -0
- package/dist/services/ToolMetricsService.js.map +1 -0
- package/dist/services/claude-router-service.d.ts +19 -0
- package/dist/services/claude-router-service.d.ts.map +1 -0
- package/dist/services/claude-router-service.js +160 -0
- package/dist/services/claude-router-service.js.map +1 -0
- package/dist/services/commands-service.d.ts +20 -0
- package/dist/services/commands-service.d.ts.map +1 -0
- package/dist/services/commands-service.js +115 -0
- package/dist/services/commands-service.js.map +1 -0
- package/dist/services/connection-debug-logger.d.ts +85 -0
- package/dist/services/connection-debug-logger.d.ts.map +1 -0
- package/dist/services/connection-debug-logger.js +221 -0
- package/dist/services/connection-debug-logger.js.map +1 -0
- package/dist/services/debug-log.d.ts +6 -0
- package/dist/services/debug-log.d.ts.map +1 -0
- package/dist/services/debug-log.js +27 -0
- package/dist/services/debug-log.js.map +1 -0
- package/dist/services/gemini-service.d.ts +35 -0
- package/dist/services/gemini-service.d.ts.map +1 -0
- package/dist/services/gemini-service.js +256 -0
- package/dist/services/gemini-service.js.map +1 -0
- package/dist/services/infrastructure/config-service.d.ts +79 -0
- package/dist/services/infrastructure/config-service.d.ts.map +1 -0
- package/dist/services/infrastructure/config-service.js +431 -0
- package/dist/services/infrastructure/config-service.js.map +1 -0
- package/dist/services/infrastructure/cost-tracker.d.ts +112 -0
- package/dist/services/infrastructure/cost-tracker.d.ts.map +1 -0
- package/dist/services/infrastructure/cost-tracker.js +423 -0
- package/dist/services/infrastructure/cost-tracker.js.map +1 -0
- package/dist/services/infrastructure/file-system-service.d.ts +61 -0
- package/dist/services/infrastructure/file-system-service.d.ts.map +1 -0
- package/dist/services/infrastructure/file-system-service.js +348 -0
- package/dist/services/infrastructure/file-system-service.js.map +1 -0
- package/dist/services/infrastructure/log-formatter.d.ts +5 -0
- package/dist/services/infrastructure/log-formatter.d.ts.map +1 -0
- package/dist/services/infrastructure/log-formatter.js +77 -0
- package/dist/services/infrastructure/log-formatter.js.map +1 -0
- package/dist/services/infrastructure/log-stream-buffer.d.ts +11 -0
- package/dist/services/infrastructure/log-stream-buffer.d.ts.map +1 -0
- package/dist/services/infrastructure/log-stream-buffer.js +36 -0
- package/dist/services/infrastructure/log-stream-buffer.js.map +1 -0
- package/dist/services/infrastructure/logger.d.ts +71 -0
- package/dist/services/infrastructure/logger.d.ts.map +1 -0
- package/dist/services/infrastructure/logger.js +215 -0
- package/dist/services/infrastructure/logger.js.map +1 -0
- package/dist/services/infrastructure/service-registry.d.ts +86 -0
- package/dist/services/infrastructure/service-registry.d.ts.map +1 -0
- package/dist/services/infrastructure/service-registry.js +162 -0
- package/dist/services/infrastructure/service-registry.js.map +1 -0
- package/dist/services/infrastructure/stream-manager.d.ts +87 -0
- package/dist/services/infrastructure/stream-manager.d.ts.map +1 -0
- package/dist/services/infrastructure/stream-manager.js +436 -0
- package/dist/services/infrastructure/stream-manager.js.map +1 -0
- package/dist/services/infrastructure/timing.d.ts +72 -0
- package/dist/services/infrastructure/timing.d.ts.map +1 -0
- package/dist/services/infrastructure/timing.js +115 -0
- package/dist/services/infrastructure/timing.js.map +1 -0
- package/dist/services/insights/anthropic-service.d.ts +224 -0
- package/dist/services/insights/anthropic-service.d.ts.map +1 -0
- package/dist/services/insights/anthropic-service.js +1062 -0
- package/dist/services/insights/anthropic-service.js.map +1 -0
- package/dist/services/insights/insight-audit-repository.d.ts +119 -0
- package/dist/services/insights/insight-audit-repository.d.ts.map +1 -0
- package/dist/services/insights/insight-audit-repository.js +242 -0
- package/dist/services/insights/insight-audit-repository.js.map +1 -0
- package/dist/services/insights/insight-queue.d.ts +99 -0
- package/dist/services/insights/insight-queue.d.ts.map +1 -0
- package/dist/services/insights/insight-queue.js +277 -0
- package/dist/services/insights/insight-queue.js.map +1 -0
- package/dist/services/insights/insights-computer.d.ts +132 -0
- package/dist/services/insights/insights-computer.d.ts.map +1 -0
- package/dist/services/insights/insights-computer.js +936 -0
- package/dist/services/insights/insights-computer.js.map +1 -0
- package/dist/services/insights/insights-coordinator.d.ts +165 -0
- package/dist/services/insights/insights-coordinator.d.ts.map +1 -0
- package/dist/services/insights/insights-coordinator.js +1678 -0
- package/dist/services/insights/insights-coordinator.js.map +1 -0
- package/dist/services/insights/insights-event-log.d.ts +196 -0
- package/dist/services/insights/insights-event-log.d.ts.map +1 -0
- package/dist/services/insights/insights-event-log.js +319 -0
- package/dist/services/insights/insights-event-log.js.map +1 -0
- package/dist/services/lattice-service.d.ts +77 -0
- package/dist/services/lattice-service.d.ts.map +1 -0
- package/dist/services/lattice-service.js +195 -0
- package/dist/services/lattice-service.js.map +1 -0
- package/dist/services/license-service.d.ts +69 -0
- package/dist/services/license-service.d.ts.map +1 -0
- package/dist/services/license-service.js +330 -0
- package/dist/services/license-service.js.map +1 -0
- package/dist/services/mcp-config-generator.d.ts +32 -0
- package/dist/services/mcp-config-generator.d.ts.map +1 -0
- package/dist/services/mcp-config-generator.js +126 -0
- package/dist/services/mcp-config-generator.js.map +1 -0
- package/dist/services/message-filter.d.ts +22 -0
- package/dist/services/message-filter.d.ts.map +1 -0
- package/dist/services/message-filter.js +57 -0
- package/dist/services/message-filter.js.map +1 -0
- package/dist/services/notification-service.d.ts +45 -0
- package/dist/services/notification-service.d.ts.map +1 -0
- package/dist/services/notification-service.js +184 -0
- package/dist/services/notification-service.js.map +1 -0
- package/dist/services/pending-question-service.d.ts +97 -0
- package/dist/services/pending-question-service.d.ts.map +1 -0
- package/dist/services/pending-question-service.js +223 -0
- package/dist/services/pending-question-service.js.map +1 -0
- package/dist/services/permission-event-log.d.ts +136 -0
- package/dist/services/permission-event-log.d.ts.map +1 -0
- package/dist/services/permission-event-log.js +252 -0
- package/dist/services/permission-event-log.js.map +1 -0
- package/dist/services/permission-pattern-matcher.d.ts +82 -0
- package/dist/services/permission-pattern-matcher.d.ts.map +1 -0
- package/dist/services/permission-pattern-matcher.js +294 -0
- package/dist/services/permission-pattern-matcher.js.map +1 -0
- package/dist/services/permission-tracker.d.ts +67 -0
- package/dist/services/permission-tracker.d.ts.map +1 -0
- package/dist/services/permission-tracker.js +162 -0
- package/dist/services/permission-tracker.js.map +1 -0
- package/dist/services/process/claude-process-manager.d.ts +142 -0
- package/dist/services/process/claude-process-manager.d.ts.map +1 -0
- package/dist/services/process/claude-process-manager.js +1218 -0
- package/dist/services/process/claude-process-manager.js.map +1 -0
- package/dist/services/process/conversation-status-manager.d.ts +110 -0
- package/dist/services/process/conversation-status-manager.d.ts.map +1 -0
- package/dist/services/process/conversation-status-manager.js +349 -0
- package/dist/services/process/conversation-status-manager.js.map +1 -0
- package/dist/services/process/json-lines-parser.d.ts +19 -0
- package/dist/services/process/json-lines-parser.d.ts.map +1 -0
- package/dist/services/process/json-lines-parser.js +59 -0
- package/dist/services/process/json-lines-parser.js.map +1 -0
- package/dist/services/process/process-event-log.d.ts +263 -0
- package/dist/services/process/process-event-log.d.ts.map +1 -0
- package/dist/services/process/process-event-log.js +509 -0
- package/dist/services/process/process-event-log.js.map +1 -0
- package/dist/services/process/process-manager-factory.d.ts +109 -0
- package/dist/services/process/process-manager-factory.d.ts.map +1 -0
- package/dist/services/process/process-manager-factory.js +338 -0
- package/dist/services/process/process-manager-factory.js.map +1 -0
- package/dist/services/question-tracker.d.ts +51 -0
- package/dist/services/question-tracker.d.ts.map +1 -0
- package/dist/services/question-tracker.js +111 -0
- package/dist/services/question-tracker.js.map +1 -0
- package/dist/services/sessions/claude-history-reader.d.ts +139 -0
- package/dist/services/sessions/claude-history-reader.d.ts.map +1 -0
- package/dist/services/sessions/claude-history-reader.js +864 -0
- package/dist/services/sessions/claude-history-reader.js.map +1 -0
- package/dist/services/sessions/conversation-cache.d.ts +98 -0
- package/dist/services/sessions/conversation-cache.d.ts.map +1 -0
- package/dist/services/sessions/conversation-cache.js +329 -0
- package/dist/services/sessions/conversation-cache.js.map +1 -0
- package/dist/services/sessions/session-activity-watcher.d.ts +67 -0
- package/dist/services/sessions/session-activity-watcher.d.ts.map +1 -0
- package/dist/services/sessions/session-activity-watcher.js +236 -0
- package/dist/services/sessions/session-activity-watcher.js.map +1 -0
- package/dist/services/sessions/session-analysis-service.d.ts +72 -0
- package/dist/services/sessions/session-analysis-service.d.ts.map +1 -0
- package/dist/services/sessions/session-analysis-service.js +373 -0
- package/dist/services/sessions/session-analysis-service.js.map +1 -0
- package/dist/services/sessions/session-branch-service.d.ts +76 -0
- package/dist/services/sessions/session-branch-service.d.ts.map +1 -0
- package/dist/services/sessions/session-branch-service.js +355 -0
- package/dist/services/sessions/session-branch-service.js.map +1 -0
- package/dist/services/sessions/session-info-service.d.ts +455 -0
- package/dist/services/sessions/session-info-service.d.ts.map +1 -0
- package/dist/services/sessions/session-info-service.js +1640 -0
- package/dist/services/sessions/session-info-service.js.map +1 -0
- package/dist/services/sessions/session-marks-repository.d.ts +78 -0
- package/dist/services/sessions/session-marks-repository.d.ts.map +1 -0
- package/dist/services/sessions/session-marks-repository.js +263 -0
- package/dist/services/sessions/session-marks-repository.js.map +1 -0
- package/dist/services/sessions/session-marks-service.d.ts +137 -0
- package/dist/services/sessions/session-marks-service.d.ts.map +1 -0
- package/dist/services/sessions/session-marks-service.js +562 -0
- package/dist/services/sessions/session-marks-service.js.map +1 -0
- package/dist/services/sessions/session-review-service.d.ts +98 -0
- package/dist/services/sessions/session-review-service.d.ts.map +1 -0
- package/dist/services/sessions/session-review-service.js +629 -0
- package/dist/services/sessions/session-review-service.js.map +1 -0
- package/dist/services/sessions/turn-capture-service.d.ts +83 -0
- package/dist/services/sessions/turn-capture-service.d.ts.map +1 -0
- package/dist/services/sessions/turn-capture-service.js +477 -0
- package/dist/services/sessions/turn-capture-service.js.map +1 -0
- package/dist/services/sessions/turn-repository.d.ts +48 -0
- package/dist/services/sessions/turn-repository.d.ts.map +1 -0
- package/dist/services/sessions/turn-repository.js +103 -0
- package/dist/services/sessions/turn-repository.js.map +1 -0
- package/dist/services/walkthrough-service.d.ts +226 -0
- package/dist/services/walkthrough-service.d.ts.map +1 -0
- package/dist/services/walkthrough-service.js +1112 -0
- package/dist/services/walkthrough-service.js.map +1 -0
- package/dist/services/walkthrough-skill-prompt.d.ts +34 -0
- package/dist/services/walkthrough-skill-prompt.d.ts.map +1 -0
- package/dist/services/walkthrough-skill-prompt.js +313 -0
- package/dist/services/walkthrough-skill-prompt.js.map +1 -0
- package/dist/services/web-push-service.d.ts +48 -0
- package/dist/services/web-push-service.d.ts.map +1 -0
- package/dist/services/web-push-service.js +186 -0
- package/dist/services/web-push-service.js.map +1 -0
- package/dist/services/working-directories-service.d.ts +19 -0
- package/dist/services/working-directories-service.d.ts.map +1 -0
- package/dist/services/working-directories-service.js +103 -0
- package/dist/services/working-directories-service.js.map +1 -0
- package/dist/types/config.d.ts +122 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +21 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/express.d.ts +5 -0
- package/dist/types/express.d.ts.map +1 -0
- package/dist/types/express.js +2 -0
- package/dist/types/express.js.map +1 -0
- package/dist/types/index.d.ts +400 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +41 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/insights.d.ts +176 -0
- package/dist/types/insights.d.ts.map +1 -0
- package/dist/types/insights.js +23 -0
- package/dist/types/insights.js.map +1 -0
- package/dist/types/license.d.ts +70 -0
- package/dist/types/license.d.ts.map +1 -0
- package/dist/types/license.js +5 -0
- package/dist/types/license.js.map +1 -0
- package/dist/types/router-config.d.ts +13 -0
- package/dist/types/router-config.d.ts.map +1 -0
- package/dist/types/router-config.js +2 -0
- package/dist/types/router-config.js.map +1 -0
- package/dist/utils/constants.d.ts +26 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +28 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/machine-id.d.ts +7 -0
- package/dist/utils/machine-id.d.ts.map +1 -0
- package/dist/utils/machine-id.js +76 -0
- package/dist/utils/machine-id.js.map +1 -0
- package/dist/utils/server-startup.d.ts +11 -0
- package/dist/utils/server-startup.d.ts.map +1 -0
- package/dist/utils/server-startup.js +9 -0
- package/dist/utils/server-startup.js.map +1 -0
- package/dist/utils/update-check.d.ts +13 -0
- package/dist/utils/update-check.d.ts.map +1 -0
- package/dist/utils/update-check.js +90 -0
- package/dist/utils/update-check.js.map +1 -0
- package/dist/web/assets/ArchivedCardPrototype-S9ifiasa.js +5 -0
- package/dist/web/assets/BannerGallery-B__rJV6F.js +1 -0
- package/dist/web/assets/BannerPrototype-DBKP9Uiu.js +52 -0
- package/dist/web/assets/CodeHikeExperiment-B8jjWAFy.js +15 -0
- package/dist/web/assets/ContextTooltipVariations-DzklAFam.js +1 -0
- package/dist/web/assets/FontShowcasePrototype-KIMEWeP2.js +13 -0
- package/dist/web/assets/GeometricGallery-DddlWhHK.js +1 -0
- package/dist/web/assets/HistoryWalkthroughPrototype-DeniRRdw.js +18 -0
- package/dist/web/assets/InlineWalkthroughPrototype-Csd5r_Hk.js +1 -0
- package/dist/web/assets/MarkButtonPrototype-CxhxE0RP.js +1 -0
- package/dist/web/assets/MenuStylesPrototype-D7neA6YM.js +1 -0
- package/dist/web/assets/MomentCardVariations-2GT7GyFn.js +1 -0
- package/dist/web/assets/MomentHeaderVariations-DhGEw4XC.js +1 -0
- package/dist/web/assets/NarrativeWalkthroughDemo-B5C566fu.js +389 -0
- package/dist/web/assets/OutcomeVariations-BrZfsVcs.js +1 -0
- package/dist/web/assets/PermissionPatternPickerPrototype-CBOhe2Me.js +1 -0
- package/dist/web/assets/PermissionPrototype-BcF-a5an.js +1 -0
- package/dist/web/assets/PipelineGallery-BJhyM0rx.js +1 -0
- package/dist/web/assets/ScopeHeaderPrototype-GD1HNfaO.js +1 -0
- package/dist/web/assets/ScopeHeaderStylesPrototype-aa4uNJJ1.js +1 -0
- package/dist/web/assets/ScrollycodingPrototype-CKW1bf72.js +70 -0
- package/dist/web/assets/SectionHeaderVariations-DM8vUwfj.js +1 -0
- package/dist/web/assets/SemanticGallery-CtQEo7St.js +1 -0
- package/dist/web/assets/SessionCardPrototype-CgHCIMHe.js +1 -0
- package/dist/web/assets/SessionSidebarVariations-DMQL3Azj.js +3 -0
- package/dist/web/assets/SessionStartPrototype-Cwsv01Rr.js +1 -0
- package/dist/web/assets/SmartMenuPrototype-Br37Qbs_.js +1 -0
- package/dist/web/assets/StyleGallery-rZgrploB.js +1 -0
- package/dist/web/assets/TimelineCardPrototype-lzPc5mhe.js +19 -0
- package/dist/web/assets/ToolbarPrototype-Dm4BNZra.js +1 -0
- package/dist/web/assets/TooltipExperiment-Dy8QzTIP.js +13 -0
- package/dist/web/assets/WalkthroughCTAPrototype-uHoovujd.js +1 -0
- package/dist/web/assets/WalkthroughHeaderVariations-Do7Di1g1.js +1 -0
- package/dist/web/assets/WalkthroughShowcase-sGmRoPoM.js +112 -0
- package/dist/web/assets/arrow-right-D46Nx1mC.js +1 -0
- package/dist/web/assets/brain-BXIZKtOZ.js +1 -0
- package/dist/web/assets/grid-3x3-Cb81B62m.js +1 -0
- package/dist/web/assets/main-B1fyog77.js +321 -0
- package/dist/web/assets/main-C2PK2Klg.css +1 -0
- package/dist/web/assets/semantic-variations-Bd-W7ea2.js +1 -0
- package/dist/web/assets/target-Cf92wDTW.js +1 -0
- package/dist/web/favicon.png +0 -0
- package/dist/web/favicon.svg +22 -0
- package/dist/web/icon-192x192.png +0 -0
- package/dist/web/icon-512x512.png +0 -0
- package/dist/web/index.html +45 -0
- package/dist/web/manifest.json +61 -0
- package/package.json +192 -0
- package/scripts/postinstall.js +60 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { createLogger } from '../infrastructure/logger.js';
|
|
3
|
+
import { connectionDebugLogger } from '../connection-debug-logger.js';
|
|
4
|
+
/**
|
|
5
|
+
* Manages streaming connections to multiple clients
|
|
6
|
+
*/
|
|
7
|
+
export class StreamManager extends EventEmitter {
|
|
8
|
+
clients = new Map();
|
|
9
|
+
logger;
|
|
10
|
+
heartbeatInterval;
|
|
11
|
+
// Event buffering for race condition between session start and SSE connection
|
|
12
|
+
eventBuffers = new Map();
|
|
13
|
+
// Buffer events for up to 2 seconds after session start
|
|
14
|
+
// This covers network latency + React state updates + SSE connection establishment
|
|
15
|
+
EVENT_BUFFER_WINDOW_MS = 2000;
|
|
16
|
+
// Maximum events to buffer per session (safety limit)
|
|
17
|
+
MAX_BUFFERED_EVENTS = 100;
|
|
18
|
+
// Send heartbeat every 30 seconds to keep connections alive
|
|
19
|
+
// IMPORTANT: Client expects heartbeat within 45s (1.5x this interval)
|
|
20
|
+
// See: web/chat/config/connection.ts HEARTBEAT_TIMEOUT_MS
|
|
21
|
+
HEARTBEAT_INTERVAL_MS = 30000;
|
|
22
|
+
constructor() {
|
|
23
|
+
super();
|
|
24
|
+
this.logger = createLogger('StreamManager');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Start buffering events for a session.
|
|
28
|
+
* Call this when a session is created, before any clients connect.
|
|
29
|
+
* Events will be replayed when the first client connects.
|
|
30
|
+
*/
|
|
31
|
+
startBuffering(streamingId) {
|
|
32
|
+
// Don't start if already buffering
|
|
33
|
+
if (this.eventBuffers.has(streamingId)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const timeoutId = setTimeout(() => {
|
|
37
|
+
this.stopBuffering(streamingId);
|
|
38
|
+
}, this.EVENT_BUFFER_WINDOW_MS);
|
|
39
|
+
this.eventBuffers.set(streamingId, {
|
|
40
|
+
events: [],
|
|
41
|
+
createdAt: Date.now(),
|
|
42
|
+
timeoutId,
|
|
43
|
+
});
|
|
44
|
+
this.logger.info('[BUFFERING] Started event buffering for session', {
|
|
45
|
+
streamingId: streamingId.slice(0, 8),
|
|
46
|
+
bufferWindowMs: this.EVENT_BUFFER_WINDOW_MS,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Stop buffering events for a session and discard any buffered events.
|
|
51
|
+
* Called automatically after the buffer window expires.
|
|
52
|
+
*/
|
|
53
|
+
stopBuffering(streamingId) {
|
|
54
|
+
const buffer = this.eventBuffers.get(streamingId);
|
|
55
|
+
if (buffer) {
|
|
56
|
+
clearTimeout(buffer.timeoutId);
|
|
57
|
+
const eventCount = buffer.events.length;
|
|
58
|
+
this.eventBuffers.delete(streamingId);
|
|
59
|
+
if (eventCount > 0) {
|
|
60
|
+
this.logger.info('Discarded buffered events (no client connected in time)', {
|
|
61
|
+
streamingId: streamingId.slice(0, 8),
|
|
62
|
+
discardedEvents: eventCount,
|
|
63
|
+
bufferAgeMs: Date.now() - buffer.createdAt,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Replay buffered events to a client and stop buffering.
|
|
70
|
+
* Called when the first client connects.
|
|
71
|
+
*/
|
|
72
|
+
replayBufferedEvents(streamingId, res) {
|
|
73
|
+
const buffer = this.eventBuffers.get(streamingId);
|
|
74
|
+
if (!buffer || buffer.events.length === 0) {
|
|
75
|
+
this.stopBuffering(streamingId);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
clearTimeout(buffer.timeoutId);
|
|
79
|
+
const events = buffer.events;
|
|
80
|
+
this.eventBuffers.delete(streamingId);
|
|
81
|
+
this.logger.info('Replaying buffered events to first client', {
|
|
82
|
+
streamingId: streamingId.slice(0, 8),
|
|
83
|
+
eventCount: events.length,
|
|
84
|
+
bufferAgeMs: Date.now() - buffer.createdAt,
|
|
85
|
+
});
|
|
86
|
+
for (const event of events) {
|
|
87
|
+
try {
|
|
88
|
+
this.sendSSEEvent(res, event);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
this.logger.error('Failed to replay buffered event', error, {
|
|
92
|
+
streamingId,
|
|
93
|
+
eventType: event?.type,
|
|
94
|
+
});
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Add a client to receive stream updates
|
|
101
|
+
*/
|
|
102
|
+
addClient(streamingId, res) {
|
|
103
|
+
this.logger.debug('Adding client to stream', { streamingId });
|
|
104
|
+
connectionDebugLogger.log('StreamManager', 'client-add-start', {
|
|
105
|
+
streamingId: streamingId.slice(0, 8),
|
|
106
|
+
existingClients: this.clients.get(streamingId)?.size || 0,
|
|
107
|
+
totalSessions: this.clients.size,
|
|
108
|
+
});
|
|
109
|
+
// Configure response for Server-Sent Events
|
|
110
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
111
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
112
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
113
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
114
|
+
// Initialize client set if needed
|
|
115
|
+
if (!this.clients.has(streamingId)) {
|
|
116
|
+
this.clients.set(streamingId, new Set());
|
|
117
|
+
}
|
|
118
|
+
// Add this client to the session
|
|
119
|
+
this.clients.get(streamingId).add(res);
|
|
120
|
+
const clientCount = this.clients.get(streamingId).size;
|
|
121
|
+
this.logger.debug('Client added successfully', {
|
|
122
|
+
streamingId,
|
|
123
|
+
totalClients: clientCount
|
|
124
|
+
});
|
|
125
|
+
connectionDebugLogger.log('StreamManager', 'client-added', {
|
|
126
|
+
streamingId: streamingId.slice(0, 8),
|
|
127
|
+
clientCount,
|
|
128
|
+
totalSessions: this.clients.size,
|
|
129
|
+
});
|
|
130
|
+
// Send initial connection confirmation
|
|
131
|
+
const connectionMessage = {
|
|
132
|
+
type: 'connected',
|
|
133
|
+
streaming_id: streamingId,
|
|
134
|
+
timestamp: new Date().toISOString()
|
|
135
|
+
};
|
|
136
|
+
this.logger.debug('Sending initial SSE connection confirmation', {
|
|
137
|
+
streamingId,
|
|
138
|
+
clientCount: this.clients.get(streamingId).size
|
|
139
|
+
});
|
|
140
|
+
this.sendSSEEvent(res, connectionMessage);
|
|
141
|
+
// Replay any buffered events to the first client
|
|
142
|
+
// This handles the race condition where events are broadcast before SSE connection
|
|
143
|
+
if (clientCount === 1) {
|
|
144
|
+
this.replayBufferedEvents(streamingId, res);
|
|
145
|
+
}
|
|
146
|
+
// Start heartbeat if this is the first client
|
|
147
|
+
this.startHeartbeat();
|
|
148
|
+
// Clean up when client disconnects
|
|
149
|
+
res.on('close', () => {
|
|
150
|
+
connectionDebugLogger.log('StreamManager', 'client-close-event', {
|
|
151
|
+
streamingId: streamingId.slice(0, 8),
|
|
152
|
+
reason: 'res.close',
|
|
153
|
+
});
|
|
154
|
+
this.removeClient(streamingId, res);
|
|
155
|
+
});
|
|
156
|
+
res.on('error', (error) => {
|
|
157
|
+
this.logger.error('Stream error for session', error, { streamingId });
|
|
158
|
+
connectionDebugLogger.log('StreamManager', 'client-error-event', {
|
|
159
|
+
streamingId: streamingId.slice(0, 8),
|
|
160
|
+
error: error.message,
|
|
161
|
+
});
|
|
162
|
+
this.removeClient(streamingId, res);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Remove a client connection
|
|
167
|
+
*/
|
|
168
|
+
removeClient(streamingId, res) {
|
|
169
|
+
const clients = this.clients.get(streamingId);
|
|
170
|
+
const hadClient = clients?.has(res);
|
|
171
|
+
if (clients) {
|
|
172
|
+
clients.delete(res);
|
|
173
|
+
if (clients.size === 0) {
|
|
174
|
+
this.clients.delete(streamingId);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
connectionDebugLogger.log('StreamManager', 'client-removed', {
|
|
178
|
+
streamingId: streamingId.slice(0, 8),
|
|
179
|
+
wasTracked: hadClient,
|
|
180
|
+
remainingClients: clients?.size || 0,
|
|
181
|
+
remainingSessions: this.clients.size,
|
|
182
|
+
});
|
|
183
|
+
this.emit('client-disconnected', { streamingId });
|
|
184
|
+
// Stop heartbeat if no clients remain
|
|
185
|
+
if (this.getTotalClientCount() === 0) {
|
|
186
|
+
this.stopHeartbeat();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Broadcast an event to all clients watching a session
|
|
191
|
+
*/
|
|
192
|
+
broadcast(streamingId, event) {
|
|
193
|
+
// Log question_request events at info level for debugging
|
|
194
|
+
const isQuestionRequest = event?.type === 'question_request';
|
|
195
|
+
const logLevel = isQuestionRequest ? 'info' : 'debug';
|
|
196
|
+
this.logger[logLevel]('Broadcasting event to clients', {
|
|
197
|
+
streamingId,
|
|
198
|
+
eventType: event?.type,
|
|
199
|
+
eventSubtype: 'subtype' in event ? event.subtype : undefined
|
|
200
|
+
});
|
|
201
|
+
const clients = this.clients.get(streamingId);
|
|
202
|
+
if (!clients || clients.size === 0) {
|
|
203
|
+
// Check if we should buffer this event (session just started, client not yet connected)
|
|
204
|
+
const buffer = this.eventBuffers.get(streamingId);
|
|
205
|
+
if (buffer) {
|
|
206
|
+
if (buffer.events.length < this.MAX_BUFFERED_EVENTS) {
|
|
207
|
+
buffer.events.push(event);
|
|
208
|
+
this.logger.debug('Buffered event for session (no clients yet)', {
|
|
209
|
+
streamingId: streamingId.slice(0, 8),
|
|
210
|
+
eventType: event?.type,
|
|
211
|
+
bufferedCount: buffer.events.length,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
this.logger.warn('Event buffer full, dropping event', {
|
|
216
|
+
streamingId: streamingId.slice(0, 8),
|
|
217
|
+
eventType: event?.type,
|
|
218
|
+
maxBuffered: this.MAX_BUFFERED_EVENTS,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// No buffer and no clients - event will be lost
|
|
224
|
+
// Log at info level for question_request events to diagnose issues
|
|
225
|
+
this.logger[isQuestionRequest ? 'info' : 'debug']('No clients found for streaming session, dropping message', {
|
|
226
|
+
streamingId,
|
|
227
|
+
eventType: event?.type
|
|
228
|
+
});
|
|
229
|
+
connectionDebugLogger.log('StreamManager', 'broadcast-no-clients', {
|
|
230
|
+
streamingId: streamingId.slice(0, 8),
|
|
231
|
+
eventType: event?.type,
|
|
232
|
+
trackedSessions: Array.from(this.clients.keys()).map(s => s.slice(0, 8)),
|
|
233
|
+
});
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this.logger.debug('Found clients for broadcast', {
|
|
237
|
+
streamingId,
|
|
238
|
+
clientCount: clients.size
|
|
239
|
+
});
|
|
240
|
+
const deadClients = [];
|
|
241
|
+
for (const client of clients) {
|
|
242
|
+
try {
|
|
243
|
+
this.sendSSEEvent(client, event);
|
|
244
|
+
this.logger.debug('Successfully sent SSE event to client', {
|
|
245
|
+
streamingId,
|
|
246
|
+
eventType: event?.type,
|
|
247
|
+
eventSubtype: 'subtype' in event ? event.subtype : undefined
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
this.logger.error('Failed to send SSE event to client', error, { streamingId });
|
|
252
|
+
deadClients.push(client);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Clean up dead clients
|
|
256
|
+
deadClients.forEach(client => this.removeClient(streamingId, client));
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Send an SSE event to a specific client
|
|
260
|
+
*/
|
|
261
|
+
sendSSEEvent(res, message, eventType) {
|
|
262
|
+
if (res.writableEnded || res.destroyed) {
|
|
263
|
+
throw new Error('Response is no longer writable');
|
|
264
|
+
}
|
|
265
|
+
let sseData = '';
|
|
266
|
+
if (eventType) {
|
|
267
|
+
sseData += `event: ${eventType}\n`;
|
|
268
|
+
}
|
|
269
|
+
sseData += `data: ${JSON.stringify(message)}\n\n`;
|
|
270
|
+
// Log SSE event data
|
|
271
|
+
this.logger.debug('Sending SSE event', {
|
|
272
|
+
eventType,
|
|
273
|
+
messageType: message?.type,
|
|
274
|
+
messageSubtype: 'subtype' in message ? message.subtype : undefined,
|
|
275
|
+
streamingId: 'streamingId' in message ? message.streamingId : 'streaming_id' in message ? message.streaming_id : undefined,
|
|
276
|
+
sseDataLength: sseData.length
|
|
277
|
+
});
|
|
278
|
+
res.write(sseData);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Send SSE heartbeat (comment) to keep connection alive
|
|
282
|
+
*/
|
|
283
|
+
sendHeartbeat(res) {
|
|
284
|
+
if (!res.writableEnded && !res.destroyed) {
|
|
285
|
+
res.write(': heartbeat\n\n');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get number of clients connected to a session
|
|
290
|
+
*/
|
|
291
|
+
getClientCount(streamingId) {
|
|
292
|
+
return this.clients.get(streamingId)?.size || 0;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Get all active sessions
|
|
296
|
+
*/
|
|
297
|
+
getActiveSessions() {
|
|
298
|
+
return Array.from(this.clients.keys());
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Close all connections for a session
|
|
302
|
+
*/
|
|
303
|
+
closeSession(streamingId) {
|
|
304
|
+
// Clean up any pending event buffer
|
|
305
|
+
this.stopBuffering(streamingId);
|
|
306
|
+
const clients = this.clients.get(streamingId);
|
|
307
|
+
if (!clients)
|
|
308
|
+
return;
|
|
309
|
+
const closeEvent = {
|
|
310
|
+
type: 'closed',
|
|
311
|
+
streamingId: streamingId,
|
|
312
|
+
timestamp: new Date().toISOString()
|
|
313
|
+
};
|
|
314
|
+
// Create array to avoid modifying set while iterating
|
|
315
|
+
const clientsArray = Array.from(clients);
|
|
316
|
+
this.logger.debug('Closing SSE session, sending close events to all clients', {
|
|
317
|
+
streamingId,
|
|
318
|
+
clientCount: clientsArray.length
|
|
319
|
+
});
|
|
320
|
+
for (const client of clientsArray) {
|
|
321
|
+
try {
|
|
322
|
+
this.sendSSEEvent(client, closeEvent);
|
|
323
|
+
this.logger.debug('Sent SSE close event to client', { streamingId });
|
|
324
|
+
client.end();
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
this.logger.error('Error closing SSE client connection', error, { streamingId });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Remove the entire session
|
|
331
|
+
this.clients.delete(streamingId);
|
|
332
|
+
// Stop heartbeat if no clients remain
|
|
333
|
+
if (this.getTotalClientCount() === 0) {
|
|
334
|
+
this.stopHeartbeat();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get total number of clients across all sessions
|
|
339
|
+
*/
|
|
340
|
+
getTotalClientCount() {
|
|
341
|
+
let total = 0;
|
|
342
|
+
for (const clients of this.clients.values()) {
|
|
343
|
+
total += clients.size;
|
|
344
|
+
}
|
|
345
|
+
return total;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Clean up orphaned sessions that don't have an active Claude process.
|
|
349
|
+
* Call this with a set of active streamingIds to close any sessions not in that set.
|
|
350
|
+
*/
|
|
351
|
+
cleanupOrphanedSessions(activeStreamingIds) {
|
|
352
|
+
const orphanedSessions = [];
|
|
353
|
+
for (const streamingId of this.clients.keys()) {
|
|
354
|
+
if (!activeStreamingIds.has(streamingId)) {
|
|
355
|
+
orphanedSessions.push(streamingId);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (orphanedSessions.length > 0) {
|
|
359
|
+
this.logger.info('Cleaning up orphaned SSE sessions', {
|
|
360
|
+
count: orphanedSessions.length,
|
|
361
|
+
orphanedIds: orphanedSessions.map(s => s.slice(0, 8)),
|
|
362
|
+
});
|
|
363
|
+
for (const streamingId of orphanedSessions) {
|
|
364
|
+
this.closeSession(streamingId);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return orphanedSessions.length;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Disconnect all clients from all sessions
|
|
371
|
+
*/
|
|
372
|
+
disconnectAll() {
|
|
373
|
+
// Clean up all event buffers first
|
|
374
|
+
for (const streamingId of this.eventBuffers.keys()) {
|
|
375
|
+
this.stopBuffering(streamingId);
|
|
376
|
+
}
|
|
377
|
+
for (const streamingId of this.clients.keys()) {
|
|
378
|
+
this.closeSession(streamingId);
|
|
379
|
+
}
|
|
380
|
+
this.stopHeartbeat();
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Start periodic heartbeat to keep SSE connections alive
|
|
384
|
+
* Also prunes stale/dead clients that failed to disconnect properly
|
|
385
|
+
*/
|
|
386
|
+
startHeartbeat() {
|
|
387
|
+
if (this.heartbeatInterval) {
|
|
388
|
+
return; // Already running
|
|
389
|
+
}
|
|
390
|
+
this.heartbeatInterval = setInterval(() => {
|
|
391
|
+
this.logger.debug('Sending heartbeat to all clients');
|
|
392
|
+
// Collect dead clients during heartbeat check
|
|
393
|
+
const deadClients = [];
|
|
394
|
+
for (const [streamingId, clients] of this.clients.entries()) {
|
|
395
|
+
for (const client of clients) {
|
|
396
|
+
try {
|
|
397
|
+
// Check if the response is still writable before sending
|
|
398
|
+
if (client.writableEnded || client.destroyed) {
|
|
399
|
+
deadClients.push({ streamingId, client });
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
this.sendHeartbeat(client);
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
this.logger.debug('Failed to send heartbeat to client, marking as dead', {
|
|
406
|
+
error,
|
|
407
|
+
streamingId: streamingId.slice(0, 8),
|
|
408
|
+
});
|
|
409
|
+
deadClients.push({ streamingId, client });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
// Clean up dead clients discovered during heartbeat
|
|
414
|
+
if (deadClients.length > 0) {
|
|
415
|
+
this.logger.info('Pruning stale SSE clients discovered during heartbeat', {
|
|
416
|
+
count: deadClients.length,
|
|
417
|
+
sessions: [...new Set(deadClients.map(d => d.streamingId.slice(0, 8)))],
|
|
418
|
+
});
|
|
419
|
+
for (const { streamingId, client } of deadClients) {
|
|
420
|
+
this.removeClient(streamingId, client);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}, this.HEARTBEAT_INTERVAL_MS);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Stop periodic heartbeat
|
|
427
|
+
*/
|
|
428
|
+
stopHeartbeat() {
|
|
429
|
+
if (this.heartbeatInterval) {
|
|
430
|
+
clearInterval(this.heartbeatInterval);
|
|
431
|
+
this.heartbeatInterval = undefined;
|
|
432
|
+
this.logger.debug('Stopped heartbeat');
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
//# sourceMappingURL=stream-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-manager.js","sourceRoot":"","sources":["../../../src/services/infrastructure/stream-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing utility for measuring and logging operation durations.
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple, reusable way to measure performance of operations
|
|
5
|
+
* (especially API endpoints) with automatic debug logging.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* const timer = createTimer('fetchConversations', logger);
|
|
10
|
+
*
|
|
11
|
+
* timer.mark('listSessions');
|
|
12
|
+
* const sessions = await listSessions();
|
|
13
|
+
*
|
|
14
|
+
* timer.mark('fetchInsights');
|
|
15
|
+
* const insights = await fetchInsights();
|
|
16
|
+
*
|
|
17
|
+
* timer.end({ sessionCount: sessions.length }); // logs all timings
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { type CUILogger } from './logger.js';
|
|
21
|
+
export interface TimingResult {
|
|
22
|
+
total: number;
|
|
23
|
+
marks: Record<string, number>;
|
|
24
|
+
}
|
|
25
|
+
export interface Timer {
|
|
26
|
+
/** Mark the start of a named phase */
|
|
27
|
+
mark(name: string): void;
|
|
28
|
+
/** End timing and log results (only in debug mode) */
|
|
29
|
+
end(extraContext?: Record<string, unknown>): TimingResult;
|
|
30
|
+
/** Get elapsed time since timer creation */
|
|
31
|
+
elapsed(): number;
|
|
32
|
+
/** Get current timings without ending */
|
|
33
|
+
getTimings(): TimingResult;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a timer for measuring operation phases.
|
|
37
|
+
*
|
|
38
|
+
* @param operation - Name of the operation being timed (e.g., 'fetchConversations')
|
|
39
|
+
* @param logger - Logger instance to use for debug output
|
|
40
|
+
* @returns Timer object with mark() and end() methods
|
|
41
|
+
*/
|
|
42
|
+
export declare function createTimer(operation: string, logger?: CUILogger): Timer;
|
|
43
|
+
/**
|
|
44
|
+
* Time a single async operation and return result with duration.
|
|
45
|
+
*
|
|
46
|
+
* @param fn - Async function to time
|
|
47
|
+
* @returns Tuple of [result, durationMs]
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const [data, ms] = await timeAsync(() => fetch('/api/data'));
|
|
51
|
+
* logger.debug('Fetch completed', { durationMs: ms });
|
|
52
|
+
*/
|
|
53
|
+
export declare function timeAsync<T>(fn: () => Promise<T>): Promise<[T, number]>;
|
|
54
|
+
/**
|
|
55
|
+
* Time a synchronous operation and return result with duration.
|
|
56
|
+
*
|
|
57
|
+
* @param fn - Function to time
|
|
58
|
+
* @returns Tuple of [result, durationMs]
|
|
59
|
+
*/
|
|
60
|
+
export declare function timeSync<T>(fn: () => T): [T, number];
|
|
61
|
+
/**
|
|
62
|
+
* Express middleware for timing requests (debug mode only).
|
|
63
|
+
* Adds X-Response-Time header in development.
|
|
64
|
+
*/
|
|
65
|
+
export declare function requestTimingMiddleware(): (req: {
|
|
66
|
+
method: string;
|
|
67
|
+
path: string;
|
|
68
|
+
}, res: {
|
|
69
|
+
setHeader: (name: string, value: string) => void;
|
|
70
|
+
on: (event: string, fn: () => void) => void;
|
|
71
|
+
}, next: () => void) => void;
|
|
72
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../../src/services/infrastructure/timing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,KAAK;IACpB,sCAAsC;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,sDAAsD;IACtD,GAAG,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAAC;IAC1D,4CAA4C;IAC5C,OAAO,IAAI,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,IAAI,YAAY,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,CAiDxE;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAI7E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAIpD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,KAC7B,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK;IAAE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;CAAE,EAAE,MAAM,MAAM,IAAI,UAiBxK"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing utility for measuring and logging operation durations.
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple, reusable way to measure performance of operations
|
|
5
|
+
* (especially API endpoints) with automatic debug logging.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* const timer = createTimer('fetchConversations', logger);
|
|
10
|
+
*
|
|
11
|
+
* timer.mark('listSessions');
|
|
12
|
+
* const sessions = await listSessions();
|
|
13
|
+
*
|
|
14
|
+
* timer.mark('fetchInsights');
|
|
15
|
+
* const insights = await fetchInsights();
|
|
16
|
+
*
|
|
17
|
+
* timer.end({ sessionCount: sessions.length }); // logs all timings
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Create a timer for measuring operation phases.
|
|
22
|
+
*
|
|
23
|
+
* @param operation - Name of the operation being timed (e.g., 'fetchConversations')
|
|
24
|
+
* @param logger - Logger instance to use for debug output
|
|
25
|
+
* @returns Timer object with mark() and end() methods
|
|
26
|
+
*/
|
|
27
|
+
export function createTimer(operation, logger) {
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
const marks = [];
|
|
30
|
+
let lastMarkTime = startTime;
|
|
31
|
+
return {
|
|
32
|
+
mark(name) {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
marks.push({ name, time: now - lastMarkTime });
|
|
35
|
+
lastMarkTime = now;
|
|
36
|
+
},
|
|
37
|
+
end(extraContext) {
|
|
38
|
+
const total = Date.now() - startTime;
|
|
39
|
+
const timings = {};
|
|
40
|
+
for (const mark of marks) {
|
|
41
|
+
timings[mark.name] = mark.time;
|
|
42
|
+
}
|
|
43
|
+
const result = { total, marks: timings };
|
|
44
|
+
// Only log in debug mode
|
|
45
|
+
if (logger) {
|
|
46
|
+
logger.debug(`${operation} timing`, {
|
|
47
|
+
durationMs: total,
|
|
48
|
+
timingsMs: timings,
|
|
49
|
+
...extraContext
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
},
|
|
54
|
+
elapsed() {
|
|
55
|
+
return Date.now() - startTime;
|
|
56
|
+
},
|
|
57
|
+
getTimings() {
|
|
58
|
+
const total = Date.now() - startTime;
|
|
59
|
+
const timings = {};
|
|
60
|
+
for (const mark of marks) {
|
|
61
|
+
timings[mark.name] = mark.time;
|
|
62
|
+
}
|
|
63
|
+
return { total, marks: timings };
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Time a single async operation and return result with duration.
|
|
69
|
+
*
|
|
70
|
+
* @param fn - Async function to time
|
|
71
|
+
* @returns Tuple of [result, durationMs]
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* const [data, ms] = await timeAsync(() => fetch('/api/data'));
|
|
75
|
+
* logger.debug('Fetch completed', { durationMs: ms });
|
|
76
|
+
*/
|
|
77
|
+
export async function timeAsync(fn) {
|
|
78
|
+
const start = Date.now();
|
|
79
|
+
const result = await fn();
|
|
80
|
+
return [result, Date.now() - start];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Time a synchronous operation and return result with duration.
|
|
84
|
+
*
|
|
85
|
+
* @param fn - Function to time
|
|
86
|
+
* @returns Tuple of [result, durationMs]
|
|
87
|
+
*/
|
|
88
|
+
export function timeSync(fn) {
|
|
89
|
+
const start = Date.now();
|
|
90
|
+
const result = fn();
|
|
91
|
+
return [result, Date.now() - start];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Express middleware for timing requests (debug mode only).
|
|
95
|
+
* Adds X-Response-Time header in development.
|
|
96
|
+
*/
|
|
97
|
+
export function requestTimingMiddleware() {
|
|
98
|
+
return (req, res, next) => {
|
|
99
|
+
const start = Date.now();
|
|
100
|
+
res.on('finish', () => {
|
|
101
|
+
const duration = Date.now() - start;
|
|
102
|
+
// Only set header in non-production (it's already handled by most frameworks)
|
|
103
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
104
|
+
try {
|
|
105
|
+
res.setHeader('X-Response-Time', `${duration}ms`);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Response already sent, ignore
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
next();
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.js","sourceRoot":"","sources":["../../../src/services/infrastructure/timing.ts"],"names":[],"mappings":"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"}
|