crewly 1.20.307 → 1.20.309
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/hooks/agent-status/report.sh +5 -5
- package/dist/backend/backend/src/constants.d.ts +80 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +80 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +9 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +161 -2
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/board/board-activity.normalizer.d.ts +17 -0
- package/dist/backend/backend/src/services/board/board-activity.normalizer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/board/board-activity.normalizer.js +8 -5
- package/dist/backend/backend/src/services/board/board-activity.normalizer.js.map +1 -1
- package/dist/backend/backend/src/services/board/board-activity.tracker.d.ts +5 -0
- package/dist/backend/backend/src/services/board/board-activity.tracker.d.ts.map +1 -1
- package/dist/backend/backend/src/services/board/board-activity.tracker.js +25 -1
- package/dist/backend/backend/src/services/board/board-activity.tracker.js.map +1 -1
- package/dist/backend/backend/src/services/board/board-interaction-hooks.d.ts +34 -0
- package/dist/backend/backend/src/services/board/board-interaction-hooks.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/board-interaction-hooks.js +60 -0
- package/dist/backend/backend/src/services/board/board-interaction-hooks.js.map +1 -0
- package/dist/backend/backend/src/services/board/board-interactions.d.ts +54 -0
- package/dist/backend/backend/src/services/board/board-interactions.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/board-interactions.js +92 -0
- package/dist/backend/backend/src/services/board/board-interactions.js.map +1 -0
- package/dist/backend/backend/src/services/board/board-links.d.ts +51 -0
- package/dist/backend/backend/src/services/board/board-links.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/board-links.js +168 -0
- package/dist/backend/backend/src/services/board/board-links.js.map +1 -0
- package/dist/backend/backend/src/services/board/board-push.service.d.ts +28 -3
- package/dist/backend/backend/src/services/board/board-push.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/board/board-push.service.js +108 -9
- package/dist/backend/backend/src/services/board/board-push.service.js.map +1 -1
- package/dist/backend/backend/src/services/board/board-snapshot.builder.d.ts +39 -2
- package/dist/backend/backend/src/services/board/board-snapshot.builder.d.ts.map +1 -1
- package/dist/backend/backend/src/services/board/board-snapshot.builder.js +85 -8
- package/dist/backend/backend/src/services/board/board-snapshot.builder.js.map +1 -1
- package/dist/backend/backend/src/services/board/board.sources.d.ts.map +1 -1
- package/dist/backend/backend/src/services/board/board.sources.js +27 -1
- package/dist/backend/backend/src/services/board/board.sources.js.map +1 -1
- package/dist/backend/backend/src/services/board/board.types.d.ts +48 -0
- package/dist/backend/backend/src/services/board/board.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/board/board.types.js +9 -1
- package/dist/backend/backend/src/services/board/board.types.js.map +1 -1
- package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.d.ts +122 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.js +339 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-redact.d.ts +44 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-redact.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-redact.js +161 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-redact.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.d.ts +57 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.js +164 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.d.ts +140 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.js +300 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.d.ts +99 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.js +223 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.d.ts +126 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.js +385 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-wiring.d.ts +103 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-wiring.js +124 -0
- package/dist/backend/backend/src/services/board/canvas/canvas-wiring.js.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas.types.d.ts +88 -0
- package/dist/backend/backend/src/services/board/canvas/canvas.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/board/canvas/canvas.types.js +8 -0
- package/dist/backend/backend/src/services/board/canvas/canvas.types.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.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 +2 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +80 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +80 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live step stream per agent (crewly#1247 v2).
|
|
3
|
+
*
|
|
4
|
+
* Pairs a tool start with its end (hook PreToolUse / PostToolUse) into one
|
|
5
|
+
* {@link StepEvent} with a duration and a status, takes instant steps (a chat
|
|
6
|
+
* reply, a browser action) and the agent's own short text lines (from the
|
|
7
|
+
* transcript tail), and keeps the last 300 per agent in memory.
|
|
8
|
+
*
|
|
9
|
+
* A step is sent again, with the same id, when it changes (`running` ->
|
|
10
|
+
* `done` / `error`): `unsent` holds the newest version of every step Cloud has
|
|
11
|
+
* not taken yet, so a failed push loses nothing (capped per agent).
|
|
12
|
+
*
|
|
13
|
+
* In memory only; nothing here reads files or the network. Everything that
|
|
14
|
+
* goes in has been through the redaction in {@link ./canvas-step.normalizer}
|
|
15
|
+
* and {@link ./canvas-redact}.
|
|
16
|
+
*
|
|
17
|
+
* @module services/board/canvas/canvas-step.stream
|
|
18
|
+
*/
|
|
19
|
+
import { CANVAS_CONSTANTS } from '../../../constants.js';
|
|
20
|
+
const C = CANVAS_CONSTANTS;
|
|
21
|
+
const sameVersion = (a, b) => a.status === b.status && a.durationMs === b.durationMs && a.text === b.text && a.target === b.target;
|
|
22
|
+
/**
|
|
23
|
+
* Steps per agent.
|
|
24
|
+
*/
|
|
25
|
+
export class StepStream {
|
|
26
|
+
sessions = new Map();
|
|
27
|
+
listeners = new Set();
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to changes.
|
|
30
|
+
*
|
|
31
|
+
* @param listener - Called with the session whose steps changed
|
|
32
|
+
* @returns Unsubscribe
|
|
33
|
+
*/
|
|
34
|
+
onChange(listener) {
|
|
35
|
+
this.listeners.add(listener);
|
|
36
|
+
return () => this.listeners.delete(listener);
|
|
37
|
+
}
|
|
38
|
+
emit(session) {
|
|
39
|
+
for (const l of this.listeners) {
|
|
40
|
+
try {
|
|
41
|
+
l(session);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// a listener must never break a hook
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
get(session) {
|
|
49
|
+
let s = this.sessions.get(session);
|
|
50
|
+
if (!s) {
|
|
51
|
+
s = { steps: [], byId: new Map(), open: [], unsent: new Map(), seq: 0 };
|
|
52
|
+
this.sessions.set(session, s);
|
|
53
|
+
}
|
|
54
|
+
return s;
|
|
55
|
+
}
|
|
56
|
+
touch(s, step) {
|
|
57
|
+
s.unsent.set(step.id, { ...step });
|
|
58
|
+
while (s.unsent.size > C.UNSENT_MAX_PER_AGENT) {
|
|
59
|
+
const oldest = s.unsent.keys().next().value;
|
|
60
|
+
s.unsent.delete(oldest);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
insert(s, step) {
|
|
64
|
+
let i = s.steps.length;
|
|
65
|
+
const at = Date.parse(step.at);
|
|
66
|
+
while (i > 0 && Date.parse(s.steps[i - 1].at) > at)
|
|
67
|
+
i -= 1;
|
|
68
|
+
s.steps.splice(i, 0, step);
|
|
69
|
+
s.byId.set(step.id, step);
|
|
70
|
+
while (s.steps.length > C.STEPS_MAX_PER_AGENT) {
|
|
71
|
+
const gone = s.steps.shift();
|
|
72
|
+
s.byId.delete(gone.id);
|
|
73
|
+
s.open = s.open.filter((id) => id !== gone.id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** A running step older than the limit lost its end: close it without a duration. */
|
|
77
|
+
sweep(session, s, now) {
|
|
78
|
+
const stale = s.open.filter((id) => {
|
|
79
|
+
const step = s.byId.get(id);
|
|
80
|
+
return !step || now - Date.parse(step.at) > C.OPEN_STEP_MAX_MS;
|
|
81
|
+
});
|
|
82
|
+
if (stale.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
for (const id of stale) {
|
|
85
|
+
const step = s.byId.get(id);
|
|
86
|
+
if (step && step.status === 'running') {
|
|
87
|
+
step.status = 'done';
|
|
88
|
+
this.touch(s, step);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
s.open = s.open.filter((id) => !stale.includes(id));
|
|
92
|
+
this.emit(session);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A step began (a tool call started).
|
|
96
|
+
*
|
|
97
|
+
* @param session - Agent session
|
|
98
|
+
* @param shape - Kind, verb and target
|
|
99
|
+
* @param opts.id - The runtime's tool-call id; a derived one when absent
|
|
100
|
+
* @param now - Clock (tests)
|
|
101
|
+
* @returns The step id
|
|
102
|
+
*/
|
|
103
|
+
start(session, shape, opts = {}, now = Date.now()) {
|
|
104
|
+
const s = this.get(session);
|
|
105
|
+
this.sweep(session, s, now);
|
|
106
|
+
s.seq += 1;
|
|
107
|
+
const id = opts.id ?? `${session}-${now.toString(36)}-${s.seq}`;
|
|
108
|
+
const existing = s.byId.get(id);
|
|
109
|
+
if (existing)
|
|
110
|
+
return id; // a repeated PreToolUse
|
|
111
|
+
const step = { session, id, at: new Date(now).toISOString(), ...shape, status: 'running' };
|
|
112
|
+
this.insert(s, step);
|
|
113
|
+
s.open.push(id);
|
|
114
|
+
this.touch(s, step);
|
|
115
|
+
this.emit(session);
|
|
116
|
+
return id;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A step ended. Without an id the oldest running step ends (a hook that
|
|
120
|
+
* did not name its tool call).
|
|
121
|
+
*
|
|
122
|
+
* @param session - Agent session
|
|
123
|
+
* @param id - Step id, if known
|
|
124
|
+
* @param status - How it ended
|
|
125
|
+
* @param now - Clock (tests)
|
|
126
|
+
*/
|
|
127
|
+
finish(session, id, status = 'done', now = Date.now()) {
|
|
128
|
+
const s = this.sessions.get(session);
|
|
129
|
+
if (!s)
|
|
130
|
+
return;
|
|
131
|
+
const target = id ?? s.open[0];
|
|
132
|
+
if (!target)
|
|
133
|
+
return;
|
|
134
|
+
const step = s.byId.get(target);
|
|
135
|
+
if (!step)
|
|
136
|
+
return;
|
|
137
|
+
s.open = s.open.filter((x) => x !== target);
|
|
138
|
+
if (step.status !== 'running' && !(status === 'error' && step.status === 'done'))
|
|
139
|
+
return;
|
|
140
|
+
step.status = status;
|
|
141
|
+
if (step.durationMs === undefined)
|
|
142
|
+
step.durationMs = Math.max(0, now - Date.parse(step.at));
|
|
143
|
+
this.touch(s, step);
|
|
144
|
+
this.emit(session);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A step turned out to have failed (the transcript's `is_error` flag), after
|
|
148
|
+
* its end was already seen.
|
|
149
|
+
*
|
|
150
|
+
* @param session - Agent session
|
|
151
|
+
* @param id - Step id
|
|
152
|
+
* @param now - Clock (tests)
|
|
153
|
+
*/
|
|
154
|
+
markError(session, id, now = Date.now()) {
|
|
155
|
+
this.finish(session, id, 'error', now);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* A step that has no duration (a message sent, a page opened by the
|
|
159
|
+
* extension). Dropped when a tool call of the same kind is running, or the
|
|
160
|
+
* previous step is the same thing within 5 s (a skill's own tool call and
|
|
161
|
+
* the controller that served it).
|
|
162
|
+
*
|
|
163
|
+
* @param session - Agent session
|
|
164
|
+
* @param shape - Kind, verb and target
|
|
165
|
+
* @param now - Clock (tests)
|
|
166
|
+
* @returns The step id, or null when it repeated the previous step
|
|
167
|
+
*/
|
|
168
|
+
instant(session, shape, now = Date.now()) {
|
|
169
|
+
const s = this.get(session);
|
|
170
|
+
// A tool call of the same kind is running: this is that very action seen from the
|
|
171
|
+
// controller that served it (a messaging skill posting, the browser skill navigating)
|
|
172
|
+
if (s.open.some((id) => s.byId.get(id)?.kind === shape.kind))
|
|
173
|
+
return null;
|
|
174
|
+
const last = s.steps[s.steps.length - 1];
|
|
175
|
+
if (last && last.kind === shape.kind && last.target === shape.target && now - Date.parse(last.at) < C.STEP_DEDUPE_MS) {
|
|
176
|
+
// A running tool call that is this very action: let it carry the duration
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
s.seq += 1;
|
|
180
|
+
const id = `${session}-${now.toString(36)}-${s.seq}`;
|
|
181
|
+
const step = { session, id, at: new Date(now).toISOString(), ...shape, status: 'done' };
|
|
182
|
+
this.insert(s, step);
|
|
183
|
+
this.touch(s, step);
|
|
184
|
+
this.emit(session);
|
|
185
|
+
return id;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* One line of the agent's own words.
|
|
189
|
+
*
|
|
190
|
+
* @param session - Agent session
|
|
191
|
+
* @param id - Stable id (the transcript entry's uuid)
|
|
192
|
+
* @param atMs - When it was written
|
|
193
|
+
* @param text - Already reduced and redacted (see shortAgentLine)
|
|
194
|
+
* @returns True when it is new
|
|
195
|
+
*/
|
|
196
|
+
text(session, id, atMs, text) {
|
|
197
|
+
const s = this.get(session);
|
|
198
|
+
const stepId = `txt-${id}`;
|
|
199
|
+
if (s.byId.has(stepId))
|
|
200
|
+
return false;
|
|
201
|
+
const step = {
|
|
202
|
+
session,
|
|
203
|
+
id: stepId,
|
|
204
|
+
at: new Date(atMs).toISOString(),
|
|
205
|
+
kind: 'text',
|
|
206
|
+
label: 'Said',
|
|
207
|
+
text: text.slice(0, C.TEXT_MAX),
|
|
208
|
+
status: 'done',
|
|
209
|
+
};
|
|
210
|
+
this.insert(s, step);
|
|
211
|
+
this.touch(s, step);
|
|
212
|
+
this.emit(session);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The turn ended: whatever still runs ended with it.
|
|
217
|
+
*
|
|
218
|
+
* @param session - Agent session
|
|
219
|
+
* @param now - Clock (tests)
|
|
220
|
+
*/
|
|
221
|
+
closeAll(session, now = Date.now()) {
|
|
222
|
+
const s = this.sessions.get(session);
|
|
223
|
+
if (!s || s.open.length === 0)
|
|
224
|
+
return;
|
|
225
|
+
for (const id of [...s.open])
|
|
226
|
+
this.finish(session, id, 'done', now);
|
|
227
|
+
s.open = [];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* A session's recent steps (oldest first).
|
|
231
|
+
*
|
|
232
|
+
* @param session - Agent session
|
|
233
|
+
* @param limit - Newest this many
|
|
234
|
+
* @param now - Clock (tests)
|
|
235
|
+
* @returns Copies
|
|
236
|
+
*/
|
|
237
|
+
recent(session, limit = 50, now = Date.now()) {
|
|
238
|
+
const s = this.sessions.get(session);
|
|
239
|
+
if (!s)
|
|
240
|
+
return [];
|
|
241
|
+
const cutoff = now - C.STEPS_MAX_AGE_MS;
|
|
242
|
+
return s.steps.filter((x) => Date.parse(x.at) >= cutoff).slice(-limit).map((x) => ({ ...x }));
|
|
243
|
+
}
|
|
244
|
+
/** Whether the session has a step that is still running. */
|
|
245
|
+
hasRunning(session) {
|
|
246
|
+
return (this.sessions.get(session)?.open.length ?? 0) > 0;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Steps (new or changed) Cloud has not taken. Call {@link ackUnsent} once
|
|
250
|
+
* it did.
|
|
251
|
+
*
|
|
252
|
+
* @param sessions - Only these sessions (all when omitted)
|
|
253
|
+
* @param max - Most steps in all
|
|
254
|
+
* @param perSession - Most steps per session (the oldest go first; the rest wait for the next delta)
|
|
255
|
+
* @returns Steps, oldest first
|
|
256
|
+
*/
|
|
257
|
+
peekUnsent(sessions, max = C.DELTA_STEPS_MAX, perSession = C.DELTA_STEPS_PER_AGENT_MAX) {
|
|
258
|
+
const out = [];
|
|
259
|
+
const keys = sessions ? [...sessions] : [...this.sessions.keys()];
|
|
260
|
+
for (const key of keys) {
|
|
261
|
+
const s = this.sessions.get(key);
|
|
262
|
+
if (!s || s.unsent.size === 0)
|
|
263
|
+
continue;
|
|
264
|
+
const list = [...s.unsent.values()].sort((a, b) => Date.parse(a.at) - Date.parse(b.at));
|
|
265
|
+
out.push(...list.slice(0, perSession).map((x) => ({ ...x })));
|
|
266
|
+
}
|
|
267
|
+
out.sort((a, b) => Date.parse(a.at) - Date.parse(b.at));
|
|
268
|
+
return out.length > max ? out.slice(0, max) : out;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Mark steps as taken. A step that changed since it was peeked stays
|
|
272
|
+
* unsent (and goes out again); steps left over by the per-delta limit stay
|
|
273
|
+
* too, for the next delta.
|
|
274
|
+
*
|
|
275
|
+
* @param steps - What {@link peekUnsent} returned and Cloud accepted
|
|
276
|
+
*/
|
|
277
|
+
ackUnsent(steps) {
|
|
278
|
+
for (const step of steps) {
|
|
279
|
+
const s = this.sessions.get(step.session);
|
|
280
|
+
if (!s)
|
|
281
|
+
continue;
|
|
282
|
+
const current = s.unsent.get(step.id);
|
|
283
|
+
if (current && sameVersion(current, step))
|
|
284
|
+
s.unsent.delete(step.id);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/** Sessions with steps not yet sent. */
|
|
288
|
+
sessionsWithUnsent() {
|
|
289
|
+
return [...this.sessions.entries()].filter(([, s]) => s.unsent.size > 0).map(([k]) => k);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Forget a session (it was deleted).
|
|
293
|
+
*
|
|
294
|
+
* @param session - Agent session
|
|
295
|
+
*/
|
|
296
|
+
forget(session) {
|
|
297
|
+
this.sessions.delete(session);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=canvas-step.stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-step.stream.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-step.stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Masked terminal tail for the canvas (crewly#1247 v2).
|
|
3
|
+
*
|
|
4
|
+
* The owner opens an agent's terminal in the portal: Cloud relays
|
|
5
|
+
* `terminal_open`, and this service posts the agent's PTY tail to Cloud about
|
|
6
|
+
* once a second - the first frame is the last 200 lines - until the viewer
|
|
7
|
+
* stops renewing (a lease of 2 minutes, renewed by `terminal_renew` every
|
|
8
|
+
* 60 s), closes it, the agent's session ends, Cloud says it is no longer
|
|
9
|
+
* wanted, or the stream has run 30 minutes.
|
|
10
|
+
*
|
|
11
|
+
* Every frame is masked on the machine ({@link maskTerminalText}: secrets by
|
|
12
|
+
* value, by name and by shape, emails, URL queries, bearer tokens, password
|
|
13
|
+
* prompts, long token-like words) BEFORE it is posted; a frame is only posted
|
|
14
|
+
* when its masked content changed. Frames are never written to disk here and
|
|
15
|
+
* Cloud keeps them in memory only.
|
|
16
|
+
*
|
|
17
|
+
* @module services/board/canvas/canvas-terminal.service
|
|
18
|
+
*/
|
|
19
|
+
import type { SecretEnvValue } from '../../../utils/secret-env.js';
|
|
20
|
+
import { type ComponentLogger } from '../../core/logger.service.js';
|
|
21
|
+
import type { TerminalFrame } from './canvas.types.js';
|
|
22
|
+
/** The Cloud session (CloudClientService). */
|
|
23
|
+
export interface TerminalCloud {
|
|
24
|
+
getToken(): string | null;
|
|
25
|
+
getCloudUrl(): string | null;
|
|
26
|
+
tryRefreshToken?(): Promise<boolean>;
|
|
27
|
+
}
|
|
28
|
+
/** Constructor dependencies. */
|
|
29
|
+
export interface CanvasTerminalDeps {
|
|
30
|
+
cloud: TerminalCloud;
|
|
31
|
+
/** This machine's Cloud instance id */
|
|
32
|
+
identity: () => Promise<{
|
|
33
|
+
instanceId: string;
|
|
34
|
+
}>;
|
|
35
|
+
/** The raw PTY tail of a session, or null when it has none */
|
|
36
|
+
capture: (session: string, lines: number) => string | null;
|
|
37
|
+
/** Whether the agent's terminal session exists */
|
|
38
|
+
exists: (session: string) => boolean;
|
|
39
|
+
/** Exact secret values to mask */
|
|
40
|
+
secrets?: () => readonly SecretEnvValue[];
|
|
41
|
+
fetchImpl?: (input: string, init: RequestInit) => Promise<Response>;
|
|
42
|
+
now?: () => number;
|
|
43
|
+
setTimeout?: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;
|
|
44
|
+
clearTimeout?: (h: ReturnType<typeof setTimeout>) => void;
|
|
45
|
+
logger?: ComponentLogger;
|
|
46
|
+
}
|
|
47
|
+
/** Why a stream could not be opened. */
|
|
48
|
+
export type TerminalOpenResult = {
|
|
49
|
+
ok: true;
|
|
50
|
+
} | {
|
|
51
|
+
ok: false;
|
|
52
|
+
code: 'no_session' | 'too_many_streams' | 'not_signed_in';
|
|
53
|
+
};
|
|
54
|
+
/** Streams masked PTY tails to Cloud while a viewer holds a lease. */
|
|
55
|
+
export declare class CanvasTerminalService {
|
|
56
|
+
private readonly deps;
|
|
57
|
+
private readonly streams;
|
|
58
|
+
private readonly logger;
|
|
59
|
+
private readonly now;
|
|
60
|
+
private readonly fetchImpl;
|
|
61
|
+
private readonly setTimer;
|
|
62
|
+
private readonly clearTimer;
|
|
63
|
+
constructor(deps: CanvasTerminalDeps);
|
|
64
|
+
/** Sessions being streamed. */
|
|
65
|
+
active(): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Start (or restart) a stream; the first frame goes out at once.
|
|
68
|
+
*
|
|
69
|
+
* @param session - Agent session
|
|
70
|
+
* @returns Whether it is streaming
|
|
71
|
+
*/
|
|
72
|
+
open(session: string): TerminalOpenResult;
|
|
73
|
+
/**
|
|
74
|
+
* The viewer is still there: extend the lease.
|
|
75
|
+
*
|
|
76
|
+
* @param session - Agent session
|
|
77
|
+
* @returns False when no stream is open (the viewer must open again)
|
|
78
|
+
*/
|
|
79
|
+
renew(session: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Stop a stream; a last frame tells Cloud it ended.
|
|
82
|
+
*
|
|
83
|
+
* @param session - Agent session
|
|
84
|
+
* @param reason - Why it ended
|
|
85
|
+
*/
|
|
86
|
+
close(session: string, reason?: NonNullable<TerminalFrame['reason']>): void;
|
|
87
|
+
/** Stop every stream (shutdown). */
|
|
88
|
+
closeAll(): void;
|
|
89
|
+
private schedule;
|
|
90
|
+
/** One frame: stop if the stream is over, else mask the tail and post it when it changed. */
|
|
91
|
+
private tick;
|
|
92
|
+
/**
|
|
93
|
+
* Post one frame.
|
|
94
|
+
*
|
|
95
|
+
* @returns `ok`; `stop` when Cloud no longer wants frames (404 / 403 / 410, `keep: false`); `retry` on any other failure
|
|
96
|
+
*/
|
|
97
|
+
private post;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=canvas-terminal.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-terminal.service.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-terminal.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvD,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC7B,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AAED,gCAAgC;AAChC,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,8DAA8D;IAC9D,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC3D,kDAAkD;IAClD,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACrC,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,SAAS,cAAc,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC3E,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,wCAAwC;AACxC,MAAM,MAAM,kBAAkB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,YAAY,GAAG,kBAAkB,GAAG,eAAe,CAAA;CAAE,CAAC;AAezH,sEAAsE;AACtE,qBAAa,qBAAqB;IAQrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0D;IACpF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgE;IACzF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6C;gBAE3C,IAAI,EAAE,kBAAkB;IAcrD,+BAA+B;IAC/B,MAAM,IAAI,MAAM,EAAE;IAIlB;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB;IAkBzC;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAO/B;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAY,GAAG,IAAI;IASrF,oCAAoC;IACpC,QAAQ,IAAI,IAAI;IAIhB,OAAO,CAAC,QAAQ;IAQhB,6FAA6F;YAC/E,IAAI;IAqClB;;;;OAIG;YACW,IAAI;CA4ClB"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Masked terminal tail for the canvas (crewly#1247 v2).
|
|
3
|
+
*
|
|
4
|
+
* The owner opens an agent's terminal in the portal: Cloud relays
|
|
5
|
+
* `terminal_open`, and this service posts the agent's PTY tail to Cloud about
|
|
6
|
+
* once a second - the first frame is the last 200 lines - until the viewer
|
|
7
|
+
* stops renewing (a lease of 2 minutes, renewed by `terminal_renew` every
|
|
8
|
+
* 60 s), closes it, the agent's session ends, Cloud says it is no longer
|
|
9
|
+
* wanted, or the stream has run 30 minutes.
|
|
10
|
+
*
|
|
11
|
+
* Every frame is masked on the machine ({@link maskTerminalText}: secrets by
|
|
12
|
+
* value, by name and by shape, emails, URL queries, bearer tokens, password
|
|
13
|
+
* prompts, long token-like words) BEFORE it is posted; a frame is only posted
|
|
14
|
+
* when its masked content changed. Frames are never written to disk here and
|
|
15
|
+
* Cloud keeps them in memory only.
|
|
16
|
+
*
|
|
17
|
+
* @module services/board/canvas/canvas-terminal.service
|
|
18
|
+
*/
|
|
19
|
+
import { gzipSync } from 'zlib';
|
|
20
|
+
import { CANVAS_CONSTANTS, BOARD_CONSTANTS } from '../../../constants.js';
|
|
21
|
+
import { LoggerService } from '../../core/logger.service.js';
|
|
22
|
+
import { maskTerminalText } from './canvas-redact.js';
|
|
23
|
+
const C = CANVAS_CONSTANTS;
|
|
24
|
+
/** Streams masked PTY tails to Cloud while a viewer holds a lease. */
|
|
25
|
+
export class CanvasTerminalService {
|
|
26
|
+
deps;
|
|
27
|
+
streams = new Map();
|
|
28
|
+
logger;
|
|
29
|
+
now;
|
|
30
|
+
fetchImpl;
|
|
31
|
+
setTimer;
|
|
32
|
+
clearTimer;
|
|
33
|
+
constructor(deps) {
|
|
34
|
+
this.deps = deps;
|
|
35
|
+
this.logger = deps.logger ?? LoggerService.getInstance().createComponentLogger('CanvasTerminal');
|
|
36
|
+
this.now = deps.now ?? Date.now;
|
|
37
|
+
this.fetchImpl = deps.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
38
|
+
this.setTimer =
|
|
39
|
+
deps.setTimeout ??
|
|
40
|
+
((fn, ms) => {
|
|
41
|
+
const t = setTimeout(fn, ms);
|
|
42
|
+
t.unref?.();
|
|
43
|
+
return t;
|
|
44
|
+
});
|
|
45
|
+
this.clearTimer = deps.clearTimeout ?? ((h) => clearTimeout(h));
|
|
46
|
+
}
|
|
47
|
+
/** Sessions being streamed. */
|
|
48
|
+
active() {
|
|
49
|
+
return [...this.streams.keys()];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Start (or restart) a stream; the first frame goes out at once.
|
|
53
|
+
*
|
|
54
|
+
* @param session - Agent session
|
|
55
|
+
* @returns Whether it is streaming
|
|
56
|
+
*/
|
|
57
|
+
open(session) {
|
|
58
|
+
if (!this.deps.cloud.getToken() || !this.deps.cloud.getCloudUrl())
|
|
59
|
+
return { ok: false, code: 'not_signed_in' };
|
|
60
|
+
if (!this.deps.exists(session))
|
|
61
|
+
return { ok: false, code: 'no_session' };
|
|
62
|
+
const existing = this.streams.get(session);
|
|
63
|
+
if (existing) {
|
|
64
|
+
existing.leaseUntil = this.now() + C.TERMINAL_LEASE_MS;
|
|
65
|
+
existing.force = true;
|
|
66
|
+
this.schedule(existing, 0);
|
|
67
|
+
return { ok: true };
|
|
68
|
+
}
|
|
69
|
+
if (this.streams.size >= C.TERMINAL_MAX_STREAMS)
|
|
70
|
+
return { ok: false, code: 'too_many_streams' };
|
|
71
|
+
const now = this.now();
|
|
72
|
+
const stream = { session, seq: 0, startedAt: now, leaseUntil: now + C.TERMINAL_LEASE_MS, lastKey: null, failures: 0, timer: null, busy: false, force: true };
|
|
73
|
+
this.streams.set(session, stream);
|
|
74
|
+
this.schedule(stream, 0);
|
|
75
|
+
return { ok: true };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The viewer is still there: extend the lease.
|
|
79
|
+
*
|
|
80
|
+
* @param session - Agent session
|
|
81
|
+
* @returns False when no stream is open (the viewer must open again)
|
|
82
|
+
*/
|
|
83
|
+
renew(session) {
|
|
84
|
+
const s = this.streams.get(session);
|
|
85
|
+
if (!s)
|
|
86
|
+
return false;
|
|
87
|
+
s.leaseUntil = this.now() + C.TERMINAL_LEASE_MS;
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Stop a stream; a last frame tells Cloud it ended.
|
|
92
|
+
*
|
|
93
|
+
* @param session - Agent session
|
|
94
|
+
* @param reason - Why it ended
|
|
95
|
+
*/
|
|
96
|
+
close(session, reason = 'closed') {
|
|
97
|
+
const s = this.streams.get(session);
|
|
98
|
+
if (!s)
|
|
99
|
+
return;
|
|
100
|
+
this.streams.delete(session);
|
|
101
|
+
if (s.timer)
|
|
102
|
+
this.clearTimer(s.timer);
|
|
103
|
+
s.timer = null;
|
|
104
|
+
void this.post(s, [], true, reason).catch(() => undefined);
|
|
105
|
+
}
|
|
106
|
+
/** Stop every stream (shutdown). */
|
|
107
|
+
closeAll() {
|
|
108
|
+
for (const session of [...this.streams.keys()])
|
|
109
|
+
this.close(session, 'closed');
|
|
110
|
+
}
|
|
111
|
+
schedule(s, delayMs) {
|
|
112
|
+
if (s.timer)
|
|
113
|
+
this.clearTimer(s.timer);
|
|
114
|
+
s.timer = this.setTimer(() => {
|
|
115
|
+
s.timer = null;
|
|
116
|
+
void this.tick(s);
|
|
117
|
+
}, delayMs);
|
|
118
|
+
}
|
|
119
|
+
/** One frame: stop if the stream is over, else mask the tail and post it when it changed. */
|
|
120
|
+
async tick(s) {
|
|
121
|
+
if (this.streams.get(s.session) !== s || s.busy)
|
|
122
|
+
return;
|
|
123
|
+
s.busy = true;
|
|
124
|
+
try {
|
|
125
|
+
const now = this.now();
|
|
126
|
+
if (now > s.leaseUntil)
|
|
127
|
+
return this.close(s.session, 'lease_expired');
|
|
128
|
+
if (now - s.startedAt > C.TERMINAL_MAX_STREAM_MS)
|
|
129
|
+
return this.close(s.session, 'too_long');
|
|
130
|
+
if (!this.deps.exists(s.session))
|
|
131
|
+
return this.close(s.session, 'session_gone');
|
|
132
|
+
let raw = null;
|
|
133
|
+
try {
|
|
134
|
+
raw = this.deps.capture(s.session, C.TERMINAL_TAIL_LINES);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
raw = null;
|
|
138
|
+
}
|
|
139
|
+
if (raw !== null) {
|
|
140
|
+
const lines = maskTerminalText(raw, this.deps.secrets?.() ?? []);
|
|
141
|
+
const key = lines.join('\n');
|
|
142
|
+
if (s.force || key !== s.lastKey) {
|
|
143
|
+
const outcome = await this.post(s, lines, false);
|
|
144
|
+
if (this.streams.get(s.session) !== s)
|
|
145
|
+
return;
|
|
146
|
+
if (outcome === 'stop')
|
|
147
|
+
return this.close(s.session, 'cloud_stopped');
|
|
148
|
+
if (outcome === 'ok') {
|
|
149
|
+
s.lastKey = key;
|
|
150
|
+
s.force = false;
|
|
151
|
+
s.failures = 0;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
s.failures += 1;
|
|
155
|
+
if (s.failures >= C.TERMINAL_MAX_FAILURES)
|
|
156
|
+
return this.close(s.session, 'send_failed');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (this.streams.get(s.session) === s)
|
|
161
|
+
this.schedule(s, C.TERMINAL_FRAME_INTERVAL_MS);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
s.busy = false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Post one frame.
|
|
169
|
+
*
|
|
170
|
+
* @returns `ok`; `stop` when Cloud no longer wants frames (404 / 403 / 410, `keep: false`); `retry` on any other failure
|
|
171
|
+
*/
|
|
172
|
+
async post(s, lines, closed, reason) {
|
|
173
|
+
const token = this.deps.cloud.getToken();
|
|
174
|
+
const base = this.deps.cloud.getCloudUrl();
|
|
175
|
+
if (!token || !base)
|
|
176
|
+
return 'retry';
|
|
177
|
+
const instanceId = (await this.deps.identity()).instanceId;
|
|
178
|
+
s.seq += 1;
|
|
179
|
+
const frame = {
|
|
180
|
+
instanceId,
|
|
181
|
+
session: s.session,
|
|
182
|
+
seq: s.seq,
|
|
183
|
+
at: new Date(this.now()).toISOString(),
|
|
184
|
+
lines,
|
|
185
|
+
...(closed ? { closed: true, ...(reason ? { reason } : {}) } : {}),
|
|
186
|
+
};
|
|
187
|
+
let refreshed = false;
|
|
188
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
189
|
+
let response;
|
|
190
|
+
try {
|
|
191
|
+
response = await this.fetchImpl(`${base.replace(/\/$/, '')}${C.TERMINAL_FRAME_PATH}`, {
|
|
192
|
+
method: 'POST',
|
|
193
|
+
headers: {
|
|
194
|
+
Authorization: `Bearer ${this.deps.cloud.getToken() ?? token}`,
|
|
195
|
+
'Content-Type': 'application/json',
|
|
196
|
+
'Content-Encoding': 'gzip',
|
|
197
|
+
[BOARD_CONSTANTS.INSTANCE_HEADER]: instanceId,
|
|
198
|
+
},
|
|
199
|
+
body: gzipSync(Buffer.from(JSON.stringify(frame))),
|
|
200
|
+
signal: AbortSignal.timeout(C.REQUEST_TIMEOUT_MS),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return 'retry';
|
|
205
|
+
}
|
|
206
|
+
if (response.status === 401 && !refreshed && this.deps.cloud.tryRefreshToken) {
|
|
207
|
+
refreshed = true;
|
|
208
|
+
if (await this.deps.cloud.tryRefreshToken().catch(() => false))
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (response.status === 404 || response.status === 403 || response.status === 410)
|
|
212
|
+
return 'stop';
|
|
213
|
+
if (!response.ok)
|
|
214
|
+
return 'retry';
|
|
215
|
+
if (closed)
|
|
216
|
+
return 'ok';
|
|
217
|
+
const parsed = (await response.json().catch(() => null));
|
|
218
|
+
return parsed?.data?.keep === false ? 'stop' : 'ok';
|
|
219
|
+
}
|
|
220
|
+
return 'retry';
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=canvas-terminal.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-terminal.service.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-terminal.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAwB,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,CAAC,GAAG,gBAAgB,CAAC;AA2C3B,sEAAsE;AACtE,MAAM,OAAO,qBAAqB;IAQJ;IAPZ,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,MAAM,CAAkB;IACxB,GAAG,CAAe;IAClB,SAAS,CAA0D;IACnE,QAAQ,CAAgE;IACxE,UAAU,CAA6C;IAExE,YAA6B,IAAwB;QAAxB,SAAI,GAAJ,IAAI,CAAoB;QACpD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;QACjG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ;YACZ,IAAI,CAAC,UAAU;gBACf,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;oBACX,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBAC7B,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;oBACZ,OAAO,CAAC,CAAC;gBACV,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,+BAA+B;IAC/B,MAAM;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAe;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;QAC/G,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACd,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,iBAAiB,CAAC;YACvD,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YAC3B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACrB,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,oBAAoB;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;QAChG,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAW,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACrK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACzB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAe;QACpB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QACrB,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,iBAAiB,CAAC;QAChD,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAe,EAAE,SAA+C,QAAQ;QAC7E,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC,KAAK;YAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC;QACf,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;IAED,oCAAoC;IACpC,QAAQ;QACP,KAAK,MAAM,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC/E,CAAC;IAEO,QAAQ,CAAC,CAAS,EAAE,OAAe;QAC1C,IAAI,CAAC,CAAC,KAAK;YAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;YAC5B,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC;YACf,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC,EAAE,OAAO,CAAC,CAAC;IACb,CAAC;IAED,6FAA6F;IACrF,KAAK,CAAC,IAAI,CAAC,CAAS;QAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO;QACxD,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;QACd,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,IAAI,GAAG,GAAG,CAAC,CAAC,UAAU;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YACtE,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,sBAAsB;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAC3F,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAC/E,IAAI,GAAG,GAAkB,IAAI,CAAC;YAC9B,IAAI,CAAC;gBACJ,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC;YAC3D,CAAC;YAAC,MAAM,CAAC;gBACR,GAAG,GAAG,IAAI,CAAC;YACZ,CAAC;YACD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBAClB,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;oBAClC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;oBACjD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;wBAAE,OAAO;oBAC9C,IAAI,OAAO,KAAK,MAAM;wBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;oBACtE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;wBACtB,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;wBAChB,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC;wBAChB,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;oBAChB,CAAC;yBAAM,CAAC;wBACP,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC;wBAChB,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,qBAAqB;4BAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;oBACxF,CAAC;gBACF,CAAC;YACF,CAAC;YACD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,0BAA0B,CAAC,CAAC;QACvF,CAAC;gBAAS,CAAC;YACV,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;QAChB,CAAC;IACF,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,IAAI,CAAC,CAAS,EAAE,KAAe,EAAE,MAAe,EAAE,MAAgC;QAC/F,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAC;QACpC,MAAM,UAAU,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC;QAC3D,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACX,MAAM,KAAK,GAAkB;YAC5B,UAAU;YACV,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,EAAE,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE;YACtC,KAAK;YACL,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE,CAAC;QACF,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YACjD,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACJ,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,mBAAmB,EAAE,EAAE;oBACrF,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACR,aAAa,EAAE,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,KAAK,EAAE;wBAC9D,cAAc,EAAE,kBAAkB;wBAClC,kBAAkB,EAAE,MAAM;wBAC1B,CAAC,eAAe,CAAC,eAAe,CAAC,EAAE,UAAU;qBAC7C;oBACD,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;oBAClD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC;iBACjD,CAAC,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,OAAO,CAAC;YAChB,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC9E,SAAS,GAAG,IAAI,CAAC;gBACjB,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;oBAAE,SAAS;YAC1E,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,MAAM,CAAC;YACjG,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,OAAO,OAAO,CAAC;YACjC,IAAI,MAAM;gBAAE,OAAO,IAAI,CAAC;YACxB,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAyC,CAAC;YACjG,OAAO,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACrD,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD"}
|