crewly 1.20.248 → 1.20.250

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.
Files changed (80) hide show
  1. package/config/skills/agent/core/list-channels/SKILL.md +61 -0
  2. package/config/skills/agent/core/list-channels/execute.sh +36 -0
  3. package/config/skills/agent/core/list-channels/execute.test.sh +17 -0
  4. package/config/skills/agent/core/reply-channel/SKILL.md +10 -0
  5. package/config/skills/agent/core/reply-channel/execute.sh +23 -1
  6. package/config/skills/agent/core/reply-channel/execute.test.sh +25 -0
  7. package/dist/backend/backend/src/constants.d.ts +25 -0
  8. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  9. package/dist/backend/backend/src/constants.js +25 -0
  10. package/dist/backend/backend/src/constants.js.map +1 -1
  11. package/dist/backend/backend/src/controllers/channels/channels.routes.d.ts +27 -0
  12. package/dist/backend/backend/src/controllers/channels/channels.routes.d.ts.map +1 -0
  13. package/dist/backend/backend/src/controllers/channels/channels.routes.js +99 -0
  14. package/dist/backend/backend/src/controllers/channels/channels.routes.js.map +1 -0
  15. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  16. package/dist/backend/backend/src/routes/api.routes.js +18 -0
  17. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  18. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  19. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +1 -0
  20. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  21. package/dist/backend/backend/src/services/channels/crewly-channel.service.d.ts +247 -0
  22. package/dist/backend/backend/src/services/channels/crewly-channel.service.d.ts.map +1 -0
  23. package/dist/backend/backend/src/services/channels/crewly-channel.service.js +631 -0
  24. package/dist/backend/backend/src/services/channels/crewly-channel.service.js.map +1 -0
  25. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +26 -0
  26. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
  27. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +40 -2
  28. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  29. package/dist/backend/backend/src/services/slack/slack-channel-members.d.ts +65 -0
  30. package/dist/backend/backend/src/services/slack/slack-channel-members.d.ts.map +1 -1
  31. package/dist/backend/backend/src/services/slack/slack-channel-members.js +74 -0
  32. package/dist/backend/backend/src/services/slack/slack-channel-members.js.map +1 -1
  33. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
  35. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  36. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +157 -1
  37. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  38. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +452 -12
  39. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  40. package/dist/backend/backend/src/services/slack/slack.service.d.ts +10 -0
  41. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  42. package/dist/backend/backend/src/services/slack/slack.service.js +15 -0
  43. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  44. package/dist/backend/backend/src/types/crewly-channel.types.d.ts +77 -0
  45. package/dist/backend/backend/src/types/crewly-channel.types.d.ts.map +1 -0
  46. package/dist/backend/backend/src/types/crewly-channel.types.js +35 -0
  47. package/dist/backend/backend/src/types/crewly-channel.types.js.map +1 -0
  48. package/dist/backend/backend/src/types/slack.types.d.ts +14 -0
  49. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  50. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  51. package/dist/backend/build-info.json +2 -2
  52. package/dist/cli/backend/src/constants.d.ts +25 -0
  53. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  54. package/dist/cli/backend/src/constants.js +25 -0
  55. package/dist/cli/backend/src/constants.js.map +1 -1
  56. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  57. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +1 -0
  58. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  59. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts +26 -0
  60. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
  61. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +40 -2
  62. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  63. package/dist/cli/backend/src/services/slack/slack-channel-members.d.ts +92 -0
  64. package/dist/cli/backend/src/services/slack/slack-channel-members.d.ts.map +1 -0
  65. package/dist/cli/backend/src/services/slack/slack-channel-members.js +128 -0
  66. package/dist/cli/backend/src/services/slack/slack-channel-members.js.map +1 -0
  67. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +157 -1
  68. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  69. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +452 -12
  70. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  71. package/dist/cli/backend/src/services/slack/slack.service.d.ts +10 -0
  72. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
  73. package/dist/cli/backend/src/services/slack/slack.service.js +15 -0
  74. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
  75. package/dist/cli/backend/src/types/slack.types.d.ts +14 -0
  76. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  77. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  78. package/frontend/dist/assets/{index-8f4d482e.js → index-2db17f1e.js} +291 -291
  79. package/frontend/dist/index.html +1 -1
  80. package/package.json +1 -1
