crewly 1.20.169 → 1.20.170
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/skills/agent/core/reply/SKILL.md +71 -0
- package/config/skills/agent/core/reply/execute.sh +81 -0
- package/config/skills/agent/core/reply/execute.test.sh +87 -0
- package/dist/backend/backend/src/constants.d.ts +62 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +68 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts +36 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +182 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts +30 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +171 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.routes.js +4 -0
- package/dist/backend/backend/src/controllers/chat/chat.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts +55 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +10 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +114 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.js +6 -0
- package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +18 -0
- 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 +48 -3
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts +271 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +605 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.d.ts +179 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.js +327 -0
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/orc/agent-reply-target.d.ts +95 -0
- package/dist/backend/backend/src/services/orc/agent-reply-target.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/agent-reply-target.js +85 -0
- package/dist/backend/backend/src/services/orc/agent-reply-target.js.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-reply-route.service.d.ts +20 -0
- package/dist/backend/backend/src/services/orc/orc-reply-route.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-reply-route.service.js +34 -1
- package/dist/backend/backend/src/services/orc/orc-reply-route.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 +5 -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 +13 -0
- 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 +40 -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.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +2 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +33 -0
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +68 -0
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts +16 -0
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +22 -5
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/types/slack.types.d.ts +6 -0
- package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/slack.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +62 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +68 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +18 -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 +48 -3
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts +271 -0
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +605 -0
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-reply-route.service.d.ts +20 -0
- package/dist/cli/backend/src/services/orc/orc-reply-route.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-reply-route.service.js +34 -1
- package/dist/cli/backend/src/services/orc/orc-reply-route.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +13 -0
- 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 +40 -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.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +2 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +33 -0
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +68 -0
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack.service.d.ts +16 -0
- package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack.service.js +22 -5
- package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/cli/backend/src/types/slack.types.d.ts +6 -0
- package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/slack.types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiring for the unanswered-owner-message watchdog: turns deliveries into
|
|
3
|
+
* tracked entries, turns what the owner can see into "answered", and
|
|
4
|
+
* implements the nudge and the note on top of the real transports.
|
|
5
|
+
*
|
|
6
|
+
* Kept apart from the service so the timeline logic stays transport-free and
|
|
7
|
+
* the transport glue stays small and testable with plain fakes.
|
|
8
|
+
*
|
|
9
|
+
* @module services/messaging/owner-message-watchdog.wiring
|
|
10
|
+
* @see specs/2026-09-30-owner-message-guarantee.md
|
|
11
|
+
*/
|
|
12
|
+
import type { ChatChannelDTO, ChatMessageDTO } from '../chat-v2/types.js';
|
|
13
|
+
import type { DispatchMessageResult } from '../chat-v2/chat-v2.dispatcher.service.js';
|
|
14
|
+
import { OwnerMessageWatchdogService, type LoginHint, type NudgeOutcome, type OwnerMessageEntry, type OwnerMessageTrackInput } from './owner-message-watchdog.service.js';
|
|
15
|
+
/**
|
|
16
|
+
* Whether a chat-v2 user turn was written by the owner: not by an agent (here
|
|
17
|
+
* or on another machine), and — for a Slack row, when the owner is known — by
|
|
18
|
+
* the owner's Slack user.
|
|
19
|
+
*
|
|
20
|
+
* @param message - The turn
|
|
21
|
+
* @param ownerSlackUserId - The workspace owner's Slack user id, when known
|
|
22
|
+
* @returns True for the owner's message
|
|
23
|
+
*/
|
|
24
|
+
export declare function isOwnerChatTurn(message: Pick<ChatMessageDTO, 'senderType' | 'metadata'>, ownerSlackUserId: string | null | undefined): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Build the entry for a chat-v2 dispatch that reached at least one agent.
|
|
27
|
+
*
|
|
28
|
+
* Responsible agent: the first recipient that had to answer; with nobody
|
|
29
|
+
* required (an un-addressed room message the awake agents were only told
|
|
30
|
+
* about), the room lead when it got the message, else the first non-
|
|
31
|
+
* orchestrator recipient. An orchestrator that was only woken to route a
|
|
32
|
+
* private room's message is never made responsible: its hand-off re-dispatches
|
|
33
|
+
* the message, and that dispatch is tracked under the same key.
|
|
34
|
+
*
|
|
35
|
+
* @param channel - Channel the message was recorded in
|
|
36
|
+
* @param message - The owner's turn
|
|
37
|
+
* @param result - Dispatch outcome
|
|
38
|
+
* @param ctx - Owner id and the room lead, when known
|
|
39
|
+
* @returns Track input, or null when nothing should be tracked
|
|
40
|
+
*/
|
|
41
|
+
export declare function trackInputFromDispatch(channel: Pick<ChatChannelDTO, 'id' | 'type' | 'agentSession'>, message: ChatMessageDTO, result: DispatchMessageResult, ctx?: {
|
|
42
|
+
ownerSlackUserId?: string | null;
|
|
43
|
+
leader?: string | null;
|
|
44
|
+
}): OwnerMessageTrackInput | null;
|
|
45
|
+
/**
|
|
46
|
+
* Login hint for a runtime waiting on a sign-in ("reply 重新登录 claude").
|
|
47
|
+
*
|
|
48
|
+
* @param runtimeType - The runtime type recorded with the login request, if any
|
|
49
|
+
* @returns The hint
|
|
50
|
+
*/
|
|
51
|
+
export declare function loginHintFor(runtimeType: string | null | undefined): LoginHint;
|
|
52
|
+
/**
|
|
53
|
+
* The reminder delivered to the responsible agent. Carries the same routing
|
|
54
|
+
* header a normal delivery does, so the agent's `reply` goes back to the
|
|
55
|
+
* owner's conversation (and thread).
|
|
56
|
+
*
|
|
57
|
+
* @param entry - The unanswered message
|
|
58
|
+
* @param waitedMinutes - How long it has waited
|
|
59
|
+
* @param opts - `withHeader: false` when the transport adds its own `[CHAT:…]` header (the orchestrator's queue)
|
|
60
|
+
* @returns The text to deliver
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildNudgeMessage(entry: OwnerMessageEntry, waitedMinutes: number, opts?: {
|
|
63
|
+
withHeader?: boolean;
|
|
64
|
+
}): string;
|
|
65
|
+
/** What the wiring needs from the rest of the backend. */
|
|
66
|
+
export interface OwnerWatchdogWiringDeps {
|
|
67
|
+
crewlyHome: string;
|
|
68
|
+
/** PTY / in-process delivery (sub-agents) */
|
|
69
|
+
sendToAgent: (session: string, text: string) => Promise<{
|
|
70
|
+
success: boolean;
|
|
71
|
+
error?: string;
|
|
72
|
+
}>;
|
|
73
|
+
/** Whether the agent's runtime session exists */
|
|
74
|
+
sessionExists: (session: string) => boolean;
|
|
75
|
+
/** User-initiated activation (same path as the dispatcher's activate-on-send) */
|
|
76
|
+
activate: (session: string) => Promise<{
|
|
77
|
+
success: boolean;
|
|
78
|
+
error?: string;
|
|
79
|
+
}>;
|
|
80
|
+
/** Orchestrator delivery (its message queue) */
|
|
81
|
+
enqueueForOrchestrator: (input: {
|
|
82
|
+
content: string;
|
|
83
|
+
conversationId: string;
|
|
84
|
+
source: string;
|
|
85
|
+
sourceMetadata?: Record<string, unknown>;
|
|
86
|
+
}) => void;
|
|
87
|
+
isBusy: (session: string) => boolean;
|
|
88
|
+
/** Pending sign-in record for the session, if any */
|
|
89
|
+
loginRequired: (session: string) => {
|
|
90
|
+
runtimeType?: string | null;
|
|
91
|
+
} | null | undefined;
|
|
92
|
+
displayNameOf?: (session: string) => string;
|
|
93
|
+
/** Slack posting (null while Slack is not wired) */
|
|
94
|
+
slack: () => {
|
|
95
|
+
isConnected(): boolean;
|
|
96
|
+
sendMessage(m: {
|
|
97
|
+
channelId: string;
|
|
98
|
+
text: string;
|
|
99
|
+
threadTs?: string;
|
|
100
|
+
botToken?: string;
|
|
101
|
+
notAnAnswer?: boolean;
|
|
102
|
+
skipChatV2Mirror?: boolean;
|
|
103
|
+
}): Promise<string>;
|
|
104
|
+
} | null;
|
|
105
|
+
/** Whether a placeholder shows in a Slack thread */
|
|
106
|
+
owesThread: (slackChannelId: string, threadTs: string) => boolean;
|
|
107
|
+
/** Bot token of the agent whose own app owns this Slack DM (the master bot cannot post there) */
|
|
108
|
+
agentDmBotToken: (slackChannelId: string) => string | undefined;
|
|
109
|
+
/** An agent's own bot token, when installed */
|
|
110
|
+
botTokenOf: (session: string) => string | undefined;
|
|
111
|
+
/** Record a system note in a chat-v2 channel; false when it could not be recorded */
|
|
112
|
+
recordChatNote: (chatChannelId: string, threadId: string | undefined, text: string) => boolean;
|
|
113
|
+
/** Tell the reply router which chat thread a nudge is about */
|
|
114
|
+
noteOriginThread?: (session: string, chatChannelId: string, threadId: string | undefined) => void;
|
|
115
|
+
}
|
|
116
|
+
/** chat-v2 metadata flag on the watchdog's own chat notes (never taken as an answer). */
|
|
117
|
+
export declare const OWNER_WATCHDOG_NOTE_METADATA_KEY = "ownerWatchdogNote";
|
|
118
|
+
/**
|
|
119
|
+
* Re-deliver an unanswered message to its responsible agent.
|
|
120
|
+
*
|
|
121
|
+
* @param deps - Wiring deps
|
|
122
|
+
* @param entry - The message
|
|
123
|
+
* @param waited - Minutes waited
|
|
124
|
+
* @returns Sent, or blocked with the reason
|
|
125
|
+
*/
|
|
126
|
+
export declare function nudgeAgent(deps: OwnerWatchdogWiringDeps, entry: OwnerMessageEntry, waited: number): Promise<NudgeOutcome>;
|
|
127
|
+
/**
|
|
128
|
+
* Post the note where the owner wrote: the Slack thread (Crewly's master bot;
|
|
129
|
+
* in an agent-owned DM the agent's bot, the only one that can post there), or
|
|
130
|
+
* a system turn in the chat channel.
|
|
131
|
+
*
|
|
132
|
+
* @param deps - Wiring deps
|
|
133
|
+
* @param entry - The message
|
|
134
|
+
* @param text - The note
|
|
135
|
+
* @returns True when posted
|
|
136
|
+
*/
|
|
137
|
+
export declare function postOwnerNote(deps: OwnerWatchdogWiringDeps, entry: OwnerMessageEntry, text: string): Promise<boolean>;
|
|
138
|
+
/**
|
|
139
|
+
* Build the watchdog on the real transports and expose it as the singleton.
|
|
140
|
+
*
|
|
141
|
+
* @param deps - Wiring deps
|
|
142
|
+
* @returns The started watchdog
|
|
143
|
+
*/
|
|
144
|
+
export declare function createOwnerMessageWatchdog(deps: OwnerWatchdogWiringDeps): OwnerMessageWatchdogService;
|
|
145
|
+
/**
|
|
146
|
+
* Feed a chat-v2 turn to the watchdog: an agent turn in a watched chat
|
|
147
|
+
* channel is the answer (an interim one is a visible "working on it").
|
|
148
|
+
*
|
|
149
|
+
* @param service - The watchdog
|
|
150
|
+
* @param dto - The recorded turn
|
|
151
|
+
*/
|
|
152
|
+
export declare function onChatTurn(service: Pick<OwnerMessageWatchdogService, 'noteChatAnswer'>, dto: ChatMessageDTO): void;
|
|
153
|
+
/**
|
|
154
|
+
* Feed a Slack post made through this machine's SlackService.
|
|
155
|
+
*
|
|
156
|
+
* @param service - The watchdog
|
|
157
|
+
* @param post - Channel, thread and whether it was flagged as not an answer
|
|
158
|
+
*/
|
|
159
|
+
export declare function onSlackOutbound(service: Pick<OwnerMessageWatchdogService, 'noteSlackAnswer'>, post: {
|
|
160
|
+
channelId: string;
|
|
161
|
+
threadTs?: string;
|
|
162
|
+
notAnAnswer?: boolean;
|
|
163
|
+
kind?: string;
|
|
164
|
+
}): void;
|
|
165
|
+
/**
|
|
166
|
+
* Feed an inbound Slack message: a colleague agent (any machine) posting in
|
|
167
|
+
* a watched thread answered it.
|
|
168
|
+
*
|
|
169
|
+
* @param service - The watchdog
|
|
170
|
+
* @param message - Inbound message fields
|
|
171
|
+
*/
|
|
172
|
+
export declare function onSlackInbound(service: Pick<OwnerMessageWatchdogService, 'noteSlackAnswer'>, message: {
|
|
173
|
+
channelId: string;
|
|
174
|
+
threadTs?: string;
|
|
175
|
+
authorAgentSession?: string;
|
|
176
|
+
}): void;
|
|
177
|
+
/** Log once when wiring is skipped (kept here so index.ts stays thin). */
|
|
178
|
+
export declare function logWiringSkipped(reason: string): void;
|
|
179
|
+
//# sourceMappingURL=owner-message-watchdog.wiring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-message-watchdog.wiring.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-message-watchdog.wiring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiring for the unanswered-owner-message watchdog: turns deliveries into
|
|
3
|
+
* tracked entries, turns what the owner can see into "answered", and
|
|
4
|
+
* implements the nudge and the note on top of the real transports.
|
|
5
|
+
*
|
|
6
|
+
* Kept apart from the service so the timeline logic stays transport-free and
|
|
7
|
+
* the transport glue stays small and testable with plain fakes.
|
|
8
|
+
*
|
|
9
|
+
* @module services/messaging/owner-message-watchdog.wiring
|
|
10
|
+
* @see specs/2026-09-30-owner-message-guarantee.md
|
|
11
|
+
*/
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { AGENT_REPLY_CONSTANTS, MESSAGE_SOURCES, ORCHESTRATOR_SESSION_NAME, OWNER_EVIDENCE_METADATA, OWNER_MESSAGE_WATCHDOG_CONSTANTS as C, SLACK_TYPING_CONSTANTS, } from '../../constants.js';
|
|
14
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
15
|
+
import { slackThreadTag } from '../slack/slack-thread-key.js';
|
|
16
|
+
import { OwnerMessageWatchdogService, setOwnerMessageWatchdog, } from './owner-message-watchdog.service.js';
|
|
17
|
+
const logger = LoggerService.getInstance().createComponentLogger('OwnerMessageWatchdogWiring');
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Delivery → tracked entry
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
/**
|
|
22
|
+
* Whether a chat-v2 user turn was written by the owner: not by an agent (here
|
|
23
|
+
* or on another machine), and — for a Slack row, when the owner is known — by
|
|
24
|
+
* the owner's Slack user.
|
|
25
|
+
*
|
|
26
|
+
* @param message - The turn
|
|
27
|
+
* @param ownerSlackUserId - The workspace owner's Slack user id, when known
|
|
28
|
+
* @returns True for the owner's message
|
|
29
|
+
*/
|
|
30
|
+
export function isOwnerChatTurn(message, ownerSlackUserId) {
|
|
31
|
+
if (message.senderType !== 'user')
|
|
32
|
+
return false;
|
|
33
|
+
const meta = message.metadata ?? {};
|
|
34
|
+
if (meta[OWNER_EVIDENCE_METADATA.AUTHOR_AGENT_SESSION] || meta[OWNER_EVIDENCE_METADATA.REMOTE_AGENT_SESSION])
|
|
35
|
+
return false;
|
|
36
|
+
const source = typeof meta.source === 'string' ? meta.source : '';
|
|
37
|
+
if (OWNER_EVIDENCE_METADATA.AGENT_REPLY_SOURCES.includes(source))
|
|
38
|
+
return false;
|
|
39
|
+
if (source === 'slack') {
|
|
40
|
+
const slackUserId = typeof meta.slackUserId === 'string' ? meta.slackUserId : '';
|
|
41
|
+
if (!slackUserId)
|
|
42
|
+
return false;
|
|
43
|
+
return !ownerSlackUserId || slackUserId === ownerSlackUserId;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the entry for a chat-v2 dispatch that reached at least one agent.
|
|
49
|
+
*
|
|
50
|
+
* Responsible agent: the first recipient that had to answer; with nobody
|
|
51
|
+
* required (an un-addressed room message the awake agents were only told
|
|
52
|
+
* about), the room lead when it got the message, else the first non-
|
|
53
|
+
* orchestrator recipient. An orchestrator that was only woken to route a
|
|
54
|
+
* private room's message is never made responsible: its hand-off re-dispatches
|
|
55
|
+
* the message, and that dispatch is tracked under the same key.
|
|
56
|
+
*
|
|
57
|
+
* @param channel - Channel the message was recorded in
|
|
58
|
+
* @param message - The owner's turn
|
|
59
|
+
* @param result - Dispatch outcome
|
|
60
|
+
* @param ctx - Owner id and the room lead, when known
|
|
61
|
+
* @returns Track input, or null when nothing should be tracked
|
|
62
|
+
*/
|
|
63
|
+
export function trackInputFromDispatch(channel, message, result, ctx = {}) {
|
|
64
|
+
if (!result.dispatched)
|
|
65
|
+
return null;
|
|
66
|
+
if (!isOwnerChatTurn(message, ctx.ownerSlackUserId))
|
|
67
|
+
return null;
|
|
68
|
+
let recipients = [];
|
|
69
|
+
let required = [];
|
|
70
|
+
if (result.strategy === 'dm') {
|
|
71
|
+
if (channel.agentSession)
|
|
72
|
+
recipients = required = [channel.agentSession];
|
|
73
|
+
}
|
|
74
|
+
else if (result.strategy === 'huddle-broadcast') {
|
|
75
|
+
const got = (result.huddleOutcomes ?? []).filter((o) => o.dispatched);
|
|
76
|
+
recipients = got.map((o) => o.sessionName);
|
|
77
|
+
required = got.filter((o) => o.responseMode === 'required').map((o) => o.sessionName);
|
|
78
|
+
}
|
|
79
|
+
else if (result.strategy === 'channel-mentions') {
|
|
80
|
+
recipients = required = (result.mentionOutcomes ?? []).filter((o) => o.dispatched).map((o) => o.target.sessionName);
|
|
81
|
+
}
|
|
82
|
+
if (recipients.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
let responsible = required[0];
|
|
85
|
+
if (!responsible) {
|
|
86
|
+
const nonOrc = recipients.filter((s) => s !== ORCHESTRATOR_SESSION_NAME);
|
|
87
|
+
responsible = ctx.leader && nonOrc.includes(ctx.leader) ? ctx.leader : nonOrc[0];
|
|
88
|
+
}
|
|
89
|
+
if (!responsible)
|
|
90
|
+
return null;
|
|
91
|
+
const meta = message.metadata ?? {};
|
|
92
|
+
const isHuddle = channel.type !== 'dm';
|
|
93
|
+
// When the owner wrote it: the timeline starts there, and an answer that
|
|
94
|
+
// beat this call (a fast agent while a colleague cold-starts) still counts.
|
|
95
|
+
const receivedAt = typeof message.createdAt === 'number' && message.createdAt > 0 ? { receivedAt: message.createdAt } : {};
|
|
96
|
+
const chatThreadId = isHuddle ? message.threadId ?? message.id : undefined;
|
|
97
|
+
const slackChannelId = meta.source === 'slack' && typeof meta.slackChannelId === 'string' ? meta.slackChannelId : undefined;
|
|
98
|
+
if (slackChannelId) {
|
|
99
|
+
const sourceTs = typeof meta.slackTs === 'string' ? meta.slackTs : undefined;
|
|
100
|
+
const threadTs = typeof meta.slackThreadTs === 'string' ? meta.slackThreadTs : sourceTs;
|
|
101
|
+
return {
|
|
102
|
+
surface: 'slack',
|
|
103
|
+
slackChannelId,
|
|
104
|
+
...(threadTs ? { threadTs } : {}),
|
|
105
|
+
...(sourceTs ? { sourceTs } : {}),
|
|
106
|
+
chatChannelId: channel.id,
|
|
107
|
+
...(chatThreadId ? { chatThreadId } : {}),
|
|
108
|
+
messageId: message.id,
|
|
109
|
+
responsible,
|
|
110
|
+
recipients,
|
|
111
|
+
required: required.length > 0,
|
|
112
|
+
text: message.content ?? '',
|
|
113
|
+
...receivedAt,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
surface: 'chat',
|
|
118
|
+
chatChannelId: channel.id,
|
|
119
|
+
...(chatThreadId ? { chatThreadId } : {}),
|
|
120
|
+
messageId: message.id,
|
|
121
|
+
responsible,
|
|
122
|
+
recipients,
|
|
123
|
+
required: required.length > 0,
|
|
124
|
+
text: message.content ?? '',
|
|
125
|
+
...receivedAt,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Login hint for a runtime waiting on a sign-in ("reply 重新登录 claude").
|
|
130
|
+
*
|
|
131
|
+
* @param runtimeType - The runtime type recorded with the login request, if any
|
|
132
|
+
* @returns The hint
|
|
133
|
+
*/
|
|
134
|
+
export function loginHintFor(runtimeType) {
|
|
135
|
+
const rt = (runtimeType ?? '').toLowerCase();
|
|
136
|
+
if (rt.includes('codex'))
|
|
137
|
+
return { runtime: 'Codex', runtimeCmd: 'codex' };
|
|
138
|
+
if (rt.includes('gemini') || rt.includes('antigravity'))
|
|
139
|
+
return { runtime: 'Gemini', runtimeCmd: 'gemini' };
|
|
140
|
+
return { runtime: 'Claude', runtimeCmd: 'claude' };
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The reminder delivered to the responsible agent. Carries the same routing
|
|
144
|
+
* header a normal delivery does, so the agent's `reply` goes back to the
|
|
145
|
+
* owner's conversation (and thread).
|
|
146
|
+
*
|
|
147
|
+
* @param entry - The unanswered message
|
|
148
|
+
* @param waitedMinutes - How long it has waited
|
|
149
|
+
* @param opts - `withHeader: false` when the transport adds its own `[CHAT:…]` header (the orchestrator's queue)
|
|
150
|
+
* @returns The text to deliver
|
|
151
|
+
*/
|
|
152
|
+
export function buildNudgeMessage(entry, waitedMinutes, opts = {}) {
|
|
153
|
+
const identity = /^[A-Za-z0-9._-]+$/.test(entry.responsible) ? `CREWLY_SESSION_NAME=${entry.responsible} ` : '';
|
|
154
|
+
const replyCmd = `${identity}bash ${AGENT_REPLY_CONSTANTS.SKILL_PATH} "<你的回复>"`;
|
|
155
|
+
const noneCmd = `${identity}bash ${AGENT_REPLY_CONSTANTS.SKILL_PATH} --none`;
|
|
156
|
+
const withHeader = opts.withHeader ?? true;
|
|
157
|
+
const head = withHeader && entry.chatChannelId ? `[CHAT:${entry.chatChannelId}] <owner@reminder>` : null;
|
|
158
|
+
const threadTag = entry.surface === 'slack' && entry.slackChannelId && (entry.threadTs ?? entry.sourceTs)
|
|
159
|
+
? slackThreadTag(entry.slackChannelId, (entry.threadTs ?? entry.sourceTs))
|
|
160
|
+
: null;
|
|
161
|
+
return [
|
|
162
|
+
...(head ? [head] : []),
|
|
163
|
+
...(threadTag ? [threadTag] : []),
|
|
164
|
+
'',
|
|
165
|
+
C.NUDGE_TEXT.replace('{waited}', String(waitedMinutes)).replace('{replyCmd}', replyCmd).replace('{noneCmd}', noneCmd),
|
|
166
|
+
'',
|
|
167
|
+
`owner 的原话: ${entry.preview}`,
|
|
168
|
+
].join('\n');
|
|
169
|
+
}
|
|
170
|
+
/** chat-v2 metadata flag on the watchdog's own chat notes (never taken as an answer). */
|
|
171
|
+
export const OWNER_WATCHDOG_NOTE_METADATA_KEY = 'ownerWatchdogNote';
|
|
172
|
+
/**
|
|
173
|
+
* Re-deliver an unanswered message to its responsible agent.
|
|
174
|
+
*
|
|
175
|
+
* @param deps - Wiring deps
|
|
176
|
+
* @param entry - The message
|
|
177
|
+
* @param waited - Minutes waited
|
|
178
|
+
* @returns Sent, or blocked with the reason
|
|
179
|
+
*/
|
|
180
|
+
export async function nudgeAgent(deps, entry, waited) {
|
|
181
|
+
const session = entry.responsible;
|
|
182
|
+
if (session === ORCHESTRATOR_SESSION_NAME) {
|
|
183
|
+
const text = buildNudgeMessage(entry, waited, { withHeader: false });
|
|
184
|
+
if (!entry.chatChannelId)
|
|
185
|
+
return { outcome: 'blocked', reason: 'error', detail: 'no conversation to re-deliver to' };
|
|
186
|
+
try {
|
|
187
|
+
deps.enqueueForOrchestrator({
|
|
188
|
+
content: text,
|
|
189
|
+
conversationId: entry.chatChannelId,
|
|
190
|
+
source: entry.surface === 'slack' ? MESSAGE_SOURCES.SLACK : MESSAGE_SOURCES.WEB_CHAT,
|
|
191
|
+
...(entry.surface === 'slack' && entry.slackChannelId
|
|
192
|
+
? { sourceMetadata: { channelId: entry.slackChannelId, threadTs: entry.threadTs ?? entry.sourceTs } }
|
|
193
|
+
: {}),
|
|
194
|
+
});
|
|
195
|
+
return { outcome: 'sent' };
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
return { outcome: 'blocked', reason: 'error', detail: err instanceof Error ? err.message : String(err) };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const text = buildNudgeMessage(entry, waited);
|
|
202
|
+
let woke = false;
|
|
203
|
+
if (!deps.sessionExists(session)) {
|
|
204
|
+
const res = await deps.activate(session).catch((err) => ({ success: false, error: err instanceof Error ? err.message : String(err) }));
|
|
205
|
+
if (!res.success)
|
|
206
|
+
return { outcome: 'blocked', reason: 'asleep', detail: res.error ?? 'activation failed' };
|
|
207
|
+
woke = true;
|
|
208
|
+
}
|
|
209
|
+
let result = await deps.sendToAgent(session, text).catch((err) => ({ success: false, error: err instanceof Error ? err.message : String(err) }));
|
|
210
|
+
if (!result.success && !woke && !deps.sessionExists(session)) {
|
|
211
|
+
const res = await deps.activate(session).catch((err) => ({ success: false, error: err instanceof Error ? err.message : String(err) }));
|
|
212
|
+
if (!res.success)
|
|
213
|
+
return { outcome: 'blocked', reason: 'asleep', detail: res.error ?? 'activation failed' };
|
|
214
|
+
result = await deps.sendToAgent(session, text).catch((err) => ({ success: false, error: err instanceof Error ? err.message : String(err) }));
|
|
215
|
+
}
|
|
216
|
+
if (!result.success)
|
|
217
|
+
return { outcome: 'blocked', reason: 'error', detail: result.error ?? 'delivery failed' };
|
|
218
|
+
if (entry.chatChannelId)
|
|
219
|
+
deps.noteOriginThread?.(session, entry.chatChannelId, entry.chatThreadId);
|
|
220
|
+
return { outcome: 'sent' };
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Post the note where the owner wrote: the Slack thread (Crewly's master bot;
|
|
224
|
+
* in an agent-owned DM the agent's bot, the only one that can post there), or
|
|
225
|
+
* a system turn in the chat channel.
|
|
226
|
+
*
|
|
227
|
+
* @param deps - Wiring deps
|
|
228
|
+
* @param entry - The message
|
|
229
|
+
* @param text - The note
|
|
230
|
+
* @returns True when posted
|
|
231
|
+
*/
|
|
232
|
+
export async function postOwnerNote(deps, entry, text) {
|
|
233
|
+
if (entry.surface === 'chat') {
|
|
234
|
+
if (!entry.chatChannelId)
|
|
235
|
+
return false;
|
|
236
|
+
return deps.recordChatNote(entry.chatChannelId, entry.chatThreadId, text);
|
|
237
|
+
}
|
|
238
|
+
const slack = deps.slack();
|
|
239
|
+
if (!slack?.isConnected() || !entry.slackChannelId)
|
|
240
|
+
return false;
|
|
241
|
+
const threadTs = entry.threadTs ?? entry.sourceTs;
|
|
242
|
+
const base = { channelId: entry.slackChannelId, text, ...(threadTs ? { threadTs } : {}), notAnAnswer: true, skipChatV2Mirror: true };
|
|
243
|
+
const dmToken = deps.agentDmBotToken(entry.slackChannelId);
|
|
244
|
+
try {
|
|
245
|
+
await slack.sendMessage(dmToken ? { ...base, botToken: dmToken } : base);
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
const fallback = !dmToken ? deps.botTokenOf(entry.responsible) : undefined;
|
|
250
|
+
if (!fallback)
|
|
251
|
+
throw err;
|
|
252
|
+
await slack.sendMessage({ ...base, botToken: fallback });
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Build the watchdog on the real transports and expose it as the singleton.
|
|
258
|
+
*
|
|
259
|
+
* @param deps - Wiring deps
|
|
260
|
+
* @returns The started watchdog
|
|
261
|
+
*/
|
|
262
|
+
export function createOwnerMessageWatchdog(deps) {
|
|
263
|
+
const service = new OwnerMessageWatchdogService({
|
|
264
|
+
isBusy: deps.isBusy,
|
|
265
|
+
hasVisiblePlaceholder: (entry) => {
|
|
266
|
+
const threadTs = entry.threadTs ?? entry.sourceTs;
|
|
267
|
+
return !!entry.slackChannelId && !!threadTs && deps.owesThread(entry.slackChannelId, threadTs);
|
|
268
|
+
},
|
|
269
|
+
nudge: (entry, waited) => nudgeAgent(deps, entry, waited),
|
|
270
|
+
postNote: (entry, text) => postOwnerNote(deps, entry, text),
|
|
271
|
+
loginRequired: (session) => {
|
|
272
|
+
const info = deps.loginRequired(session);
|
|
273
|
+
return info ? loginHintFor(info.runtimeType) : null;
|
|
274
|
+
},
|
|
275
|
+
...(deps.displayNameOf ? { displayNameOf: deps.displayNameOf } : {}),
|
|
276
|
+
storePath: path.join(deps.crewlyHome, C.STORE_FILENAME),
|
|
277
|
+
});
|
|
278
|
+
setOwnerMessageWatchdog(service);
|
|
279
|
+
service.start();
|
|
280
|
+
return service;
|
|
281
|
+
}
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
// Answer signals
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
/**
|
|
286
|
+
* Feed a chat-v2 turn to the watchdog: an agent turn in a watched chat
|
|
287
|
+
* channel is the answer (an interim one is a visible "working on it").
|
|
288
|
+
*
|
|
289
|
+
* @param service - The watchdog
|
|
290
|
+
* @param dto - The recorded turn
|
|
291
|
+
*/
|
|
292
|
+
export function onChatTurn(service, dto) {
|
|
293
|
+
if (dto.senderType !== 'agent')
|
|
294
|
+
return;
|
|
295
|
+
if (dto.metadata?.[OWNER_WATCHDOG_NOTE_METADATA_KEY])
|
|
296
|
+
return;
|
|
297
|
+
const interim = dto.metadata?.[SLACK_TYPING_CONSTANTS.INTERIM_METADATA_KEY] === true;
|
|
298
|
+
service.noteChatAnswer(dto.channelId, dto.threadId ?? null, interim);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Feed a Slack post made through this machine's SlackService.
|
|
302
|
+
*
|
|
303
|
+
* @param service - The watchdog
|
|
304
|
+
* @param post - Channel, thread and whether it was flagged as not an answer
|
|
305
|
+
*/
|
|
306
|
+
export function onSlackOutbound(service, post) {
|
|
307
|
+
if (post.notAnAnswer)
|
|
308
|
+
return;
|
|
309
|
+
service.noteSlackAnswer(post.channelId, post.threadTs, post.kind ?? 'post');
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Feed an inbound Slack message: a colleague agent (any machine) posting in
|
|
313
|
+
* a watched thread answered it.
|
|
314
|
+
*
|
|
315
|
+
* @param service - The watchdog
|
|
316
|
+
* @param message - Inbound message fields
|
|
317
|
+
*/
|
|
318
|
+
export function onSlackInbound(service, message) {
|
|
319
|
+
if (!message.authorAgentSession || !message.threadTs)
|
|
320
|
+
return;
|
|
321
|
+
service.noteSlackAnswer(message.channelId, message.threadTs, `agent ${message.authorAgentSession} posted`);
|
|
322
|
+
}
|
|
323
|
+
/** Log once when wiring is skipped (kept here so index.ts stays thin). */
|
|
324
|
+
export function logWiringSkipped(reason) {
|
|
325
|
+
logger.warn('Owner message watchdog not started', { reason });
|
|
326
|
+
}
|
|
327
|
+
//# sourceMappingURL=owner-message-watchdog.wiring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-message-watchdog.wiring.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-message-watchdog.wiring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an agent's `reply` goes — decided by the harness from the delivery
|
|
3
|
+
* the agent is answering, not by the agent picking the right tool and ids.
|
|
4
|
+
*
|
|
5
|
+
* Agents had to choose between reply-channel / reply-chat / reply-slack /
|
|
6
|
+
* report-status and pass the right ids; Codex agents in particular got this
|
|
7
|
+
* wrong and the owner's answer went to the orchestrator as "status" or into
|
|
8
|
+
* the wrong conversation. `reply "<text>"` names nothing: the answer goes to
|
|
9
|
+
* the turn origin recorded when the owner's message was delivered
|
|
10
|
+
* (`OrcReplyRouteService`). Explicit ids that are the agent's own still win.
|
|
11
|
+
*
|
|
12
|
+
* @module services/orc/agent-reply-target
|
|
13
|
+
* @see specs/2026-09-30-owner-message-guarantee.md §B
|
|
14
|
+
*/
|
|
15
|
+
import type { TurnOrigin } from './orc-reply-route.service.js';
|
|
16
|
+
/** The decision. */
|
|
17
|
+
export type AgentReplyPlan =
|
|
18
|
+
/** A report-status line: to the orchestrator, exactly like report-status. */
|
|
19
|
+
{
|
|
20
|
+
kind: 'status';
|
|
21
|
+
}
|
|
22
|
+
/** No answer needed: close what the agent was asked, post nothing. */
|
|
23
|
+
| {
|
|
24
|
+
kind: 'none';
|
|
25
|
+
origin?: TurnOrigin;
|
|
26
|
+
}
|
|
27
|
+
/** Post as the agent into a chat-v2 conversation (DM / room / huddle), in `thread` when set. */
|
|
28
|
+
| {
|
|
29
|
+
kind: 'post';
|
|
30
|
+
conversationId: string;
|
|
31
|
+
thread?: string;
|
|
32
|
+
via: 'explicit' | 'origin';
|
|
33
|
+
reason: string;
|
|
34
|
+
}
|
|
35
|
+
/** The orchestrator answering a Slack thread it was asked in through the master bot. */
|
|
36
|
+
| {
|
|
37
|
+
kind: 'orc-slack';
|
|
38
|
+
channelId: string;
|
|
39
|
+
threadTs?: string;
|
|
40
|
+
reason: string;
|
|
41
|
+
}
|
|
42
|
+
/** The orchestrator answering in a chat conversation (its own reply routing applies). */
|
|
43
|
+
| {
|
|
44
|
+
kind: 'orc-chat';
|
|
45
|
+
conversationId?: string;
|
|
46
|
+
reason: string;
|
|
47
|
+
}
|
|
48
|
+
/** Nothing to answer into. */
|
|
49
|
+
| {
|
|
50
|
+
kind: 'no-target';
|
|
51
|
+
reason: string;
|
|
52
|
+
};
|
|
53
|
+
/** Inputs of {@link planAgentReply}. */
|
|
54
|
+
export interface AgentReplyRequest {
|
|
55
|
+
/** Replying session (X-Agent-Session) */
|
|
56
|
+
session: string;
|
|
57
|
+
/** Whether it is the orchestrator */
|
|
58
|
+
isOrchestrator: boolean;
|
|
59
|
+
/** Reply text ('' with `none`) */
|
|
60
|
+
content: string;
|
|
61
|
+
/** `reply --none`: no answer needed */
|
|
62
|
+
none?: boolean;
|
|
63
|
+
/** Ids the agent passed, if any (may be missing, legacy or wrong) */
|
|
64
|
+
requested?: {
|
|
65
|
+
conversationId?: string;
|
|
66
|
+
thread?: string;
|
|
67
|
+
};
|
|
68
|
+
/** The recorded turn origin */
|
|
69
|
+
origin?: TurnOrigin;
|
|
70
|
+
/** Whether `conversationId` is one this agent may answer in (its DM, a room it is in) */
|
|
71
|
+
ownsConversation: (conversationId: string) => boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Whether text is a report-status line for the orchestrator.
|
|
75
|
+
*
|
|
76
|
+
* @param content - Reply text
|
|
77
|
+
* @returns True for `[DONE]`, `[WORKING]`, … at the start
|
|
78
|
+
*/
|
|
79
|
+
export declare function isStatusReport(content: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The thread an origin's answer belongs in: the Slack thread key when the
|
|
82
|
+
* message came from Slack, else the chat-v2 thread.
|
|
83
|
+
*
|
|
84
|
+
* @param origin - Turn origin
|
|
85
|
+
* @returns Thread reference, or undefined
|
|
86
|
+
*/
|
|
87
|
+
export declare function originThread(origin: TurnOrigin | undefined): string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Decide where a reply goes.
|
|
90
|
+
*
|
|
91
|
+
* @param req - Who is replying, what, the ids it passed and its turn origin
|
|
92
|
+
* @returns The plan
|
|
93
|
+
*/
|
|
94
|
+
export declare function planAgentReply(req: AgentReplyRequest): AgentReplyPlan;
|
|
95
|
+
//# sourceMappingURL=agent-reply-target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-reply-target.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/agent-reply-target.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,oBAAoB;AACpB,MAAM,MAAM,cAAc;AACxB,6EAA6E;AAC3E;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE;AACpB,sEAAsE;GACpE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE;AACvC,gGAAgG;GAC9F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,UAAU,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACvG,wFAAwF;GACtF;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC7E,yFAAyF;GACvF;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC/D,8BAA8B;GAC5B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qEAAqE;IACrE,SAAS,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,+BAA+B;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,yFAAyF;IACzF,gBAAgB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC;CACvD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,cAAc,CA2CrE"}
|