crewly 1.6.5 → 1.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/config/roles/auditor/prompt.md +24 -0
- package/config/roles/developer/prompt.md +2 -1
- package/config/roles/orchestrator/prompt.md +74 -2
- package/config/roles/team-leader/prompt.md +6 -0
- package/config/skills/agent/core/create-request/SKILL.md +1 -1
- package/config/skills/agent/core/create-request/execute.sh +29 -2
- package/config/skills/agent/core/create-request/execute.test.sh +168 -0
- package/config/skills/agent/core/report-status/SKILL.md +8 -1
- package/config/skills/agent/core/report-status/execute.sh +23 -1
- package/config/skills/orchestrator/heartbeat/execute.sh +48 -6
- package/config/sops/common/mid-flight-milestone-surface.md +128 -0
- package/config/sops/common/owner-facing-communication.md +46 -2
- package/config/sops/developer/git-workflow.md +33 -0
- package/dist/backend/backend/src/constants.d.ts +12 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +12 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.controller.js +2 -2
- package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +6 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +73 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +128 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts +3 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js +8 -0
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.controller.js +50 -8
- package/dist/backend/backend/src/controllers/session/session.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +215 -94
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +185 -36
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +11 -1
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +42 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +218 -6
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +61 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +117 -9
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts +33 -0
- package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.js +108 -4
- package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js +40 -2
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat/chat.service.d.ts +48 -331
- package/dist/backend/backend/src/services/chat/chat.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat/chat.service.js +261 -712
- package/dist/backend/backend/src/services/chat/chat.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +82 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +120 -2
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.d.ts +114 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.d.ts.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.js +182 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.js.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.d.ts +188 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.js +434 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.js.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +401 -5
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +619 -3
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.d.ts +93 -0
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.js +138 -0
- package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.js.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts +46 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js +75 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts +10 -2
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js +178 -10
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +37 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +71 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/types.d.ts +33 -1
- package/dist/backend/backend/src/services/chat-v2/types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/types.js +1 -1
- package/dist/backend/backend/src/services/chat-v2/types.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.d.ts +22 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.js +71 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +102 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +61 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts +21 -3
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js +47 -13
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/system-health.util.d.ts +25 -4
- package/dist/backend/backend/src/services/core/system-health.util.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/system-health.util.js +30 -5
- package/dist/backend/backend/src/services/core/system-health.util.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js +22 -11
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +35 -3
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-replay.service.d.ts +2 -4
- package/dist/backend/backend/src/services/messaging/message-replay.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-replay.service.js +22 -12
- package/dist/backend/backend/src/services/messaging/message-replay.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +25 -5
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/system-resource-alert.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/system-resource-alert.service.js +13 -3
- package/dist/backend/backend/src/services/monitoring/system-resource-alert.service.js.map +1 -1
- package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.d.ts +99 -0
- package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.js +225 -0
- package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +39 -18
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +60 -32
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +134 -0
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +416 -13
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js +73 -7
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-handoff.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-handoff.service.js +30 -4
- package/dist/backend/backend/src/services/session/session-handoff.service.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-executor.service.js +13 -1
- package/dist/backend/backend/src/services/skill/skill-executor.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/notify-reconciliation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/notify-reconciliation.service.js +9 -6
- package/dist/backend/backend/src/services/slack/notify-reconciliation.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +21 -2
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +120 -46
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +49 -0
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +33 -2
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +160 -8
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/cascade-request-status.js +55 -2
- package/dist/backend/backend/src/services/v3/cascade-request-status.js.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-executor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-executor.service.js +9 -1
- package/dist/backend/backend/src/services/v3/mission-executor.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js +28 -3
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +5 -2
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js +57 -15
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +39 -0
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js +81 -0
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts +17 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +22 -3
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts +1 -1
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +26 -10
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.js +68 -5
- package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/team-identifier-resolver.d.ts +44 -0
- package/dist/backend/backend/src/services/workflow/team-identifier-resolver.d.ts.map +1 -0
- package/dist/backend/backend/src/services/workflow/team-identifier-resolver.js +57 -0
- package/dist/backend/backend/src/services/workflow/team-identifier-resolver.js.map +1 -0
- package/dist/backend/backend/src/types/credential.types.d.ts +17 -1
- package/dist/backend/backend/src/types/credential.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/credential.types.js +15 -5
- package/dist/backend/backend/src/types/credential.types.js.map +1 -1
- package/dist/backend/backend/src/types/cron-task.types.d.ts +17 -0
- package/dist/backend/backend/src/types/cron-task.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.js +12 -0
- package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.d.ts +10 -13
- package/dist/backend/backend/src/types/intent-task.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.js +4 -1
- package/dist/backend/backend/src/types/intent-task.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +23 -0
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/backend/src/utils/team.utils.d.ts +3 -1
- package/dist/backend/backend/src/utils/team.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/team.utils.js +26 -5
- package/dist/backend/backend/src/utils/team.utils.js.map +1 -1
- package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts +23 -0
- package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/chat-v2.gateway.js +56 -7
- package/dist/backend/backend/src/websocket/chat-v2.gateway.js.map +1 -1
- package/dist/backend/backend/src/websocket/chat.gateway.d.ts +19 -4
- package/dist/backend/backend/src/websocket/chat.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/chat.gateway.js +78 -63
- package/dist/backend/backend/src/websocket/chat.gateway.js.map +1 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.js +10 -2
- package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +12 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +12 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/event-bus/event-bus.service.js +22 -11
- package/dist/cli/backend/src/services/event-bus/event-bus.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +35 -3
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/skill/skill-executor.service.js +13 -1
- package/dist/cli/backend/src/services/skill/skill-executor.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +33 -2
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +160 -8
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/types/credential.types.d.ts +17 -1
- package/dist/cli/backend/src/types/credential.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/credential.types.js +15 -5
- package/dist/cli/backend/src/types/credential.types.js.map +1 -1
- package/dist/cli/backend/src/types/event-bus.types.d.ts +1 -1
- package/dist/cli/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/event-bus.types.js +12 -0
- package/dist/cli/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +23 -0
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/cli/cli/src/commands/start.js +73 -12
- package/dist/cli/cli/src/commands/start.js.map +1 -1
- package/frontend/dist/assets/index-b279da34.js +4926 -0
- package/frontend/dist/assets/{index-b7e59b2b.css → index-c07e04c0.css} +2 -2
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-698305f3.js +0 -5228
|
@@ -25,6 +25,7 @@ import { getSettingsService } from './services/settings/index.js';
|
|
|
25
25
|
import { MemoryService } from './services/memory/memory.service.js';
|
|
26
26
|
import { getImprovementStartupService } from './services/orchestrator/improvement-startup.service.js';
|
|
27
27
|
import { initializeSlackIfConfigured, shutdownSlack } from './services/slack/index.js';
|
|
28
|
+
import { resolveTeamByIdOrSlug, slugifyTeamName } from './services/workflow/team-identifier-resolver.js';
|
|
28
29
|
import { initializeWhatsAppIfConfigured, shutdownWhatsApp } from './services/whatsapp/index.js';
|
|
29
30
|
import { initializeGoogleChatIfConfigured } from './services/messaging/google-chat-initializer.js';
|
|
30
31
|
import { initializeTelegramIfConfigured, shutdownTelegram } from './services/telegram/index.js';
|
|
@@ -34,6 +35,7 @@ import { ThreadStatusQueueService } from './services/messaging/thread-status-que
|
|
|
34
35
|
import { EventBusService } from './services/event-bus/index.js';
|
|
35
36
|
import { EventToWorkItemBridge } from './services/event-bus/event-to-workitem-bridge.service.js';
|
|
36
37
|
import { AutoLearningSubscriber } from './services/memory/auto-learning.subscriber.js';
|
|
38
|
+
import { MilestoneNotificationSubscriber } from './services/notification/milestone-notification.subscriber.js';
|
|
37
39
|
import { RequestSlaSubscriber, setRequestSlaSubscriber, } from './services/v3/request-sla.subscriber.js';
|
|
38
40
|
import { RequestDecomposeSubscriber, setRequestDecomposeSubscriber, } from './services/v3/request-decompose.subscriber.js';
|
|
39
41
|
import { RequestStatusUpdateSubscriber } from './services/v3/request-status-update.subscriber.js';
|
|
@@ -138,6 +140,9 @@ export class CrewlyServer {
|
|
|
138
140
|
eventToWorkItemBridge = null;
|
|
139
141
|
/** LEARN-1: subscribes to terminal task / mission:replanned events and auto-records learnings. */
|
|
140
142
|
autoLearningSubscriber = null;
|
|
143
|
+
// DF-1 #438 — symmetric to AutoLearningSubscriber; surfaces milestones
|
|
144
|
+
// to orc's chat queue.
|
|
145
|
+
milestoneNotificationSubscriber = null;
|
|
141
146
|
/** INBOUND-1: subscribes to request:created and tracks 5/10 min SLA on respond_to_user WIs. */
|
|
142
147
|
requestSlaSubscriber = null;
|
|
143
148
|
/** Pipeline-#4 follow-up: subscribes to request:created and auto-decomposes actionable L2 Requests via plan() → addToPool. */
|
|
@@ -330,6 +335,19 @@ export class CrewlyServer {
|
|
|
330
335
|
// contract (V1) and the V7/V9 self-checks in the co-located test.
|
|
331
336
|
this.autoLearningSubscriber = AutoLearningSubscriber.boot(this.eventBusService);
|
|
332
337
|
this.autoLearningSubscriber.start();
|
|
338
|
+
// DF-1 #438: symmetric notification subscriber. Same architectural
|
|
339
|
+
// pattern as AutoLearningSubscriber — listens to terminal lifecycle
|
|
340
|
+
// events (`task:verified`, `mission:replanned`) and enqueues a
|
|
341
|
+
// `[MILESTONE]` envelope into orc's chat queue. The QW-3 row in
|
|
342
|
+
// `config/roles/orchestrator/prompt.md` (#436) handles the
|
|
343
|
+
// always-forward-to-owner rule on the orc side; this subscriber
|
|
344
|
+
// closes the gap where an agent ships work but forgets to call
|
|
345
|
+
// `report-status --status milestone` (the agent-side QW-1 path).
|
|
346
|
+
this.milestoneNotificationSubscriber = new MilestoneNotificationSubscriber({
|
|
347
|
+
eventBus: this.eventBusService,
|
|
348
|
+
messageQueueService: this.messageQueueService,
|
|
349
|
+
});
|
|
350
|
+
this.milestoneNotificationSubscriber.start();
|
|
333
351
|
// INBOUND-1 + Pipeline-#4 follow-up: wire RequestService → bus, then
|
|
334
352
|
// boot both v3 subscribers (SLA tracker + auto-decompose). Order
|
|
335
353
|
// matters within the block: setRequestServiceEventBus must run
|
|
@@ -473,28 +491,45 @@ export class CrewlyServer {
|
|
|
473
491
|
}
|
|
474
492
|
}
|
|
475
493
|
});
|
|
494
|
+
// Shared LiveReconcilerDataProvider instance used by both the
|
|
495
|
+
// Reconciler service and the TeamHealthWatchdog data provider.
|
|
496
|
+
// Sharing is required so the memory-pressure broadcast state
|
|
497
|
+
// (`consecutivePressureSkips` / `lastPressureNotifiedAt`) is
|
|
498
|
+
// counted ONCE per sustained pressure episode. Two separate
|
|
499
|
+
// instances would each cross the 5-skip threshold around the same
|
|
500
|
+
// time and publish two `system:memory_pressure` events with
|
|
501
|
+
// distinct `event.id` values (no debounce match), so orc would
|
|
502
|
+
// receive duplicates. See follow-up #5 from PR #543 review.
|
|
503
|
+
const liveDataProvider = new LiveReconcilerDataProvider();
|
|
504
|
+
liveDataProvider.setEventBus(this.eventBusService);
|
|
505
|
+
// Wire AgentRegistrationService so the memory-pressure eviction
|
|
506
|
+
// path can terminate idle agents to free wake slots (issue surfaced
|
|
507
|
+
// 2026-05-16: queued WIs for inactive Atlas could not get woken
|
|
508
|
+
// because the floor was held by idle product/marketing agents).
|
|
509
|
+
liveDataProvider.setAgentRegistrationService(this.apiController.agentRegistrationService);
|
|
476
510
|
// Initialize Reconciler Service (V2 — system truth recomputation)
|
|
477
511
|
{
|
|
478
512
|
const reconcilerLogger = LoggerService.getInstance().createComponentLogger('ReconcilerInit');
|
|
479
513
|
// Live data provider — connects Reconciler to Task Pool, Claim Service,
|
|
480
514
|
// Storage Service, and Agent Suspend for real reconciliation including
|
|
481
515
|
// Hybrid Wake (auto-rehydrating suspended agents when tasks go unclaimed).
|
|
482
|
-
const liveDataProvider = new LiveReconcilerDataProvider();
|
|
483
516
|
this.reconcilerService = new ReconcilerService(liveDataProvider);
|
|
484
517
|
setReconcilerService(this.reconcilerService);
|
|
485
518
|
// Subscribe EventBus events for targeted reconciliation
|
|
486
519
|
if (this.reconcilerService) {
|
|
487
520
|
const reconciler = this.reconcilerService;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
521
|
+
// 2026-05-15 Steve dogfood: the prior `subscribe({ subscriberSession:
|
|
522
|
+
// '__reconciler__' })` loop here was redundant AND wrong. The
|
|
523
|
+
// subscribe path routes critical events through
|
|
524
|
+
// `MessageQueueService.enqueue` keyed by `targetSession`, which
|
|
525
|
+
// then fails noisily because `__reconciler__` is not a PTY
|
|
526
|
+
// session ("Session '__reconciler__' does not exist", every
|
|
527
|
+
// reconciler tick). The in-process `event_published` listener
|
|
528
|
+
// below already drives the reconciler — no second wiring needed.
|
|
529
|
+
// Removed the subscribe-block; if a future change needs persistent
|
|
530
|
+
// metadata for the reconciler subscription, attach it as a real
|
|
531
|
+
// in-process subscriber via `onInProcess` rather than the
|
|
532
|
+
// session-targeted `subscribe` API.
|
|
498
533
|
// Listen for all published events and trigger targeted reconciliation
|
|
499
534
|
this.eventBusService.on('event_published', (payload) => {
|
|
500
535
|
const targetedEventTypes = ['task:completed', 'task:failed', 'agent:idle', 'agent:inactive'];
|
|
@@ -527,9 +562,11 @@ export class CrewlyServer {
|
|
|
527
562
|
thwLogger.warn('Reconciler not available; skipping TeamHealthWatchdog init.');
|
|
528
563
|
}
|
|
529
564
|
else {
|
|
530
|
-
|
|
565
|
+
// Reuse the shared LiveReconcilerDataProvider declared
|
|
566
|
+
// above (follow-up #5 from PR #543 review) — instantiating
|
|
567
|
+
// a second copy would double-broadcast memory-pressure.
|
|
531
568
|
const dataProvider = new LiveTeamHealthDataProvider({
|
|
532
|
-
reconcilerProvider,
|
|
569
|
+
reconcilerProvider: liveDataProvider,
|
|
533
570
|
getTeams: async () => StorageService.getInstance().getTeams(),
|
|
534
571
|
bootedAt: new Date(),
|
|
535
572
|
});
|
|
@@ -1078,6 +1115,11 @@ export class CrewlyServer {
|
|
|
1078
1115
|
const chatDispatcher = new ChatV2DispatcherService({
|
|
1079
1116
|
agentSink: this.apiController.agentRegistrationService,
|
|
1080
1117
|
mentionResolver: chatMentionResolver,
|
|
1118
|
+
// Phase B-2 — huddle roster lookup. ChatV2Service owns
|
|
1119
|
+
// the chat_channel_members table; the dispatcher just
|
|
1120
|
+
// needs the list of session names for a given channel
|
|
1121
|
+
// to fan-out a user message to every huddle member.
|
|
1122
|
+
huddleMembersFor: (channelId) => chatService.queryHuddleMembersForDispatch(channelId),
|
|
1081
1123
|
});
|
|
1082
1124
|
this.chatV2Gateway = chatGateway;
|
|
1083
1125
|
this.chatV2Dispatcher = chatDispatcher;
|
|
@@ -1089,6 +1131,39 @@ export class CrewlyServer {
|
|
|
1089
1131
|
path: '/ws/chat',
|
|
1090
1132
|
authMode: jwtSecret ? 'jwt' : 'dev-anonymous',
|
|
1091
1133
|
});
|
|
1134
|
+
// Cloud Portal relay bridge — gives the Crewly Portal at
|
|
1135
|
+
// crewlyai.com the same /agents experience by tunnelling chat-v2
|
|
1136
|
+
// RPC calls through the Cloud relay queue + forwarding gateway
|
|
1137
|
+
// broadcasts as `chat_event` messages. Only wired when Cloud Sync
|
|
1138
|
+
// is running (BrowserRelayAdapter pattern).
|
|
1139
|
+
try {
|
|
1140
|
+
const { ChatV2RelayAdapter } = await import('./services/chat-v2/chat-v2.relay-adapter.service.js');
|
|
1141
|
+
const { CloudSyncService } = await import('./services/cloud/cloud-sync.service.js');
|
|
1142
|
+
const { createOssAgentDirectoryProvider, createOssAgentPresenceProvider, } = await import('./services/chat-v2/chat-v2.providers.js');
|
|
1143
|
+
const sync = CloudSyncService.getInstance();
|
|
1144
|
+
if (sync) {
|
|
1145
|
+
const chatRelayAdapter = new ChatV2RelayAdapter({
|
|
1146
|
+
service: chatService,
|
|
1147
|
+
gateway: chatGateway,
|
|
1148
|
+
cloudSync: sync,
|
|
1149
|
+
// Wire the dispatcher so Portal-sent user messages also fire the
|
|
1150
|
+
// agent-side prompt (parity with the HTTP controller path).
|
|
1151
|
+
// Without this, Portal user-messages persist but the bound agent
|
|
1152
|
+
// never receives the `[CHAT:<id>]` prompt — orc/etc. stay silent.
|
|
1153
|
+
dispatcher: chatDispatcher,
|
|
1154
|
+
directory: createOssAgentDirectoryProvider(this.storageService),
|
|
1155
|
+
presence: createOssAgentPresenceProvider(this.storageService),
|
|
1156
|
+
});
|
|
1157
|
+
chatRelayAdapter.start();
|
|
1158
|
+
this.logger.info('ChatV2RelayAdapter started — Cloud Portal can now drive chat-v2 via relay');
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
catch (err) {
|
|
1162
|
+
// Adapter wiring failure is non-fatal — local OSS UI still works.
|
|
1163
|
+
this.logger.warn('ChatV2RelayAdapter wiring skipped', {
|
|
1164
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1092
1167
|
// Onboarding v3 (B1) — wire the cold-start detector with the
|
|
1093
1168
|
// chat-v2 service we just stood up. The orc bootstrap path
|
|
1094
1169
|
// (CrewlyAgentRuntimeService.detectOnboardingMode) probes this
|
|
@@ -1209,6 +1284,7 @@ export class CrewlyServer {
|
|
|
1209
1284
|
// resume notification won't re-send already-answered conversations.
|
|
1210
1285
|
try {
|
|
1211
1286
|
const { RequestService } = await import('./services/v3/request.service.js');
|
|
1287
|
+
const { extractSlackChannelId, extractSlackThreadTs } = await import('./services/v3/request-sla.subscriber.js');
|
|
1212
1288
|
const reqSvc = RequestService.getInstance();
|
|
1213
1289
|
const allReqs = await reqSvc.listAll();
|
|
1214
1290
|
let backfilled = 0;
|
|
@@ -1216,13 +1292,17 @@ export class CrewlyServer {
|
|
|
1216
1292
|
if (req.status !== 'done')
|
|
1217
1293
|
continue;
|
|
1218
1294
|
const scid = req.sourceConversationItemId || '';
|
|
1219
|
-
|
|
1295
|
+
// `extractSlack*` strips the optional `-msg-{ts}` thread-reply
|
|
1296
|
+
// suffix before parsing, so both top-level and in-thread
|
|
1297
|
+
// Requests resolve to the canonical `{channelId}:{threadRoot}`.
|
|
1298
|
+
// Previously a local regex was used here and its greedy `.+`
|
|
1299
|
+
// swallowed the suffix, producing a malformed threadKey that
|
|
1300
|
+
// missed the dedup check and bloated the persistence file.
|
|
1301
|
+
const channelId = extractSlackChannelId(scid);
|
|
1302
|
+
const threadTs = extractSlackThreadTs(scid);
|
|
1303
|
+
if (!channelId || !threadTs)
|
|
1220
1304
|
continue;
|
|
1221
|
-
const
|
|
1222
|
-
if (!m)
|
|
1223
|
-
continue;
|
|
1224
|
-
const [, channelId, t1, t2] = m;
|
|
1225
|
-
const threadKey = `${channelId}:${t1}.${t2}`;
|
|
1305
|
+
const threadKey = `${channelId}:${threadTs}`;
|
|
1226
1306
|
if (this.threadStatusQueueService.get(threadKey))
|
|
1227
1307
|
continue;
|
|
1228
1308
|
this.threadStatusQueueService.trackInbound({
|
|
@@ -1248,9 +1328,7 @@ export class CrewlyServer {
|
|
|
1248
1328
|
// but before the queue processor starts (so replayed messages are ready for delivery).
|
|
1249
1329
|
try {
|
|
1250
1330
|
const { MessageReplayService } = await import('./services/messaging/message-replay.service.js');
|
|
1251
|
-
const
|
|
1252
|
-
const chatService = getChatService();
|
|
1253
|
-
const replayService = new MessageReplayService(this.messageQueueService, chatService, this.config.crewlyHome);
|
|
1331
|
+
const replayService = new MessageReplayService(this.messageQueueService, this.config.crewlyHome);
|
|
1254
1332
|
const replayResult = await replayService.replayPendingMessages();
|
|
1255
1333
|
if (replayResult.replayedCount > 0) {
|
|
1256
1334
|
this.logger.info('Replayed pending messages from offline period (#247)', {
|
|
@@ -1306,6 +1384,16 @@ export class CrewlyServer {
|
|
|
1306
1384
|
this.logger.info('Executing cron task', { id: task.id, target: task.targetAgent });
|
|
1307
1385
|
await registrationRef.sendMessageToAgent(task.targetAgent, `[CRON_TASK:${task.id}] ${task.taskDescription}`);
|
|
1308
1386
|
});
|
|
1387
|
+
// Issue #307: cron tasks created with `targetTeamId` set to a
|
|
1388
|
+
// name slug (e.g. "stock-ops-team") instead of the UUID would
|
|
1389
|
+
// silently 404 on every fire — `teams.find(t => t.id === teamId)`
|
|
1390
|
+
// returned undefined and both callbacks returned `false` with
|
|
1391
|
+
// no log surface. `resolveTeamByIdOrSlug` (imported statically
|
|
1392
|
+
// at the top of the file) tries UUID first, then falls back
|
|
1393
|
+
// to a slug match against `name`. Misses now surface a distinct
|
|
1394
|
+
// warn-log with the available slugs so the cause is visible
|
|
1395
|
+
// instead of hiding behind the generic "agent offline" warn
|
|
1396
|
+
// from cron-task.service.
|
|
1309
1397
|
cronTaskService.setAgentStatusCallback(async (sessionName, teamId) => {
|
|
1310
1398
|
// Handle orchestrator separately — it's not in regular teams
|
|
1311
1399
|
if (sessionName === CREWLY_CONSTANTS.SESSIONS.ORCHESTRATOR_NAME || teamId === 'orchestrator') {
|
|
@@ -1313,9 +1401,16 @@ export class CrewlyServer {
|
|
|
1313
1401
|
return orchStatus?.agentStatus === 'active' || orchStatus?.agentStatus === 'started';
|
|
1314
1402
|
}
|
|
1315
1403
|
const teams = await storageRef.getTeams();
|
|
1316
|
-
const team = teams
|
|
1317
|
-
if (!team)
|
|
1404
|
+
const team = resolveTeamByIdOrSlug(teams, teamId);
|
|
1405
|
+
if (!team) {
|
|
1406
|
+
this.logger.warn('CronTask: targetTeamId resolves to no team', {
|
|
1407
|
+
sessionName,
|
|
1408
|
+
targetTeamId: teamId,
|
|
1409
|
+
availableSlugs: teams.slice(0, 10).map((t) => slugifyTeamName(t.name)),
|
|
1410
|
+
hint: 'Set targetTeamId to either the team UUID or one of availableSlugs (lowercase, spaces→-)',
|
|
1411
|
+
});
|
|
1318
1412
|
return false;
|
|
1413
|
+
}
|
|
1319
1414
|
const member = team.members.find((m) => m.sessionName === sessionName);
|
|
1320
1415
|
if (!member)
|
|
1321
1416
|
return false;
|
|
@@ -1325,16 +1420,25 @@ export class CrewlyServer {
|
|
|
1325
1420
|
cronTaskService.setAgentStartCallback(async (sessionName, teamId) => {
|
|
1326
1421
|
try {
|
|
1327
1422
|
const teams = await storageRef.getTeams();
|
|
1328
|
-
const team = teams
|
|
1329
|
-
if (!team)
|
|
1423
|
+
const team = resolveTeamByIdOrSlug(teams, teamId);
|
|
1424
|
+
if (!team) {
|
|
1425
|
+
this.logger.warn('CronTask auto-start: targetTeamId resolves to no team', {
|
|
1426
|
+
sessionName,
|
|
1427
|
+
targetTeamId: teamId,
|
|
1428
|
+
availableSlugs: teams.slice(0, 10).map((t) => slugifyTeamName(t.name)),
|
|
1429
|
+
hint: 'Set targetTeamId to either the team UUID or one of availableSlugs (lowercase, spaces→-)',
|
|
1430
|
+
});
|
|
1330
1431
|
return false;
|
|
1432
|
+
}
|
|
1331
1433
|
const member = team.members.find((m) => m.sessionName === sessionName);
|
|
1332
1434
|
if (!member)
|
|
1333
1435
|
return false;
|
|
1334
1436
|
await registrationRef.createAgentSession({
|
|
1335
1437
|
sessionName: member.sessionName,
|
|
1336
1438
|
role: member.role,
|
|
1337
|
-
|
|
1439
|
+
// Use the resolved team's UUID — not the user-supplied identifier
|
|
1440
|
+
// — so downstream agent-registration always sees the canonical id.
|
|
1441
|
+
teamId: team.id,
|
|
1338
1442
|
memberId: member.id,
|
|
1339
1443
|
});
|
|
1340
1444
|
return true;
|
|
@@ -2046,15 +2150,56 @@ export class CrewlyServer {
|
|
|
2046
2150
|
// and auditor sessions when auditor is disabled
|
|
2047
2151
|
const isAuditorEnabled = process.env[AUDITOR_CONSTANTS.ENV_VAR]?.toLowerCase() === 'true'
|
|
2048
2152
|
|| (process.env[AUDITOR_CONSTANTS.ENV_VAR] === undefined && AUDITOR_CONSTANTS.ENABLED_BY_DEFAULT);
|
|
2049
|
-
const
|
|
2153
|
+
const baselineSessions = state.sessions.filter((s) => {
|
|
2050
2154
|
if (s.role === ORCHESTRATOR_ROLE)
|
|
2051
2155
|
return false;
|
|
2052
2156
|
if (!isAuditorEnabled && s.name === AUDITOR_SCHEDULER_CONSTANTS.AUDITOR_SESSION_NAME)
|
|
2053
2157
|
return false;
|
|
2054
2158
|
return true;
|
|
2055
2159
|
});
|
|
2160
|
+
// 2026-05-17 — gate by task-pool work. Pre-fix the boot path
|
|
2161
|
+
// blindly resurrected every persisted session even when none had
|
|
2162
|
+
// pending work, defeating the wake-gate philosophy (PR #574/#585)
|
|
2163
|
+
// and bloating RAM until IdleDetection eventually drained them
|
|
2164
|
+
// back. Now: only restore a session if the pool has at least one
|
|
2165
|
+
// non-terminal WorkItem with `target === sessionName`. Idle
|
|
2166
|
+
// agents stay dead until orc dispatches new work, at which point
|
|
2167
|
+
// the dispatcher / wake path raises them on demand.
|
|
2168
|
+
//
|
|
2169
|
+
// Safety valve: if the pool lookup throws (e.g. SQLite not yet
|
|
2170
|
+
// open during early boot), preserve the legacy behaviour rather
|
|
2171
|
+
// than block all restores — better to over-restore than to
|
|
2172
|
+
// silently strand work.
|
|
2173
|
+
let agentSessions = baselineSessions;
|
|
2174
|
+
try {
|
|
2175
|
+
const pool = TaskPoolService.getInstance();
|
|
2176
|
+
const allItems = await pool.getAllItems();
|
|
2177
|
+
const targetedSessions = new Set();
|
|
2178
|
+
for (const wi of allItems) {
|
|
2179
|
+
if (wi.status === 'done' || wi.status === 'cancelled')
|
|
2180
|
+
continue;
|
|
2181
|
+
const t = wi.target;
|
|
2182
|
+
if (typeof t === 'string' && t.length > 0)
|
|
2183
|
+
targetedSessions.add(t);
|
|
2184
|
+
}
|
|
2185
|
+
const filtered = baselineSessions.filter((s) => targetedSessions.has(s.name));
|
|
2186
|
+
const skipped = baselineSessions
|
|
2187
|
+
.filter((s) => !targetedSessions.has(s.name))
|
|
2188
|
+
.map((s) => s.name);
|
|
2189
|
+
if (skipped.length > 0) {
|
|
2190
|
+
this.logger.info('Skipping auto-restore for sessions with no pending WorkItem (idle agents stay dead until dispatched work arrives)', {
|
|
2191
|
+
skippedCount: skipped.length,
|
|
2192
|
+
skipped: skipped.slice(0, 20),
|
|
2193
|
+
truncated: skipped.length > 20,
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
agentSessions = filtered;
|
|
2197
|
+
}
|
|
2198
|
+
catch (poolErr) {
|
|
2199
|
+
this.logger.warn('Auto-restore could not query task pool; falling back to restoring every persisted session', { error: poolErr instanceof Error ? poolErr.message : String(poolErr) });
|
|
2200
|
+
}
|
|
2056
2201
|
if (agentSessions.length === 0) {
|
|
2057
|
-
this.logger.
|
|
2202
|
+
this.logger.info('No persisted agent sessions to restore (all idle, no pending WorkItems)');
|
|
2058
2203
|
return;
|
|
2059
2204
|
}
|
|
2060
2205
|
this.logger.info('Auto-restoring agent sessions from persisted state', {
|
|
@@ -2480,14 +2625,13 @@ export class CrewlyServer {
|
|
|
2480
2625
|
if (req.sourceConversationItemId.startsWith('slack-')) {
|
|
2481
2626
|
try {
|
|
2482
2627
|
const { ThreadStatusQueueService } = await import('./services/messaging/thread-status-queue.service.js');
|
|
2628
|
+
const { extractSlackChannelId, extractSlackThreadTs } = await import('./services/v3/request-sla.subscriber.js');
|
|
2483
2629
|
const tsq = ThreadStatusQueueService.getInstance();
|
|
2484
|
-
//
|
|
2485
|
-
//
|
|
2486
|
-
|
|
2487
|
-
const
|
|
2488
|
-
if (
|
|
2489
|
-
const channelId = match[1];
|
|
2490
|
-
const threadTs = `${match[2]}.${match[3]}`;
|
|
2630
|
+
// Use the canonical parser (handles both `slack-{ch}-{ts}` and
|
|
2631
|
+
// the thread-reply `slack-{ch}-{root}-msg-{msgTs}` shapes).
|
|
2632
|
+
const channelId = extractSlackChannelId(req.sourceConversationItemId);
|
|
2633
|
+
const threadTs = extractSlackThreadTs(req.sourceConversationItemId);
|
|
2634
|
+
if (channelId && threadTs) {
|
|
2491
2635
|
const threadKey = `${channelId}:${threadTs}`;
|
|
2492
2636
|
// Create entry if not tracked, then mark terminal
|
|
2493
2637
|
if (!tsq.get(threadKey)) {
|
|
@@ -2684,6 +2828,11 @@ export class CrewlyServer {
|
|
|
2684
2828
|
this.autoLearningSubscriber.stop();
|
|
2685
2829
|
this.autoLearningSubscriber = null;
|
|
2686
2830
|
}
|
|
2831
|
+
// DF-1 #438: same shutdown window as auto-learning above.
|
|
2832
|
+
if (this.milestoneNotificationSubscriber) {
|
|
2833
|
+
this.milestoneNotificationSubscriber.stop();
|
|
2834
|
+
this.milestoneNotificationSubscriber = null;
|
|
2835
|
+
}
|
|
2687
2836
|
// INBOUND-1: stop the SLA subscriber and unset the module-level
|
|
2688
2837
|
// references so a follow-up start() doesn't see stale singletons.
|
|
2689
2838
|
if (this.requestSlaSubscriber) {
|