crewly 1.1.2 → 1.2.0

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 (216) hide show
  1. package/README.md +6 -6
  2. package/config/roles/ops/prompt.md +140 -0
  3. package/config/roles/ops/role.json +13 -0
  4. package/config/skills/agent/browse-stealth/execute.sh +84 -0
  5. package/config/skills/agent/browse-stealth/instructions.md +108 -0
  6. package/config/skills/agent/browse-stealth/launch-chrome-cdp.sh +141 -0
  7. package/config/skills/agent/browse-stealth/skill.json +20 -0
  8. package/config/skills/agent/browse-stealth/stealth-browse.py +330 -0
  9. package/config/skills/agent/competitor-content-tracker/execute.sh +232 -0
  10. package/config/skills/agent/competitor-content-tracker/instructions.md +210 -0
  11. package/config/skills/agent/competitor-content-tracker/skill.json +22 -0
  12. package/config/skills/agent/content-calendar/execute.sh +294 -0
  13. package/config/skills/agent/content-calendar/instructions.md +122 -0
  14. package/config/skills/agent/content-calendar/skill.json +22 -0
  15. package/config/skills/agent/content-repurposer/execute.sh +194 -0
  16. package/config/skills/agent/content-repurposer/instructions.md +69 -0
  17. package/config/skills/agent/content-repurposer/skill.json +22 -0
  18. package/config/skills/agent/content-writer/execute.sh +311 -0
  19. package/config/skills/agent/content-writer/instructions.md +124 -0
  20. package/config/skills/agent/content-writer/skill.json +22 -0
  21. package/config/skills/agent/core/generate-pdf/execute.sh +88 -0
  22. package/config/skills/agent/core/generate-pdf/instructions.md +46 -0
  23. package/config/skills/agent/core/generate-pdf/skill.json +20 -0
  24. package/config/skills/agent/core/report-status/execute.sh +6 -0
  25. package/config/skills/agent/trend-monitor/execute.sh +211 -0
  26. package/config/skills/agent/trend-monitor/instructions.md +207 -0
  27. package/config/skills/agent/trend-monitor/skill.json +22 -0
  28. package/config/skills/agent/vnc-browser/execute.sh +261 -0
  29. package/config/skills/agent/vnc-browser/instructions.md +102 -0
  30. package/config/skills/agent/vnc-browser/skill.json +20 -0
  31. package/config/skills/orchestrator/delegate-task/execute.sh +63 -4
  32. package/config/skills/orchestrator/delegate-task/instructions.md +60 -0
  33. package/config/skills/orchestrator/delegate-task/skill.json +4 -4
  34. package/config/skills/orchestrator/reply-slack/execute.sh +2 -0
  35. package/config/skills/orchestrator/send-key/execute.sh +19 -6
  36. package/config/skills/orchestrator/send-key/instructions.md +44 -0
  37. package/config/skills/orchestrator/send-key/skill.json +20 -0
  38. package/config/skills/orchestrator/send-message/execute.sh +9 -1
  39. package/config/skills/registry.json +256 -0
  40. package/config/templates/code-review-team/README.md +176 -0
  41. package/config/templates/code-review-team/team-config.json +16 -0
  42. package/config/templates/code-review-team.json +62 -0
  43. package/config/templates/content-generation-team/README.md +128 -0
  44. package/config/templates/content-generation-team/team-config.json +21 -0
  45. package/config/templates/content-generation-team.json +67 -0
  46. package/config/templates/demo-team.json +22 -0
  47. package/config/templates/social-media-ops-team/README.md +145 -0
  48. package/config/templates/social-media-ops-team/team-config.json +21 -0
  49. package/config/templates/social-media-ops-team.json +67 -0
  50. package/dist/backend/backend/src/constants.d.ts +69 -6
  51. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  52. package/dist/backend/backend/src/constants.js +75 -6
  53. package/dist/backend/backend/src/constants.js.map +1 -1
  54. package/dist/backend/backend/src/controllers/index.d.ts.map +1 -1
  55. package/dist/backend/backend/src/controllers/index.js +2 -0
  56. package/dist/backend/backend/src/controllers/index.js.map +1 -1
  57. package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts +8 -0
  58. package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
  59. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +110 -63
  60. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
  61. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  62. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +31 -4
  63. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  64. package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts +8 -0
  65. package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts.map +1 -1
  66. package/dist/backend/backend/src/controllers/oauth/oauth.routes.js +127 -111
  67. package/dist/backend/backend/src/controllers/oauth/oauth.routes.js.map +1 -1
  68. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +34 -0
  69. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
  70. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +219 -2
  71. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
  72. package/dist/backend/backend/src/controllers/user/user.routes.d.ts +7 -0
  73. package/dist/backend/backend/src/controllers/user/user.routes.d.ts.map +1 -1
  74. package/dist/backend/backend/src/controllers/user/user.routes.js +45 -38
  75. package/dist/backend/backend/src/controllers/user/user.routes.js.map +1 -1
  76. package/dist/backend/backend/src/controllers/whatsapp/index.d.ts +17 -0
  77. package/dist/backend/backend/src/controllers/whatsapp/index.d.ts.map +1 -0
  78. package/dist/backend/backend/src/controllers/whatsapp/index.js +18 -0
  79. package/dist/backend/backend/src/controllers/whatsapp/index.js.map +1 -0
  80. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts +12 -0
  81. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts.map +1 -0
  82. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js +185 -0
  83. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js.map +1 -0
  84. package/dist/backend/backend/src/index.d.ts +5 -0
  85. package/dist/backend/backend/src/index.d.ts.map +1 -1
  86. package/dist/backend/backend/src/index.js +35 -0
  87. package/dist/backend/backend/src/index.js.map +1 -1
  88. package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
  89. package/dist/backend/backend/src/routes/modules/task-management.routes.js +4 -0
  90. package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
  91. package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js +1 -1
  92. package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js.map +1 -1
  93. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +14 -3
  94. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  95. package/dist/backend/backend/src/services/agent/agent-registration.service.js +160 -29
  96. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  97. package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts +4 -3
  98. package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -1
  99. package/dist/backend/backend/src/services/agent/claude-runtime.service.js +29 -4
  100. package/dist/backend/backend/src/services/agent/claude-runtime.service.js.map +1 -1
  101. package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
  102. package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +11 -0
  103. package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
  104. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +32 -2
  105. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  106. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +69 -8
  107. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  108. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  109. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +14 -2
  110. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  111. package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.d.ts.map +1 -1
  112. package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js +11 -2
  113. package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js.map +1 -1
  114. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.d.ts +18 -0
  115. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.d.ts.map +1 -1
  116. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.js +28 -4
  117. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.js.map +1 -1
  118. package/dist/backend/backend/src/services/messaging/adapters/slack-messenger.adapter.js +2 -2
  119. package/dist/backend/backend/src/services/messaging/adapters/slack-messenger.adapter.js.map +1 -1
  120. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts +18 -0
  121. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts.map +1 -1
  122. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js +26 -4
  123. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js.map +1 -1
  124. package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts +28 -2
  125. package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts.map +1 -1
  126. package/dist/backend/backend/src/services/messaging/messenger-registry.service.d.ts +33 -2
  127. package/dist/backend/backend/src/services/messaging/messenger-registry.service.d.ts.map +1 -1
  128. package/dist/backend/backend/src/services/messaging/messenger-registry.service.js +33 -0
  129. package/dist/backend/backend/src/services/messaging/messenger-registry.service.js.map +1 -1
  130. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
  131. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +4 -2
  132. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
  133. package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.d.ts.map +1 -1
  134. package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js +4 -3
  135. package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js.map +1 -1
  136. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +27 -0
  137. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
  138. package/dist/backend/backend/src/services/project/task-tracking.service.js +54 -0
  139. package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
  140. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +36 -6
  141. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  142. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +238 -36
  143. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  144. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  145. package/dist/backend/backend/src/services/slack/slack.service.js +6 -4
  146. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  147. package/dist/backend/backend/src/services/user/user-identity.service.d.ts +44 -0
  148. package/dist/backend/backend/src/services/user/user-identity.service.d.ts.map +1 -1
  149. package/dist/backend/backend/src/services/user/user-identity.service.js +75 -8
  150. package/dist/backend/backend/src/services/user/user-identity.service.js.map +1 -1
  151. package/dist/backend/backend/src/services/whatsapp/index.d.ts +11 -0
  152. package/dist/backend/backend/src/services/whatsapp/index.d.ts.map +1 -0
  153. package/dist/backend/backend/src/services/whatsapp/index.js +11 -0
  154. package/dist/backend/backend/src/services/whatsapp/index.js.map +1 -0
  155. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts +66 -0
  156. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts.map +1 -0
  157. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js +96 -0
  158. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js.map +1 -0
  159. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts +109 -0
  160. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -0
  161. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +234 -0
  162. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -0
  163. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts +127 -0
  164. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts.map +1 -0
  165. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js +347 -0
  166. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js.map +1 -0
  167. package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
  168. package/dist/backend/backend/src/services/workflow/scheduler.service.js +4 -0
  169. package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
  170. package/dist/backend/backend/src/types/index.d.ts +1 -0
  171. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  172. package/dist/backend/backend/src/types/index.js.map +1 -1
  173. package/dist/backend/backend/src/types/slack.types.d.ts +24 -0
  174. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  175. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  176. package/dist/backend/backend/src/types/task-tracking.types.d.ts +4 -0
  177. package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
  178. package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
  179. package/dist/backend/backend/src/types/whatsapp.types.d.ts +84 -0
  180. package/dist/backend/backend/src/types/whatsapp.types.d.ts.map +1 -0
  181. package/dist/backend/backend/src/types/whatsapp.types.js +33 -0
  182. package/dist/backend/backend/src/types/whatsapp.types.js.map +1 -0
  183. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +11 -0
  184. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  185. package/dist/backend/backend/src/websocket/terminal.gateway.js +35 -1
  186. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  187. package/dist/cli/backend/src/constants.d.ts +69 -6
  188. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  189. package/dist/cli/backend/src/constants.js +75 -6
  190. package/dist/cli/backend/src/constants.js.map +1 -1
  191. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  192. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +14 -2
  193. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  194. package/dist/cli/backend/src/types/index.d.ts +1 -0
  195. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  196. package/dist/cli/backend/src/types/index.js.map +1 -1
  197. package/dist/cli/cli/src/commands/publish.d.ts.map +1 -1
  198. package/dist/cli/cli/src/commands/publish.js +17 -15
  199. package/dist/cli/cli/src/commands/publish.js.map +1 -1
  200. package/dist/cli/cli/src/index.js +2 -2
  201. package/dist/cli/cli/src/index.js.map +1 -1
  202. package/dist/cli/cli/src/utils/gh-submit.d.ts +46 -0
  203. package/dist/cli/cli/src/utils/gh-submit.d.ts.map +1 -0
  204. package/dist/cli/cli/src/utils/gh-submit.js +167 -0
  205. package/dist/cli/cli/src/utils/gh-submit.js.map +1 -0
  206. package/dist/cli/cli/src/utils/marketplace.d.ts.map +1 -1
  207. package/dist/cli/cli/src/utils/marketplace.js +13 -5
  208. package/dist/cli/cli/src/utils/marketplace.js.map +1 -1
  209. package/dist/cli/cli/src/utils/templates.d.ts +3 -2
  210. package/dist/cli/cli/src/utils/templates.d.ts.map +1 -1
  211. package/dist/cli/cli/src/utils/templates.js +5 -4
  212. package/dist/cli/cli/src/utils/templates.js.map +1 -1
  213. package/frontend/dist/assets/{index-45eeea99.js → index-a23214ae.js} +241 -241
  214. package/frontend/dist/assets/{index-6972eeee.css → index-c407fe13.css} +1 -1
  215. package/frontend/dist/index.html +2 -2
  216. package/package.json +3 -1
