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.
Files changed (93) hide show
  1. package/config/skills/agent/core/app-data/SKILL.md +117 -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 +248 -0
  5. package/config/skills/agent/core/publish-app/execute.sh +302 -0
  6. package/config/skills/agent/core/publish-app/execute.test.sh +205 -0
  7. package/dist/backend/backend/src/constants.d.ts +115 -0
  8. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  9. package/dist/backend/backend/src/constants.js +115 -0
  10. package/dist/backend/backend/src/constants.js.map +1 -1
  11. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +55 -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 +131 -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 +53 -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 +108 -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 +5 -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-open-link.d.ts +61 -0
  34. package/dist/backend/backend/src/services/apps/app-open-link.d.ts.map +1 -0
  35. package/dist/backend/backend/src/services/apps/app-open-link.js +112 -0
  36. package/dist/backend/backend/src/services/apps/app-open-link.js.map +1 -0
  37. package/dist/backend/backend/src/services/apps/app-wake-message.d.ts +136 -0
  38. package/dist/backend/backend/src/services/apps/app-wake-message.d.ts.map +1 -0
  39. package/dist/backend/backend/src/services/apps/app-wake-message.js +253 -0
  40. package/dist/backend/backend/src/services/apps/app-wake-message.js.map +1 -0
  41. package/dist/backend/backend/src/services/apps/app-wake.service.d.ts +145 -0
  42. package/dist/backend/backend/src/services/apps/app-wake.service.d.ts.map +1 -0
  43. package/dist/backend/backend/src/services/apps/app-wake.service.js +455 -0
  44. package/dist/backend/backend/src/services/apps/app-wake.service.js.map +1 -0
  45. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts +74 -0
  46. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts.map +1 -0
  47. package/dist/backend/backend/src/services/apps/apps-cloud.client.js +120 -0
  48. package/dist/backend/backend/src/services/apps/apps-cloud.client.js.map +1 -0
  49. package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts +125 -0
  50. package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts.map +1 -0
  51. package/dist/backend/backend/src/services/apps/apps-registry.service.js +192 -0
  52. package/dist/backend/backend/src/services/apps/apps-registry.service.js.map +1 -0
  53. package/dist/backend/backend/src/services/apps/apps.service.d.ts +466 -0
  54. package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/apps/apps.service.js +740 -0
  56. package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -0
  57. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts +97 -0
  58. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -0
  59. package/dist/backend/backend/src/services/apps/apps.wiring.js +153 -0
  60. package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -0
  61. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
  63. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/core/logger.service.d.ts +5 -0
  65. package/dist/backend/backend/src/services/core/logger.service.d.ts.map +1 -1
  66. package/dist/backend/backend/src/services/core/logger.service.js +8 -0
  67. package/dist/backend/backend/src/services/core/logger.service.js.map +1 -1
  68. package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +3 -1
  70. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
  71. package/dist/backend/build-info.json +2 -2
  72. package/dist/cli/backend/src/constants.d.ts +115 -0
  73. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  74. package/dist/cli/backend/src/constants.js +115 -0
  75. package/dist/cli/backend/src/constants.js.map +1 -1
  76. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  77. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
  78. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  79. package/dist/cli/backend/src/services/apps/app-open-link.d.ts +61 -0
  80. package/dist/cli/backend/src/services/apps/app-open-link.d.ts.map +1 -0
  81. package/dist/cli/backend/src/services/apps/app-open-link.js +112 -0
  82. package/dist/cli/backend/src/services/apps/app-open-link.js.map +1 -0
  83. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  84. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
  85. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  86. package/dist/cli/backend/src/services/core/logger.service.d.ts +5 -0
  87. package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -1
  88. package/dist/cli/backend/src/services/core/logger.service.js +8 -0
  89. package/dist/cli/backend/src/services/core/logger.service.js.map +1 -1
  90. package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
  91. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +3 -1
  92. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
  93. package/package.json +1 -1
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Crewly Apps controller — `/api/apps/*` on this instance.
3
+ *
4
+ * Agents publish apps and read/write their data here; this backend calls
5
+ * Crewly Cloud with the token it holds, so agents never touch it
6
+ * (specs/2026-10-04-crewly-apps-p2.md §1). Backs the publish-app and
7
+ * app-data skills. P3 (specs/2026-10-04-crewly-apps-p3.md) adds signed
8
+ * open-link cards, link management and public-app requests; the signed URL
9
+ * never appears in a response.
10
+ *
11
+ * @module controllers/apps/apps.controller
12
+ */
13
+ import { LoggerService } from '../../services/core/logger.service.js';
14
+ import { callerAgentSession } from '../../middleware/caller-identity.middleware.js';
15
+ import { AppsCloudError } from '../../services/apps/apps-cloud.client.js';
16
+ import { getAppsParts } from '../../services/apps/apps.wiring.js';
17
+ import { CREWLY_APPS_CONSTANTS } from '../../constants.js';
18
+ import { redactOpenLinkTokens } from '../../services/apps/app-open-link.js';
19
+ const logger = LoggerService.getInstance().createComponentLogger('AppsController');
20
+ /**
21
+ * Who is calling: the verified agent session, or the owner.
22
+ *
23
+ * @param req - Request (already through `ownerOrVerifiedAgent`)
24
+ * @returns Caller
25
+ */
26
+ function callerOf(req) {
27
+ const session = callerAgentSession(req);
28
+ return session ? { agentSession: session } : {};
29
+ }
30
+ /**
31
+ * Answer a failure as `{ success:false, error, message, hint? }`.
32
+ *
33
+ * @param res - Response
34
+ * @param err - The failure
35
+ */
36
+ export function sendAppsError(res, err) {
37
+ if (err instanceof AppsCloudError) {
38
+ const hint = err.code === CREWLY_APPS_CONSTANTS.ERROR_CODES.NOT_LOGGED_IN
39
+ ? 'Ask the owner to sign this machine in to Crewly Cloud (`crewly cloud login`).'
40
+ : err.code === 'not_found'
41
+ ? 'No such app, document or version for this account.'
42
+ : undefined;
43
+ res.status(err.status).json({ success: false, error: err.code, message: redactOpenLinkTokens(err.message), ...(hint ? { hint } : {}) });
44
+ return;
45
+ }
46
+ const message = redactOpenLinkTokens(err instanceof Error ? err.message : String(err));
47
+ logger.error('Unexpected Crewly Apps failure', { error: message });
48
+ res.status(500).json({ success: false, error: 'internal', message: 'Crewly Apps failed unexpectedly; check the backend log.' });
49
+ }
50
+ /**
51
+ * Wrap a handler: run it, answer `{ success:true, data }`, map errors.
52
+ *
53
+ * @param fn - Produces the data
54
+ * @param status - Success status
55
+ * @returns Express handler
56
+ */
57
+ function handle(fn, status = 200, opts = {}) {
58
+ return async (req, res) => {
59
+ try {
60
+ let data = await fn(req, callerOf(req));
61
+ // Belt and braces for the routes that touch open-links: whatever the
62
+ // service returns, no open-link token reaches the caller (P3 §1).
63
+ if (opts.redact && data !== undefined)
64
+ data = JSON.parse(redactOpenLinkTokens(JSON.stringify(data)));
65
+ res.status(status).json({ success: true, data });
66
+ }
67
+ catch (err) {
68
+ sendAppsError(res, err);
69
+ }
70
+ };
71
+ }
72
+ const body = (req) => req.body && typeof req.body === 'object' && !Array.isArray(req.body) ? req.body : {};
73
+ /** POST /api/apps/publish */
74
+ export const publishApp = handle(async (req, caller) => {
75
+ const b = body(req);
76
+ const result = await getAppsParts().service.publish({ files: b.files, name: b.name, appId: b.appId, source: b.source, entry: b.entry, note: b.note, notify: b.notify, publicRequest: b.publicRequest }, caller);
77
+ logger.info('App published', {
78
+ appId: result.appId,
79
+ version: result.version,
80
+ created: result.created,
81
+ agent: caller.agentSession ?? 'owner',
82
+ ...(result.card ? { card: result.card } : {}),
83
+ ...(result.publicRequested !== undefined ? { publicRequested: result.publicRequested } : {}),
84
+ });
85
+ return result;
86
+ }, 200, { redact: true });
87
+ /** POST /api/apps/:appId/share `{ ttlDays? }` — fresh signed link, card to the owner */
88
+ export const shareApp = handle(async (req, caller) => {
89
+ const result = await getAppsParts().service.share(req.params.appId, { ttlDays: body(req).ttlDays }, caller);
90
+ logger.info('App card shared', { appId: result.appId, card: result.card ?? 'none', place: result.cardPlace ?? 'none', agent: caller.agentSession ?? 'owner' });
91
+ return result;
92
+ }, 200, { redact: true });
93
+ /** GET /api/apps/:appId/links — open-links (never tokens) */
94
+ export const listLinks = handle((req, caller) => getAppsParts().service.links(req.params.appId, caller), 200, { redact: true });
95
+ /** DELETE /api/apps/:appId/links/:linkId */
96
+ export const revokeLink = handle((req, caller) => getAppsParts().service.revokeLink(req.params.appId, req.params.linkId, caller));
97
+ /** DELETE /api/apps/:appId/links — revoke all */
98
+ export const revokeLinks = handle((req, caller) => getAppsParts().service.revokeLinks(req.params.appId, caller));
99
+ /** POST /api/apps/:appId/visibility-request `{ publicRead?, publicSubmit?, note? }` — the owner approves in the app */
100
+ export const requestPublic = handle(async (req, caller) => {
101
+ const b = body(req);
102
+ const result = await getAppsParts().service.requestPublic(req.params.appId, { publicRead: b.publicRead, publicSubmit: b.publicSubmit, note: b.note }, caller);
103
+ logger.info('Public app requested', { appId: result.appId, agent: caller.agentSession ?? 'owner', card: result.card ?? 'none' });
104
+ return result;
105
+ }, 200, { redact: true });
106
+ /** DELETE /api/apps/:appId/visibility-request */
107
+ export const cancelPublicRequest = handle((req, caller) => getAppsParts().service.cancelPublicRequest(req.params.appId, caller));
108
+ /** POST /api/apps/:appId/make-private */
109
+ export const makePrivate = handle((req, caller) => getAppsParts().service.makePrivate(req.params.appId, caller));
110
+ /** POST /api/apps/:appId/rollback `{ version }` */
111
+ export const rollbackApp = handle((req, caller) => getAppsParts().service.rollback(req.params.appId, body(req).version, caller));
112
+ /** GET /api/apps — apps this instance published */
113
+ export const listApps = handle((_req, caller) => getAppsParts().service.list(caller));
114
+ /** GET /api/apps/:appId/versions */
115
+ export const listVersions = handle((req, caller) => getAppsParts().service.versions(req.params.appId, caller));
116
+ /** GET /api/apps/:appId/data/:collection?limit&after */
117
+ export const listDocs = handle((req, caller) => getAppsParts().service.listDocs(req.params.appId, req.params.collection, { limit: req.query.limit, after: req.query.after }, caller));
118
+ /** POST /api/apps/:appId/data/:collection `{ data }` */
119
+ export const addDoc = handle((req, caller) => getAppsParts().service.addDoc(req.params.appId, req.params.collection, body(req).data, caller), 201);
120
+ /** GET /api/apps/:appId/data/:collection/:docId */
121
+ export const getDoc = handle((req, caller) => getAppsParts().service.getDoc(req.params.appId, req.params.collection, req.params.docId, caller));
122
+ /** PUT /api/apps/:appId/data/:collection/:docId `{ data }` */
123
+ export const setDoc = handle((req, caller) => getAppsParts().service.setDoc(req.params.appId, req.params.collection, req.params.docId, body(req).data, caller));
124
+ /** PATCH /api/apps/:appId/data/:collection/:docId `{ data, ifRev? }` */
125
+ export const updateDoc = handle((req, caller) => {
126
+ const b = body(req);
127
+ return getAppsParts().service.updateDoc(req.params.appId, req.params.collection, req.params.docId, b.data, b.ifRev, caller);
128
+ });
129
+ /** DELETE /api/apps/:appId/data/:collection/:docId */
130
+ export const deleteDoc = handle((req, caller) => getAppsParts().service.deleteDoc(req.params.appId, req.params.collection, req.params.docId, caller));
131
+ //# sourceMappingURL=apps.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.controller.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/apps/apps.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Crewly Apps routes — mounted at `/api/apps`. Owner or a verified agent
3
+ * (badge / process tree) only (specs/2026-10-04-crewly-apps-p2.md §1).
4
+ *
5
+ * - POST /publish — publish a bundle (find/create the app)
6
+ * - GET / — apps of the caller (owner: all)
7
+ * - POST /:appId/rollback — `{ version }`
8
+ * - GET /:appId/versions — versions, newest first
9
+ * - GET /:appId/data/:collection — `?limit&after`
10
+ * - POST /:appId/data/:collection — add `{ data }`
11
+ * - GET /:appId/data/:collection/:docId — one doc
12
+ * - PUT /:appId/data/:collection/:docId — replace `{ data }`
13
+ * - PATCH /:appId/data/:collection/:docId — merge `{ data, ifRev? }`
14
+ * - DELETE /:appId/data/:collection/:docId — delete
15
+ * - POST /:appId/share — fresh signed link, card to the owner DM (P3)
16
+ * - GET /:appId/links — open-links (never tokens)
17
+ * - DELETE /:appId/links/:linkId — revoke one
18
+ * - DELETE /:appId/links — revoke all
19
+ * - POST /:appId/visibility-request — ask the owner to make it public
20
+ * - DELETE /:appId/visibility-request — withdraw the request
21
+ * - POST /:appId/make-private — private again (instant)
22
+ *
23
+ * The publish body is skipped by the app-wide parsers (index.ts) and parsed
24
+ * here, after the caller check, so an unauthenticated client cannot make the
25
+ * server buffer a large body.
26
+ *
27
+ * @module controllers/apps/apps.routes
28
+ */
29
+ import { Router, type NextFunction, type Request, type RequestHandler, type Response } from 'express';
30
+ /**
31
+ * The caller gate. A refused request that declares a large body is answered
32
+ * with `Connection: close`, so the server stops receiving the upload rather
33
+ * than draining it.
34
+ *
35
+ * @param gate - The identity gate
36
+ * @returns Middleware
37
+ */
38
+ export declare function gateClosingLargeRejects(gate: RequestHandler): RequestHandler;
39
+ /**
40
+ * Refuse a publish whose declared size is over the limit before reading it.
41
+ *
42
+ * @param req - Request
43
+ * @param res - Response
44
+ * @param next - Next
45
+ */
46
+ export declare function rejectOversizedPublish(req: Request, res: Response, next: NextFunction): void;
47
+ /**
48
+ * Creates the Crewly Apps router.
49
+ *
50
+ * @returns Express router
51
+ */
52
+ export declare function createAppsRouter(): Router;
53
+ //# sourceMappingURL=apps.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/apps/apps.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAgB,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAqC/G;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,CAS5E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAQ5F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAqBzC"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Crewly Apps routes — mounted at `/api/apps`. Owner or a verified agent
3
+ * (badge / process tree) only (specs/2026-10-04-crewly-apps-p2.md §1).
4
+ *
5
+ * - POST /publish — publish a bundle (find/create the app)
6
+ * - GET / — apps of the caller (owner: all)
7
+ * - POST /:appId/rollback — `{ version }`
8
+ * - GET /:appId/versions — versions, newest first
9
+ * - GET /:appId/data/:collection — `?limit&after`
10
+ * - POST /:appId/data/:collection — add `{ data }`
11
+ * - GET /:appId/data/:collection/:docId — one doc
12
+ * - PUT /:appId/data/:collection/:docId — replace `{ data }`
13
+ * - PATCH /:appId/data/:collection/:docId — merge `{ data, ifRev? }`
14
+ * - DELETE /:appId/data/:collection/:docId — delete
15
+ * - POST /:appId/share — fresh signed link, card to the owner DM (P3)
16
+ * - GET /:appId/links — open-links (never tokens)
17
+ * - DELETE /:appId/links/:linkId — revoke one
18
+ * - DELETE /:appId/links — revoke all
19
+ * - POST /:appId/visibility-request — ask the owner to make it public
20
+ * - DELETE /:appId/visibility-request — withdraw the request
21
+ * - POST /:appId/make-private — private again (instant)
22
+ *
23
+ * The publish body is skipped by the app-wide parsers (index.ts) and parsed
24
+ * here, after the caller check, so an unauthenticated client cannot make the
25
+ * server buffer a large body.
26
+ *
27
+ * @module controllers/apps/apps.routes
28
+ */
29
+ import express, { Router } from 'express';
30
+ import { ownerOrVerifiedAgent } from '../../middleware/caller-identity.middleware.js';
31
+ import { CREWLY_APPS_CONSTANTS } from '../../constants.js';
32
+ import { publishApp, listApps, rollbackApp, listVersions, listDocs, addDoc, getDoc, setDoc, updateDoc, deleteDoc, shareApp, listLinks, revokeLink, revokeLinks, requestPublic, cancelPublicRequest, makePrivate, } from './apps.controller.js';
33
+ const C = CREWLY_APPS_CONSTANTS;
34
+ /**
35
+ * The declared body size, or null when the request does not say.
36
+ *
37
+ * @param req - Request
38
+ * @returns Bytes or null
39
+ */
40
+ function declaredLength(req) {
41
+ const raw = req.headers['content-length'];
42
+ const n = typeof raw === 'string' ? Number(raw) : NaN;
43
+ return Number.isFinite(n) && n >= 0 ? n : null;
44
+ }
45
+ /**
46
+ * The caller gate. A refused request that declares a large body is answered
47
+ * with `Connection: close`, so the server stops receiving the upload rather
48
+ * than draining it.
49
+ *
50
+ * @param gate - The identity gate
51
+ * @returns Middleware
52
+ */
53
+ export function gateClosingLargeRejects(gate) {
54
+ return (req, res, next) => {
55
+ const large = (declaredLength(req) ?? 0) > C.PUBLISH_CLOSE_ABOVE_BYTES || req.headers['transfer-encoding'] !== undefined;
56
+ if (large)
57
+ res.setHeader('Connection', 'close');
58
+ gate(req, res, (err) => {
59
+ if (large)
60
+ res.removeHeader('Connection');
61
+ next(err);
62
+ });
63
+ };
64
+ }
65
+ /**
66
+ * Refuse a publish whose declared size is over the limit before reading it.
67
+ *
68
+ * @param req - Request
69
+ * @param res - Response
70
+ * @param next - Next
71
+ */
72
+ export function rejectOversizedPublish(req, res, next) {
73
+ const n = declaredLength(req);
74
+ if (n !== null && n > C.PUBLISH_BODY_MAX_BYTES) {
75
+ res.setHeader('Connection', 'close');
76
+ res.status(413).json({ success: false, error: 'too_large', message: `A publish can be at most ${C.PUBLISH_BODY_LIMIT}.` });
77
+ return;
78
+ }
79
+ next();
80
+ }
81
+ /**
82
+ * Creates the Crewly Apps router.
83
+ *
84
+ * @returns Express router
85
+ */
86
+ export function createAppsRouter() {
87
+ const router = Router();
88
+ router.use(gateClosingLargeRejects(ownerOrVerifiedAgent('Crewly Apps')));
89
+ router.post('/publish', rejectOversizedPublish, express.json({ limit: C.PUBLISH_BODY_LIMIT }), publishApp);
90
+ router.get('/', listApps);
91
+ router.post('/:appId/rollback', rollbackApp);
92
+ router.get('/:appId/versions', listVersions);
93
+ router.get('/:appId/data/:collection', listDocs);
94
+ router.post('/:appId/data/:collection', addDoc);
95
+ router.get('/:appId/data/:collection/:docId', getDoc);
96
+ router.put('/:appId/data/:collection/:docId', setDoc);
97
+ router.patch('/:appId/data/:collection/:docId', updateDoc);
98
+ router.delete('/:appId/data/:collection/:docId', deleteDoc);
99
+ router.post('/:appId/share', shareApp);
100
+ router.get('/:appId/links', listLinks);
101
+ router.delete('/:appId/links/:linkId', revokeLink);
102
+ router.delete('/:appId/links', revokeLinks);
103
+ router.post('/:appId/visibility-request', requestPublic);
104
+ router.delete('/:appId/visibility-request', cancelPublicRequest);
105
+ router.post('/:appId/make-private', makePrivate);
106
+ return router;
107
+ }
108
+ //# sourceMappingURL=apps.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/apps/apps.routes.ts"],"names":[],"mappings":"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"}
@@ -306,6 +306,7 @@ export declare class CrewlyServer {
306
306
  * @param tokenUsage - The ledger
307
307
  */
308
308
  private startRuntimeUsageSyncs;
309
+ private startCrewlyApps;
309
310
  private startDecisionCards;
310
311
  private startOwnerMessageWatchdog;
311
312
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../backend/src/index.ts"],"names":[],"mappings":";AA4CA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA+SjD,qBAAa,YAAY;IACxB,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,EAAE,CAAiB;IAC3B,iFAAiF;IACjF,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAqE;IACnF,gFAAgF;IAChF,OAAO,CAAC,iBAAiB,CAAC,CAAyD;IAEnF,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,uBAAuB,CAA2B;IAC1D,OAAO,CAAC,sBAAsB,CAA0B;IACxD,OAAO,CAAC,4BAA4B,CAAgC;IACpE,OAAO,CAAC,uBAAuB,CAA2B;IAC1D,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,eAAe,CAAmB;IAC1C,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,qBAAqB,CAAyB;IACtD,OAAO,CAAC,wBAAwB,CAA4B;IAC5D,OAAO,CAAC,eAAe,CAAmB;IAC1C,qEAAqE;IACrE,OAAO,CAAC,qBAAqB,CAAsC;IACnE,OAAO,CAAC,sBAAsB,CAAuC;IACrE,OAAO,CAAC,sBAAsB,CAAiD;IAC/E,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,0BAA0B,CAA2C;IAC7E,kGAAkG;IAClG,OAAO,CAAC,sBAAsB,CAAuC;IAGrE,OAAO,CAAC,+BAA+B,CAAgD;IACvF,+FAA+F;IAC/F,OAAO,CAAC,oBAAoB,CAAqC;IACjE,8HAA8H;IAC9H,OAAO,CAAC,0BAA0B,CAA2C;IAC7E,OAAO,CAAC,6BAA6B,CAA8C;IACnF,OAAO,CAAC,wBAAwB,CAAyC;IACzE,OAAO,CAAC,2BAA2B,CAA+B;IAClE,OAAO,CAAC,0BAA0B,CAA8B;IAChE,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,kBAAkB,CAA0C;IAKpE,OAAO,CAAC,aAAa,CAAuE;IAC5F,OAAO,CAAC,gBAAgB,CAET;IAGf,OAAO,CAAC,cAAc,CAAS;IAC/B,oEAAoE;IACpE,OAAO,CAAC,qBAAqB,CAA6C;IAC1E,OAAO,CAAC,qBAAqB,CAA2G;IACxI,0EAA0E;IAC1E,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,gBAAgB,CAAiG;IACzH,oFAAoF;IACpF,OAAO,CAAC,oBAAoB,CAAK;IACjC,2EAA2E;IAC3E,OAAO,CAAC,sBAAsB,CAA8B;IAC5D,yGAAyG;IACzG,OAAO,CAAC,sBAAsB,CAAuB;IACrD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAMhC;IACH,oGAAoG;IACpG,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,wBAAwB,CAA+B;gBAEnD,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAsE3C,OAAO,CAAC,kBAAkB;IAguC1B,OAAO,CAAC,mBAAmB;IA4D3B,OAAO,CAAC,eAAe;IAsMvB,OAAO,CAAC,kBAAkB;IA0BpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAy5D5B;;;OAGG;YACW,2BAA2B;IAuCzC;;;OAGG;YACW,8BAA8B;IAsB5C;;;OAGG;YACW,gCAAgC;IAsB9C;;;OAGG;YACW,8BAA8B;IAsB5C;;;;OAIG;YACW,8BAA8B;IA8M5C;;;;;;;;;;;;OAYG;YACW,6BAA6B;IAsB3C;;;;;OAKG;YACW,iCAAiC;IA0L/C;;;;OAIG;YACW,2BAA2B;YA0B3B,qBAAqB;IAsBnC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAwBlC;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;YAqCZ,eAAe;YAoFf,kBAAkB;IAgBhC,OAAO,CAAC,WAAW,CAAK;IAExB,OAAO,CAAC,sBAAsB;IAsC9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAwB5B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAoBvB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAyEvB;;;;;;;OAOG;YACW,2BAA2B;IAWzC;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IA+E1B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IA4DvB;;;;;;;OAOG;IACH,OAAO,CAAC,0BAA0B;IAuClC;;;;;OAKG;YACW,0BAA0B;IAkExC;;;;OAIG;YACW,qBAAqB;IA6DnC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAuBlC;;;;;;OAMG;YACW,kBAAkB;IAmBhC;;;;;OAKG;YACW,8BAA8B;IA6C5C;;;;OAIG;YACW,+BAA+B;IA2C7C;;;;;;OAMG;YACW,kBAAkB;IA6BhC,OAAO,CAAC,qBAAqB;IAoC7B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAoE1B;;;;;;;;;OASG;IACH;;;;;;;;;;;;;;OAcG;IACH,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAE1D;;;;;;;;OAQG;IACH;;OAEG;IACH;;;;;OAKG;YACW,sBAAsB;YA4CtB,kBAAkB;YAqHlB,yBAAyB;IAyFvC;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IA8B5B;;;;;;;OAOG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,cAAc;IA2BtB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAmChC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;YAkEf,wBAAwB;IAWtC,OAAO,CAAC,qBAAqB;IA8H7B,OAAO,CAAC,cAAc;IActB;;;;;;;;OAQG;IACG,QAAQ,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA4W1H,SAAS,IAAI,aAAa;CAG1B;AAmCD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../backend/src/index.ts"],"names":[],"mappings":"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"}
@@ -75,7 +75,7 @@ import { parseInboundOrigin } from './services/orc/orc-reply-route.service.js';
75
75
  import { parseSlackThreadKey } from './services/slack/slack-thread-key.js';
76
76
  import { LIVENESS_MONITOR_CONSTANTS } from './constants.js';
77
77
  import { InputBlockedRetryService } from './services/messaging/input-blocked-retry.service.js';
78
- import { SUB_AGENT_QUEUE_CONSTANTS, CHAT_CONTEXT_CONSTANTS, SAFE_RESTART, AUTO_UPDATE_CONSTANTS, PROCESS_EXIT_CODES, CLAUDE_STARTUP_CONSTANTS, WEB_CONSTANTS, TICKET_CONSTANTS, UNASSIGNED_ROUTE_CONSTANTS, CLOUD_TALK_CONSTANTS, STANDING_ANSWERS_CONSTANTS, TICKET_AUTOPILOT_CONSTANTS, EXPERIMENT_CONSTANTS, WORK_ITEM_DESTINATION_CONSTANTS, CODEX_USAGE_SYNC_CONSTANTS, ANTIGRAVITY_USAGE_SYNC_CONSTANTS, OWNER_AUTH_CONSTANTS } from './constants.js';
78
+ import { SUB_AGENT_QUEUE_CONSTANTS, CHAT_CONTEXT_CONSTANTS, SAFE_RESTART, AUTO_UPDATE_CONSTANTS, PROCESS_EXIT_CODES, CLAUDE_STARTUP_CONSTANTS, WEB_CONSTANTS, TICKET_CONSTANTS, UNASSIGNED_ROUTE_CONSTANTS, CLOUD_TALK_CONSTANTS, STANDING_ANSWERS_CONSTANTS, TICKET_AUTOPILOT_CONSTANTS, EXPERIMENT_CONSTANTS, WORK_ITEM_DESTINATION_CONSTANTS, CODEX_USAGE_SYNC_CONSTANTS, ANTIGRAVITY_USAGE_SYNC_CONSTANTS, OWNER_AUTH_CONSTANTS, CREWLY_APPS_CONSTANTS } from './constants.js';
79
79
  import { PtyActivityTrackerService } from './services/agent/pty-activity-tracker.service.js';
80
80
  import { InFlightTurnTracker } from './services/restart/in-flight-turn-tracker.service.js';
81
81
  import { TicketIntakeService, setTicketIntakeService, resolveTicketIdForSession, } from './services/v3/ticket-intake.service.js';
@@ -108,6 +108,7 @@ import { TokenUsageService } from './services/monitoring/token-usage.service.js'
108
108
  import { agentHeartbeatMiddleware } from './middleware/agent-heartbeat.middleware.js';
109
109
  import { agentOriginMiddleware, liveSessionPids } from './middleware/agent-origin.middleware.js';
110
110
  import { createCallerIdentityMiddleware } from './middleware/caller-identity.middleware.js';
111
+ import { bodyParserExcept } from './middleware/body-parser-except.js';
111
112
  import { PeerProcessService } from './services/core/peer-process.service.js';
112
113
  import { createOwnerSessionPageMiddleware, createOwnerSessionRouter } from './controllers/auth/owner-session.controller.js';
113
114
  import { dashboardBuildHeader, dashboardBuildMessage, loadDashboardEntry } from './services/core/dashboard-build.js';
@@ -1550,23 +1551,27 @@ export class CrewlyServer {
1550
1551
  }));
