crewly 1.20.209 → 1.20.211
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/app-data/SKILL.md +117 -0
- package/config/skills/agent/core/app-data/execute.sh +141 -0
- package/config/skills/agent/core/app-data/execute.test.sh +108 -0
- package/config/skills/agent/core/publish-app/SKILL.md +248 -0
- package/config/skills/agent/core/publish-app/execute.sh +302 -0
- package/config/skills/agent/core/publish-app/execute.test.sh +205 -0
- package/dist/backend/backend/src/constants.d.ts +115 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +115 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +55 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.js +131 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +53 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.js +108 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +57 -5
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/body-parser-except.d.ts +25 -0
- package/dist/backend/backend/src/middleware/body-parser-except.d.ts.map +1 -0
- package/dist/backend/backend/src/middleware/body-parser-except.js +33 -0
- package/dist/backend/backend/src/middleware/body-parser-except.js.map +1 -0
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +4 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/apps/app-open-link.d.ts +61 -0
- package/dist/backend/backend/src/services/apps/app-open-link.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-open-link.js +112 -0
- package/dist/backend/backend/src/services/apps/app-open-link.js.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.d.ts +136 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.js +253 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.js.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.d.ts +145 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.js +455 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts +74 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.js +120 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts +125 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.js +192 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.service.d.ts +466 -0
- package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.service.js +740 -0
- package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.d.ts +97 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.js +153 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -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 +3 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.d.ts +5 -0
- package/dist/backend/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.js +8 -0
- package/dist/backend/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +3 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +115 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +115 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/apps/app-open-link.d.ts +61 -0
- package/dist/cli/backend/src/services/apps/app-open-link.d.ts.map +1 -0
- package/dist/cli/backend/src/services/apps/app-open-link.js +112 -0
- package/dist/cli/backend/src/services/apps/app-open-link.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.d.ts +5 -0
- package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.js +8 -0
- package/dist/cli/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +3 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppWakeService — polls the change feed of every app this instance
|
|
3
|
+
* published and wakes the agent that published it when the owner changes
|
|
4
|
+
* something (specs/2026-10-04-crewly-apps-p2.md §5).
|
|
5
|
+
*
|
|
6
|
+
* - Every POLL_INTERVAL_MS, the apps that are due are polled with
|
|
7
|
+
* `GET changes?since=<cursor>&wait=0`, POLL_CONCURRENCY at a time, each
|
|
8
|
+
* request capped at POLL_REQUEST_TIMEOUT_MS. A failing app backs off on
|
|
9
|
+
* its own (×2 up to POLL_MAX_BACKOFF_MS); the others keep their cadence.
|
|
10
|
+
* - Only owner changes wake (data written in the app, `notify` / `ask`),
|
|
11
|
+
* plus anonymous submissions on a public app (`actor.kind === 'visitor'`,
|
|
12
|
+
* P3), which are labelled apart; every agent write — the agent's own
|
|
13
|
+
* included — is skipped.
|
|
14
|
+
* - Visitor submissions never START an agent (P3 §3): a batch holding only
|
|
15
|
+
* visitor submissions waits, pending, until the publisher is running
|
|
16
|
+
* (checked every VISITOR_WAKE.PENDING_RECHECK_MS), then is delivered. An
|
|
17
|
+
* owner change joining the batch brings back P2's behaviour (start it).
|
|
18
|
+
* - At most VISITOR_WAKE.MAX_PER_DAY visitor-triggered wakes per app per
|
|
19
|
+
* UTC day (persisted in the registry). Past it, visitor submissions are
|
|
20
|
+
* counted, not delivered; the next message delivered for the app states
|
|
21
|
+
* how many were skipped (on a new UTC day a short notice goes out even if
|
|
22
|
+
* nothing new arrived).
|
|
23
|
+
* - The first change for (app, recipient) opens a BATCH_WINDOW_MS window; a
|
|
24
|
+
* successful wake starts a COOLDOWN_MS quiet period (persisted, so it
|
|
25
|
+
* survives a restart) during which changes keep collecting.
|
|
26
|
+
* - A failed delivery keeps the batch (and the cursor before it) and is
|
|
27
|
+
* retried with backoff; after WAKE_FAILS_BEFORE_ORC_NOTICE failures the
|
|
28
|
+
* orchestrator is told once.
|
|
29
|
+
* - An `ask` reaches a named agent only when it is in the publisher's team
|
|
30
|
+
* and already running; it never starts a stopped agent.
|
|
31
|
+
*
|
|
32
|
+
* @module services/apps/app-wake.service
|
|
33
|
+
*/
|
|
34
|
+
import { CREWLY_APPS_CONSTANTS } from '../../constants.js';
|
|
35
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
36
|
+
import { AppsCloudError } from './apps-cloud.client.js';
|
|
37
|
+
import { buildAppWakeMessage, safeAppName } from './app-wake-message.js';
|
|
38
|
+
const C = CREWLY_APPS_CONSTANTS;
|
|
39
|
+
/** Recipient key for the orchestrator (never a valid session name). */
|
|
40
|
+
export const ORC_RECIPIENT = '\u0000orchestrator';
|
|
41
|
+
/**
|
|
42
|
+
* Change poller and agent waker for Crewly Apps.
|
|
43
|
+
*/
|
|
44
|
+
export class AppWakeService {
|
|
45
|
+
deps;
|
|
46
|
+
now;
|
|
47
|
+
logger;
|
|
48
|
+
timer = null;
|
|
49
|
+
running = false;
|
|
50
|
+
ticking = null;
|
|
51
|
+
batches = new Map();
|
|
52
|
+
lastWakeAt = new Map();
|
|
53
|
+
/** Highest seq read per app (the registry holds what is safe to persist) */
|
|
54
|
+
fetched = new Map();
|
|
55
|
+
/** Seqs above the safe cursor already delivered, per app */
|
|
56
|
+
delivered = new Map();
|
|
57
|
+
backoff = new Map();
|
|
58
|
+
/** Visitor-wake cap state per app (the registry holds the persisted copy) */
|
|
59
|
+
visitorWakes = new Map();
|
|
60
|
+
visitorDirty = new Set();
|
|
61
|
+
constructor(deps) {
|
|
62
|
+
this.deps = deps;
|
|
63
|
+
this.now = deps.now ?? (() => Date.now());
|
|
64
|
+
this.logger = deps.logger ?? LoggerService.getInstance().createComponentLogger('AppWake');
|
|
65
|
+
}
|
|
66
|
+
/** Start polling (first tick after one interval). */
|
|
67
|
+
start() {
|
|
68
|
+
if (this.running)
|
|
69
|
+
return;
|
|
70
|
+
this.running = true;
|
|
71
|
+
this.schedule();
|
|
72
|
+
}
|
|
73
|
+
/** Stop polling and drop timers. Unsent batches stay behind the persisted cursor and are re-read next start. */
|
|
74
|
+
stop() {
|
|
75
|
+
this.running = false;
|
|
76
|
+
if (this.timer)
|
|
77
|
+
clearTimeout(this.timer);
|
|
78
|
+
this.timer = null;
|
|
79
|
+
for (const b of this.batches.values())
|
|
80
|
+
if (b.timer)
|
|
81
|
+
clearTimeout(b.timer);
|
|
82
|
+
this.batches.clear();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Per-app backoff state (tests).
|
|
86
|
+
*
|
|
87
|
+
* @param appId - App id
|
|
88
|
+
* @returns Failures in a row and when the app is next due, or null when healthy
|
|
89
|
+
*/
|
|
90
|
+
appBackoff(appId) {
|
|
91
|
+
const b = this.backoff.get(appId);
|
|
92
|
+
return b ? { ...b } : null;
|
|
93
|
+
}
|
|
94
|
+
schedule() {
|
|
95
|
+
if (!this.running)
|
|
96
|
+
return;
|
|
97
|
+
this.timer = setTimeout(() => {
|
|
98
|
+
this.timer = null;
|
|
99
|
+
void this.tick().finally(() => this.schedule());
|
|
100
|
+
}, C.POLL_INTERVAL_MS);
|
|
101
|
+
this.timer.unref?.();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* One pass over the apps that are due. Exposed for tests and for an immediate poll.
|
|
105
|
+
*/
|
|
106
|
+
async tick() {
|
|
107
|
+
if (this.ticking)
|
|
108
|
+
return this.ticking;
|
|
109
|
+
this.ticking = this.runTick().finally(() => {
|
|
110
|
+
this.ticking = null;
|
|
111
|
+
});
|
|
112
|
+
return this.ticking;
|
|
113
|
+
}
|
|
114
|
+
async runTick() {
|
|
115
|
+
if (!this.deps.client.isAvailable())
|
|
116
|
+
return;
|
|
117
|
+
const now = this.now();
|
|
118
|
+
const due = (await this.deps.registry.list()).filter((e) => !e.deleted && (this.backoff.get(e.appId)?.nextAt ?? 0) <= now);
|
|
119
|
+
let next = 0;
|
|
120
|
+
const worker = async () => {
|
|
121
|
+
while (next < due.length) {
|
|
122
|
+
const app = due[next++];
|
|
123
|
+
await this.pollOne(app);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
await Promise.all(Array.from({ length: Math.min(C.POLL_CONCURRENCY, due.length) }, worker));
|
|
127
|
+
}
|
|
128
|
+
async pollOne(app) {
|
|
129
|
+
try {
|
|
130
|
+
await this.pollApp(app);
|
|
131
|
+
this.backoff.delete(app.appId);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (err instanceof AppsCloudError && err.status === 404) {
|
|
135
|
+
this.logger.info('App no longer exists in Crewly Cloud; stopped polling it', { appId: app.appId });
|
|
136
|
+
await this.deps.registry.markDeleted(app.appId);
|
|
137
|
+
this.backoff.delete(app.appId);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const failures = (this.backoff.get(app.appId)?.failures ?? 0) + 1;
|
|
141
|
+
const wait = Math.min(C.POLL_INTERVAL_MS * 2 ** failures, C.POLL_MAX_BACKOFF_MS);
|
|
142
|
+
this.backoff.set(app.appId, { failures, nextAt: this.now() + wait });
|
|
143
|
+
this.logger.warn('Polling app changes failed', { appId: app.appId, failures, retryInMs: wait, error: err instanceof Error ? err.message : String(err) });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
deliveredSet(app) {
|
|
147
|
+
let set = this.delivered.get(app.appId);
|
|
148
|
+
if (!set) {
|
|
149
|
+
set = new Set(app.delivered ?? []);
|
|
150
|
+
this.delivered.set(app.appId, set);
|
|
151
|
+
}
|
|
152
|
+
return set;
|
|
153
|
+
}
|
|
154
|
+
async pollApp(app) {
|
|
155
|
+
const opts = { timeoutMs: C.POLL_REQUEST_TIMEOUT_MS };
|
|
156
|
+
if (app.cursor === null || app.cursor === undefined) {
|
|
157
|
+
// Never polled: start from now, never replay history.
|
|
158
|
+
const head = await this.deps.client.request('GET', `/apps/${app.appId}/changes`, opts);
|
|
159
|
+
this.fetched.set(app.appId, head.seq);
|
|
160
|
+
await this.deps.registry.setProgress(app.appId, head.seq, []);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const done = this.deliveredSet(app);
|
|
164
|
+
this.maybeOpenSkippedNotice(app);
|
|
165
|
+
let since = Math.max(app.cursor, this.fetched.get(app.appId) ?? app.cursor);
|
|
166
|
+
for (let page = 0; page < C.POLL_MAX_PAGES; page++) {
|
|
167
|
+
const res = await this.deps.client.request('GET', `/apps/${app.appId}/changes`, { ...opts, query: { since, wait: 0 } });
|
|
168
|
+
const changes = Array.isArray(res.changes) ? res.changes : [];
|
|
169
|
+
for (const change of changes) {
|
|
170
|
+
if (typeof change.seq === 'number' && change.seq > since && !done.has(change.seq))
|
|
171
|
+
await this.handle(app, change);
|
|
172
|
+
}
|
|
173
|
+
since = Math.max(since, typeof res.seq === 'number' ? res.seq : since);
|
|
174
|
+
this.fetched.set(app.appId, since);
|
|
175
|
+
if (changes.length < C.CHANGES_PAGE)
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
await this.persistProgress(app.appId);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Persist the safe cursor — before the first change of any unsent batch
|
|
182
|
+
* for the app — plus the seqs above it that were already delivered, so a
|
|
183
|
+
* restart neither loses a pending batch nor repeats a delivered one.
|
|
184
|
+
*/
|
|
185
|
+
async persistProgress(appId) {
|
|
186
|
+
const fetched = this.fetched.get(appId);
|
|
187
|
+
if (fetched === undefined)
|
|
188
|
+
return;
|
|
189
|
+
let safe = fetched;
|
|
190
|
+
for (const b of this.batches.values()) {
|
|
191
|
+
if (b.appId === appId)
|
|
192
|
+
safe = Math.min(safe, b.firstSeq - 1);
|
|
193
|
+
}
|
|
194
|
+
const set = this.delivered.get(appId) ?? new Set();
|
|
195
|
+
for (const seq of set)
|
|
196
|
+
if (seq <= safe)
|
|
197
|
+
set.delete(seq);
|
|
198
|
+
while (set.size > C.MAX_DELIVERED_SEQS)
|
|
199
|
+
set.delete(Math.min(...set));
|
|
200
|
+
this.delivered.set(appId, set);
|
|
201
|
+
await this.deps.registry.setProgress(appId, safe, [...set]);
|
|
202
|
+
await this.persistVisitorWakes(appId);
|
|
203
|
+
}
|
|
204
|
+
today() {
|
|
205
|
+
return new Date(this.now()).toISOString().slice(0, 10);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The app's visitor-wake cap state for today: a new UTC day resets the
|
|
209
|
+
* count but keeps the skipped submissions not yet reported.
|
|
210
|
+
*/
|
|
211
|
+
visitorState(app) {
|
|
212
|
+
const today = this.today();
|
|
213
|
+
let st = this.visitorWakes.get(app.appId);
|
|
214
|
+
if (!st) {
|
|
215
|
+
const p = app.visitorWakes;
|
|
216
|
+
st = p && typeof p.day === 'string' ? { day: p.day, count: Number(p.count) || 0, skipped: Number(p.skipped) || 0 } : { day: today, count: 0, skipped: 0 };
|
|
217
|
+
this.visitorWakes.set(app.appId, st);
|
|
218
|
+
}
|
|
219
|
+
if (st.day !== today) {
|
|
220
|
+
st.day = today;
|
|
221
|
+
st.count = 0;
|
|
222
|
+
this.visitorDirty.add(app.appId);
|
|
223
|
+
}
|
|
224
|
+
return st;
|
|
225
|
+
}
|
|
226
|
+
async persistVisitorWakes(appId) {
|
|
227
|
+
if (!this.visitorDirty.has(appId))
|
|
228
|
+
return;
|
|
229
|
+
const st = this.visitorWakes.get(appId);
|
|
230
|
+
if (!st)
|
|
231
|
+
return;
|
|
232
|
+
this.visitorDirty.delete(appId);
|
|
233
|
+
await this.deps.registry.setVisitorWakes(appId, { ...st });
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* On a new UTC day, submissions skipped over yesterday's cap are reported
|
|
237
|
+
* even if nothing new arrives: open a notice-only batch for the publisher.
|
|
238
|
+
*/
|
|
239
|
+
maybeOpenSkippedNotice(app) {
|
|
240
|
+
const st = this.visitorState(app);
|
|
241
|
+
if (st.skipped <= 0 || st.count >= C.VISITOR_WAKE.MAX_PER_DAY)
|
|
242
|
+
return;
|
|
243
|
+
const session = app.agentSession ?? null;
|
|
244
|
+
const key = `${app.appId}\u0000${session ?? ORC_RECIPIENT}`;
|
|
245
|
+
if (this.batches.has(key))
|
|
246
|
+
return;
|
|
247
|
+
const batch = this.newBatch(app.appId, session, false, Number.POSITIVE_INFINITY);
|
|
248
|
+
batch.skippedNotice = true;
|
|
249
|
+
this.batches.set(key, batch);
|
|
250
|
+
const last = this.lastWakeAt.get(key) ?? app.wakes?.[session ?? ORC_RECIPIENT] ?? -Infinity;
|
|
251
|
+
this.arm(key, batch, Math.max(C.BATCH_WINDOW_MS, last + C.COOLDOWN_MS - this.now()));
|
|
252
|
+
}
|
|
253
|
+
newBatch(appId, session, activate, firstSeq) {
|
|
254
|
+
return {
|
|
255
|
+
appId,
|
|
256
|
+
session,
|
|
257
|
+
activate,
|
|
258
|
+
dataChanges: [],
|
|
259
|
+
events: [],
|
|
260
|
+
visitorChanges: [],
|
|
261
|
+
dataTotal: 0,
|
|
262
|
+
eventsTotal: 0,
|
|
263
|
+
visitorTotal: 0,
|
|
264
|
+
seqs: [],
|
|
265
|
+
firstSeq,
|
|
266
|
+
timer: null,
|
|
267
|
+
failures: 0,
|
|
268
|
+
orcNotified: false,
|
|
269
|
+
skippedNotice: false,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
async recipientFor(app, change) {
|
|
273
|
+
const publisher = app.agentSession ?? null;
|
|
274
|
+
const named = change.kind === 'event' && change.event?.type === 'ask' ? change.event.agent : undefined;
|
|
275
|
+
if (publisher && typeof named === 'string' && this.deps.resolveAgent) {
|
|
276
|
+
const target = await this.deps.resolveAgent(named, publisher).catch(() => null);
|
|
277
|
+
// Only a running teammate; an ask never starts a stopped agent.
|
|
278
|
+
if (target && target !== publisher && this.deps.isRunning?.(target))
|
|
279
|
+
return { session: target, activate: false };
|
|
280
|
+
}
|
|
281
|
+
return { session: publisher, activate: true };
|
|
282
|
+
}
|
|
283
|
+
async handle(app, change) {
|
|
284
|
+
// The owner's changes and anonymous visitors' submissions wake; any agent
|
|
285
|
+
// write (its own included) does not.
|
|
286
|
+
const visitor = change.actor?.kind === 'visitor';
|
|
287
|
+
if (change.actor?.kind !== 'owner' && !visitor)
|
|
288
|
+
return;
|
|
289
|
+
// A visitor can only add data (P3); anything else from one is ignored.
|
|
290
|
+
if (visitor && change.kind !== 'data')
|
|
291
|
+
return;
|
|
292
|
+
if (change.kind === 'event') {
|
|
293
|
+
if (change.event?.type !== 'notify' && change.event?.type !== 'ask')
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
else if (change.kind !== 'data') {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (visitor) {
|
|
300
|
+
// Daily cap on visitor-triggered wakes: past it, count, do not deliver.
|
|
301
|
+
const st = this.visitorState(app);
|
|
302
|
+
if (st.count >= C.VISITOR_WAKE.MAX_PER_DAY) {
|
|
303
|
+
st.skipped++;
|
|
304
|
+
this.visitorDirty.add(app.appId);
|
|
305
|
+
// Handled: a re-read after a restart must not count it twice.
|
|
306
|
+
this.deliveredSet(app).add(change.seq);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const recipientInfo = await this.recipientFor(app, change);
|
|
311
|
+
const session = recipientInfo.session;
|
|
312
|
+
// A visitor never starts a stopped agent; only the owner's changes may.
|
|
313
|
+
const activate = visitor ? false : recipientInfo.activate;
|
|
314
|
+
const recipient = session ?? ORC_RECIPIENT;
|
|
315
|
+
const key = `${app.appId}\u0000${recipient}`;
|
|
316
|
+
let batch = this.batches.get(key);
|
|
317
|
+
if (!batch) {
|
|
318
|
+
const last = this.lastWakeAt.get(key) ?? app.wakes?.[recipient] ?? -Infinity;
|
|
319
|
+
const delay = Math.max(C.BATCH_WINDOW_MS, last + C.COOLDOWN_MS - this.now());
|
|
320
|
+
batch = this.newBatch(app.appId, session, activate, change.seq);
|
|
321
|
+
this.batches.set(key, batch);
|
|
322
|
+
this.arm(key, batch, delay);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
batch.activate = batch.activate || activate;
|
|
326
|
+
if (batch.skippedNotice)
|
|
327
|
+
batch.firstSeq = Math.min(batch.firstSeq, change.seq);
|
|
328
|
+
}
|
|
329
|
+
batch.seqs.push(change.seq);
|
|
330
|
+
if (batch.seqs.length > C.MAX_DELIVERED_SEQS)
|
|
331
|
+
batch.seqs.shift();
|
|
332
|
+
if (visitor) {
|
|
333
|
+
batch.visitorTotal++;
|
|
334
|
+
batch.visitorChanges.push(change);
|
|
335
|
+
if (batch.visitorChanges.length > C.MAX_BATCH_DATA_CHANGES)
|
|
336
|
+
batch.visitorChanges.shift();
|
|
337
|
+
}
|
|
338
|
+
else if (change.kind === 'event') {
|
|
339
|
+
batch.eventsTotal++;
|
|
340
|
+
batch.events.push(change);
|
|
341
|
+
if (batch.events.length > C.MAX_EVENTS_PER_WAKE)
|
|
342
|
+
batch.events.shift();
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
batch.dataTotal++;
|
|
346
|
+
batch.dataChanges.push(change);
|
|
347
|
+
if (batch.dataChanges.length > C.MAX_BATCH_DATA_CHANGES)
|
|
348
|
+
batch.dataChanges.shift();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
arm(key, batch, delay) {
|
|
352
|
+
if (batch.timer)
|
|
353
|
+
clearTimeout(batch.timer);
|
|
354
|
+
batch.timer = setTimeout(() => void this.flush(key), delay);
|
|
355
|
+
batch.timer.unref?.();
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Send one batch now (timer callback; tests). On failure the batch stays
|
|
359
|
+
* pending and is retried with backoff.
|
|
360
|
+
*
|
|
361
|
+
* @param key - Batch key
|
|
362
|
+
* @returns Whether a message was delivered
|
|
363
|
+
*/
|
|
364
|
+
async flush(key) {
|
|
365
|
+
const batch = this.batches.get(key);
|
|
366
|
+
if (!batch)
|
|
367
|
+
return false;
|
|
368
|
+
if (batch.timer)
|
|
369
|
+
clearTimeout(batch.timer);
|
|
370
|
+
batch.timer = null;
|
|
371
|
+
const app = await this.deps.registry.get(batch.appId);
|
|
372
|
+
const recipient = batch.session ?? ORC_RECIPIENT;
|
|
373
|
+
// Visitor submissions alone never start the agent: wait until it runs.
|
|
374
|
+
const visitorOnly = batch.dataTotal === 0 && batch.eventsTotal === 0;
|
|
375
|
+
if (visitorOnly && batch.session !== null && this.deps.isRunning && !this.deps.isRunning(batch.session)) {
|
|
376
|
+
if (this.batches.get(key) === batch)
|
|
377
|
+
this.arm(key, batch, C.VISITOR_WAKE.PENDING_RECHECK_MS);
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
// Skipped visitor submissions are reported in the next message to the
|
|
381
|
+
// agent visitors wake (the publisher, else the orchestrator).
|
|
382
|
+
const isVisitorRecipient = (app?.agentSession ?? null) === batch.session;
|
|
383
|
+
const vstate = app && isVisitorRecipient ? this.visitorState(app) : null;
|
|
384
|
+
const skipped = vstate?.skipped ?? 0;
|
|
385
|
+
if (visitorOnly && batch.visitorTotal === 0 && skipped === 0) {
|
|
386
|
+
// A notice-only batch with nothing left to report.
|
|
387
|
+
this.batches.delete(key);
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
const text = buildAppWakeMessage({
|
|
391
|
+
appId: batch.appId,
|
|
392
|
+
appName: app?.name ?? batch.appId,
|
|
393
|
+
isPublisher: (app?.agentSession ?? null) === batch.session,
|
|
394
|
+
dataChanges: batch.dataChanges,
|
|
395
|
+
events: batch.events,
|
|
396
|
+
dataTotal: batch.dataTotal,
|
|
397
|
+
eventsTotal: batch.eventsTotal,
|
|
398
|
+
visitorChanges: batch.visitorChanges,
|
|
399
|
+
visitorTotal: batch.visitorTotal,
|
|
400
|
+
visitorSkipped: skipped,
|
|
401
|
+
skillsPath: this.deps.skillsPath,
|
|
402
|
+
});
|
|
403
|
+
let ok = false;
|
|
404
|
+
try {
|
|
405
|
+
ok = await this.deps.deliver(batch.session, text, { activate: batch.activate });
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
this.logger.warn('App change wake failed', { appId: batch.appId, session: batch.session, error: err instanceof Error ? err.message : String(err) });
|
|
409
|
+
}
|
|
410
|
+
if (!ok) {
|
|
411
|
+
batch.failures++;
|
|
412
|
+
const retry = Math.min(C.WAKE_RETRY_BASE_MS * 2 ** (batch.failures - 1), C.WAKE_RETRY_MAX_MS);
|
|
413
|
+
this.logger.warn('App change wake was not delivered; will retry', { appId: batch.appId, session: batch.session ?? 'orchestrator', failures: batch.failures, retryInMs: retry });
|
|
414
|
+
if (batch.failures >= C.WAKE_FAILS_BEFORE_ORC_NOTICE && !batch.orcNotified && batch.session !== null) {
|
|
415
|
+
batch.orcNotified = true;
|
|
416
|
+
const notice = `[APP CHANGES] Changes in app "${safeAppName(app?.name ?? batch.appId)}" (${batch.appId}) could not be delivered to ` +
|
|
417
|
+
`${batch.session} after ${batch.failures} tries. Crewly keeps retrying. Check whether that agent is stuck or signed out.`;
|
|
418
|
+
await this.deps.deliver(null, notice, { activate: false }).catch(() => false);
|
|
419
|
+
}
|
|
420
|
+
if (this.batches.get(key) === batch)
|
|
421
|
+
this.arm(key, batch, retry);
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
this.batches.delete(key);
|
|
425
|
+
const at = this.now();
|
|
426
|
+
this.lastWakeAt.set(key, at);
|
|
427
|
+
await this.deps.registry.setLastWake(batch.appId, recipient, at).catch(() => undefined);
|
|
428
|
+
if (vstate) {
|
|
429
|
+
if (batch.visitorTotal > 0 || batch.skippedNotice)
|
|
430
|
+
vstate.count++;
|
|
431
|
+
vstate.skipped = Math.max(0, vstate.skipped - skipped);
|
|
432
|
+
this.visitorDirty.add(batch.appId);
|
|
433
|
+
await this.persistVisitorWakes(batch.appId).catch(() => undefined);
|
|
434
|
+
}
|
|
435
|
+
const set = this.delivered.get(batch.appId) ?? new Set();
|
|
436
|
+
for (const seq of batch.seqs)
|
|
437
|
+
set.add(seq);
|
|
438
|
+
this.delivered.set(batch.appId, set);
|
|
439
|
+
this.logger.info('Woke agent for app changes', {
|
|
440
|
+
appId: batch.appId,
|
|
441
|
+
session: batch.session ?? 'orchestrator',
|
|
442
|
+
dataChanges: batch.dataTotal,
|
|
443
|
+
events: batch.eventsTotal,
|
|
444
|
+
visitorSubmissions: batch.visitorTotal,
|
|
445
|
+
...(skipped > 0 ? { visitorSkippedReported: skipped } : {}),
|
|
446
|
+
});
|
|
447
|
+
await this.persistProgress(batch.appId).catch(() => undefined);
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
/** @returns Keys of batches waiting to be sent (tests) */
|
|
451
|
+
pendingKeys() {
|
|
452
|
+
return [...this.batches.keys()];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
//# sourceMappingURL=app-wake.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-wake.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/app-wake.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppsCloudClient — this instance's calls to the Crewly Apps agent API
|
|
3
|
+
* (`<cloudUrl>/api/apps/v1`, crewly-services apps/SPEC.md §3.1).
|
|
4
|
+
*
|
|
5
|
+
* Authenticates with the Cloud access token the {@link CloudClientService}
|
|
6
|
+
* holds and refreshes, bound to this instance (`X-Crewly-Instance`) and
|
|
7
|
+
* attributed to the calling agent (`X-Crewly-Agent`). Agents never see the
|
|
8
|
+
* token: they reach this through `/api/apps` (specs/2026-10-04-crewly-apps-p2.md).
|
|
9
|
+
*
|
|
10
|
+
* @module services/apps/apps-cloud.client
|
|
11
|
+
*/
|
|
12
|
+
/** The slice of the Cloud client used here (injectable for tests). */
|
|
13
|
+
export interface AppsCloudSession {
|
|
14
|
+
isConnected(): boolean;
|
|
15
|
+
getToken(): string | null;
|
|
16
|
+
getCloudUrl(): string | null;
|
|
17
|
+
tryRefreshToken(): Promise<boolean>;
|
|
18
|
+
}
|
|
19
|
+
/** Constructor dependencies. */
|
|
20
|
+
export interface AppsCloudClientDeps {
|
|
21
|
+
cloud?: AppsCloudSession;
|
|
22
|
+
/** This instance's Cloud device id (the Slack instance registry's id) */
|
|
23
|
+
instanceId: () => Promise<string | null>;
|
|
24
|
+
fetchImpl?: typeof fetch;
|
|
25
|
+
}
|
|
26
|
+
/** A failed Apps call: HTTP status and a stable code for the controller and skills. */
|
|
27
|
+
export declare class AppsCloudError extends Error {
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly code: string;
|
|
30
|
+
constructor(status: number, code: string, message: string);
|
|
31
|
+
}
|
|
32
|
+
/** Options of one request. */
|
|
33
|
+
export interface AppsRequestOptions {
|
|
34
|
+
/** JSON body */
|
|
35
|
+
body?: unknown;
|
|
36
|
+
/** Query parameters (undefined values are dropped) */
|
|
37
|
+
query?: Record<string, string | number | undefined>;
|
|
38
|
+
/** Agent session to attribute the call to; omitted for the owner */
|
|
39
|
+
agent?: string;
|
|
40
|
+
/** Request timeout (default REQUEST_TIMEOUT_MS) */
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Typed wrapper over the Apps agent API.
|
|
45
|
+
*/
|
|
46
|
+
export declare class AppsCloudClient {
|
|
47
|
+
private readonly deps;
|
|
48
|
+
private readonly cloud;
|
|
49
|
+
private readonly fetchImpl;
|
|
50
|
+
constructor(deps: AppsCloudClientDeps);
|
|
51
|
+
/**
|
|
52
|
+
* Whether a Cloud login is present (a call can be attempted).
|
|
53
|
+
*
|
|
54
|
+
* @returns True when connected with a token and URL
|
|
55
|
+
*/
|
|
56
|
+
isAvailable(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Call the Apps API and return its `data`.
|
|
59
|
+
*
|
|
60
|
+
* A 401 refreshes the Cloud token once and retries. Cloud's
|
|
61
|
+
* `{ success:false, error, code }` becomes an {@link AppsCloudError} with
|
|
62
|
+
* Cloud's status and code. The token is never part of an error.
|
|
63
|
+
*
|
|
64
|
+
* @param method - HTTP method
|
|
65
|
+
* @param path - Path under `/api/apps/v1` (starts with `/`)
|
|
66
|
+
* @param opts - Body, query, agent attribution
|
|
67
|
+
* @returns The response `data`
|
|
68
|
+
* @throws AppsCloudError not_logged_in / instance_unknown / network / Cloud's code
|
|
69
|
+
*/
|
|
70
|
+
request<T>(method: string, path: string, opts?: AppsRequestOptions): Promise<T>;
|
|
71
|
+
private static readJson;
|
|
72
|
+
private send;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=apps-cloud.client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-cloud.client.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps-cloud.client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,WAAW,IAAI,OAAO,CAAC;IACvB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AAED,gCAAgC;AAChC,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,yEAAyE;IACzE,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,uFAAuF;AACvF,qBAAa,cAAe,SAAQ,KAAK;aAErB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAED,8BAA8B;AAC9B,MAAM,WAAW,kBAAkB;IACjC,gBAAgB;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEZ,IAAI,EAAE,mBAAmB;IAKtD;;;;OAIG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;;;;;;;;OAYG;IACG,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,CAAC,CAAC;mBAwBpE,QAAQ;YASf,IAAI;CAwBnB"}
|