@@ -1,127 +1,143 @@
1
1
  import { Router } from 'express';
2
+ import crypto from 'crypto';
3
+ import { GOOGLE_OAUTH_CONSTANTS } from '../../constants.js';
2
4
  import { UserIdentityService } from '../../services/user/user-identity.service.js';
3
- const router = Router();
4
- const users = UserIdentityService.getInstance();
5
- const GOOGLE_AUTH_BASE = 'https://accounts.google.com/o/oauth2/v2/auth';
6
- const GOOGLE_TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token';
7
- const GOOGLE_USERINFO_ENDPOINT = 'https://www.googleapis.com/oauth2/v2/userinfo';
5
+ import { LoggerService } from '../../services/core/logger.service.js';
6
+ /**
7
+ * Build Google OAuth client config from environment variables.
8
+ *
9
+ * @param req - Express request (used to derive the default redirect URI)
10
+ * @returns Object with clientId, clientSecret, and redirectUri
11
+ */
8
12
  function getGoogleConfig(req) {
9
13
  const clientId = process.env.GOOGLE_OAUTH_CLIENT_ID || '';
10
14
  const clientSecret = process.env.GOOGLE_OAUTH_CLIENT_SECRET || '';
11
15
  const redirectUri = process.env.GOOGLE_OAUTH_REDIRECT_URI || `${req.protocol}://${req.get('host')}/api/oauth/google/callback`;
12
16
  return { clientId, clientSecret, redirectUri };
13
17
  }