1551
1552
  // Logging
1552
1553
  this.app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
1554
+ // Crewly Apps publish (a whole bundle as base64) is NOT parsed here:
1555
+ // these parsers run before authentication, so its router parses it with
1556
+ // a larger limit only after the caller is the owner or a verified agent.
1557
+ const unparsedHere = [CREWLY_APPS_CONSTANTS.PUBLISH_ROUTE];
1553
1558
  // Body parsing — `verify` captures the raw bytes so the error handler
1554
1559
  // below can log the exact payload when JSON parsing fails. Without this
1555
1560
  // we only see the position-of-failure, not the bytes.
1556
- this.app.use(express.json({
1561
+ this.app.use(bodyParserExcept(unparsedHere, express.json({
1557
1562
  limit: '10mb',
1558
1563
  verify: (req, _res, buf) => {
1559
1564
  req.rawBody = buf.toString('utf8');
1560
1565
  },
1561
- }));
1562
- this.app.use(express.urlencoded({
1566
+ })));
1567
+ this.app.use(bodyParserExcept(unparsedHere, express.urlencoded({
1563
1568
  extended: true,
1564
1569
  limit: '10mb',
1565
1570
  // Slack's interactive `payload=` form is verified over the exact bytes.
1566
1571
  verify: (req, _res, buf) => {
1567
1572
  req.rawBody = buf.toString('utf8');
1568
1573
  },
1569
- }));
1574
+ })));
1570
1575
  // Note: Static files are configured in configureRoutes() after API routes