@@ -0,0 +1,631 @@
1
+ /**
2
+ * Crewly Channel Service
3
+ *
4
+ * A Crewly channel is a named room whose members are agents from any team —
5
+ * the Slack channel concept, next to teams. Every channel is a chat-v2 huddle
6
+ * (so routing, threads and replies are the huddle's), and its id is the
7
+ * huddle id. When Slack is connected the channel is one Slack channel:
8
+ *
9
+ * Crewly → Slack: creating a channel creates the Slack channel and invites
10
+ * the owner and each member's bot; adding/removing a member invites/removes
11
+ * its bot; renaming renames the Slack channel (Slack's normalised name is
12
+ * what Crewly shows); archiving archives it (or, for a channel found in
13
+ * Slack, takes the bots out).
14
+ * Slack → Crewly: a Slack channel agent bots were invited to (an ad-hoc room
15
+ * of the team-channel service) shows up as a channel automatically; its
16
+ * name and members follow Slack on the periodic/lazy refresh.
17
+ *
18
+ * The Slack side lives in {@link SlackTeamChannelService} (ad-hoc rooms);
19
+ * this service owns the registry (`~/.crewly/crewly-channels.json`) and the
20
+ * owner-facing operations. Without Slack, channels are Crewly-only huddles.
21
+ *
22
+ * @module services/channels/crewly-channel.service
23
+ */
24
+ import * as path from 'path';
25
+ import { promises as fs } from 'fs';
26
+ import { CREWLY_CHANNEL_CONSTANTS } from '../../constants.js';
27
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
28
+ import { atomicWriteJson, safeReadJson } from '../../utils/file-io.utils.js';
29
+ import { LoggerService } from '../core/logger.service.js';
30
+ import { OWNER_EVIDENCE_METADATA } from '../../constants.js';
31
+ import { isAdhocMapping, slackChannelNameFor, teamChannelMembers, } from '../slack/slack-team-channel.service.js';
32
+ import { isCrewlyChannelRecord, } from '../../types/crewly-channel.types.js';
33
+ /** Error with an HTTP status for the REST layer. */
34
+ export class CrewlyChannelError extends Error {
35
+ httpStatus;
36
+ code;
37
+ constructor(message, httpStatus, code) {
38
+ super(message);
39
+ this.httpStatus = httpStatus;
40
+ this.code = code;
41
+ this.name = 'CrewlyChannelError';
42
+ }
43
+ }
44
+ /** Placeholder rosters bridges put in a huddle that has no real member yet. */
45
+ const PLACEHOLDER_MEMBER = /^(team|channel):/;
46
+ const SYSTEM_PRINCIPAL = { userId: 'system', source: 'oss' };
47
+ /**
48
+ * Owner-facing Crewly channels: list, create, rename, members, archive.
49
+ */
50
+ export class CrewlyChannelService {
51
+ deps;
52
+ storePath;
53
+ logger;
54
+ store = null;
55
+ loading = null;
56
+ lastSlackRefresh = 0;
57
+ refreshing = null;
58
+ syncTimer = null;
59
+ /** Agent-to-agent hand-offs per channel since the owner last spoke there. */
60
+ agentChain = new Map();
61
+ onChatMessage = (dto) => {
62
+ void this.handleChatMessage(dto).catch((err) => {
63
+ this.logger.warn('Channel hand-off failed (non-fatal)', { error: err instanceof Error ? err.message : String(err) });
64
+ });
65
+ };
66
+ constructor(deps) {
67
+ this.deps = deps;
68
+ this.storePath = deps.storePath ?? path.join(getCrewlyHomePath(), CREWLY_CHANNEL_CONSTANTS.STORE_FILENAME);
69
+ this.logger = LoggerService.getInstance().createComponentLogger('CrewlyChannels');
70
+ }
71
+ /**
72
+ * Load the registry and open Crewly channels to the owner in chat-v2
73
+ * (they are created under the `'system'` owner). Idempotent.
74
+ */
75
+ async start() {
76
+ await this.load();
77
+ this.deps.chat.setSharedChannelResolver((id) => this.isChannel(id));
78
+ this.deps.chat.on?.('chat_message', this.onChatMessage);
79
+ if (!this.syncTimer) {
80
+ // Links channels made while Slack was off once it is on, and picks up
81
+ // Slack-side renames and members, without waiting for someone to look.
82
+ this.syncTimer = setInterval(() => void this.refreshFromSlack(), CREWLY_CHANNEL_CONSTANTS.SLACK_SYNC_INTERVAL_MS);
83
+ this.syncTimer.unref?.();
84
+ }
85
+ }
86
+ /** Undo {@link start}. */
87
+ stop() {
88
+ this.deps.chat.off?.('chat_message', this.onChatMessage);
89
+ if (this.syncTimer)
90
+ clearInterval(this.syncTimer);
91
+ this.syncTimer = null;
92
+ }
93
+ /**
94
+ * Link every channel the owner made in Crewly while Slack was off: create
95
+ * its Slack channel (owner and member bots invited) and keep the huddle,
96
+ * so the id and history stay. Channels found in Slack always have a link.
97
+ *
98
+ * @returns Ids of the channels linked
99
+ */
100
+ async linkUnlinked() {
101
+ const rooms = this.deps.getRooms();
102
+ if (!rooms?.isConnected())
103
+ return [];
104
+ const store = await this.load();
105
+ const linked = [];
106
+ for (const rec of store.channels) {
107
+ if (rec.archivedAt || rec.slackChannelId || rec.origin !== 'crewly')
108
+ continue;
109
+ const members = this.memberSessions(rec.id);
110
+ try {
111
+ const mapping = await rooms.ensureAgentChannel({
112
+ name: rec.name,
113
+ purpose: rec.purpose ?? CREWLY_CHANNEL_CONSTANTS.DEFAULT_PURPOSE,
114
+ memberSessions: members,
115
+ applyPrefix: false,
116
+ chatChannelId: rec.id,
117
+ });
118
+ rec.slackChannelId = mapping.slackChannelId;
119
+ rec.name = mapping.slackChannelName;
120
+ linked.push(rec.id);
121
+ }
122
+ catch (err) {
123
+ this.logger.warn('Could not link a channel to Slack yet', { name: rec.name, error: err instanceof Error ? err.message : String(err) });
124
+ }
125
+ }
126
+ if (linked.length > 0) {
127
+ await this.save();
128
+ this.logger.info('Channels linked to Slack', { count: linked.length });
129
+ }
130
+ return linked;
131
+ }
132
+ /**
133
+ * Wake the members an agent @'d in a channel without Slack, the way an
134
+ * agent's @ wakes a colleague in a Slack room. Only @'d members hear it
135
+ * (never the whole room, never the author), and at most
136
+ * AGENT_CHAIN_MAX hand-offs happen in a row before the owner speaks again.
137
+ * Channels linked to Slack are left to the Slack path.
138
+ *
139
+ * @param dto - A chat-v2 message
140
+ * @returns Who was woken (empty when nothing was dispatched)
141
+ */
142
+ async handleChatMessage(dto) {
143
+ const rec = this.store?.channels.find((c) => c.id === dto.channelId && !c.archivedAt);
144
+ if (!rec)
145
+ return [];
146
+ if (dto.senderType === 'user') {
147
+ if (!dto.metadata?.[OWNER_EVIDENCE_METADATA.AUTHOR_AGENT_SESSION])
148
+ this.agentChain.delete(rec.id);
149
+ return [];
150
+ }
151
+ if (dto.senderType !== 'agent' || rec.slackChannelId)
152
+ return [];
153
+ const dispatcher = this.deps.getDispatcher?.();
154
+ if (!dispatcher)
155
+ return [];
156
+ const members = this.memberSessions(rec.id);
157
+ const author = dto.senderId;
158
+ const agents = await this.agentIndex();
159
+ const addressed = new Set((dto.mentions ?? []).filter((m) => members.includes(m)));
160
+ for (const session of members) {
161
+ const name = agents.get(session)?.name;
162
+ if (name && mentionsName(dto.content, name))
163
+ addressed.add(session);
164
+ }
165
+ addressed.delete(author);
166
+ if (addressed.size === 0)
167
+ return [];
168
+ const chain = (this.agentChain.get(rec.id) ?? 0) + 1;
169
+ if (chain > CREWLY_CHANNEL_CONSTANTS.AGENT_CHAIN_MAX) {
170
+ this.logger.info('Agent hand-off cap reached in a channel — not waking anyone until the owner speaks', { channel: rec.name, author });
171
+ return [];
172
+ }
173
+ this.agentChain.set(rec.id, chain);
174
+ const channel = this.deps.chat.getChannelForBridge(rec.id);
175
+ if (!channel)
176
+ return [];
177
+ const targets = [...addressed];
178
+ // Delivered as a user turn written by the agent (never passes as the owner).
179
+ const turn = {
180
+ ...dto,
181
+ senderType: 'user',
182
+ mentions: targets,
183
+ metadata: { ...(dto.metadata ?? {}), [OWNER_EVIDENCE_METADATA.AUTHOR_AGENT_SESSION]: author },
184
+ };
185
+ await dispatcher.dispatchMessage(channel, turn, {
186
+ excludeSessions: members.filter((m) => !addressed.has(m)),
187
+ threadId: dto.threadId ?? dto.id,
188
+ });
189
+ return targets;
190
+ }
191
+ /**
192
+ * Whether a chat-v2 channel id is a live Crewly channel (sync — the chat
193
+ * read path asks on every request).
194
+ *
195
+ * @param chatChannelId - chat-v2 channel id
196
+ * @returns True for a registered, non-archived channel or a Slack room
197
+ */
198
+ isChannel(chatChannelId) {
199
+ const rec = this.store?.channels.find((c) => c.id === chatChannelId);
200
+ if (rec)
201
+ return !rec.archivedAt;
202
+ const mapping = this.deps.getRooms()?.findByChatChannelId(chatChannelId);
203
+ return !!mapping && isAdhocMapping(mapping);
204
+ }
205
+ // -------------------------------------------------------------------------
206
+ // Queries
207
+ // -------------------------------------------------------------------------
208
+ /**
209
+ * Every channel, with members and Slack link. Picks up Slack rooms found
210
+ * since the last call; at most once a minute it also asks Slack for
211
+ * renames and new members (in the background — this call does not wait).
212
+ *
213
+ * @param options - `member` (session) to list only that agent's channels; `includeArchived`
214
+ * @returns Channels, newest first
215
+ */
216
+ async list(options = {}) {
217
+ await this.reconcile();
218
+ this.refreshInBackground();
219
+ const agents = await this.agentIndex();
220
+ const out = (this.store?.channels ?? [])
221
+ .filter((c) => options.includeArchived || !c.archivedAt)
222
+ .map((c) => this.toDTO(c, agents))
223
+ .filter((c) => !options.member || c.members.some((m) => m.sessionName === options.member));
224
+ return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
225
+ }
226
+ /**
227
+ * One channel by id, `#name`, name or Slack channel id.
228
+ *
229
+ * @param ref - What to look for
230
+ * @returns The channel
231
+ * @throws CrewlyChannelError 404 when no live channel matches
232
+ */
233
+ async get(ref) {
234
+ await this.reconcile();
235
+ return this.toDTO(this.requireRecord(ref), await this.agentIndex());
236
+ }
237
+ /**
238
+ * Ask Slack now for renames and new members, then return the list.
239
+ *
240
+ * @returns Channels after the refresh
241
+ */
242
+ async refresh() {
243
+ await this.refreshFromSlack();
244
+ return this.list();
245
+ }
246
+ // -------------------------------------------------------------------------
247
+ // Mutations (owner only — enforced by the routes)
248
+ // -------------------------------------------------------------------------
249
+ /**
250
+ * Create a channel. With Slack connected the Slack channel is created (or
251
+ * an existing one of that name reused), the owner and the members' bots
252
+ * are invited; without Slack it is a Crewly-only channel.
253
+ *
254
+ * @param input - Name (normalised the Slack way), optional purpose, agent sessions from any team
255
+ * @returns The channel
256
+ * @throws CrewlyChannelError 400 on a bad name/roster, 409 on a name in use, 502 when Slack refuses
257
+ */
258
+ async create(input) {
259
+ const name = this.normaliseName(input.name);
260
+ const purpose = this.validatePurpose(input.purpose);
261
+ const members = await this.validateMembers(input.memberSessions, { min: 1 });
262
+ await this.reconcile();
263
+ this.assertNameFree(name);
264
+ const store = await this.load();
265
+ const rooms = this.deps.getRooms();
266
+ let record;
267
+ if (rooms?.isConnected()) {
268
+ let mapping;
269
+ try {
270
+ mapping = await rooms.ensureAgentChannel({
271
+ name,
272
+ purpose: purpose ?? CREWLY_CHANNEL_CONSTANTS.DEFAULT_PURPOSE,
273
+ memberSessions: members,
274
+ applyPrefix: false,
275
+ });
276
+ }
277
+ catch (err) {
278
+ throw new CrewlyChannelError(`Slack could not create #${name}: ${err instanceof Error ? err.message : String(err)}`, 502, 'slack_error');
279
+ }
280
+ record = {
281
+ id: mapping.chatChannelId,
282
+ name: mapping.slackChannelName,
283
+ ...(purpose ? { purpose } : {}),
284
+ slackChannelId: mapping.slackChannelId,
285
+ origin: 'crewly',
286
+ createdAt: this.nowIso(),
287
+ };
288
+ }
289
+ else {
290
+ const huddle = this.deps.chat.createHuddle({
291
+ name: `#${name}`,
292
+ purpose: purpose ?? CREWLY_CHANNEL_CONSTANTS.DEFAULT_PURPOSE,
293
+ memberSessions: members,
294
+ principal: SYSTEM_PRINCIPAL,
295
+ });
296
+ record = { id: huddle.id, name, ...(purpose ? { purpose } : {}), origin: 'crewly', createdAt: this.nowIso() };
297
+ }
298
+ store.channels = store.channels.filter((c) => c.id !== record.id);
299
+ store.channels.push(record);
300
+ await this.save();
301
+ this.logger.info('Channel created', { id: record.id, name: record.name, slack: record.slackChannelId ?? null, members });
302
+ return this.toDTO(record, await this.agentIndex());
303
+ }
304
+ /**
305
+ * Rename a channel. A linked Slack channel is renamed first; Crewly then
306
+ * shows the name Slack applied.
307
+ *
308
+ * @param ref - Channel id / name
309
+ * @param rawName - The new name
310
+ * @returns The channel
311
+ * @throws CrewlyChannelError 400/404/409, 502 when Slack refuses
312
+ */
313
+ async rename(ref, rawName) {
314
+ await this.reconcile();
315
+ const record = this.requireRecord(ref);
316
+ const name = this.normaliseName(rawName);
317
+ if (name !== record.name)
318
+ this.assertNameFree(name, record.id);
319
+ let applied = name;
320
+ const rooms = this.deps.getRooms();
321
+ if (record.slackChannelId && rooms) {
322
+ try {
323
+ applied = await rooms.renameRoom(record.slackChannelId, name);
324
+ }
325
+ catch (err) {
326
+ throw new CrewlyChannelError(err instanceof Error ? err.message : String(err), 502, 'slack_error');
327
+ }
328
+ }
329
+ else {
330
+ this.deps.chat.renameChannelForBridge(record.id, `#${applied}`);
331
+ }
332
+ record.name = applied;
333
+ await this.save();
334
+ return this.toDTO(record, await this.agentIndex());
335
+ }
336
+ /**
337
+ * Add one agent (any team).
338
+ *
339
+ * @param ref - Channel id / name
340
+ * @param sessionName - The agent's session
341
+ * @returns The channel and what Slack did
342
+ */
343
+ async addMember(ref, sessionName) {
344
+ await this.reconcile();
345
+ const record = this.requireRecord(ref);
346
+ const [session] = await this.validateMembers([sessionName], { min: 1 });
347
+ const current = this.memberSessions(record.id);
348
+ if (current.includes(session)) {
349
+ return { channel: this.toDTO(record, await this.agentIndex()), change: emptyChange() };
350
+ }
351
+ if (current.length >= CREWLY_CHANNEL_CONSTANTS.MAX_MEMBERS) {
352
+ throw new CrewlyChannelError(`A channel holds at most ${CREWLY_CHANNEL_CONSTANTS.MAX_MEMBERS} agents`, 400, 'validation_error');
353
+ }
354
+ return this.setMembers(record, [...current, session]);
355
+ }
356
+ /**
357
+ * Remove one agent.
358
+ *
359
+ * @param ref - Channel id / name
360
+ * @param sessionName - The agent's session
361
+ * @returns The channel and what Slack did
362
+ */
363
+ async removeMember(ref, sessionName) {
364
+ await this.reconcile();
365
+ const record = this.requireRecord(ref);
366
+ const current = this.memberSessions(record.id);
367
+ if (!current.includes(sessionName)) {
368
+ throw new CrewlyChannelError(`${sessionName} is not in #${record.name}`, 404, 'not_found');
369
+ }
370
+ return this.setMembers(record, current.filter((s) => s !== sessionName));
371
+ }
372
+ /**
373
+ * Archive a channel. A Slack channel Crewly created is archived too; one
374
+ * found in Slack is left to its people (the agents' bots leave it).
375
+ *
376
+ * @param ref - Channel id / name
377
+ * @returns The archived channel
378
+ */
379
+ async archive(ref) {
380
+ await this.reconcile();
381
+ const record = this.requireRecord(ref);
382
+ const rooms = this.deps.getRooms();
383
+ if (record.slackChannelId && rooms) {
384
+ await rooms.archiveRoom(record.slackChannelId, { archiveSlackChannel: record.origin === 'crewly' });
385
+ }
386
+ this.deps.chat.archiveChannelForBridge(record.id);
387
+ record.archivedAt = this.nowIso();
388
+ await this.save();
389
+ this.logger.info('Channel archived', { id: record.id, name: record.name });
390
+ return this.toDTO(record, await this.agentIndex());
391
+ }
392
+ // -------------------------------------------------------------------------
393
+ // Internals
394
+ // -------------------------------------------------------------------------
395
+ async setMembers(record, sessions) {
396
+ const rooms = this.deps.getRooms();
397
+ let change;
398
+ if (record.slackChannelId && rooms) {
399
+ change = await rooms.setRoomMembers(record.slackChannelId, sessions);
400
+ }
401
+ else {
402
+ const diff = this.deps.chat.setHuddleMembers(record.id, sessions);
403
+ change = { ...emptyChange(), added: diff.added, removed: diff.removed };
404
+ }
405
+ return { channel: this.toDTO(record, await this.agentIndex()), change };
406
+ }
407
+ /**
408
+ * Bring the registry in step with the Slack rooms: a room not yet listed
409
+ * becomes a channel (origin `slack`); a listed one takes its current Slack
410
+ * name; a channel whose room is gone loses the link (or is archived when
411
+ * its huddle was archived).
412
+ */
413
+ async reconcile() {
414
+ const store = await this.load();
415
+ const rooms = this.deps.getRooms();
416
+ if (!rooms)
417
+ return;
418
+ const mappings = (await rooms.listMappings()).filter((m) => isAdhocMapping(m));
419
+ let changed = false;
420
+ for (const m of mappings) {
421
+ const rec = store.channels.find((c) => c.id === m.chatChannelId);
422
+ if (!rec) {
423
+ store.channels.push({
424
+ id: m.chatChannelId,
425
+ name: m.slackChannelName,
426
+ slackChannelId: m.slackChannelId,
427
+ origin: m.autoCreated ? 'crewly' : 'slack',
428
+ createdAt: m.createdAt,
429
+ });
430
+ changed = true;
431
+ this.logger.info('Slack channel found — listed as a Crewly channel', { name: m.slackChannelName, members: m.members ?? [] });
432
+ continue;
433
+ }
434
+ if (rec.name !== m.slackChannelName || rec.slackChannelId !== m.slackChannelId) {
435
+ rec.name = m.slackChannelName;
436
+ rec.slackChannelId = m.slackChannelId;
437
+ changed = true;
438
+ }
439
+ }
440
+ const linked = new Set(mappings.map((m) => m.chatChannelId));
441
+ for (const rec of store.channels) {
442
+ if (rec.archivedAt || !rec.slackChannelId || linked.has(rec.id))
443
+ continue;
444
+ const huddle = this.deps.chat.getChannelForBridge(rec.id);
445
+ if (!huddle || huddle.archivedAt)
446
+ rec.archivedAt = this.nowIso();
447
+ else
448
+ delete rec.slackChannelId;
449
+ changed = true;
450
+ }
451
+ if (changed)
452
+ await this.save();
453
+ }
454
+ /** Throttled background Slack refresh (names + members). */
455
+ refreshInBackground() {
456
+ const now = this.deps.now?.().getTime() ?? Date.now();
457
+ if (this.refreshing || now - this.lastSlackRefresh < CREWLY_CHANNEL_CONSTANTS.SLACK_REFRESH_MIN_INTERVAL_MS)
458
+ return;
459
+ this.lastSlackRefresh = now;
460
+ void this.refreshFromSlack();
461
+ }
462
+ refreshFromSlack() {
463
+ if (this.refreshing)
464
+ return this.refreshing;
465
+ const rooms = this.deps.getRooms();
466
+ if (!rooms)
467
+ return Promise.resolve();
468
+ this.refreshing = this.linkUnlinked()
469
+ .then(() => rooms.syncRoomsFromSlack())
470
+ .then(() => this.reconcile())
471
+ .catch((err) => {
472
+ this.logger.warn('Channel refresh from Slack failed (non-fatal)', { error: err instanceof Error ? err.message : String(err) });
473
+ })
474
+ .finally(() => {
475
+ this.refreshing = null;
476
+ });
477
+ return this.refreshing;
478
+ }
479
+ requireRecord(ref) {
480
+ const key = (ref ?? '').trim();
481
+ const name = key.replace(/^#/, '').toLowerCase();
482
+ const live = (this.store?.channels ?? []).filter((c) => !c.archivedAt);
483
+ const rec = live.find((c) => c.id === key) ??
484
+ live.find((c) => c.slackChannelId === key) ??
485
+ live.find((c) => c.name.toLowerCase() === name);
486
+ if (!rec)
487
+ throw new CrewlyChannelError(`No channel ${key}`, 404, 'not_found');
488
+ return rec;
489
+ }
490
+ memberSessions(chatChannelId) {
491
+ return this.deps.chat.queryHuddleMembersForDispatch(chatChannelId).filter((s) => !PLACEHOLDER_MEMBER.test(s));
492
+ }
493
+ normaliseName(raw) {
494
+ const trimmed = (raw ?? '').trim().replace(/^#/, '');
495
+ if (!trimmed || !/[\p{L}\p{N}]/u.test(trimmed)) {
496
+ throw new CrewlyChannelError('name is required', 400, 'validation_error');
497
+ }
498
+ return slackChannelNameFor(trimmed);
499
+ }
500
+ validatePurpose(raw) {
501
+ const purpose = (raw ?? '').trim();
502
+ if (purpose.length > CREWLY_CHANNEL_CONSTANTS.MAX_PURPOSE_LENGTH) {
503
+ throw new CrewlyChannelError(`purpose exceeds ${CREWLY_CHANNEL_CONSTANTS.MAX_PURPOSE_LENGTH} characters`, 400, 'validation_error');
504
+ }
505
+ return purpose || undefined;
506
+ }
507
+ async validateMembers(raw, opts) {
508
+ const sessions = [...new Set((Array.isArray(raw) ? raw : []).map((s) => (typeof s === 'string' ? s.trim() : '')).filter(Boolean))];
509
+ if (sessions.length < opts.min)
510
+ throw new CrewlyChannelError('pick at least one agent', 400, 'validation_error');
511
+ if (sessions.length > CREWLY_CHANNEL_CONSTANTS.MAX_MEMBERS) {
512
+ throw new CrewlyChannelError(`A channel holds at most ${CREWLY_CHANNEL_CONSTANTS.MAX_MEMBERS} agents`, 400, 'validation_error');
513
+ }
514
+ const known = new Set((await this.deps.listAgents()).map((a) => a.sessionName));
515
+ const unknown = sessions.filter((s) => !known.has(s));
516
+ if (unknown.length > 0)
517
+ throw new CrewlyChannelError(`Unknown agent: ${unknown.join(', ')}`, 400, 'validation_error');
518
+ return sessions;
519
+ }
520
+ assertNameFree(name, exceptId) {
521
+ const taken = (this.store?.channels ?? []).some((c) => !c.archivedAt && c.id !== exceptId && c.name === name);
522
+ if (taken)
523
+ throw new CrewlyChannelError(`#${name} already exists`, 409, 'conflict');
524
+ }
525
+ async agentIndex() {
526
+ const agents = await this.deps.listAgents().catch(() => []);
527
+ return new Map(agents.map((a) => [a.sessionName, a]));
528
+ }
529
+ toDTO(rec, agents) {
530
+ const members = this.memberSessions(rec.id).map((sessionName) => {
531
+ const a = agents.get(sessionName);
532
+ return a ? { sessionName, name: a.name, teamId: a.teamId, teamName: a.teamName } : { sessionName };
533
+ });
534
+ return {
535
+ id: rec.id,
536
+ name: rec.name,
537
+ ...(rec.purpose ? { purpose: rec.purpose } : {}),
538
+ origin: rec.origin,
539
+ createdAt: rec.createdAt,
540
+ ...(rec.archivedAt ? { archivedAt: rec.archivedAt } : {}),
541
+ slack: rec.slackChannelId ? { channelId: rec.slackChannelId, channelName: rec.name } : null,
542
+ members,
543
+ };
544
+ }
545
+ nowIso() {
546
+ return (this.deps.now?.() ?? new Date()).toISOString();
547
+ }
548
+ async load() {
549
+ if (this.store)
550
+ return this.store;
551
+ if (!this.loading) {
552
+ this.loading = safeReadJson(this.storePath, { version: 1, channels: [] })
553
+ .then((raw) => {
554
+ const store = {
555
+ version: 1,
556
+ channels: Array.isArray(raw?.channels) ? raw.channels.filter(isCrewlyChannelRecord) : [],
557
+ };
558
+ this.store = store;
559
+ return store;
560
+ })
561
+ .catch((err) => {
562
+ this.loading = null;
563
+ throw err;
564
+ });
565
+ }
566
+ return this.loading;
567
+ }
568
+ async save() {
569
+ const store = await this.load();
570
+ await fs.mkdir(path.dirname(this.storePath), { recursive: true });
571
+ await atomicWriteJson(this.storePath, store);
572
+ }
573
+ }
574
+ /**
575
+ * Every agent that can join a channel: the members of every live team, with
576
+ * their team (an agent on two teams is listed once, under its first team).
577
+ *
578
+ * @param teams - Teams from storage
579
+ * @returns Agents
580
+ */
581
+ export function agentsFromTeams(teams) {
582
+ const seen = new Set();
583
+ const out = [];
584
+ for (const team of teams) {
585
+ if (team.archived)
586
+ continue;
587
+ for (const m of teamChannelMembers(team)) {
588
+ if (seen.has(m.sessionName))
589
+ continue;
590
+ seen.add(m.sessionName);
591
+ out.push({ sessionName: m.sessionName, name: m.name, teamId: team.id, teamName: team.name });
592
+ }
593
+ }
594
+ return out;
595
+ }
596
+ /**
597
+ * Whether text @-mentions a name (`@Atlas`, case-insensitive, whole name).
598
+ *
599
+ * @param text - Message text
600
+ * @param name - Display name
601
+ * @returns True when mentioned
602
+ */
603
+ export function mentionsName(text, name) {
604
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
605
+ return new RegExp(`(?<![\\w@])@${escaped}(?![\\p{L}\\p{N}_])`, 'iu').test(text ?? '');
606
+ }
607
+ /** A membership change with nothing in it. */
608
+ function emptyChange() {
609
+ return { added: [], removed: [], invited: [], notInvited: [], removedFromSlack: [], stillInSlack: [] };
610
+ }
611
+ // ---------------------------------------------------------------------------
612
+ // Singleton
613
+ // ---------------------------------------------------------------------------
614
+ let instance = null;
615
+ /**
616
+ * Install the process-wide instance (composition root).
617
+ *
618
+ * @param service - The configured service, or null to clear
619
+ */
620
+ export function setCrewlyChannelService(service) {
621
+ instance = service;
622
+ }
623
+ /**
624
+ * The process-wide instance, or null before the composition root wires it.
625
+ *
626
+ * @returns The service or null
627
+ */
628
+ export function getCrewlyChannelService() {
629
+ return instance;
630
+ }
631
+ //# sourceMappingURL=crewly-channel.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crewly-channel.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/channels/crewly-channel.service.ts"],"names":[],"mappings":"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"}