crewly 1.20.209 → 1.20.210

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 (65) hide show
  1. package/config/skills/agent/core/app-data/SKILL.md +88 -0
  2. package/config/skills/agent/core/app-data/execute.sh +141 -0
  3. package/config/skills/agent/core/app-data/execute.test.sh +108 -0
  4. package/config/skills/agent/core/publish-app/SKILL.md +181 -0
  5. package/config/skills/agent/core/publish-app/execute.sh +181 -0
  6. package/config/skills/agent/core/publish-app/execute.test.sh +114 -0
  7. package/dist/backend/backend/src/constants.d.ts +62 -0
  8. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  9. package/dist/backend/backend/src/constants.js +62 -0
  10. package/dist/backend/backend/src/constants.js.map +1 -1
  11. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +39 -0
  12. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -0
  13. package/dist/backend/backend/src/controllers/apps/apps.controller.js +94 -0
  14. package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -0
  15. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +46 -0
  16. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -0
  17. package/dist/backend/backend/src/controllers/apps/apps.routes.js +94 -0
  18. package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -0
  19. package/dist/backend/backend/src/index.d.ts +1 -0
  20. package/dist/backend/backend/src/index.d.ts.map +1 -1
  21. package/dist/backend/backend/src/index.js +57 -5
  22. package/dist/backend/backend/src/index.js.map +1 -1
  23. package/dist/backend/backend/src/middleware/body-parser-except.d.ts +25 -0
  24. package/dist/backend/backend/src/middleware/body-parser-except.d.ts.map +1 -0
  25. package/dist/backend/backend/src/middleware/body-parser-except.js +33 -0
  26. package/dist/backend/backend/src/middleware/body-parser-except.js.map +1 -0
  27. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  28. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  29. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  30. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  31. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +4 -0
  32. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  33. package/dist/backend/backend/src/services/apps/app-wake-message.d.ts +95 -0
  34. package/dist/backend/backend/src/services/apps/app-wake-message.d.ts.map +1 -0
  35. package/dist/backend/backend/src/services/apps/app-wake-message.js +161 -0
  36. package/dist/backend/backend/src/services/apps/app-wake-message.js.map +1 -0
  37. package/dist/backend/backend/src/services/apps/app-wake.service.d.ts +118 -0
  38. package/dist/backend/backend/src/services/apps/app-wake.service.d.ts.map +1 -0
  39. package/dist/backend/backend/src/services/apps/app-wake.service.js +325 -0
  40. package/dist/backend/backend/src/services/apps/app-wake.service.js.map +1 -0
  41. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts +74 -0
  42. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts.map +1 -0
  43. package/dist/backend/backend/src/services/apps/apps-cloud.client.js +120 -0
  44. package/dist/backend/backend/src/services/apps/apps-cloud.client.js.map +1 -0
  45. package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts +107 -0
  46. package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts.map +1 -0
  47. package/dist/backend/backend/src/services/apps/apps-registry.service.js +178 -0
  48. package/dist/backend/backend/src/services/apps/apps-registry.service.js.map +1 -0
  49. package/dist/backend/backend/src/services/apps/apps.service.d.ts +217 -0
  50. package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -0
  51. package/dist/backend/backend/src/services/apps/apps.service.js +383 -0
  52. package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -0
  53. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts +83 -0
  54. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/apps/apps.wiring.js +133 -0
  56. package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -0
  57. package/dist/backend/build-info.json +2 -2
  58. package/dist/cli/backend/src/constants.d.ts +62 -0
  59. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  60. package/dist/cli/backend/src/constants.js +62 -0
  61. package/dist/cli/backend/src/constants.js.map +1 -1
  62. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  63. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +4 -0
  64. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,383 @@