1571
1576
  }
1572
1577
  configureRoutes() {
@@ -3206,6 +3211,9 @@ export class CrewlyServer {
3206
3211
  // questions posted by the responsible agent's own bot, answered by
3207
3212
  // button / reaction / thread reply / dashboard; deadlines applied here.
3208
3213
  await this.startDecisionCards();
3214
+ // Crewly Apps (specs/2026-10-04-crewly-apps-p2.md): the owner's edits in
3215
+ // an app wake the agent that published it.
3216
+ await this.startCrewlyApps();
3209
3217
  }
3210
3218
  catch (autoClaimErr) {
3211
3219
  this.logger.warn('AgentAutoClaimService initialization failed (non-critical)', {
@@ -5198,6 +5206,49 @@ export class CrewlyServer {
5198
5206
  this.logger.warn('Antigravity usage sync not started (non-fatal)', { error: err instanceof Error ? err.message : String(err) });
5199
5207
  }
5200
5208
  }
5209
+ async startCrewlyApps() {
5210
+ try {
5211
+ const { startAppWake } = await import('./services/apps/apps.wiring.js');
5212
+ startAppWake({
5213
+ skillsPath: path.join(findPackageRoot(__dirname), 'config', 'skills', 'agent'),
5214
+ getTeams: () => this.storageService.getTeams(),
5215
+ sessionExists: (session) => {
5216
+ try {
5217
+ return getSessionBackendSync()?.sessionExists(session) ?? false;
5218
+ }
5219
+ catch {
5220
+ return false;
5221
+ }
5222
+ },
5223
+ sendToAgent: async (session, text, activate) => {
5224
+ let exists = false;
5225
+ try {
5226
+ exists = getSessionBackendSync()?.sessionExists(session) ?? false;
5227
+ }
5228
+ catch {
5229
+ exists = false;
5230
+ }
5231
+ if (!exists) {
5232
+ // Only the app's publisher is started; an `ask` never starts a stopped agent.
5233
+ if (!activate)
5234
+ return false;
5235
+ const { activateAgentBySession } = await import('./controllers/team/team.controller.js');
5236
+ await activateAgentBySession(this.apiController, session).catch(() => undefined);
5237
+ }
5238
+ const result = await this.apiController.agentRegistrationService.sendMessageToAgent(session, text);
5239
+ return result.success;
5240
+ },
5241
+ sendToOrchestrator: async (text) => {
5242
+ this.messageQueueService.enqueue({ content: text, conversationId: 'system', source: 'system_event' });
5243
+ return true;
5244
+ },
5245
+ });
5246
+ this.logger.info('Crewly Apps change poller started');
5247
+ }
5248
+ catch (error) {
5249
+ this.logger.warn('Crewly Apps change poller not started (non-critical)', { error: error instanceof Error ? error.message : String(error) });
5250
+ }
5251
+ }
5201
5252
  async startDecisionCards() {
5202
5253
  try {
5203
5254
  const { createDecisionService, attachDecisionSlackListeners, attachSkipAllCommand } = await import('./services/decisions/decision.wiring.js');
@@ -5798,6 +5849,7 @@ export class CrewlyServer {
5798
5849
  }
5799
5850
  this.logger.info('Shutting down Crewly server...', { reason: options.reason ?? 'unspecified' });
5800
5851
  AutoUpdateService.getInstance()?.stop();
5852
+ void import('./services/apps/apps.wiring.js').then((m) => m.stopAppWake()).catch(() => undefined);
5801
5853
  this.cloudDisconnectNotice?.stop();
5802
5854
  this.conversationCloudSync?.stop();
5803
5855
  this.waitingItemsSync?.stop();