14
- router.get('/google/start', async (req, res, next) => {
15
- try {
16
- const { clientId, redirectUri } = getGoogleConfig(req);
17
- if (!clientId) {
18
- res.status(500).json({ success: false, error: 'GOOGLE_OAUTH_CLIENT_ID is not configured' });
19
- return;
20
- }
21
- const slackUserId = req.query.slackUserId ? String(req.query.slackUserId) : undefined;
22
- const statePayload = {
23
- slackUserId,
24
- t: Date.now(),
25
- nonce: Math.random().toString(36).slice(2),
26
- };
27
- const state = Buffer.from(JSON.stringify(statePayload)).toString('base64url');
28
- const scopes = [
29
- 'openid',
30
- 'email',
31
- 'https://www.googleapis.com/auth/gmail.readonly',
32
- 'https://www.googleapis.com/auth/gmail.send',
33
- ];
34
- const url = new URL(GOOGLE_AUTH_BASE);
35
- url.searchParams.set('client_id', clientId);
36
- url.searchParams.set('redirect_uri', redirectUri);
37
- url.searchParams.set('response_type', 'code');
38
- url.searchParams.set('access_type', 'offline');
39
- url.searchParams.set('prompt', 'consent');
40
- url.searchParams.set('scope', scopes.join(' '));
41
- url.searchParams.set('state', state);
42
- res.json({ success: true, data: { authUrl: url.toString(), state } });
43
- }
44
- catch (error) {
45
- next(error);
46
- }
47
- });
48
- router.get('/google/callback', async (req, res, next) => {
49
- try {
50
- const code = req.query.code ? String(req.query.code) : '';
51
- const state = req.query.state ? String(req.query.state) : '';
52
- if (!code) {
53
- res.status(400).json({ success: false, error: 'Missing code' });
54
- return;
55
- }
56
- const { clientId, clientSecret, redirectUri } = getGoogleConfig(req);
57
- if (!clientId || !clientSecret) {
58
- res.status(500).json({ success: false, error: 'Google OAuth credentials are not configured' });
59
- return;
60
- }
61
- const tokenResp = await fetch(GOOGLE_TOKEN_ENDPOINT, {
62
- method: 'POST',
63
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
64
- body: new URLSearchParams({
65
- code,
66
- client_id: clientId,
67
- client_secret: clientSecret,
68
- redirect_uri: redirectUri,
69
- grant_type: 'authorization_code',
70
- }),
71
- });
72
- if (!tokenResp.ok) {
73
- const details = await tokenResp.text();
74
- res.status(400).json({ success: false, error: `Failed to exchange OAuth code: ${details}` });
75
- return;
76
- }
77
- const tokenData = await tokenResp.json();
78
- const profileResp = await fetch(GOOGLE_USERINFO_ENDPOINT, {
79
- headers: { Authorization: `Bearer ${tokenData.access_token}` },
80
- });
81
- if (!profileResp.ok) {
82
- const details = await profileResp.text();
83
- res.status(400).json({ success: false, error: `Failed to load Google profile: ${details}` });
84
- return;
18
+ /**
19
+ * Create the OAuth API router.
20
+ *
21
+ * Provides Google OAuth start and callback endpoints for connecting
22
+ * user accounts to Google services.
23
+ *
24
+ * @returns Express Router with OAuth routes
25
+ */
26
+ export function createOAuthRouter() {
27
+ const router = Router();
28
+ const users = UserIdentityService.getInstance();
29
+ const logger = LoggerService.getInstance().createComponentLogger('OAuthRoutes');
30
+ router.get('/google/start', async (req, res, next) => {
31
+ try {
32
+ const { clientId, redirectUri } = getGoogleConfig(req);
33
+ if (!clientId) {
34
+ res.status(500).json({ success: false, error: 'GOOGLE_OAUTH_CLIENT_ID is not configured' });
35
+ return;
36
+ }
37
+ const slackUserId = req.query.slackUserId ? String(req.query.slackUserId) : undefined;
38
+ const statePayload = {
39
+ slackUserId,
40
+ t: Date.now(),
41
+ nonce: crypto.randomUUID(),
42
+ };
43
+ const state = Buffer.from(JSON.stringify(statePayload)).toString('base64url');
44
+ const url = new URL(GOOGLE_OAUTH_CONSTANTS.AUTH_BASE_URL);
45
+ url.searchParams.set('client_id', clientId);
46
+ url.searchParams.set('redirect_uri', redirectUri);
47
+ url.searchParams.set('response_type', 'code');
48
+ url.searchParams.set('access_type', 'offline');
49
+ url.searchParams.set('prompt', 'consent');
50
+ url.searchParams.set('scope', GOOGLE_OAUTH_CONSTANTS.DEFAULT_SCOPES.join(' '));
51
+ url.searchParams.set('state', state);
52
+ res.json({ success: true, data: { authUrl: url.toString(), state } });
85
53
  }
86
- const profile = await profileResp.json();
87
- if (!profile.email) {
88
- res.status(400).json({ success: false, error: 'Google profile did not include email' });
89
- return;
54
+ catch (error) {
55
+ next(error);
90
56
  }
91
- let statePayload = {};
92
- if (state) {
93
- try {
94
- statePayload = JSON.parse(Buffer.from(state, 'base64url').toString('utf8'));
57
+ });
58
+ router.get('/google/callback', async (req, res, next) => {
59
+ try {
60
+ const code = req.query.code ? String(req.query.code) : '';
61
+ const state = req.query.state ? String(req.query.state) : '';
62
+ if (!code) {
63
+ res.status(400).json({ success: false, error: 'Missing code' });
64
+ return;
65
+ }
66
+ const { clientId, clientSecret, redirectUri } = getGoogleConfig(req);
67
+ if (!clientId || !clientSecret) {
68
+ res.status(500).json({ success: false, error: 'Google OAuth credentials are not configured' });
69
+ return;
95
70
  }
96
- catch {
97
- // best effort only
71
+ const tokenResp = await fetch(GOOGLE_OAUTH_CONSTANTS.TOKEN_ENDPOINT, {
72
+ method: 'POST',
73
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
74
+ body: new URLSearchParams({
75
+ code,
76
+ client_id: clientId,
77
+ client_secret: clientSecret,
78
+ redirect_uri: redirectUri,
79
+ grant_type: 'authorization_code',
80
+ }),
81
+ });
82
+ if (!tokenResp.ok) {
83
+ const details = await tokenResp.text();
84
+ res.status(400).json({ success: false, error: `Failed to exchange OAuth code: ${details}` });
85
+ return;
98
86
  }
87
+ const tokenData = await tokenResp.json();
88
+ const profileResp = await fetch(GOOGLE_OAUTH_CONSTANTS.USERINFO_ENDPOINT, {
89
+ headers: { Authorization: `Bearer ${tokenData.access_token}` },
90
+ });
91
+ if (!profileResp.ok) {
92
+ const details = await profileResp.text();
93
+ res.status(400).json({ success: false, error: `Failed to load Google profile: ${details}` });
94
+ return;
95
+ }
96
+ const profile = await profileResp.json();
97
+ if (!profile.email) {
98
+ res.status(400).json({ success: false, error: 'Google profile did not include email' });
99
+ return;
100
+ }
101
+ let statePayload = {};
102
+ if (state) {
103
+ try {
104
+ statePayload = JSON.parse(Buffer.from(state, 'base64url').toString('utf8'));
105
+ }
106
+ catch (err) {
107
+ logger.warn('Failed to parse OAuth state parameter', {
108
+ error: err instanceof Error ? err.message : String(err),
109
+ });
110
+ }
111
+ }
112
+ const user = await users.createOrUpdateUser({
113
+ email: profile.email,
114
+ slackUserId: statePayload.slackUserId,
115
+ });
116
+ if (!tokenData.refresh_token) {
117
+ logger.warn('Google OAuth did not return a refresh_token — using access_token as fallback', {
118
+ email: profile.email,
119
+ });
120
+ }
121
+ await users.connectService(user.id, 'google', {
122
+ refreshToken: tokenData.refresh_token || tokenData.access_token,
123
+ accessToken: tokenData.access_token,
124
+ scopes: (tokenData.scope || '').split(' ').filter(Boolean),
125
+ });
126
+ res.json({
127
+ success: true,
128
+ data: {
129
+ userId: user.id,
130
+ email: user.email,
131
+ connectedProvider: 'google',
132
+ slackUserId: user.slackUserId,
133
+ },
134
+ message: 'Google OAuth connected successfully',
135
+ });
99
136
  }
100
- const user = await users.createOrUpdateUser({
101
- email: profile.email,
102
- slackUserId: statePayload.slackUserId,
103
- });
104
- await users.connectService(user.id, 'google', {
105
- refreshToken: tokenData.refresh_token || tokenData.access_token,
106
- accessToken: tokenData.access_token,
107
- scopes: (tokenData.scope || '').split(' ').filter(Boolean),
108
- });
109
- res.json({
110
- success: true,
111
- data: {
112
- userId: user.id,
113
- email: user.email,
114
- connectedProvider: 'google',
115
- slackUserId: user.slackUserId,
116
- },
117
- message: 'Google OAuth connected successfully',
118
- });
119
- }
120
- catch (error) {
121
- next(error);
122
- }
123
- });
124
- export function createOAuthRouter() {
137
+ catch (error) {
138
+ next(error);
139
+ }
140
+ });
125
141
  return router;
126
142
  }
127
143
  //# sourceMappingURL=oauth.routes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/oauth/oauth.routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AAEnF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AACxB,MAAM,KAAK,GAAG,mBAAmB,CAAC,WAAW,EAAE,CAAC;AAEhD,MAAM,gBAAgB,GAAG,8CAA8C,CAAC;AACxE,MAAM,qBAAqB,GAAG,qCAAqC,CAAC;AACpE,MAAM,wBAAwB,GAAG,+CAA+C,CAAC;AAEjF,SAAS,eAAe,CAAC,GAAY;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC;IAC1D,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC;IAClE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,4BAA4B,CAAC;IAC9H,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACpF,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,0CAA0C,EAAE,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACtF,MAAM,YAAY,GAAG;YACnB,WAAW;YACX,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE;YACb,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;SAC3C,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAE9E,MAAM,MAAM,GAAG;YACb,QAAQ;YACR,OAAO;YACP,gDAAgD;YAChD,4CAA4C;SAC7C,CAAC;QAEF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACtC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC5C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAClD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAC9C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QAC/C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC1C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAErC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAC;IACd,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACvF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAChE,OAAO;QACT,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACrE,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6CAA6C,EAAE,CAAC,CAAC;YAC/F,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,qBAAqB,EAAE;YACnD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,IAAI;gBACJ,SAAS,EAAE,QAAQ;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,WAAW;gBACzB,UAAU,EAAE,oBAAoB;aACjC,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YACvC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7F,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,IAAI,EAKrC,CAAC;QAEF,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,wBAAwB,EAAE;YACxD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,SAAS,CAAC,YAAY,EAAE,EAAE;SAC/D,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7F,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,EAAwB,CAAC;QAC/D,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC,CAAC;YACxF,OAAO;QACT,CAAC;QAED,IAAI,YAAY,GAA6B,EAAE,CAAC;QAChD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC;gBACH,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9E,CAAC;YAAC,MAAM,CAAC;gBACP,mBAAmB;YACrB,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC;YAC1C,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,YAAY,CAAC,WAAW;SACtC,CAAC,CAAC;QAEH,MAAM,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE;YAC5C,YAAY,EAAE,SAAS,CAAC,aAAa,IAAI,SAAS,CAAC,YAAY;YAC/D,WAAW,EAAE,SAAS,CAAC,YAAY;YACnC,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;SAC3D,CAAC,CAAC;QAEH,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,iBAAiB,EAAE,QAAQ;gBAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B;YACD,OAAO,EAAE,qCAAqC;SAC/C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAC;IACd,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"oauth.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/oauth/oauth.routes.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,20 @@
1
1
  import { Request, Response } from 'express';
2
2
  import type { ApiController } from '../api.controller.js';
3
3
  import type { ApiContext } from '../types.js';
4
+ import type { EventBusService } from '../../services/event-bus/event-bus.service.js';
5
+ /**
6
+ * Set the EventBusService instance for task monitoring cleanup.
7
+ * Called during server initialization.
8
+ *
9
+ * @param service - The EventBusService instance
10
+ */
11
+ export declare function setEventBusServiceForTaskCleanup(service: EventBusService): void;
12
+ /**
13
+ * Get the current EventBusService reference (exposed for testing).
14
+ *
15
+ * @returns The EventBusService or null
16
+ */
17
+ export declare function getEventBusServiceForTaskCleanup(): EventBusService | null;
4
18
  /**
5
19
  * Creates a new task MD file in the project's .crewly/tasks/ directory.
6
20
  * Optionally assigns it immediately if a sessionName is provided.
@@ -99,4 +113,24 @@ export declare function getTaskOutput(this: ApiController, req: Request, res: Re
99
113
  * @param res - Response with { success, data: { message: string } }
100
114
  */
101
115
  export declare function requestReview(this: ApiController, req: Request, res: Response): Promise<void>;
116
+ /**
117
+ * Adds monitoring IDs (schedule and subscription IDs) to tasks for a given agent session.
118
+ * Called by delegate-task after setting up auto-monitoring to link monitoring resources
119
+ * to the task for auto-cleanup on completion.
120
+ *
121
+ * @param req - Request containing sessionName, scheduleIds, subscriptionIds
122
+ * @param res - Response with success status
123
+ */
124
+ export declare function addMonitoring(this: ApiController, req: Request, res: Response): Promise<void>;
125
+ /**
126
+ * Completes all tasks assigned to a given agent session.
127
+ *
128
+ * Called by the report-status skill when an agent reports status=done.
129
+ * Finds all in-progress/assigned tasks for the session, marks them as
130
+ * completed in task tracking, and cleans up monitoring resources.
131
+ *
132
+ * @param req - Request containing sessionName
133
+ * @param res - Response with list of completed tasks
134
+ */
135
+ export declare function completeTasksBySession(this: ApiController, req: Request, res: Response): Promise<void>;
102
136
  //# sourceMappingURL=task-management.controller.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"task-management.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/task-management/task-management.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa9C;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAsGhG;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HhG;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CAuNf;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA+D/F;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DjG;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CA+Df;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACpC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CA4Ff;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACvC,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CA+Gf;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B3G;AAED,wBAAsB,qBAAqB,CAC1C,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CAkIf;AA6ID;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C9F;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCnG;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAClC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,CAoCf"}
1
+ {"version":3,"file":"task-management.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/task-management/task-management.controller.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,25 @@ import { LoggerService } from '../../services/core/logger.service.js';
8
8
  import { TaskOutputValidatorService } from '../../services/quality/task-output-validator.service.js';
9
9
  import { TASK_OUTPUT_CONSTANTS } from '../../types/task-output.types.js';
10
10
  const logger = LoggerService.getInstance().createComponentLogger('TaskManagementController');
11
+ /** Module-level reference to EventBusService for auto-cleanup on task completion */
12
+ let eventBusService = null;
13
+ /**
14
+ * Set the EventBusService instance for task monitoring cleanup.
15
+ * Called during server initialization.
16
+ *
17
+ * @param service - The EventBusService instance
18
+ */
19
+ export function setEventBusServiceForTaskCleanup(service) {
20
+ eventBusService = service;
21
+ }
22
+ /**
23
+ * Get the current EventBusService reference (exposed for testing).
24
+ *
25
+ * @returns The EventBusService or null
26
+ */
27
+ export function getEventBusServiceForTaskCleanup() {
28
+ return eventBusService;
29
+ }
11
30
  /**
12
31
  * Creates a new task MD file in the project's .crewly/tasks/ directory.
13
32
  * Optionally assigns it immediately if a sessionName is provided.
@@ -351,10 +370,12 @@ export async function completeTask(req, res) {
351
370
  const updatedContent = addTaskCompletionInfo(taskContent);
352
371
  await writeFile(doneTargetPath, updatedContent, 'utf-8');
353
372
  await unlinkFile(taskPath);
354
- // Remove from task tracking
373
+ // Remove from task tracking and clean up monitoring
355
374
  const allTasksWithSchema = await this.taskTrackingService.getAllInProgressTasks();
356
375
  const taskToRemoveWithSchema = allTasksWithSchema.find(t => t.taskFilePath === taskPath);
376
+ let cleanupResultSchema = { cancelledSchedules: 0, unsubscribedEvents: 0 };
357
377
  if (taskToRemoveWithSchema) {
378
+ cleanupResultSchema = await cleanupTaskMonitoring(this, taskToRemoveWithSchema);
358
379
  await this.taskTrackingService.removeTask(taskToRemoveWithSchema.id);
359
380
  }
360
381
  res.json({
@@ -365,6 +386,7 @@ export async function completeTask(req, res) {
365
386
  outputPath: outputFilePath,
366
387
  status: 'done',
367
388
  completedAt: new Date().toISOString(),
389
+ monitoringCleanup: cleanupResultSchema,
368
390
  });
369
391
  return;
370
392
  }
@@ -378,10 +400,12 @@ export async function completeTask(req, res) {
378
400
  const updatedContent = addTaskCompletionInfo(taskContent);
379
401
  await writeFile(targetPath, updatedContent, 'utf-8');
380
402
  await unlinkFile(taskPath);
381
- // Remove from task tracking (find task by file path and remove it)
403
+ // Remove from task tracking and clean up monitoring
382
404
  const allTasks = await this.taskTrackingService.getAllInProgressTasks();
383
405
  const taskToRemove = allTasks.find(t => t.taskFilePath === taskPath);
406
+ let cleanupResult = { cancelledSchedules: 0, unsubscribedEvents: 0 };
384
407
  if (taskToRemove) {
408
+ cleanupResult = await cleanupTaskMonitoring(this, taskToRemove);
385
409
  await this.taskTrackingService.removeTask(taskToRemove.id);
386
410
  }
387
411
  res.json({
@@ -391,6 +415,7 @@ export async function completeTask(req, res) {
391
415
  newPath: targetPath,
392
416
  status: 'done',
393
417
  completedAt: new Date().toISOString(),
418
+ monitoringCleanup: cleanupResult,
394
419
  });
395
420
  }
396
421
  catch (error) {
@@ -1203,4 +1228,196 @@ export async function requestReview(req, res) {
1203
1228
  });
1204
1229
  }
1205
1230
  }
1231
+ /**
1232
+ * Cleans up monitoring resources (scheduled checks and event subscriptions)
1233
+ * linked to a task. Called automatically when a task is completed.
1234
+ *
1235
+ * @param controller - The ApiController instance (for schedulerService access)
1236
+ * @param task - The task whose monitoring to clean up
1237
+ * @returns Object with counts of cancelled schedules and unsubscribed events
1238
+ */
1239
+ async function cleanupTaskMonitoring(controller, task) {
1240
+ let cancelledSchedules = 0;
1241
+ let unsubscribedEvents = 0;
1242
+ // Cancel linked schedules
1243
+ if (task.scheduleIds && task.scheduleIds.length > 0) {
1244
+ for (const scheduleId of task.scheduleIds) {
1245
+ try {
1246
+ controller.schedulerService.cancelCheck(scheduleId);
1247
+ cancelledSchedules++;
1248
+ }
1249
+ catch (error) {
1250
+ logger.warn('Failed to cancel schedule during task cleanup', {
1251
+ scheduleId,
1252
+ error: error instanceof Error ? error.message : String(error),
1253
+ });
1254
+ }
1255
+ }
1256
+ }
1257
+ // Unsubscribe linked event subscriptions
1258
+ if (task.subscriptionIds && task.subscriptionIds.length > 0 && eventBusService) {
1259
+ for (const subscriptionId of task.subscriptionIds) {
1260
+ try {
1261
+ eventBusService.unsubscribe(subscriptionId);
1262
+ unsubscribedEvents++;
1263
+ }
1264
+ catch (error) {
1265
+ logger.warn('Failed to unsubscribe event during task cleanup', {
1266
+ subscriptionId,
1267
+ error: error instanceof Error ? error.message : String(error),
1268
+ });
1269
+ }
1270
+ }
1271
+ }
1272
+ if (cancelledSchedules > 0 || unsubscribedEvents > 0) {
1273
+ logger.info('Task monitoring cleaned up', { cancelledSchedules, unsubscribedEvents });
1274
+ }
1275
+ return { cancelledSchedules, unsubscribedEvents };
1276
+ }
1277
+ /**
1278
+ * Adds monitoring IDs (schedule and subscription IDs) to tasks for a given agent session.
1279
+ * Called by delegate-task after setting up auto-monitoring to link monitoring resources
1280
+ * to the task for auto-cleanup on completion.
1281
+ *
1282
+ * @param req - Request containing sessionName, scheduleIds, subscriptionIds
1283
+ * @param res - Response with success status
1284
+ */
1285
+ export async function addMonitoring(req, res) {
1286
+ try {
1287
+ const { sessionName, scheduleIds = [], subscriptionIds = [] } = req.body;
1288
+ if (!sessionName) {
1289
+ res.status(400).json({ success: false, error: 'sessionName is required' });
1290
+ return;
1291
+ }
1292
+ if (scheduleIds.length === 0 && subscriptionIds.length === 0) {
1293
+ res.status(400).json({ success: false, error: 'At least one scheduleId or subscriptionId is required' });
1294
+ return;
1295
+ }
1296
+ // Find the most recent task assigned to this session
1297
+ const tasks = await this.taskTrackingService.getTasksBySessionName(sessionName);
1298
+ if (tasks.length === 0) {
1299
+ // No tracked task found — store IDs anyway by finding any in_progress_tasks entry
1300
+ logger.warn('No tracked tasks found for session, storing monitoring IDs for session-level cleanup', { sessionName });
1301
+ res.json({
1302
+ success: true,
1303
+ message: 'No tracked task found for session; monitoring IDs noted but not linked to a task',
1304
+ sessionName,
1305
+ scheduleIds,
1306
+ subscriptionIds,
1307
+ });
1308
+ return;
1309
+ }
1310
+ // Link to the most recently assigned task
1311
+ const latestTask = tasks.sort((a, b) => new Date(b.assignedAt).getTime() - new Date(a.assignedAt).getTime())[0];
1312
+ await this.taskTrackingService.addMonitoringIds(latestTask.id, scheduleIds, subscriptionIds);
1313
+ res.json({
1314
+ success: true,
1315
+ message: 'Monitoring IDs linked to task',
1316
+ taskId: latestTask.id,
1317
+ taskName: latestTask.taskName,
1318
+ scheduleIds,
1319
+ subscriptionIds,
1320
+ });
1321
+ }
1322
+ catch (error) {
1323
+ logger.error('Error adding monitoring IDs', { error: error instanceof Error ? error.message : String(error) });
1324
+ res.status(500).json({ success: false, error: 'Failed to add monitoring IDs' });
1325
+ }
1326
+ }
1327
+ /**
1328
+ * Completes all tasks assigned to a given agent session.
1329
+ *
1330
+ * Called by the report-status skill when an agent reports status=done.
1331
+ * Finds all in-progress/assigned tasks for the session, marks them as
1332
+ * completed in task tracking, and cleans up monitoring resources.
1333
+ *
1334
+ * @param req - Request containing sessionName
1335
+ * @param res - Response with list of completed tasks
1336
+ */
1337
+ export async function completeTasksBySession(req, res) {
1338
+ try {
1339
+ const { sessionName } = req.body;
1340
+ if (!sessionName) {
1341
+ res.status(400).json({ success: false, error: 'sessionName is required' });
1342
+ return;
1343
+ }
1344
+ const tasks = await this.taskTrackingService.getTasksBySessionName(sessionName);
1345
+ const activeTasks = tasks.filter(t => t.status === 'assigned' || t.status === 'active');
1346
+ if (activeTasks.length === 0) {
1347
+ res.json({
1348
+ success: true,
1349
+ message: 'No active tasks found for session',
1350
+ sessionName,
1351
+ completedCount: 0,
1352
+ completedTasks: [],
1353
+ });
1354
+ return;
1355
+ }
1356
+ const completedTasks = [];
1357
+ let totalCancelledSchedules = 0;
1358
+ let totalUnsubscribedEvents = 0;
1359
+ for (const task of activeTasks) {
1360
+ try {
1361
+ // Move task file from in_progress/ to done/ if it exists
1362
+ if (task.taskFilePath && task.taskFilePath.includes('/in_progress/') && existsSync(task.taskFilePath)) {
1363
+ try {
1364
+ const targetPath = task.taskFilePath.replace('/in_progress/', '/done/');
1365
+ const targetDir = dirname(targetPath);
1366
+ await ensureDirectoryExists(targetDir);
1367
+ const taskContent = await readFile(task.taskFilePath, 'utf-8');
1368
+ const updatedContent = addTaskCompletionInfo(taskContent);
1369
+ await writeFile(targetPath, updatedContent, 'utf-8');
1370
+ await unlink(task.taskFilePath);
1371
+ logger.debug('Moved task file to done', {
1372
+ taskId: task.id,
1373
+ from: task.taskFilePath,
1374
+ to: targetPath,
1375
+ });
1376
+ }
1377
+ catch (fileError) {
1378
+ logger.warn('Failed to move task file to done (continuing with tracking cleanup)', {
1379
+ taskId: task.id,
1380
+ taskFilePath: task.taskFilePath,
1381
+ error: fileError instanceof Error ? fileError.message : String(fileError),
1382
+ });
1383
+ }
1384
+ }
1385
+ // Clean up monitoring resources
1386
+ const cleanup = await cleanupTaskMonitoring(this, task);
1387
+ totalCancelledSchedules += cleanup.cancelledSchedules;
1388
+ totalUnsubscribedEvents += cleanup.unsubscribedEvents;
1389
+ // Remove from tracking
1390
+ await this.taskTrackingService.removeTask(task.id);
1391
+ completedTasks.push(task.taskName);
1392
+ logger.info('Auto-completed task for session', {
1393
+ taskId: task.id,
1394
+ taskName: task.taskName,
1395
+ sessionName,
1396
+ });
1397
+ }
1398
+ catch (error) {
1399
+ logger.warn('Failed to auto-complete task', {
1400
+ taskId: task.id,
1401
+ taskName: task.taskName,
1402
+ error: error instanceof Error ? error.message : String(error),
1403
+ });
1404
+ }
1405
+ }
1406
+ res.json({
1407
+ success: true,
1408
+ message: `Completed ${completedTasks.length} task(s) for session ${sessionName}`,
1409
+ sessionName,
1410
+ completedCount: completedTasks.length,
1411
+ completedTasks,
1412
+ monitoringCleanup: {
1413
+ cancelledSchedules: totalCancelledSchedules,
1414
+ unsubscribedEvents: totalUnsubscribedEvents,
1415
+ },
1416
+ });
1417
+ }
1418
+ catch (error) {
1419
+ logger.error('Error completing tasks by session', { error: error instanceof Error ? error.message : String(error) });
1420
+ res.status(500).json({ success: false, error: 'Failed to complete tasks by session' });
1421
+ }
1422
+ }
1206
1423
  //# sourceMappingURL=task-management.controller.js.map