1
+ /**
2
+ * AppsService — publish, roll back and read/write the data of Crewly Apps
3
+ * on behalf of an agent (or the owner), through {@link AppsCloudClient}.
4
+ *
5
+ * Backs `/api/apps` and the publish-app / app-data skills
6
+ * (specs/2026-10-04-crewly-apps-p2.md).
7
+ *
8
+ * @module services/apps/apps.service
9
+ */
10
+ import path from 'path';
11
+ import { CREWLY_APPS_CONSTANTS } from '../../constants.js';
12
+ import { AppsCloudError } from './apps-cloud.client.js';
13
+ const C = CREWLY_APPS_CONSTANTS;
14
+ const APP_ID_RE = /^[a-km-np-z2-9]{10}$/;
15
+ const COLLECTION_RE = /^[A-Za-z0-9_-]{1,64}$/;
16
+ const DOC_ID_RE = /^[A-Za-z0-9_.:-]{1,128}$/;
17
+ function validation(message) {
18
+ return new AppsCloudError(400, C.ERROR_CODES.VALIDATION, message);
19
+ }
20
+ /**
21
+ * Check an app id's shape.
22
+ *
23
+ * @param appId - Candidate
24
+ * @returns The id
25
+ * @throws AppsCloudError validation
26
+ */
27
+ export function requireAppId(appId) {
28
+ if (typeof appId !== 'string' || !APP_ID_RE.test(appId))
29
+ throw validation('appId must be a 10-character Crewly app id.');
30
+ return appId;
31
+ }
32
+ function requireCollection(c) {
33
+ if (typeof c !== 'string' || !COLLECTION_RE.test(c))
34
+ throw validation('collection must be 1-64 of A-Z a-z 0-9 _ -.');
35
+ return c;
36
+ }
37
+ function requireDocId(id) {
38
+ if (typeof id !== 'string' || !DOC_ID_RE.test(id) || id === '.' || id === '..') {
39
+ throw validation('docId must be 1-128 of A-Z a-z 0-9 _ . : - (and not "." or "..").');
40
+ }
41
+ return id;
42
+ }
43
+ function notYourApp() {
44
+ return new AppsCloudError(403, C.ERROR_CODES.NOT_YOUR_APP, 'This app was published by another agent. Only its publisher can publish or roll it back, and only the publisher and its team can use its data. Ask the owner if you need it.');
45
+ }
46
+ function requireData(data) {
47
+ if (!data || typeof data !== 'object' || Array.isArray(data))
48
+ throw validation('data must be a JSON object.');
49
+ return data;
50
+ }
51
+ function optString(v) {
52
+ return typeof v === 'string' && v.trim() ? v.trim() : undefined;
53
+ }
54
+ /**
55
+ * The "📱 <name> · Open app" card text. Markdown link: the reply path turns
56
+ * it into a Slack link.
57
+ *
58
+ * @param name - App name
59
+ * @param appId - App id
60
+ * @returns Card text
61
+ */
62
+ export function appCardText(name, appId) {
63
+ const clean = name.replace(/[[\]()\r\n]/g, ' ').replace(/\s+/g, ' ').trim() || 'App';
64
+ return `📱 ${clean} · [Open app](${C.APPS_ORIGIN}/${appId})`;
65
+ }
66
+ /**
67
+ * Publishing and data access for Crewly Apps.
68
+ */
69
+ export class AppsService {
70
+ deps;
71
+ constructor(deps) {
72
+ this.deps = deps;
73
+ }
74
+ /**
75
+ * Publish a bundle: find the caller's app (or create one), upload a new
76
+ * version, record it locally, and optionally post the Slack card.
77
+ *
78
+ * @param input - Files and options from the skill
79
+ * @param caller - Agent session or owner
80
+ * @returns appId, url, version, whether it was created / notified
81
+ * @throws AppsCloudError on validation or a Cloud failure
82
+ */
83
+ async publish(input, caller) {
84
+ const files = this.validateFiles(input.files);
85
+ const explicitId = input.appId !== undefined && input.appId !== null && input.appId !== '' ? requireAppId(input.appId) : undefined;
86
+ const source = optString(input.source) ?? null;
87
+ const name = optString(input.name);
88
+ const agentSession = caller.agentSession ?? null;
89
+ if (name && name.length > 80)
90
+ throw validation('name is at most 80 characters.');
91
+ const { registry, client } = this.deps;
92
+ let entry = await registry.find({ appId: explicitId, agentSession, source, name });
93
+ // An agent publishes only to its own apps; adopting an app made elsewhere is the owner's call.
94
+ if (explicitId && agentSession && (!entry || entry.agentSession !== agentSession))
95
+ throw notYourApp();
96
+ let app = null;
97
+ let created = false;
98
+ if (entry && !explicitId) {
99
+ // Found by source/name: if the owner deleted it, publish a new app instead.
100
+ try {
101
+ app = await client.request('GET', `/apps/${entry.appId}`, { agent: caller.agentSession });
102
+ }
103
+ catch (err) {
104
+ if (!(err instanceof AppsCloudError) || err.status !== 404)
105
+ throw err;
106
+ await registry.markDeleted(entry.appId);
107
+ entry = null;
108
+ }
109
+ }
110
+ else if (entry) {
111
+ app = await client.request('GET', `/apps/${entry.appId}`, { agent: caller.agentSession });
112
+ }
113
+ if (entry && app) {
114
+ if (name && name !== app.name) {
115
+ app = await client.request('PATCH', `/apps/${app.appId}`, { body: { name }, agent: caller.agentSession });
116
+ }
117
+ }
118
+ else if (explicitId) {
119
+ // An app made elsewhere (another machine, the portal): adopt it.
120
+ app = await client.request('GET', `/apps/${explicitId}`, { agent: caller.agentSession });
121
+ }
122
+ else {
123
+ const newName = name ?? (source ? path.basename(source).replace(/\.[^.]+$/, '') : '');
124
+ app = await client.request('POST', '/apps', { body: { name: newName.slice(0, 80) || 'App' }, agent: caller.agentSession });
125
+ created = true;
126
+ }
127
+ const entryFile = optString(input.entry);
128
+ const note = optString(input.note);
129
+ const version = await client.request('POST', `/apps/${app.appId}/versions`, {
130
+ body: {
131
+ files,
132
+ ...(entryFile ? { entry: entryFile } : {}),
133
+ ...(note ? { note: note.slice(0, 200) } : {}),
134
+ },
135
+ agent: caller.agentSession,
136
+ });
137
+ entry = await registry.upsert(app.appId, {
138
+ name: app.name,
139
+ url: app.url,
140
+ // The last agent to publish owns the wake; an owner publish keeps it.
141
+ ...(agentSession ? { agentSession } : {}),
142
+ ...(source ? { source } : {}),
143
+ currentVersion: version.version,
144
+ // A brand-new app has no history: start right before its first change,
145
+ // so an owner edit made before the first poll is not skipped.
146
+ ...(created ? { cursor: 0 } : {}),
147
+ deleted: false,
148
+ });
149
+ let notified = false;
150
+ let notifyError;
151
+ if (input.notify === true) {
152
+ if (!caller.agentSession) {
153
+ notifyError = 'Only an agent can post the app card (it goes out under the agent’s identity).';
154
+ }
155
+ else if (!this.deps.notifyCard) {
156
+ notifyError = 'Posting the app card is not available on this instance.';
157
+ }
158
+ else {
159
+ const r = await this.deps.notifyCard(caller.agentSession, appCardText(app.name, app.appId)).catch((err) => ({
160
+ ok: false,
161
+ error: err instanceof Error ? err.message : String(err),
162
+ }));
163
+ notified = r.ok;
164
+ if (!r.ok)
165
+ notifyError = r.error ?? 'The card could not be delivered.';
166
+ }
167
+ }
168
+ return {
169
+ appId: app.appId,
170
+ name: app.name,
171
+ url: `${C.APPS_ORIGIN}/${app.appId}`,
172
+ version: version.version,
173
+ created,
174
+ notified,
175
+ ...(notifyError ? { notifyError } : {}),
176
+ };
177
+ }
178
+ /**
179
+ * Make an earlier retained version current.
180
+ *
181
+ * @param appId - App id
182
+ * @param version - Version number
183
+ * @param caller - Agent or owner
184
+ * @returns The app after rollback
185
+ */
186
+ async rollback(appId, version, caller) {
187
+ const id = requireAppId(appId);
188
+ const v = typeof version === 'string' ? Number(version) : version;
189
+ if (typeof v !== 'number' || !Number.isInteger(v) || v < 1)
190
+ throw validation('version must be a positive integer.');
191
+ await this.assertPublisher(id, caller);
192
+ const app = await this.deps.client.request('POST', `/apps/${id}/rollback`, { body: { version: v }, agent: caller.agentSession });
193
+ if (await this.deps.registry.get(id))
194
+ await this.deps.registry.upsert(id, { currentVersion: app.currentVersion });
195
+ return app;
196
+ }
197
+ /**
198
+ * Versions of an app, newest first.
199
+ *
200
+ * @param appId - App id
201
+ * @param caller - Agent or owner
202
+ * @returns Versions
203
+ */
204
+ async versions(appId, caller) {
205
+ const id = requireAppId(appId);
206
+ await this.assertPublisher(id, caller);
207
+ return this.deps.client.request('GET', `/apps/${id}/versions`, { agent: caller.agentSession });
208
+ }
209
+ /**
210
+ * Agents may manage (publish, roll back, list versions of) only apps they
211
+ * published. The owner may manage any.
212
+ *
213
+ * @param appId - App id
214
+ * @param caller - Agent or owner
215
+ * @throws AppsCloudError 403 not_your_app
216
+ */
217
+ async assertPublisher(appId, caller) {
218
+ if (!caller.agentSession)
219
+ return;
220
+ const entry = await this.deps.registry.get(appId);
221
+ if (!entry || entry.agentSession !== caller.agentSession)
222
+ throw notYourApp();
223
+ }
224
+ /**
225
+ * Agents may read and write the data of apps they published, or that a
226
+ * teammate published. The owner may use any.
227
+ *
228
+ * @param appId - App id
229
+ * @param caller - Agent or owner
230
+ * @throws AppsCloudError 403 not_your_app
231
+ */
232
+ async assertDataAccess(appId, caller) {
233
+ const me = caller.agentSession;
234
+ if (!me)
235
+ return;
236
+ const entry = await this.deps.registry.get(appId);
237
+ const publisher = entry?.agentSession;
238
+ if (!publisher)
239
+ throw notYourApp();
240
+ if (publisher === me)
241
+ return;
242
+ if (this.deps.sameTeam && (await this.deps.sameTeam(me, publisher).catch(() => false)))
243
+ return;
244
+ throw notYourApp();
245
+ }
246
+ /**
247
+ * Apps this instance published (local registry, not Cloud).
248
+ *
249
+ * @returns Entries without the poller cursor
250
+ */
251
+ async list(caller = {}) {
252
+ return (await this.deps.registry.list())
253
+ .filter((e) => !caller.agentSession || e.agentSession === caller.agentSession)
254
+ .map(({ cursor: _cursor, delivered: _delivered, wakes: _wakes, ...rest }) => rest);
255
+ }
256
+ /**
257
+ * One page of a collection.
258
+ *
259
+ * @param appId - App id
260
+ * @param collection - Collection
261
+ * @param opts - limit / after
262
+ * @param caller - Agent or owner
263
+ * @returns `{ docs, next }`
264
+ */
265
+ async listDocs(appId, collection, opts, caller) {
266
+ const limit = opts.limit !== undefined && opts.limit !== '' ? Number(opts.limit) : undefined;
267
+ if (limit !== undefined && (!Number.isInteger(limit) || limit < 1 || limit > 500))
268
+ throw validation('limit is 1-500.');
269
+ const after = opts.after !== undefined && opts.after !== '' ? requireDocId(opts.after) : undefined;
270
+ const path = `/apps/${requireAppId(appId)}/data/${requireCollection(collection)}`;
271
+ await this.assertDataAccess(appId, caller);
272
+ return this.deps.client.request('GET', path, {
273
+ query: { limit, after },
274
+ agent: caller.agentSession,
275
+ });
276
+ }
277
+ /**
278
+ * One document (`{ id, data, rev, … }`); a missing one throws 404 not_found.
279
+ *
280
+ * @param appId - App id
281
+ * @param collection - Collection
282
+ * @param docId - Document id
283
+ * @param caller - Agent or owner
284
+ * @returns The document
285
+ */
286
+ async getDoc(appId, collection, docId, caller) {
287
+ const path = this.docPath(appId, collection, docId);
288
+ await this.assertDataAccess(appId, caller);
289
+ return this.deps.client.request('GET', path, { agent: caller.agentSession });
290
+ }
291
+ /**
292
+ * Replace (or create) a document.
293
+ *
294
+ * @param appId - App id
295
+ * @param collection - Collection
296
+ * @param docId - Document id
297
+ * @param data - New content
298
+ * @param caller - Agent or owner
299
+ * @returns The stored document
300
+ */
301
+ async setDoc(appId, collection, docId, data, caller) {
302
+ const path = this.docPath(appId, collection, docId);
303
+ const body = { data: requireData(data) };
304
+ await this.assertDataAccess(appId, caller);
305
+ return this.deps.client.request('PUT', path, { body, agent: caller.agentSession });
306
+ }
307
+ /**
308
+ * Shallow-merge into a document; `ifRev` makes it conditional (409 conflict).
309
+ *
310
+ * @param appId - App id
311
+ * @param collection - Collection
312
+ * @param docId - Document id
313
+ * @param data - Fields to merge
314
+ * @param ifRev - Expected current rev (optional)
315
+ * @param caller - Agent or owner
316
+ * @returns The stored document
317
+ */
318
+ async updateDoc(appId, collection, docId, data, ifRev, caller) {
319
+ const rev = ifRev === undefined || ifRev === null || ifRev === '' ? undefined : Number(ifRev);
320
+ if (rev !== undefined && (!Number.isInteger(rev) || rev < 0))
321
+ throw validation('ifRev must be a non-negative integer.');
322
+ const path = this.docPath(appId, collection, docId);
323
+ const body = { data: requireData(data), ...(rev !== undefined ? { ifRev: rev } : {}) };
324
+ await this.assertDataAccess(appId, caller);
325
+ return this.deps.client.request('PATCH', path, {
326
+ body,
327
+ agent: caller.agentSession,
328
+ });
329
+ }
330
+ /**
331
+ * Add a document with a generated id.
332
+ *
333
+ * @param appId - App id
334
+ * @param collection - Collection
335
+ * @param data - Content
336
+ * @param caller - Agent or owner
337
+ * @returns The stored document
338
+ */
339
+ async addDoc(appId, collection, data, caller) {
340
+ const path = `/apps/${requireAppId(appId)}/data/${requireCollection(collection)}`;
341
+ const body = { data: requireData(data) };
342
+ await this.assertDataAccess(appId, caller);
343
+ return this.deps.client.request('POST', path, {
344
+ body,
345
+ agent: caller.agentSession,
346
+ });
347
+ }
348
+ /**
349
+ * Delete a document.
350
+ *
351
+ * @param appId - App id
352
+ * @param collection - Collection
353
+ * @param docId - Document id
354
+ * @param caller - Agent or owner
355
+ * @returns `{ deleted: true }`
356
+ */
357
+ async deleteDoc(appId, collection, docId, caller) {
358
+ const path = this.docPath(appId, collection, docId);
359
+ await this.assertDataAccess(appId, caller);
360
+ return this.deps.client.request('DELETE', path, { agent: caller.agentSession });
361
+ }
362
+ docPath(appId, collection, docId) {
363
+ return `/apps/${requireAppId(appId)}/data/${requireCollection(collection)}/${encodeURIComponent(requireDocId(docId))}`;
364
+ }
365
+ validateFiles(files) {
366
+ if (!Array.isArray(files) || files.length === 0)
367
+ throw validation('files must be a non-empty array of { path, contentBase64 }.');
368
+ return files.map((f, i) => {
369
+ const o = (f ?? {});
370
+ if (typeof o.path !== 'string' || !o.path || o.path.startsWith('/') || o.path.split('/').includes('..')) {
371
+ throw validation(`files[${i}].path must be a relative path inside the bundle.`);
372
+ }
373
+ if (typeof o.contentBase64 !== 'string')
374
+ throw validation(`files[${i}].contentBase64 is required.`);
375
+ return {
376
+ path: o.path,
377
+ contentBase64: o.contentBase64,
378
+ ...(typeof o.contentType === 'string' && o.contentType ? { contentType: o.contentType } : {}),
379
+ };
380
+ });
381
+ }
382
+ }
383
+ //# sourceMappingURL=apps.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Crewly Apps wiring: the shared registry / Cloud client / service the
3
+ * `/api/apps` controller uses, and the change poller started at boot
4
+ * (specs/2026-10-04-crewly-apps-p2.md).
5
+ *
6
+ * @module services/apps/apps.wiring
7
+ */
8
+ import { AppsCloudClient } from './apps-cloud.client.js';
9
+ import { AppsRegistryService } from './apps-registry.service.js';
10
+ import { AppsService } from './apps.service.js';
11
+ import { AppWakeService } from './app-wake.service.js';
12
+ /** The team shape the apps code reads. */
13
+ export interface AppsTeam {
14
+ members?: Array<{
15
+ sessionName?: string;
16
+ name?: string;
17
+ }>;
18
+ }
19
+ /** Where teams come from. */
20
+ export type AppsTeamsSource = () => Promise<AppsTeam[]>;
21
+ interface AppsParts {
22
+ client: AppsCloudClient;
23
+ registry: AppsRegistryService;
24
+ service: AppsService;
25
+ }
26
+ /**
27
+ * This instance's Cloud device id (what `X-Crewly-Instance` names).
28
+ *
29
+ * @returns The id, or null before the Slack instance registry resolved it
30
+ */
31
+ export declare function currentInstanceId(): Promise<string | null>;
32
+ /**
33
+ * Whether two sessions are members of the same team.
34
+ *
35
+ * @param teams - Teams source
36
+ * @returns Predicate
37
+ */
38
+ export declare function sameTeamFrom(teams: AppsTeamsSource): (a: string, b: string) => Promise<boolean>;
39
+ /**
40
+ * Resolve an `ask` target name to a session — only inside the publisher's
41
+ * own team (by session or display name, case-insensitive).
42
+ *
43
+ * @param teams - Teams source
44
+ * @returns Resolver
45
+ */
46
+ export declare function teamAgentResolver(teams: AppsTeamsSource): (name: string, publisher: string) => Promise<string | null>;
47
+ /**
48
+ * The shared Apps parts, built on first use.
49
+ *
50
+ * @param teams - Teams source (default: the storage service)
51
+ * @returns Client, registry and service
52
+ */
53
+ export declare function getAppsParts(teams?: AppsTeamsSource): AppsParts;
54
+ /**
55
+ * Replace the shared parts (tests), or null to rebuild lazily.
56
+ *
57
+ * @param next - Parts or null
58
+ */
59
+ export declare function setAppsParts(next: AppsParts | null): void;
60
+ /** Inputs of {@link startAppWake}. */
61
+ export interface StartAppWakeInput {
62
+ /** Agent skills root (`config/skills/agent`) */
63
+ skillsPath: string;
64
+ /** Wake an agent with a message; `activate` = start it first when it is down */
65
+ sendToAgent: (session: string, text: string, activate: boolean) => Promise<boolean>;
66
+ /** Hand a message to the orchestrator */
67
+ sendToOrchestrator: (text: string) => Promise<boolean>;
68
+ /** Whether an agent's session is running */
69
+ sessionExists: (session: string) => boolean;
70
+ /** Teams on this instance */
71
+ getTeams: AppsTeamsSource;
72
+ }
73
+ /**
74
+ * Start the app change poller (idempotent).
75
+ *
76
+ * @param input - Delivery callbacks and paths
77
+ * @returns The running service
78
+ */
79
+ export declare function startAppWake(input: StartAppWakeInput): AppWakeService;
80
+ /** Stop the poller (shutdown; tests). */
81
+ export declare function stopAppWake(): void;
82
+ export {};
83
+ //# sourceMappingURL=apps.wiring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.wiring.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps.wiring.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAwB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,0CAA0C;AAC1C,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1D;AAED,6BAA6B;AAC7B,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;AAExD,UAAU,SAAS;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAWD;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIhE;AAaD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAK/F;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWrH;AAYD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAE,eAA8B,GAAG,SAAS,CAO7E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAEzD;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,yCAAyC;IACzC,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,4CAA4C;IAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,6BAA6B;IAC7B,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,cAAc,CAarE;AAED,yCAAyC;AACzC,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Crewly Apps wiring: the shared registry / Cloud client / service the
3
+ * `/api/apps` controller uses, and the change poller started at boot
4
+ * (specs/2026-10-04-crewly-apps-p2.md).
5
+ *
6
+ * @module services/apps/apps.wiring
7
+ */
8
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
9
+ import { getSlackInstanceRegistryService } from '../slack/slack-instance-registry.service.js';
10
+ import { AppsCloudClient } from './apps-cloud.client.js';
11
+ import { AppsRegistryService } from './apps-registry.service.js';
12
+ import { AppsService } from './apps.service.js';
13
+ import { AppWakeService } from './app-wake.service.js';
14
+ let parts = null;
15
+ let wake = null;
16
+ /** Default teams source: the storage service, loaded lazily. */
17
+ const defaultTeams = async () => {
18
+ const { StorageService } = await import('../core/storage.service.js');
19
+ return StorageService.getInstance().getTeams();
20
+ };
21
+ /**
22
+ * This instance's Cloud device id (what `X-Crewly-Instance` names).
23
+ *
24
+ * @returns The id, or null before the Slack instance registry resolved it
25
+ */
26
+ export async function currentInstanceId() {
27
+ const registry = getSlackInstanceRegistryService();
28
+ if (!registry)
29
+ return null;
30
+ return registry.getInstanceId() ?? (await registry.resolveInstanceId());
31
+ }
32
+ /**
33
+ * The team that has this session as a member.
34
+ *
35
+ * @param teams - Teams
36
+ * @param session - Agent session
37
+ * @returns The team, or undefined
38
+ */
39
+ function teamOf(teams, session) {
40
+ return teams.find((t) => (t.members ?? []).some((m) => m.sessionName === session));
41
+ }
42
+ /**
43
+ * Whether two sessions are members of the same team.
44
+ *
45
+ * @param teams - Teams source
46
+ * @returns Predicate
47
+ */
48
+ export function sameTeamFrom(teams) {
49
+ return async (a, b) => {
50
+ const team = teamOf(await teams(), a);
51
+ return !!team && (team.members ?? []).some((m) => m.sessionName === b);
52
+ };
53
+ }
54
+ /**
55
+ * Resolve an `ask` target name to a session — only inside the publisher's
56
+ * own team (by session or display name, case-insensitive).
57
+ *
58
+ * @param teams - Teams source
59
+ * @returns Resolver
60
+ */
61
+ export function teamAgentResolver(teams) {
62
+ return async (name, publisher) => {
63
+ const team = teamOf(await teams(), publisher);
64
+ if (!team)
65
+ return null;
66
+ const wanted = name.trim().toLowerCase();
67
+ for (const m of team.members ?? []) {
68
+ if (!m.sessionName)
69
+ continue;
70
+ if (m.sessionName.toLowerCase() === wanted || (m.name ?? '').trim().toLowerCase() === wanted)
71
+ return m.sessionName;
72
+ }
73
+ return null;
74
+ };
75
+ }
76
+ /**
77
+ * Post the app card where the agent talks with the owner, through the same
78
+ * resolver `reply` uses.
79
+ */
80
+ const defaultNotifyCard = async (agentSession, text) => {
81
+ const { deliverReply } = await import('../orc/reply-destination.wiring.js');
82
+ const r = await deliverReply({ session: agentSession, content: text, addsNew: true });
83
+ return r.ok ? { ok: true } : { ok: false, error: r.error };
84
+ };
85
+ /**
86
+ * The shared Apps parts, built on first use.
87
+ *
88
+ * @param teams - Teams source (default: the storage service)
89
+ * @returns Client, registry and service
90
+ */
91
+ export function getAppsParts(teams = defaultTeams) {
92
+ if (!parts) {
93
+ const client = new AppsCloudClient({ instanceId: currentInstanceId });
94
+ const registry = new AppsRegistryService(getCrewlyHomePath());
95
+ parts = { client, registry, service: new AppsService({ client, registry, notifyCard: defaultNotifyCard, sameTeam: sameTeamFrom(teams) }) };
96
+ }
97
+ return parts;
98
+ }
99
+ /**
100
+ * Replace the shared parts (tests), or null to rebuild lazily.
101
+ *
102
+ * @param next - Parts or null
103
+ */
104
+ export function setAppsParts(next) {
105
+ parts = next;
106
+ }
107
+ /**
108
+ * Start the app change poller (idempotent).
109
+ *
110
+ * @param input - Delivery callbacks and paths
111
+ * @returns The running service
112
+ */
113
+ export function startAppWake(input) {
114
+ if (wake)
115
+ return wake;
116
+ const { client, registry } = getAppsParts(input.getTeams);
117
+ wake = new AppWakeService({
118
+ client,
119
+ registry,
120
+ skillsPath: input.skillsPath,
121
+ deliver: (session, text, opts) => (session ? input.sendToAgent(session, text, opts.activate) : input.sendToOrchestrator(text)),
122
+ resolveAgent: teamAgentResolver(input.getTeams),
123
+ isRunning: input.sessionExists,
124
+ });
125
+ wake.start();
126
+ return wake;
127
+ }
128
+ /** Stop the poller (shutdown; tests). */
129
+ export function stopAppWake() {
130
+ wake?.stop();
131
+ wake = null;
132
+ }
133
+ //# sourceMappingURL=apps.wiring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.wiring.js","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps.wiring.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  {
2
- "commit": "5693fbb61016f2c5d2202310e10a8ad1319a7a02",
3
- "builtAt": "2026-10-04T12:54:51.246Z"
2
+ "commit": "5c77668fe72f598fee8e54c1b1ec144c7d9975af",
3
+ "builtAt": "2026-10-04T14:00:16.980Z"
4
4
  }