crewly 1.20.210 → 1.20.212
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/orchestrator/prompt.md +1 -0
- package/config/skills/agent/core/app-data/SKILL.md +30 -1
- package/config/skills/agent/core/publish-app/SKILL.md +73 -6
- package/config/skills/agent/core/publish-app/execute.sh +125 -4
- package/config/skills/agent/core/publish-app/execute.test.sh +95 -4
- package/config/skills/agent/core/send-message/SKILL.md +9 -0
- package/config/skills/orchestrator/delegate-task/SKILL.md +9 -0
- package/config/skills/orchestrator/get-team-status/SKILL.md +9 -0
- package/config/skills/orchestrator/get-team-status/execute.sh +5 -1
- package/config/skills/orchestrator/send-message/SKILL.md +9 -0
- package/config/skills/orchestrator/start-agent/SKILL.md +9 -0
- package/config/skills/orchestrator/start-team/SKILL.md +9 -0
- package/config/skills/team-leader/assign-ticket/SKILL.md +9 -0
- package/config/skills/team-leader/delegate-task/SKILL.md +9 -0
- package/dist/backend/backend/src/constants.d.ts +78 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +78 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +17 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.js +45 -8
- package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +7 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.routes.js +15 -1
- package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts +12 -0
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +36 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/request-types.d.ts +10 -1
- package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +0 -36
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +41 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team-pause.controller.d.ts +59 -0
- package/dist/backend/backend/src/controllers/team/team-pause.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/team/team-pause.controller.js +161 -0
- package/dist/backend/backend/src/controllers/team/team-pause.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts +14 -0
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +78 -5
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js +7 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +18 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/models/Team.d.ts +5 -1
- package/dist/backend/backend/src/models/Team.d.ts.map +1 -1
- package/dist/backend/backend/src/models/Team.js +8 -0
- package/dist/backend/backend/src/models/Team.js.map +1 -1
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.d.ts +7 -2
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.js +9 -3
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +3 -2
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/apps/app-open-link.d.ts +61 -0
- package/dist/backend/backend/src/services/apps/app-open-link.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-open-link.js +112 -0
- package/dist/backend/backend/src/services/apps/app-open-link.js.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.d.ts +44 -3
- package/dist/backend/backend/src/services/apps/app-wake-message.d.ts.map +1 -1
- package/dist/backend/backend/src/services/apps/app-wake-message.js +99 -7
- package/dist/backend/backend/src/services/apps/app-wake-message.js.map +1 -1
- package/dist/backend/backend/src/services/apps/app-wake.service.d.ts +29 -2
- package/dist/backend/backend/src/services/apps/app-wake.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/apps/app-wake.service.js +151 -21
- package/dist/backend/backend/src/services/apps/app-wake.service.js.map +1 -1
- package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts +18 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/apps/apps-registry.service.js +14 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.js.map +1 -1
- package/dist/backend/backend/src/services/apps/apps.service.d.ts +261 -12
- package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/apps/apps.service.js +387 -30
- package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -1
- package/dist/backend/backend/src/services/apps/apps.wiring.d.ts +15 -1
- package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/apps/apps.wiring.js +27 -7
- package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -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 +17 -5
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.d.ts +5 -0
- package/dist/backend/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.js +8 -0
- package/dist/backend/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.js +6 -0
- package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.js +6 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +12 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js +59 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +12 -6
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +5 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.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 +4 -0
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +22 -0
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-channel-members.d.ts +27 -0
- package/dist/backend/backend/src/services/slack/slack-channel-members.d.ts.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-channel-members.js +54 -0
- package/dist/backend/backend/src/services/slack/slack-channel-members.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-directory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-directory.service.js +7 -2
- package/dist/backend/backend/src/services/slack/slack-directory.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +3 -0
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- 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 +19 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +48 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +155 -4
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +3 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +11 -0
- 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 +36 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/untargeted-router.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/untargeted-router.js +14 -6
- package/dist/backend/backend/src/services/task-pool/untargeted-router.js.map +1 -1
- package/dist/backend/backend/src/services/team/team-pause-command.d.ts +97 -0
- package/dist/backend/backend/src/services/team/team-pause-command.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause-command.js +177 -0
- package/dist/backend/backend/src/services/team/team-pause-command.js.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause-notice.d.ts +43 -0
- package/dist/backend/backend/src/services/team/team-pause-notice.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause-notice.js +61 -0
- package/dist/backend/backend/src/services/team/team-pause-notice.js.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause.registry.d.ts +167 -0
- package/dist/backend/backend/src/services/team/team-pause.registry.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause.registry.js +263 -0
- package/dist/backend/backend/src/services/team/team-pause.registry.js.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause.service.d.ts +172 -0
- package/dist/backend/backend/src/services/team/team-pause.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause.service.js +254 -0
- package/dist/backend/backend/src/services/team/team-pause.service.js.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause.wiring.d.ts +30 -0
- package/dist/backend/backend/src/services/team/team-pause.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team/team-pause.wiring.js +48 -0
- package/dist/backend/backend/src/services/team/team-pause.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js +11 -0
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +9 -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 +27 -2
- 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.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +7 -0
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.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 +14 -0
- package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.js +5 -0
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js +6 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +22 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +78 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +78 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/models/Team.d.ts +5 -1
- package/dist/cli/backend/src/models/Team.d.ts.map +1 -1
- package/dist/cli/backend/src/models/Team.js +8 -0
- package/dist/cli/backend/src/models/Team.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +3 -2
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/apps/app-open-link.d.ts +61 -0
- package/dist/cli/backend/src/services/apps/app-open-link.d.ts.map +1 -0
- package/dist/cli/backend/src/services/apps/app-open-link.js +112 -0
- package/dist/cli/backend/src/services/apps/app-open-link.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +17 -5
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.d.ts +5 -0
- package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.js +8 -0
- package/dist/cli/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.js +6 -0
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +22 -0
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-directory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-directory.service.js +7 -2
- package/dist/cli/backend/src/services/slack/slack-directory.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +19 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +48 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +155 -4
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +3 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +11 -0
- 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 +36 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/team/team-pause-notice.d.ts +43 -0
- package/dist/cli/backend/src/services/team/team-pause-notice.d.ts.map +1 -0
- package/dist/cli/backend/src/services/team/team-pause-notice.js +61 -0
- package/dist/cli/backend/src/services/team/team-pause-notice.js.map +1 -0
- package/dist/cli/backend/src/services/team/team-pause.registry.d.ts +167 -0
- package/dist/cli/backend/src/services/team/team-pause.registry.d.ts.map +1 -0
- package/dist/cli/backend/src/services/team/team-pause.registry.js +263 -0
- package/dist/cli/backend/src/services/team/team-pause.registry.js.map +1 -0
- package/dist/cli/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/workflow/cron-task.service.js +14 -0
- package/dist/cli/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +22 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/frontend/dist/assets/{index-f64b333a.js → index-917db1b8.js} +279 -279
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
*
|
|
25
25
|
* @module services/slack/slack-team-channel.service
|
|
26
26
|
*/
|
|
27
|
+
import { isSessionPaused, pausedTeamOfSession } from '../team/team-pause.registry.js';
|
|
28
|
+
import { pausedSlackNotice, pausedThreadNotices } from '../team/team-pause-notice.js';
|
|
27
29
|
import { notePerson } from '../people/people-directory.service.js';
|
|
28
30
|
import { dedicatedDecisionFor } from '../people/dedicated-agent.js';
|
|
29
31
|
import { getTicketIntakeService } from '../v3/ticket-intake.service.js';
|
|
@@ -88,6 +90,7 @@ export function slackChannelNameFor(teamName, prefix = '') {
|
|
|
88
90
|
* awake room member. Null when nobody is awake (Cloud's fallback decides).
|
|
89
91
|
*
|
|
90
92
|
* Cloud's delivery facts come first (specs/2026-10-04-room-delivery-audit.md):
|
|
93
|
+
* with `nobody-awake`, Cloud's fallback machine is the owner; otherwise
|
|
91
94
|
* the responder Cloud names (`delivery.owner`) is the owner — Cloud pushes it
|
|
92
95
|
* first and names another if it cannot be reached. Without one, the owner is
|
|
93
96
|
* computed among the machines Cloud delivered to (`delivery.targets`) only,
|
|
@@ -102,6 +105,11 @@ export function roomOwnerInstance(room) {
|
|
|
102
105
|
const delivery = room.delivery;
|
|
103
106
|
if (delivery?.owner)
|
|
104
107
|
return delivery.owner;
|
|
108
|
+
// Nobody awake anywhere: Cloud's one fallback machine wakes its lead and
|
|
109
|
+
// every other machine defers — never dispatching to agents that are awake
|
|
110
|
+
// only by its own count (review of crewly-services#34: two machines acted).
|
|
111
|
+
if (delivery?.rule === 'nobody-awake' && room.fallback?.instanceId)
|
|
112
|
+
return room.fallback.instanceId;
|
|
105
113
|
const targets = delivery && Array.isArray(delivery.targets) && delivery.targets.length > 0 ? delivery.targets : null;
|
|
106
114
|
const awakeMembers = room.members.filter((m) => m.awake && (!targets || targets.includes(m.instanceId)));
|
|
107
115
|
const awake = [...new Set(awakeMembers.map((m) => m.instanceId))].sort();
|
|
@@ -351,6 +359,8 @@ export class SlackTeamChannelService {
|
|
|
351
359
|
deps;
|
|
352
360
|
storePath;
|
|
353
361
|
store = null;
|
|
362
|
+
pruneTimer = null;
|
|
363
|
+
pruneInterval = null;
|
|
354
364
|
loading = null;
|
|
355
365
|
unsubscribeStorage = null;
|
|
356
366
|
unsubscribeIdentity = null;
|
|
@@ -423,6 +433,94 @@ export class SlackTeamChannelService {
|
|
|
423
433
|
this.logger.warn('Team channel reconcile failed (non-fatal)', { error: err instanceof Error ? err.message : String(err) });
|
|
424
434
|
});
|
|
425
435
|
void this.rejoinMappedChannels();
|
|
436
|
+
// Ad-hoc rosters only ever grew: an agent stayed a "member" of a room its
|
|
437
|
+
// bot had left (or was never in), and Cloud counted that machine as being
|
|
438
|
+
// in the room (2026-10-03 / 2026-10-04, #content-team). Check against
|
|
439
|
+
// Slack now and periodically.
|
|
440
|
+
if (this.deps.listChannelMembers) {
|
|
441
|
+
const run = () => void this.pruneAdhocMembers().catch((err) => this.logger.warn('Ad-hoc room prune failed (non-fatal)', { error: err instanceof Error ? err.message : String(err) }));
|
|
442
|
+
this.pruneTimer = setTimeout(run, SLACK_TEAM_CHANNEL_CONSTANTS.ADHOC_PRUNE_FIRST_DELAY_MS);
|
|
443
|
+
this.pruneInterval = setInterval(run, SLACK_TEAM_CHANNEL_CONSTANTS.ADHOC_PRUNE_INTERVAL_MS);
|
|
444
|
+
this.pruneTimer.unref?.();
|
|
445
|
+
this.pruneInterval.unref?.();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Drop ad-hoc room members whose bot is not in the Slack channel.
|
|
450
|
+
*
|
|
451
|
+
* Each room is read with its members' own bot tokens, one after another,
|
|
452
|
+
* until one can read it (`conversations.members`): members whose bot user
|
|
453
|
+
* is not in that list are dropped. A bot that gets `not_in_channel` /
|
|
454
|
+
* `channel_not_found` is itself not in the room and is dropped. A member
|
|
455
|
+
* with no bot of its own, or a read that fails otherwise (rate limit,
|
|
456
|
+
* network), is kept — nothing is dropped on a guess. A dropped agent comes
|
|
457
|
+
* back on its own the next time a copy arrives through its app.
|
|
458
|
+
*
|
|
459
|
+
* @returns Per room changed: the channel and the sessions dropped
|
|
460
|
+
*/
|
|
461
|
+
async pruneAdhocMembers() {
|
|
462
|
+
const list = this.deps.listChannelMembers;
|
|
463
|
+
const identities = this.deps.identities;
|
|
464
|
+
if (!list || !identities)
|
|
465
|
+
return [];
|
|
466
|
+
await this.load();
|
|
467
|
+
await identities.load();
|
|
468
|
+
const changed = [];
|
|
469
|
+
// Who of a room's members is not in the Slack channel, by the bot ids
|
|
470
|
+
// and tokens the identity store holds right now.
|
|
471
|
+
const absent = async (mapping) => {
|
|
472
|
+
const bots = (mapping.members ?? []).map((session) => {
|
|
473
|
+
const installed = identities.getInstalled(session);
|
|
474
|
+
return { session, token: installed?.botToken ?? null, botUserId: installed?.botUserId ?? identities.get(session)?.botUserId ?? null };
|
|
475
|
+
});
|
|
476
|
+
const notInChannel = new Set();
|
|
477
|
+
let inChannel = null;
|
|
478
|
+
for (const bot of bots) {
|
|
479
|
+
if (!bot.token)
|
|
480
|
+
continue;
|
|
481
|
+
const res = await list(mapping.slackChannelId, bot.token);
|
|
482
|
+
if (res.ok) {
|
|
483
|
+
inChannel = new Set(res.members);
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
if (res.error === 'not_in_channel' || res.error === 'channel_not_found')
|
|
487
|
+
notInChannel.add(bot.session);
|
|
488
|
+
}
|
|
489
|
+
const seen = inChannel;
|
|
490
|
+
return bots.filter((b) => notInChannel.has(b.session) || (seen !== null && !!b.botUserId && !seen.has(b.botUserId))).map((b) => b.session);
|
|
491
|
+
};
|
|
492
|
+
let refreshed = false;
|
|
493
|
+
for (const mapping of this.store?.mappings ?? []) {
|
|
494
|
+
if (!isAdhocMapping(mapping) || (mapping.members ?? []).length === 0)
|
|
495
|
+
continue;
|
|
496
|
+
let removed = await absent(mapping);
|
|
497
|
+
if (removed.length > 0 && this.deps.refreshIdentities) {
|
|
498
|
+
// A reinstalled app has a new bot user id and token: re-read them and
|
|
499
|
+
// check again before dropping anyone, so a reinstall does not flap
|
|
500
|
+
// the roster (review of crewly#1067).
|
|
501
|
+
if (!refreshed) {
|
|
502
|
+
refreshed = true;
|
|
503
|
+
await this.deps.refreshIdentities().catch((err) => this.logger.warn('Could not refresh agent identities before pruning', { error: err instanceof Error ? err.message : String(err) }));
|
|
504
|
+
}
|
|
505
|
+
const again = new Set(await absent(mapping));
|
|
506
|
+
removed = removed.filter((s) => again.has(s));
|
|
507
|
+
}
|
|
508
|
+
if (removed.length === 0)
|
|
509
|
+
continue;
|
|
510
|
+
mapping.members = (mapping.members ?? []).filter((m) => !removed.includes(m));
|
|
511
|
+
this.deps.chat.setHuddleMembers(mapping.chatChannelId, mapping.members);
|
|
512
|
+
changed.push({ slackChannelId: mapping.slackChannelId, removed });
|
|
513
|
+
this.logger.info('Ad-hoc room members dropped — their bots are not in the Slack channel', {
|
|
514
|
+
slackChannel: `#${mapping.slackChannelName}`,
|
|
515
|
+
removed,
|
|
516
|
+
remaining: mapping.members,
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
if (changed.length > 0) {
|
|
520
|
+
await this.save();
|
|
521
|
+
this.deps.onRoomsChanged?.();
|
|
522
|
+
}
|
|
523
|
+
return changed;
|
|
426
524
|
}
|
|
427
525
|
/**
|
|
428
526
|
* Make sure the master bot is still a member of every channel we map.
|
|
@@ -565,6 +663,12 @@ export class SlackTeamChannelService {
|
|
|
565
663
|
for (const pending of this.unanswered.values())
|
|
566
664
|
clearTimeout(pending.timer);
|
|
567
665
|
this.unanswered.clear();
|
|
666
|
+
if (this.pruneTimer)
|
|
667
|
+
clearTimeout(this.pruneTimer);
|
|
668
|
+
if (this.pruneInterval)
|
|
669
|
+
clearInterval(this.pruneInterval);
|
|
670
|
+
this.pruneTimer = null;
|
|
671
|
+
this.pruneInterval = null;
|
|
568
672
|
}
|
|
569
673
|
// -------------------------------------------------------------------------
|
|
570
674
|
// Store
|
|
@@ -1098,6 +1202,40 @@ export class SlackTeamChannelService {
|
|
|
1098
1202
|
}
|
|
1099
1203
|
return declined;
|
|
1100
1204
|
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Take every @'d agent of a paused team off the list
|
|
1207
|
+
* (specs/2026-10-04-team-pause.md): it is not woken; the thread gets one
|
|
1208
|
+
* short auto-reply from that agent's bot, at most once per thread.
|
|
1209
|
+
*
|
|
1210
|
+
* @param message - Inbound channel message
|
|
1211
|
+
* @param mentions - Sessions it addressed
|
|
1212
|
+
* @param nameOf - Display name of a session
|
|
1213
|
+
* @returns The sessions taken off
|
|
1214
|
+
*/
|
|
1215
|
+
async declinePausedMentions(message, mentions, nameOf) {
|
|
1216
|
+
const declined = [];
|
|
1217
|
+
for (const sessionName of mentions) {
|
|
1218
|
+
const paused = pausedTeamOfSession(sessionName);
|
|
1219
|
+
if (!paused)
|
|
1220
|
+
continue;
|
|
1221
|
+
declined.push(sessionName);
|
|
1222
|
+
const threadTs = message.threadTs || message.ts;
|
|
1223
|
+
if (!pausedThreadNotices.claim(message.channelId, threadTs, paused.teamId))
|
|
1224
|
+
continue;
|
|
1225
|
+
const botToken = this.deps.identities?.getInstalled(sessionName)?.botToken;
|
|
1226
|
+
await this.deps.slack
|
|
1227
|
+
.sendMessage({
|
|
1228
|
+
channelId: message.channelId,
|
|
1229
|
+
text: pausedSlackNotice(paused, nameOf(sessionName), { toAgent: !!message.authorAgentSession }),
|
|
1230
|
+
threadTs,
|
|
1231
|
+
...(botToken ? { botToken } : {}),
|
|
1232
|
+
skipChatV2Mirror: true,
|
|
1233
|
+
})
|
|
1234
|
+
.catch((err) => this.logger.warn('Could not post the paused-team notice', { sessionName, error: err instanceof Error ? err.message : String(err) }));
|
|
1235
|
+
this.logger.info('Paused agent @-mentioned in Slack — not woken, thread told', { sessionName, team: paused.teamName });
|
|
1236
|
+
}
|
|
1237
|
+
return declined;
|
|
1238
|
+
}
|
|
1101
1239
|
/**
|
|
1102
1240
|
* Route an inbound Slack message that arrived in a mapped channel.
|
|
1103
1241
|
*
|
|
@@ -1218,8 +1356,14 @@ export class SlackTeamChannelService {
|
|
|
1218
1356
|
// posts a polite decline from its own bot and is taken off the list —
|
|
1219
1357
|
// nothing is dispatched to it and it is not woken.
|
|
1220
1358
|
const declinedDedicated = !message.authorAgentSession && message.userId && resolved.mentions.length > 0 ? await this.declineDedicatedMentions(message, resolved.mentions) : [];
|
|
1221
|
-
|
|
1222
|
-
|
|
1359
|
+
// Agents of a paused team (specs/2026-10-04-team-pause.md) are taken off
|
|
1360
|
+
// too: not woken, and the thread is told once.
|
|
1361
|
+
const declinedPaused = resolved.mentions.length > 0
|
|
1362
|
+
? await this.declinePausedMentions(message, resolved.mentions.filter((sess) => !declinedDedicated.includes(sess)), (sess) => candidates.find((c) => c.sessionName === sess)?.name ?? sess)
|
|
1363
|
+
: [];
|
|
1364
|
+
const declinedAll = [...declinedDedicated, ...declinedPaused];
|
|
1365
|
+
const declinedOnly = declinedAll.length > 0 && resolved.mentions.every((sess) => declinedAll.includes(sess));
|
|
1366
|
+
for (const sess of declinedAll)
|
|
1223
1367
|
resolved.mentions.splice(resolved.mentions.indexOf(sess), 1);
|
|
1224
1368
|
const agentsMentionedViaCloud = [...new Set([...(message.mentionedAgentSessions ?? []), ...namedElsewhere])];
|
|
1225
1369
|
const mentionedElsewhere = agentsMentionedViaCloud.filter((sess) => !isLocal(sess));
|
|
@@ -2191,7 +2335,8 @@ export class SlackTeamChannelService {
|
|
|
2191
2335
|
const team = teams.find((t) => t.id === mapping.teamId) ?? null;
|
|
2192
2336
|
const isLocal = (s) => this.deps.isLocalAgent?.(s) ?? true;
|
|
2193
2337
|
const roster = team ? teamChannelMembers(team) : null;
|
|
2194
|
-
|
|
2338
|
+
// Never a paused team's agent (specs/2026-10-04-team-pause.md).
|
|
2339
|
+
const local = (roster ? roster.map((m) => m.sessionName) : (mapping.members ?? [])).filter((s) => isLocal(s) && !isSessionPaused(s));
|
|
2195
2340
|
if (local.length === 0)
|
|
2196
2341
|
return null;
|
|
2197
2342
|
const turns = this.deps.chat.queryRecentTurnsForDispatch?.(mapping.chatChannelId, undefined, SLACK_TEAM_CHANNEL_CONSTANTS.ROOM_LAST_SPEAKER_SCAN) ?? [];
|
|
@@ -2388,7 +2533,13 @@ export class SlackTeamChannelService {
|
|
|
2388
2533
|
const me = this.deps.resolveInstanceId ? await this.deps.resolveInstanceId().catch(() => null) : null;
|
|
2389
2534
|
const isHere = (m) => me ? m.instanceId === me : (this.deps.isLocalAgent?.(localAgentSession(m.agentSession)) ?? false);
|
|
2390
2535
|
const owner = me ? roomOwnerInstance(room) : null;
|
|
2391
|
-
|
|
2536
|
+
if (!owner || owner === me)
|
|
2537
|
+
return false;
|
|
2538
|
+
// Cloud named the machine (its responder, or its fallback when nobody is
|
|
2539
|
+
// awake): that machine has the message and acts; this one defers.
|
|
2540
|
+
if (room.delivery?.owner || room.delivery?.rule === 'nobody-awake')
|
|
2541
|
+
return true;
|
|
2542
|
+
return room.members.some((m) => !isHere(m) && m.awake);
|
|
2392
2543
|
}
|
|
2393
2544
|
/**
|
|
2394
2545
|
* Hand a room message to one agent, wherever it runs.
|