crewly 1.20.305 → 1.20.307

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 (111) hide show
  1. package/config/hooks/agent-status/report.sh +39 -1
  2. package/dist/backend/backend/src/constants.d.ts +54 -0
  3. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  4. package/dist/backend/backend/src/constants.js +54 -0
  5. package/dist/backend/backend/src/constants.js.map +1 -1
  6. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts +2 -1
  7. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts.map +1 -1
  8. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js +18 -1
  9. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js.map +1 -1
  10. package/dist/backend/backend/src/controllers/board/board.controller.d.ts +23 -0
  11. package/dist/backend/backend/src/controllers/board/board.controller.d.ts.map +1 -0
  12. package/dist/backend/backend/src/controllers/board/board.controller.js +48 -0
  13. package/dist/backend/backend/src/controllers/board/board.controller.js.map +1 -0
  14. package/dist/backend/backend/src/controllers/board/board.routes.d.ts +15 -0
  15. package/dist/backend/backend/src/controllers/board/board.routes.d.ts.map +1 -0
  16. package/dist/backend/backend/src/controllers/board/board.routes.js +21 -0
  17. package/dist/backend/backend/src/controllers/board/board.routes.js.map +1 -0
  18. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  19. package/dist/backend/backend/src/controllers/browser/browser.controller.js +2 -0
  20. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  21. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  22. package/dist/backend/backend/src/controllers/chat/chat.controller.js +5 -0
  23. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  24. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  25. package/dist/backend/backend/src/controllers/slack/slack.controller.js +3 -0
  26. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  27. package/dist/backend/backend/src/index.d.ts +9 -0
  28. package/dist/backend/backend/src/index.d.ts.map +1 -1
  29. package/dist/backend/backend/src/index.js +46 -0
  30. package/dist/backend/backend/src/index.js.map +1 -1
  31. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  32. package/dist/backend/backend/src/routes/api.routes.js +3 -0
  33. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  34. package/dist/backend/backend/src/services/board/board-activity.normalizer.d.ts +85 -0
  35. package/dist/backend/backend/src/services/board/board-activity.normalizer.d.ts.map +1 -0
  36. package/dist/backend/backend/src/services/board/board-activity.normalizer.js +241 -0
  37. package/dist/backend/backend/src/services/board/board-activity.normalizer.js.map +1 -0
  38. package/dist/backend/backend/src/services/board/board-activity.tracker.d.ts +154 -0
  39. package/dist/backend/backend/src/services/board/board-activity.tracker.d.ts.map +1 -0
  40. package/dist/backend/backend/src/services/board/board-activity.tracker.js +322 -0
  41. package/dist/backend/backend/src/services/board/board-activity.tracker.js.map +1 -0
  42. package/dist/backend/backend/src/services/board/board-outcome-phrases.d.ts +43 -0
  43. package/dist/backend/backend/src/services/board/board-outcome-phrases.d.ts.map +1 -0
  44. package/dist/backend/backend/src/services/board/board-outcome-phrases.js +76 -0
  45. package/dist/backend/backend/src/services/board/board-outcome-phrases.js.map +1 -0
  46. package/dist/backend/backend/src/services/board/board-push.service.d.ts +114 -0
  47. package/dist/backend/backend/src/services/board/board-push.service.d.ts.map +1 -0
  48. package/dist/backend/backend/src/services/board/board-push.service.js +312 -0
  49. package/dist/backend/backend/src/services/board/board-push.service.js.map +1 -0
  50. package/dist/backend/backend/src/services/board/board-redact.d.ts +90 -0
  51. package/dist/backend/backend/src/services/board/board-redact.d.ts.map +1 -0
  52. package/dist/backend/backend/src/services/board/board-redact.js +359 -0
  53. package/dist/backend/backend/src/services/board/board-redact.js.map +1 -0
  54. package/dist/backend/backend/src/services/board/board-snapshot.builder.d.ts +176 -0
  55. package/dist/backend/backend/src/services/board/board-snapshot.builder.d.ts.map +1 -0
  56. package/dist/backend/backend/src/services/board/board-snapshot.builder.js +342 -0
  57. package/dist/backend/backend/src/services/board/board-snapshot.builder.js.map +1 -0
  58. package/dist/backend/backend/src/services/board/board-usage.d.ts +20 -0
  59. package/dist/backend/backend/src/services/board/board-usage.d.ts.map +1 -0
  60. package/dist/backend/backend/src/services/board/board-usage.js +82 -0
  61. package/dist/backend/backend/src/services/board/board-usage.js.map +1 -0
  62. package/dist/backend/backend/src/services/board/board.service.d.ts +60 -0
  63. package/dist/backend/backend/src/services/board/board.service.d.ts.map +1 -0
  64. package/dist/backend/backend/src/services/board/board.service.js +82 -0
  65. package/dist/backend/backend/src/services/board/board.service.js.map +1 -0
  66. package/dist/backend/backend/src/services/board/board.sources.d.ts +25 -0
  67. package/dist/backend/backend/src/services/board/board.sources.d.ts.map +1 -0
  68. package/dist/backend/backend/src/services/board/board.sources.js +293 -0
  69. package/dist/backend/backend/src/services/board/board.sources.js.map +1 -0
  70. package/dist/backend/backend/src/services/board/board.types.d.ts +117 -0
  71. package/dist/backend/backend/src/services/board/board.types.d.ts.map +1 -0
  72. package/dist/backend/backend/src/services/board/board.types.js +8 -0
  73. package/dist/backend/backend/src/services/board/board.types.js.map +1 -0
  74. package/dist/backend/backend/src/services/google/google-reauth-notifier.service.d.ts +13 -0
  75. package/dist/backend/backend/src/services/google/google-reauth-notifier.service.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/google/google-reauth-notifier.service.js +15 -0
  77. package/dist/backend/backend/src/services/google/google-reauth-notifier.service.js.map +1 -1
  78. package/dist/backend/backend/src/services/runtime-fallback/runtime-availability.js +2 -2
  79. package/dist/backend/backend/src/services/runtime-fallback/runtime-availability.js.map +1 -1
  80. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.d.ts +9 -0
  81. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.d.ts.map +1 -1
  82. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.js +61 -5
  83. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.js.map +1 -1
  84. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts +2 -0
  85. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts.map +1 -1
  86. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.types.js.map +1 -1
  87. package/dist/backend/backend/src/services/team-move/team-move-cloud.client.d.ts +6 -0
  88. package/dist/backend/backend/src/services/team-move/team-move-cloud.client.d.ts.map +1 -1
  89. package/dist/backend/backend/src/services/team-move/team-move-cloud.client.js +22 -1
  90. package/dist/backend/backend/src/services/team-move/team-move-cloud.client.js.map +1 -1
  91. package/dist/backend/backend/src/services/team-move/team-move-driver.service.js +1 -1
  92. package/dist/backend/backend/src/services/team-move/team-move-driver.service.js.map +1 -1
  93. package/dist/backend/backend/src/services/team-move/team-move-importer.d.ts +15 -1
  94. package/dist/backend/backend/src/services/team-move/team-move-importer.d.ts.map +1 -1
  95. package/dist/backend/backend/src/services/team-move/team-move-importer.js +38 -4
  96. package/dist/backend/backend/src/services/team-move/team-move-importer.js.map +1 -1
  97. package/dist/backend/backend/src/services/team-move/team-move-runtime.d.ts.map +1 -1
  98. package/dist/backend/backend/src/services/team-move/team-move-runtime.js +22 -1
  99. package/dist/backend/backend/src/services/team-move/team-move-runtime.js.map +1 -1
  100. package/dist/backend/backend/src/services/team-move/team-move.types.d.ts +19 -5
  101. package/dist/backend/backend/src/services/team-move/team-move.types.d.ts.map +1 -1
  102. package/dist/backend/backend/src/services/team-move/team-move.types.js.map +1 -1
  103. package/dist/backend/build-info.json +2 -2
  104. package/dist/cli/backend/src/constants.d.ts +54 -0
  105. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  106. package/dist/cli/backend/src/constants.js +54 -0
  107. package/dist/cli/backend/src/constants.js.map +1 -1
  108. package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts +2 -0
  109. package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts.map +1 -1
  110. package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.js.map +1 -1
  111. package/package.json +1 -1
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Live activity per agent (crewly#1247): the current activity, the last
3
+ * meaningful action and a rolling timeline, fed by hook events, browser
4
+ * actions, chat replies and owner waits. In memory only: a restart starts the
5
+ * timeline over (the agents restart with it).
6
+ *
7
+ * Event-driven: `record*` do a few map operations and tell the listeners; the
8
+ * push scheduler decides when to send. Nothing here reads files or the
9
+ * network.
10
+ *
11
+ * @module services/board/board-activity.tracker
12
+ */
13
+ import { BOARD_CONSTANTS } from '../../constants.js';
14
+ import { normalizeBrowserAction, normalizeMessage, normalizeOwnerWait, normalizeToolUse, THINKING, } from './board-activity.normalizer.js';
15
+ const C = BOARD_CONSTANTS;
16
+ /**
17
+ * Per-session board activity.
18
+ */
19
+ export class BoardActivityTracker {
20
+ static instance = null;
21
+ sessions = new Map();
22
+ listeners = new Set();
23
+ /** Project roots by session, for relative paths */
24
+ rootsOf = () => [];
25
+ /** @returns The process-wide tracker */
26
+ static getInstance() {
27
+ if (!BoardActivityTracker.instance)
28
+ BoardActivityTracker.instance = new BoardActivityTracker();
29
+ return BoardActivityTracker.instance;
30
+ }
31
+ /** Drop the process-wide tracker (tests). */
32
+ static resetInstance() {
33
+ BoardActivityTracker.instance = null;
34
+ }
35
+ /**
36
+ * Where an agent's project roots come from.
37
+ *
38
+ * @param fn - Session -> project roots
39
+ */
40
+ setRootsResolver(fn) {
41
+ this.rootsOf = fn;
42
+ }
43
+ /**
44
+ * Subscribe to changes.
45
+ *
46
+ * @param listener - Called with the session whose row may have changed
47
+ * @returns Unsubscribe
48
+ */
49
+ onChange(listener) {
50
+ this.listeners.add(listener);
51
+ return () => this.listeners.delete(listener);
52
+ }
53
+ emit(session) {
54
+ for (const l of this.listeners) {
55
+ try {
56
+ l(session);
57
+ }
58
+ catch {
59
+ // a listener must never break a hook
60
+ }
61
+ }
62
+ }
63
+ get(session) {
64
+ let s = this.sessions.get(session);
65
+ if (!s) {
66
+ s = { open: new Map(), current: null, last: null, ownerWait: null, timeline: [], unsent: [], seq: 0 };
67
+ this.sessions.set(session, s);
68
+ }
69
+ return s;
70
+ }
71
+ /**
72
+ * A hook event arrived. PreToolUse starts an activity; PostToolUse ends
73
+ * it; UserPromptSubmit / Stop / SessionStart reset the turn; a permission
74
+ * prompt or question is a wait on the owner.
75
+ *
76
+ * @param session - Agent session
77
+ * @param event - Hook event name
78
+ * @param info - Tool details (PreToolUse / PostToolUse) and the notification type
79
+ * @param now - Clock (tests)
80
+ */
81
+ recordHook(session, event, info = {}, now = Date.now()) {
82
+ const s = this.get(session);
83
+ switch (event) {
84
+ case 'PreToolUse': {
85
+ if (!info.toolName)
86
+ return;
87
+ const roots = this.safeRoots(session);
88
+ const activity = normalizeToolUse(info.toolName, info.toolInput ?? {}, { roots });
89
+ s.open.set(info.toolUseId ?? `anon-${(s.seq += 1)}`, now);
90
+ s.ownerWait = null;
91
+ this.show(session, s, activity, now);
92
+ return;
93
+ }
94
+ case 'PostToolUse': {
95
+ if (info.toolUseId)
96
+ s.open.delete(info.toolUseId);
97
+ else if (s.open.size > 0)
98
+ s.open.delete(s.open.keys().next().value);
99
+ if (s.current)
100
+ s.current.lastEventAt = now;
101
+ s.ownerWait = null;
102
+ return;
103
+ }
104
+ case 'UserPromptSubmit':
105
+ case 'SessionStart':
106
+ s.open.clear();
107
+ s.ownerWait = null;
108
+ s.current = { activity: THINKING, since: now, lastEventAt: now };
109
+ this.emit(session);
110
+ return;
111
+ case 'Stop':
112
+ s.open.clear();
113
+ s.ownerWait = null;
114
+ s.current = null;
115
+ this.emit(session);
116
+ return;
117
+ case 'Notification':
118
+ case 'PermissionRequest':
119
+ if (event === 'PermissionRequest' || info.notificationType === 'permission_prompt') {
120
+ this.setOwnerWait(session, 'permission to continue', now);
121
+ }
122
+ else if (info.notificationType === 'elicitation_dialog') {
123
+ this.setOwnerWait(session, 'an answer to its question', now);
124
+ }
125
+ return;
126
+ default:
127
+ return;
128
+ }
129
+ }
130
+ /**
131
+ * An agent action in Chrome.
132
+ *
133
+ * @param session - Agent session
134
+ * @param tool - Extension tool name
135
+ * @param url - Page URL, if known
136
+ * @param now - Clock (tests)
137
+ */
138
+ recordBrowser(session, tool, url, now = Date.now()) {
139
+ const s = this.get(session);
140
+ this.show(session, s, normalizeBrowserAction(tool, url), now);
141
+ }
142
+ /**
143
+ * An agent posted to a channel or the owner chat.
144
+ *
145
+ * @param session - Agent session
146
+ * @param channel - Channel or chat name
147
+ * @param now - Clock (tests)
148
+ */
149
+ recordMessage(session, channel, now = Date.now()) {
150
+ const s = this.get(session);
151
+ this.show(session, s, normalizeMessage(channel), now);
152
+ }
153
+ /**
154
+ * An agent waits on the owner.
155
+ *
156
+ * @param session - Agent session
157
+ * @param what - Short plain-words description
158
+ * @param now - Clock (tests)
159
+ */
160
+ setOwnerWait(session, what, now = Date.now()) {
161
+ const s = this.get(session);
162
+ if (s.ownerWait)
163
+ return;
164
+ const activity = normalizeOwnerWait(what);
165
+ s.ownerWait = { activity, since: now };
166
+ this.pushTimeline(s, session, activity, now);
167
+ this.emit(session);
168
+ }
169
+ /**
170
+ * The wait is over.
171
+ *
172
+ * @param session - Agent session
173
+ */
174
+ clearOwnerWait(session) {
175
+ const s = this.sessions.get(session);
176
+ if (!s?.ownerWait)
177
+ return;
178
+ s.ownerWait = null;
179
+ this.emit(session);
180
+ }
181
+ /** Make `activity` current and the last action; notify when the row changed. */
182
+ show(session, s, activity, now) {
183
+ const prev = s.current;
184
+ const same = prev !== null && prev.activity.type === activity.type && prev.activity.detail === activity.detail;
185
+ s.current = { activity, since: same && prev ? prev.since : now, lastEventAt: now };
186
+ if (activity.type !== 'thinking') {
187
+ const changedText = s.last?.text !== activity.text;
188
+ s.last = { text: activity.text, at: now };
189
+ this.pushTimeline(s, session, activity, now);
190
+ if (!same || changedText)
191
+ this.emit(session);
192
+ }
193
+ else if (!same) {
194
+ this.emit(session);
195
+ }
196
+ }
197
+ pushTimeline(s, session, activity, now) {
198
+ const tail = s.timeline[s.timeline.length - 1];
199
+ // The same line twice within 10 s is one event (a tool called in a loop)
200
+ if (tail && tail.text === activity.text && now - Date.parse(tail.at) < 10_000)
201
+ return;
202
+ const event = { session, at: new Date(now).toISOString(), type: activity.type, text: activity.text };
203
+ s.timeline.push(event);
204
+ s.unsent.push(event);
205
+ if (s.timeline.length > C.TIMELINE_MAX_EVENTS)
206
+ s.timeline.splice(0, s.timeline.length - C.TIMELINE_MAX_EVENTS);
207
+ if (s.unsent.length > C.TIMELINE_MAX_EVENTS)
208
+ s.unsent.splice(0, s.unsent.length - C.TIMELINE_MAX_EVENTS);
209
+ }
210
+ safeRoots(session) {
211
+ try {
212
+ return this.rootsOf(session);
213
+ }
214
+ catch {
215
+ return [];
216
+ }
217
+ }
218
+ /**
219
+ * What the session shows now. While a tool runs it is that tool; for
220
+ * {@link BOARD_CONSTANTS.ACTIVITY_LINGER_MS} after it, the same; then
221
+ * "thinking" (when `working`), else nothing.
222
+ *
223
+ * @param session - Agent session
224
+ * @param working - The runtime says the agent is in a turn
225
+ * @param now - Clock (tests)
226
+ * @returns Activity and last action
227
+ */
228
+ live(session, working, now = Date.now()) {
229
+ const s = this.sessions.get(session);
230
+ if (!s)
231
+ return { activity: working ? { type: 'thinking', detail: THINKING.detail, since: new Date(now).toISOString() } : null, lastAction: null };
232
+ const lastAction = s.last ? { text: s.last.text, at: new Date(s.last.at).toISOString() } : null;
233
+ if (s.ownerWait) {
234
+ return { activity: { type: s.ownerWait.activity.type, detail: s.ownerWait.activity.detail, since: new Date(s.ownerWait.since).toISOString() }, lastAction };
235
+ }
236
+ // A lost PostToolUse must not pin a tool forever
237
+ for (const [id, at] of s.open)
238
+ if (now - at > C.OPEN_TOOL_MAX_MS)
239
+ s.open.delete(id);
240
+ const cur = s.current;
241
+ if (!working && s.open.size === 0)
242
+ return { activity: null, lastAction };
243
+ if (cur && (s.open.size > 0 || now - cur.lastEventAt <= C.ACTIVITY_LINGER_MS || cur.activity.type === 'thinking')) {
244
+ return { activity: { type: cur.activity.type, detail: cur.activity.detail, since: new Date(cur.since).toISOString() }, lastAction };
245
+ }
246
+ if (working) {
247
+ const since = cur ? cur.lastEventAt + C.ACTIVITY_LINGER_MS : now;
248
+ return { activity: { type: 'thinking', detail: THINKING.detail, since: new Date(Math.min(since, now)).toISOString() }, lastAction };
249
+ }
250
+ return { activity: null, lastAction };
251
+ }
252
+ /**
253
+ * Timeline events not sent yet. Call {@link ackUnsent} once Cloud took them;
254
+ * until then they stay queued (capped), so a failed push loses nothing.
255
+ *
256
+ * @param sessions - Only these sessions (all when omitted)
257
+ * @returns Events, oldest first, at most {@link BOARD_CONSTANTS.DELTA_TIMELINE_MAX} per session
258
+ */
259
+ peekUnsent(sessions) {
260
+ const out = [];
261
+ const keys = sessions ? [...sessions] : [...this.sessions.keys()];
262
+ for (const key of keys) {
263
+ const s = this.sessions.get(key);
264
+ if (!s || s.unsent.length === 0)
265
+ continue;
266
+ out.push(...s.unsent.slice(-C.DELTA_TIMELINE_MAX));
267
+ }
268
+ return out.sort((a, b) => Date.parse(a.at) - Date.parse(b.at));
269
+ }
270
+ /**
271
+ * Mark events as sent (everything unsent up to the newest of them is
272
+ * dropped, including older ones cut by the per-delta limit).
273
+ *
274
+ * @param events - Events returned by {@link peekUnsent} that Cloud took
275
+ */
276
+ ackUnsent(events) {
277
+ const newest = new Map();
278
+ for (const e of events)
279
+ newest.set(e.session, Math.max(newest.get(e.session) ?? 0, Date.parse(e.at)));
280
+ for (const [session, at] of newest) {
281
+ const s = this.sessions.get(session);
282
+ if (s)
283
+ s.unsent = s.unsent.filter((e) => Date.parse(e.at) > at);
284
+ }
285
+ }
286
+ /** Sessions with timeline events not yet sent. */
287
+ sessionsWithUnsent() {
288
+ return [...this.sessions.entries()].filter(([, s]) => s.unsent.length > 0).map(([k]) => k);
289
+ }
290
+ /**
291
+ * A session's recent timeline (24 h, newest last).
292
+ *
293
+ * @param session - Agent session
294
+ * @param now - Clock (tests)
295
+ * @returns Events
296
+ */
297
+ timeline(session, now = Date.now()) {
298
+ const s = this.sessions.get(session);
299
+ if (!s)
300
+ return [];
301
+ const cutoff = now - C.TIMELINE_MAX_AGE_MS;
302
+ s.timeline = s.timeline.filter((e) => Date.parse(e.at) >= cutoff);
303
+ return [...s.timeline];
304
+ }
305
+ /**
306
+ * Forget a session (it was deleted).
307
+ *
308
+ * @param session - Agent session
309
+ */
310
+ forget(session) {
311
+ this.sessions.delete(session);
312
+ }
313
+ }
314
+ /**
315
+ * The process-wide tracker.
316
+ *
317
+ * @returns The tracker
318
+ */
319
+ export function getBoardActivity() {
320
+ return BoardActivityTracker.getInstance();
321
+ }
322
+ //# sourceMappingURL=board-activity.tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-activity.tracker.js","sourceRoot":"","sources":["../../../../../../backend/src/services/board/board-activity.tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Result phrases for the "Done today" strip (crewly#1247): a finished
3
+ * ticket or WorkItem is described by what it produced ("post published"),
4
+ * and equal results are counted ("2 posts published"). Deterministic keyword
5
+ * rules over the title and kind; no model call.
6
+ *
7
+ * Pure (no I/O).
8
+ *
9
+ * @module services/board/board-outcome-phrases
10
+ */
11
+ /** One kind of result. */
12
+ interface ResultRule {
13
+ /** Matches the title (and kind label) */
14
+ pattern: RegExp;
15
+ one: string;
16
+ many: string;
17
+ }
18
+ /**
19
+ * The rule describing a finished item.
20
+ *
21
+ * @param title - Item title
22
+ * @param kind - Ticket kind (`issue`, `feature`, ...), when known
23
+ * @returns A rule (a generic one when no keyword matches)
24
+ */
25
+ export declare function ruleFor(title: string, kind?: string): ResultRule;
26
+ /**
27
+ * The result of one finished item, in singular ("post published").
28
+ *
29
+ * @param title - Item title
30
+ * @param kind - Ticket kind, when known
31
+ * @returns Result phrase
32
+ */
33
+ export declare function resultOf(title: string, kind?: string): string;
34
+ /**
35
+ * Count equal results: ["post published","post published","bug fixed"] ->
36
+ * ["2 posts published", "1 bug fixed"], most frequent first.
37
+ *
38
+ * @param results - Singular result phrases
39
+ * @returns Summary phrases (at most {@link BOARD_CONSTANTS.MAX_SUMMARY_PHRASES})
40
+ */
41
+ export declare function summarizeResults(results: readonly string[]): string[];
42
+ export {};
43
+ //# sourceMappingURL=board-outcome-phrases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-outcome-phrases.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/board/board-outcome-phrases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,0BAA0B;AAC1B,UAAU,UAAU;IACnB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACb;AAyBD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAIhE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CASrE"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Result phrases for the "Done today" strip (crewly#1247): a finished
3
+ * ticket or WorkItem is described by what it produced ("post published"),
4
+ * and equal results are counted ("2 posts published"). Deterministic keyword
5
+ * rules over the title and kind; no model call.
6
+ *
7
+ * Pure (no I/O).
8
+ *
9
+ * @module services/board/board-outcome-phrases
10
+ */
11
+ import { BOARD_CONSTANTS } from '../../constants.js';
12
+ const RULES = [
13
+ { pattern: /\b(?:posts?|tweets?|threads?|linkedin|newsletter|publish(?:ed|ing)?|announce(?:ment)?s?|social)\b/i, one: 'post published', many: 'posts published' },
14
+ { pattern: /\b(?:customers?|clients?|support|inquir(?:y|ies)|repl(?:y|ies|ied)|dms?)\b/i, one: 'customer answered', many: 'customers answered' },
15
+ { pattern: /\b(?:bugs?|fix(?:es|ed)?|hotfix|regression|crash|broken)\b/i, one: 'bug fixed', many: 'bugs fixed' },
16
+ { pattern: /\b(?:releases?|deploy(?:ed|ment)?|ship(?:ped)?|rollout|launch)\b/i, one: 'release shipped', many: 'releases shipped' },
17
+ { pattern: /\b(?:pull request|pr #?\d+|merge[ds]?)\b/i, one: 'change merged', many: 'changes merged' },
18
+ { pattern: /\b(?:reports?|summary|digest|analysis|research|audit|review(?:ed)?|survey)\b/i, one: 'report delivered', many: 'reports delivered' },
19
+ { pattern: /\b(?:videos?|designs?|images?|banners?|graphics?|canva|thumbnails?|logo)\b/i, one: 'design created', many: 'designs created' },
20
+ { pattern: /\b(?:docs?|documents?|articles?|blog|write-?ups?|specs?|guides?|sop|copy|draft)\b/i, one: 'document written', many: 'documents written' },
21
+ { pattern: /\b(?:tests?|ci|lint|refactor|cleanup|chore|migrat(?:e|ion))\b/i, one: 'chore finished', many: 'chores finished' },
22
+ { pattern: /\b(?:features?|implement(?:ed)?|add(?:ed)?|build|built|page|app)\b/i, one: 'feature built', many: 'features built' },
23
+ ];
24
+ /** Kind of a finished item, from its ticket kind when it has one. */
25
+ const KIND_FALLBACK = {
26
+ issue: { pattern: /./, one: 'issue resolved', many: 'issues resolved' },
27
+ feature: { pattern: /./, one: 'feature built', many: 'features built' },
28
+ idea: { pattern: /./, one: 'idea explored', many: 'ideas explored' },
29
+ question: { pattern: /./, one: 'question answered', many: 'questions answered' },
30
+ };
31
+ const GENERIC = { pattern: /./, one: 'task done', many: 'tasks done' };
32
+ /**
33
+ * The rule describing a finished item.
34
+ *
35
+ * @param title - Item title
36
+ * @param kind - Ticket kind (`issue`, `feature`, ...), when known
37
+ * @returns A rule (a generic one when no keyword matches)
38
+ */
39
+ export function ruleFor(title, kind) {
40
+ for (const rule of RULES)
41
+ if (rule.pattern.test(title))
42
+ return rule;
43
+ if (kind && KIND_FALLBACK[kind])
44
+ return KIND_FALLBACK[kind];
45
+ return GENERIC;
46
+ }
47
+ /**
48
+ * The result of one finished item, in singular ("post published").
49
+ *
50
+ * @param title - Item title
51
+ * @param kind - Ticket kind, when known
52
+ * @returns Result phrase
53
+ */
54
+ export function resultOf(title, kind) {
55
+ return ruleFor(title, kind).one;
56
+ }
57
+ /**
58
+ * Count equal results: ["post published","post published","bug fixed"] ->
59
+ * ["2 posts published", "1 bug fixed"], most frequent first.
60
+ *
61
+ * @param results - Singular result phrases
62
+ * @returns Summary phrases (at most {@link BOARD_CONSTANTS.MAX_SUMMARY_PHRASES})
63
+ */
64
+ export function summarizeResults(results) {
65
+ const counts = new Map();
66
+ for (const r of results)
67
+ counts.set(r, (counts.get(r) ?? 0) + 1);
68
+ const byOne = new Map();
69
+ for (const rule of [...RULES, ...Object.values(KIND_FALLBACK), GENERIC])
70
+ byOne.set(rule.one, rule);
71
+ return [...counts.entries()]
72
+ .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
73
+ .slice(0, BOARD_CONSTANTS.MAX_SUMMARY_PHRASES)
74
+ .map(([one, n]) => `${n} ${n === 1 ? one : (byOne.get(one)?.many ?? one)}`);
75
+ }
76
+ //# sourceMappingURL=board-outcome-phrases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-outcome-phrases.js","sourceRoot":"","sources":["../../../../../../backend/src/services/board/board-outcome-phrases.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Pushes the owner board to Crewly Cloud (crewly#1247).
3
+ *
4
+ * - a full snapshot every 60 s (Cloud may ask for another cadence);
5
+ * - a delta (only the agent rows that changed, plus new timeline events)
6
+ * within {@link BOARD_CONSTANTS.DELTA_DELAY_MS} of an activity change;
7
+ * - gzip bodies, exponential backoff on failure, an hour's pause when Cloud
8
+ * does not take board pushes (not deployed / refusing);
9
+ * - nothing is sent when the machine is not signed in to Cloud, or when
10
+ * `CREWLY_BOARD_PUSH=0`.
11
+ *
12
+ * Event-driven: a change only marks a session dirty and arms one timer; the
13
+ * delta is built from the builder's cache and the live tracker, never from a
14
+ * disk scan.
15
+ *
16
+ * @module services/board/board-push.service
17
+ */
18
+ import { type ComponentLogger } from '../core/logger.service.js';
19
+ import type { BoardActivityTracker } from './board-activity.tracker.js';
20
+ import type { BoardSnapshotBuilder } from './board-snapshot.builder.js';
21
+ import type { BoardSnapshot } from './board.types.js';
22
+ /** The Cloud session (CloudClientService). */
23
+ export interface BoardCloudSession {
24
+ getToken(): string | null;
25
+ getCloudUrl(): string | null;
26
+ tryRefreshToken?(): Promise<boolean>;
27
+ }
28
+ /** Constructor dependencies. */
29
+ export interface BoardPushDeps {
30
+ builder: BoardSnapshotBuilder;
31
+ tracker: BoardActivityTracker;
32
+ cloud: BoardCloudSession;
33
+ env?: NodeJS.ProcessEnv;
34
+ fetchImpl?: (input: string, init: RequestInit) => Promise<Response>;
35
+ now?: () => number;
36
+ setTimeout?: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;
37
+ clearTimeout?: (handle: ReturnType<typeof setTimeout>) => void;
38
+ logger?: ComponentLogger;
39
+ }
40
+ /** What one push did. */
41
+ export type BoardPushOutcome = 'sent' | 'nothing' | 'skipped' | 'paused' | 'failed';
42
+ /**
43
+ * Whether the board push is switched off.
44
+ *
45
+ * @param env - Environment
46
+ * @returns True for `CREWLY_BOARD_PUSH=0` (also `false` / `off`)
47
+ */
48
+ export declare function isBoardPushDisabled(env?: NodeJS.ProcessEnv): boolean;
49
+ /**
50
+ * Shrink a snapshot until its JSON fits the body limit: the longest list
51
+ * loses its tail first.
52
+ *
53
+ * @param snapshot - Snapshot (mutated)
54
+ * @returns The same snapshot
55
+ */
56
+ export declare function fitSnapshot(snapshot: BoardSnapshot): BoardSnapshot;
57
+ /** Pushes snapshots and deltas. */
58
+ export declare class BoardPushService {
59
+ private readonly deps;
60
+ private readonly logger;
61
+ private readonly fetchImpl;
62
+ private readonly now;
63
+ private readonly setTimer;
64
+ private readonly clearTimer;
65
+ private started;
66
+ private fullTimer;
67
+ private deltaTimer;
68
+ private unsubscribe;
69
+ private readonly dirty;
70
+ /** Rows Cloud has, as JSON, by session */
71
+ private readonly lastSent;
72
+ private lastToken;
73
+ private fullOk;
74
+ private fullAfterMs;
75
+ private failures;
76
+ private pausedUntil;
77
+ private pauseLogged;
78
+ private inFlight;
79
+ constructor(deps: BoardPushDeps);
80
+ /** Whether the push is switched off in the environment. */
81
+ get disabled(): boolean;
82
+ /** Start pushing. Idempotent; a no-op when switched off. Never throws. */
83
+ start(): void;
84
+ /** Stop timers and the subscription. */
85
+ stop(): void;
86
+ /**
87
+ * A session's row may have changed: send a delta soon.
88
+ *
89
+ * @param session - Agent session
90
+ */
91
+ markDirty(session: string): void;
92
+ private scheduleFull;
93
+ private nextFullDelay;
94
+ /** The Cloud endpoint and token, or null when the machine is not signed in or a pause is on. */
95
+ private target;
96
+ /**
97
+ * Build and send the full snapshot, then any timeline events that are
98
+ * waiting. Serialised with deltas. Never throws.
99
+ *
100
+ * @returns What happened
101
+ */
102
+ pushFull(): Promise<BoardPushOutcome>;
103
+ private doFull;
104
+ /**
105
+ * Send a delta for the sessions marked dirty. Serialised with full pushes.
106
+ * Never throws.
107
+ *
108
+ * @returns What happened
109
+ */
110
+ flushDelta(): Promise<BoardPushOutcome>;
111
+ private doDelta;
112
+ private post;
113
+ }
114
+ //# sourceMappingURL=board-push.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-push.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/board/board-push.service.ts"],"names":[],"mappings":"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"}