crewly 1.3.31 → 1.4.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.
- package/config/constants.ts +18 -3
- package/config/hooks/install-hooks.sh +88 -0
- package/config/hooks/pre-commit +104 -0
- package/config/orchestrator_tasks/prompts/orchestrator-prompt.md +17 -24
- package/config/roles/auditor/role.json +13 -0
- package/config/roles/orchestrator/prompt.md +25 -0
- package/config/roles/product-manager/prompt.md +18 -1
- package/config/roles/researcher/prompt.md +110 -0
- package/config/roles/team-leader/prompt.md +31 -8
- package/config/roles/team-leader/tl-addon.md +40 -9
- package/config/roles/ux-designer/prompt.md +111 -0
- package/config/skills/_common/lib.sh +33 -0
- package/config/skills/agent/browse-stealth/{instructions.md → SKILL.md} +40 -0
- package/config/skills/agent/chrome-attach/SKILL.md +84 -0
- package/config/skills/agent/chrome-attach/execute.sh +279 -0
- package/config/skills/agent/competitor-content-tracker/{instructions.md → SKILL.md} +34 -0
- package/config/skills/agent/computer-use/{instructions.md → SKILL.md} +43 -0
- package/config/skills/agent/content-calendar/{instructions.md → SKILL.md} +32 -0
- package/config/skills/agent/content-repurposer/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/content-writer/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/core/accept-task/{instructions.md → SKILL.md} +37 -0
- package/config/skills/agent/core/block-task/{instructions.md → SKILL.md} +37 -0
- package/config/skills/agent/core/check-quality-gates/{instructions.md → SKILL.md} +40 -0
- package/config/skills/agent/core/complete-task/{instructions.md → SKILL.md} +37 -0
- package/config/skills/agent/core/complete-task/execute.sh +15 -0
- package/config/skills/agent/core/generate-pdf/{instructions.md → SKILL.md} +42 -0
- package/config/skills/agent/core/get-my-context/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/core/get-sops/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/core/get-team-norms/execute.sh +106 -0
- package/config/skills/agent/core/get-team-status/SKILL.md +55 -0
- package/config/skills/agent/core/handoff-task/execute.sh +150 -0
- package/config/skills/agent/core/heartbeat/{instructions.md → SKILL.md} +27 -0
- package/config/skills/agent/core/marketplace-search/{instructions.md → SKILL.md} +41 -0
- package/config/skills/agent/core/query-knowledge/{instructions.md → SKILL.md} +40 -0
- package/config/skills/agent/core/read-task/SKILL.md +56 -0
- package/config/skills/agent/core/recall/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/core/record-learning/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/core/register-self/SKILL.md +54 -0
- package/config/skills/agent/core/remember/{instructions.md → SKILL.md} +37 -0
- package/config/skills/agent/core/remember/execute.sh +6 -0
- package/config/skills/agent/core/reply-chat/{instructions.md → SKILL.md} +37 -0
- package/config/skills/agent/core/report-progress/{instructions.md → SKILL.md} +38 -0
- package/config/skills/agent/core/report-status/{instructions.md → SKILL.md} +39 -0
- package/config/skills/agent/core/send-chat-response/{instructions.md → SKILL.md} +37 -0
- package/config/skills/agent/core/send-message/SKILL.md +58 -0
- package/config/skills/agent/core/update-team-norm/execute.sh +115 -0
- package/config/skills/agent/desktop-app-control/{instructions.md → SKILL.md} +42 -0
- package/config/skills/agent/trend-monitor/{instructions.md → SKILL.md} +34 -0
- package/config/skills/agent/vnc-browser/{instructions.md → SKILL.md} +38 -0
- package/config/skills/auditor/score-task/SKILL.md +28 -0
- package/config/skills/auditor/score-task/execute.sh +21 -0
- package/config/skills/examples/enterprise-skill-example.json +22 -0
- package/config/skills/examples/premium-skill-example.json +22 -0
- package/config/skills/orchestrator/assign-task/SKILL.md +41 -0
- package/config/skills/orchestrator/assign-team-to-project/{instructions.md → SKILL.md} +25 -0
- package/config/skills/orchestrator/broadcast/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/broadcast-to-org/{instructions.md → SKILL.md} +25 -0
- package/config/skills/orchestrator/cancel-all-schedules/{instructions.md → SKILL.md} +5 -0
- package/config/skills/orchestrator/cancel-schedule/SKILL.md +43 -0
- package/config/skills/orchestrator/complete-task/SKILL.md +41 -0
- package/config/skills/orchestrator/create-project/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/create-team/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/delegate-task/{instructions.md → SKILL.md} +27 -0
- package/config/skills/orchestrator/delegate-task/execute.sh +31 -2
- package/config/skills/orchestrator/get-agent-logs/{instructions.md → SKILL.md} +25 -0
- package/config/skills/orchestrator/get-agent-status/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/get-project-overview/SKILL.md +41 -0
- package/config/skills/orchestrator/get-tasks/SKILL.md +41 -0
- package/config/skills/orchestrator/get-team-status/SKILL.md +43 -0
- package/config/skills/orchestrator/handle-agent-failure/{instructions.md → SKILL.md} +27 -0
- package/config/skills/orchestrator/heartbeat/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/list-schedules/{instructions.md → SKILL.md} +5 -0
- package/config/skills/orchestrator/list-subscriptions/SKILL.md +41 -0
- package/config/skills/orchestrator/query-knowledge/{instructions.md → SKILL.md} +28 -0
- package/config/skills/orchestrator/read-session-logs/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/read-system-logs/{instructions.md → SKILL.md} +25 -0
- package/config/skills/orchestrator/recall/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/record-failure/{instructions.md → SKILL.md} +27 -0
- package/config/skills/orchestrator/record-learning/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/record-success/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/register-self/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/remember/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/reply-chat/{instructions.md → SKILL.md} +25 -0
- package/config/skills/orchestrator/reply-chat/execute.sh +0 -13
- package/config/skills/orchestrator/reply-gchat/{instructions.md → SKILL.md} +25 -0
- package/config/skills/orchestrator/reply-gchat/execute.sh +0 -18
- package/config/skills/orchestrator/reply-slack/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/reply-slack/execute.sh +18 -31
- package/config/skills/orchestrator/report-bug/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/restart-crewly/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/resume-session/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/schedule-check/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/send-key/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/send-message/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/send-pdf-to-slack/{instructions.md → SKILL.md} +27 -0
- package/config/skills/orchestrator/set-goal/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/start-agent/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/start-team/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/stop-agent/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/stop-team/SKILL.md +43 -0
- package/config/skills/orchestrator/subscribe-event/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/terminate-agent/{instructions.md → SKILL.md} +24 -0
- package/config/skills/orchestrator/unsubscribe-event/SKILL.md +42 -0
- package/config/skills/orchestrator/update-focus/{instructions.md → SKILL.md} +26 -0
- package/config/skills/orchestrator/update-team/{instructions.md → SKILL.md} +24 -0
- package/config/skills/team-leader/aggregate-results/{instructions.md → SKILL.md} +26 -0
- package/config/skills/team-leader/decompose-goal/{instructions.md → SKILL.md} +26 -0
- package/config/skills/team-leader/delegate-task/{instructions.md → SKILL.md} +26 -0
- package/config/skills/team-leader/delegate-task/execute.sh +14 -6
- package/config/skills/team-leader/delegate-task/execute.test.sh +401 -0
- package/config/skills/team-leader/handle-failure/{instructions.md → SKILL.md} +27 -0
- package/config/skills/team-leader/schedule-check/{instructions.md → SKILL.md} +26 -0
- package/config/skills/team-leader/start-agent/{instructions.md → SKILL.md} +26 -0
- package/config/skills/team-leader/stop-agent/{instructions.md → SKILL.md} +26 -0
- package/config/skills/team-leader/verify-output/{instructions.md → SKILL.md} +27 -0
- package/config/templates/agent-agents-md.md +35 -0
- package/config/templates/agent-gemini-md.md +35 -0
- package/config/templates/code-review-team/team-config.json +7 -0
- package/config/templates/content-generation-team/norms/brand-guidelines.md +64 -0
- package/config/templates/content-generation-team/norms/content-review.md +66 -0
- package/config/templates/content-generation-team/norms/publish-checklist.md +58 -0
- package/config/templates/content-generation-team/team-config.json +8 -0
- package/config/templates/dev-fullstack/norms/code-commit-sop.md +40 -0
- package/config/templates/dev-fullstack/norms/quality-gates.md +35 -0
- package/config/templates/dev-fullstack/template.json +17 -1
- package/config/templates/education-smb/template.json +10 -1
- package/config/templates/insurance-smb/template.json +10 -1
- package/config/templates/research-analysis/norms/research-methodology.md +36 -0
- package/config/templates/research-analysis/norms/source-citation.md +33 -0
- package/config/templates/research-analysis/template.json +17 -1
- package/config/templates/security-audit-team.json +67 -0
- package/config/templates/social-media-ops/norms/engagement-rules.md +35 -0
- package/config/templates/social-media-ops/norms/posting-schedule.md +43 -0
- package/config/templates/social-media-ops/template.json +17 -1
- package/config/templates/video-production/template.json +10 -1
- package/dist/backend/backend/src/constants.d.ts +80 -11
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +85 -11
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.d.ts +99 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.js +183 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.d.ts +15 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.js +27 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-google-auth.controller.d.ts +70 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-google-auth.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-google-auth.controller.js +368 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-google-auth.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts +24 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +195 -3
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts +9 -4
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.js +19 -5
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/index.d.ts +1 -0
- package/dist/backend/backend/src/controllers/cloud/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/index.js +1 -0
- package/dist/backend/backend/src/controllers/cloud/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/index.js +2 -0
- package/dist/backend/backend/src/controllers/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.d.ts +3 -3
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.js +9 -9
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js +6 -6
- package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts +0 -7
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +2 -135
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts +14 -0
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +96 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.js +8 -1
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/payment/payment.controller.js +2 -2
- package/dist/backend/backend/src/controllers/payment/payment.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/payment/payment.routes.d.ts +3 -3
- package/dist/backend/backend/src/controllers/payment/payment.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/payment/payment.routes.js +4 -14
- package/dist/backend/backend/src/controllers/payment/payment.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/payment/payment.types.d.ts +15 -94
- package/dist/backend/backend/src/controllers/payment/payment.types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/payment/payment.types.js +11 -35
- package/dist/backend/backend/src/controllers/payment/payment.types.js.map +1 -1
- package/dist/backend/backend/src/controllers/pr-review/pr-review.controller.d.ts +49 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.controller.js +138 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.routes.d.ts +20 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.routes.js +30 -0
- package/dist/backend/backend/src/controllers/pr-review/pr-review.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/quality-gate/quality-gate.controller.d.ts +12 -0
- package/dist/backend/backend/src/controllers/quality-gate/quality-gate.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/quality-gate/quality-gate.controller.js +107 -0
- package/dist/backend/backend/src/controllers/quality-gate/quality-gate.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/request-types.d.ts +20 -1
- package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +11 -5
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +46 -0
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +598 -326
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts +12 -0
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +105 -36
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js +2 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/template/template.controller.d.ts +11 -0
- package/dist/backend/backend/src/controllers/template/template.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/template/template.controller.js +59 -0
- package/dist/backend/backend/src/controllers/template/template.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/template/template.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/template/template.routes.js +2 -1
- package/dist/backend/backend/src/controllers/template/template.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/workspace/workspace.controller.d.ts +39 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.controller.js +120 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.routes.d.ts +18 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.routes.js +27 -0
- package/dist/backend/backend/src/controllers/workspace/workspace.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +108 -15
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/require-auth.middleware.d.ts +20 -0
- package/dist/backend/backend/src/middleware/require-auth.middleware.d.ts.map +1 -0
- package/dist/backend/backend/src/middleware/require-auth.middleware.js +21 -0
- package/dist/backend/backend/src/middleware/require-auth.middleware.js.map +1 -0
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +18 -5
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/quality-gate.routes.d.ts +2 -1
- package/dist/backend/backend/src/routes/modules/quality-gate.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/quality-gate.routes.js +4 -2
- package/dist/backend/backend/src/routes/modules/quality-gate.routes.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.js +8 -0
- package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/terminal.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/terminal.routes.js +4 -0
- package/dist/backend/backend/src/routes/modules/terminal.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/adaptive-heartbeat.service.d.ts +149 -0
- package/dist/backend/backend/src/services/agent/adaptive-heartbeat.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/adaptive-heartbeat.service.js +200 -0
- package/dist/backend/backend/src/services/agent/adaptive-heartbeat.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.d.ts +13 -0
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.js +65 -6
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +36 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +174 -52
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/auditor-scheduler.service.d.ts +66 -20
- package/dist/backend/backend/src/services/agent/auditor-scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/auditor-scheduler.service.js +261 -60
- package/dist/backend/backend/src/services/agent/auditor-scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts +19 -0
- package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.js +80 -0
- package/dist/backend/backend/src/services/agent/claude-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts +11 -0
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +49 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +74 -3
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +248 -18
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/approval-queue.service.d.ts +161 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/approval-queue.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/approval-queue.service.js +237 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/approval-queue.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts +74 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js +140 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js +50 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +16 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +45 -5
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts +3 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/index.js +3 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts +135 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js +185 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +10 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +22 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +143 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +264 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js +2 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts +55 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js +660 -45
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +75 -3
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js +49 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +17 -2
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +37 -0
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js +170 -3
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/browser/chrome-discovery.service.d.ts +108 -0
- package/dist/backend/backend/src/services/browser/chrome-discovery.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/browser/chrome-discovery.service.js +251 -0
- package/dist/backend/backend/src/services/browser/chrome-discovery.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +12 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +19 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts +191 -0
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js +415 -0
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/device-identity.service.d.ts +89 -0
- package/dist/backend/backend/src/services/cloud/device-identity.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/device-identity.service.js +148 -0
- package/dist/backend/backend/src/services/cloud/device-identity.service.js.map +1 -0
- package/dist/backend/backend/src/services/core/tracing.service.d.ts +127 -0
- package/dist/backend/backend/src/services/core/tracing.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/core/tracing.service.js +238 -0
- package/dist/backend/backend/src/services/core/tracing.service.js.map +1 -0
- package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js +11 -3
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
- package/dist/backend/backend/src/services/index.d.ts +1 -0
- package/dist/backend/backend/src/services/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/index.js +1 -0
- package/dist/backend/backend/src/services/index.js.map +1 -1
- package/dist/backend/backend/src/services/knowledge/embedding-provider.d.ts +78 -0
- package/dist/backend/backend/src/services/knowledge/embedding-provider.d.ts.map +1 -0
- package/dist/backend/backend/src/services/knowledge/embedding-provider.js +164 -0
- package/dist/backend/backend/src/services/knowledge/embedding-provider.js.map +1 -0
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts +39 -13
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +114 -17
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
- package/dist/backend/backend/src/services/knowledge/vector-store.service.d.ts +170 -23
- package/dist/backend/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/knowledge/vector-store.service.js +565 -73
- package/dist/backend/backend/src/services/knowledge/vector-store.service.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js +8 -11
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace.service.js +1 -0
- package/dist/backend/backend/src/services/marketplace/marketplace.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/context-flush.service.d.ts +73 -0
- package/dist/backend/backend/src/services/memory/context-flush.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/context-flush.service.js +131 -0
- package/dist/backend/backend/src/services/memory/context-flush.service.js.map +1 -0
- package/dist/backend/backend/src/services/memory/learning-accumulation.service.d.ts +23 -2
- package/dist/backend/backend/src/services/memory/learning-accumulation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/learning-accumulation.service.js +78 -16
- package/dist/backend/backend/src/services/memory/learning-accumulation.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.d.ts +38 -0
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +121 -2
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.d.ts +29 -207
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js +97 -683
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/google-chat-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/google-chat-initializer.js +13 -12
- package/dist/backend/backend/src/services/messaging/google-chat-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts +2 -0
- package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts +6 -23
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +48 -184
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +51 -5
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/index.d.ts +1 -1
- package/dist/backend/backend/src/services/orchestrator/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/index.js +1 -1
- package/dist/backend/backend/src/services/orchestrator/index.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts +65 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +165 -2
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts +8 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js +23 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -1
- package/dist/backend/backend/src/services/payment/stripe.service.d.ts +95 -43
- package/dist/backend/backend/src/services/payment/stripe.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/payment/stripe.service.js +229 -190
- package/dist/backend/backend/src/services/payment/stripe.service.js.map +1 -1
- package/dist/backend/backend/src/services/pr-review/pr-review.service.d.ts +181 -0
- package/dist/backend/backend/src/services/pr-review/pr-review.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/pr-review/pr-review.service.js +336 -0
- package/dist/backend/backend/src/services/pr-review/pr-review.service.js.map +1 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +23 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js +88 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/index.d.ts +2 -0
- package/dist/backend/backend/src/services/session/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/index.js +2 -0
- package/dist/backend/backend/src/services/session/index.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-handoff.service.d.ts +260 -0
- package/dist/backend/backend/src/services/session/session-handoff.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/session/session-handoff.service.js +565 -0
- package/dist/backend/backend/src/services/session/session-handoff.service.js.map +1 -0
- package/dist/backend/backend/src/services/skill/index.d.ts +1 -0
- package/dist/backend/backend/src/services/skill/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/index.js +1 -0
- package/dist/backend/backend/src/services/skill/index.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-catalog.service.d.ts +25 -6
- package/dist/backend/backend/src/services/skill/skill-catalog.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-catalog.service.js +78 -20
- package/dist/backend/backend/src/services/skill/skill-catalog.service.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-tier.service.d.ts +116 -0
- package/dist/backend/backend/src/services/skill/skill-tier.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/skill/skill-tier.service.js +155 -0
- package/dist/backend/backend/src/services/skill/skill-tier.service.js.map +1 -0
- package/dist/backend/backend/src/services/skill/skill.service.d.ts +35 -7
- package/dist/backend/backend/src/services/skill/skill.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill.service.js +128 -35
- package/dist/backend/backend/src/services/skill/skill.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +50 -47
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +267 -202
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts +28 -2
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +69 -3
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.d.ts +19 -1
- package/dist/backend/backend/src/services/template/template.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.js +110 -3
- package/dist/backend/backend/src/services/template/template.service.js.map +1 -1
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts +11 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +57 -3
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.js +6 -0
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts +52 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js +319 -6
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/chat.types.d.ts +2 -2
- package/dist/backend/backend/src/types/chat.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/chat.types.js +18 -22
- package/dist/backend/backend/src/types/chat.types.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +37 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/marketplace.types.d.ts +1 -1
- package/dist/backend/backend/src/types/marketplace.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/scheduler.types.d.ts +4 -0
- package/dist/backend/backend/src/types/scheduler.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/scheduler.types.js.map +1 -1
- package/dist/backend/backend/src/types/skill.types.d.ts +4 -0
- package/dist/backend/backend/src/types/skill.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/skill.types.js.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.d.ts +6 -0
- package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
- package/dist/backend/backend/src/types/team-template.types.d.ts +2 -0
- package/dist/backend/backend/src/types/team-template.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/team-template.types.js.map +1 -1
- package/dist/backend/backend/src/utils/skill-md-parser.d.ts +38 -0
- package/dist/backend/backend/src/utils/skill-md-parser.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/skill-md-parser.js +47 -0
- package/dist/backend/backend/src/utils/skill-md-parser.js.map +1 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +0 -154
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.js +0 -515
- package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
- package/dist/backend/config/constants.d.ts +18 -3
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +18 -3
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +80 -11
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +85 -11
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/knowledge/embedding-provider.d.ts +78 -0
- package/dist/cli/backend/src/services/knowledge/embedding-provider.d.ts.map +1 -0
- package/dist/cli/backend/src/services/knowledge/embedding-provider.js +164 -0
- package/dist/cli/backend/src/services/knowledge/embedding-provider.js.map +1 -0
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts +39 -13
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +114 -17
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
- package/dist/cli/backend/src/services/knowledge/vector-store.service.d.ts +170 -23
- package/dist/cli/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/knowledge/vector-store.service.js +565 -73
- package/dist/cli/backend/src/services/knowledge/vector-store.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.d.ts +38 -0
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +121 -2
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/types/chat.types.d.ts +2 -2
- package/dist/cli/backend/src/types/chat.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/chat.types.js +18 -22
- package/dist/cli/backend/src/types/chat.types.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +37 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/scheduler.types.d.ts +4 -0
- package/dist/cli/backend/src/types/scheduler.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/scheduler.types.js.map +1 -1
- package/dist/cli/backend/src/types/skill.types.d.ts +4 -0
- package/dist/cli/backend/src/types/skill.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/skill.types.js.map +1 -1
- package/dist/cli/cli/src/commands/onboard.d.ts +19 -2
- package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/onboard.js +58 -15
- package/dist/cli/cli/src/commands/onboard.js.map +1 -1
- package/dist/cli/cli/src/commands/pair.d.ts +46 -0
- package/dist/cli/cli/src/commands/pair.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/pair.js +258 -0
- package/dist/cli/cli/src/commands/pair.js.map +1 -0
- package/dist/cli/cli/src/commands/service.d.ts +86 -0
- package/dist/cli/cli/src/commands/service.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/service.js +687 -0
- package/dist/cli/cli/src/commands/service.js.map +1 -0
- package/dist/cli/cli/src/index.js +17 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/config/constants.d.ts +18 -3
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +18 -3
- package/dist/cli/config/constants.js.map +1 -1
- package/frontend/dist/assets/index-1d23cce8.js +4919 -0
- package/frontend/dist/assets/index-60a9e4ea.css +33 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +22 -10
- package/config/skills/agent/browse-stealth/skill.json +0 -20
- package/config/skills/agent/competitor-content-tracker/skill.json +0 -22
- package/config/skills/agent/computer-use/skill.json +0 -29
- package/config/skills/agent/content-calendar/skill.json +0 -22
- package/config/skills/agent/content-repurposer/skill.json +0 -22
- package/config/skills/agent/content-writer/skill.json +0 -22
- package/config/skills/agent/core/accept-task/skill.json +0 -20
- package/config/skills/agent/core/block-task/skill.json +0 -20
- package/config/skills/agent/core/check-quality-gates/skill.json +0 -20
- package/config/skills/agent/core/complete-task/skill.json +0 -20
- package/config/skills/agent/core/generate-pdf/skill.json +0 -20
- package/config/skills/agent/core/get-my-context/skill.json +0 -20
- package/config/skills/agent/core/get-sops/skill.json +0 -20
- package/config/skills/agent/core/get-team-status/instructions.md +0 -17
- package/config/skills/agent/core/get-team-status/skill.json +0 -20
- package/config/skills/agent/core/heartbeat/skill.json +0 -20
- package/config/skills/agent/core/marketplace-search/skill.json +0 -20
- package/config/skills/agent/core/query-knowledge/skill.json +0 -20
- package/config/skills/agent/core/read-task/instructions.md +0 -19
- package/config/skills/agent/core/read-task/skill.json +0 -20
- package/config/skills/agent/core/recall/skill.json +0 -20
- package/config/skills/agent/core/record-learning/skill.json +0 -20
- package/config/skills/agent/core/register-self/instructions.md +0 -18
- package/config/skills/agent/core/register-self/skill.json +0 -20
- package/config/skills/agent/core/remember/skill.json +0 -20
- package/config/skills/agent/core/reply-chat/skill.json +0 -20
- package/config/skills/agent/core/report-progress/skill.json +0 -20
- package/config/skills/agent/core/report-status/skill.json +0 -20
- package/config/skills/agent/core/send-chat-response/skill.json +0 -20
- package/config/skills/agent/core/send-message/instructions.md +0 -20
- package/config/skills/agent/core/send-message/skill.json +0 -20
- package/config/skills/agent/desktop-app-control/skill.json +0 -33
- package/config/skills/agent/trend-monitor/skill.json +0 -22
- package/config/skills/agent/vnc-browser/skill.json +0 -20
- package/config/skills/orchestrator/assign-task/instructions.md +0 -17
- package/config/skills/orchestrator/assign-task/skill.json +0 -20
- package/config/skills/orchestrator/assign-team-to-project/skill.json +0 -20
- package/config/skills/orchestrator/broadcast/skill.json +0 -20
- package/config/skills/orchestrator/broadcast-to-org/skill.json +0 -20
- package/config/skills/orchestrator/cancel-all-schedules/skill.json +0 -17
- package/config/skills/orchestrator/cancel-schedule/instructions.md +0 -19
- package/config/skills/orchestrator/cancel-schedule/skill.json +0 -20
- package/config/skills/orchestrator/complete-task/instructions.md +0 -17
- package/config/skills/orchestrator/complete-task/skill.json +0 -20
- package/config/skills/orchestrator/create-project/skill.json +0 -20
- package/config/skills/orchestrator/create-team/skill.json +0 -20
- package/config/skills/orchestrator/delegate-task/skill.json +0 -20
- package/config/skills/orchestrator/get-agent-logs/skill.json +0 -20
- package/config/skills/orchestrator/get-agent-status/skill.json +0 -20
- package/config/skills/orchestrator/get-project-overview/instructions.md +0 -17
- package/config/skills/orchestrator/get-project-overview/skill.json +0 -20
- package/config/skills/orchestrator/get-tasks/instructions.md +0 -17
- package/config/skills/orchestrator/get-tasks/skill.json +0 -20
- package/config/skills/orchestrator/get-team-status/instructions.md +0 -17
- package/config/skills/orchestrator/get-team-status/skill.json +0 -20
- package/config/skills/orchestrator/handle-agent-failure/skill.json +0 -20
- package/config/skills/orchestrator/heartbeat/skill.json +0 -20
- package/config/skills/orchestrator/list-schedules/skill.json +0 -12
- package/config/skills/orchestrator/list-subscriptions/instructions.md +0 -17
- package/config/skills/orchestrator/list-subscriptions/skill.json +0 -20
- package/config/skills/orchestrator/query-knowledge/skill.json +0 -20
- package/config/skills/orchestrator/read-session-logs/skill.json +0 -20
- package/config/skills/orchestrator/read-system-logs/skill.json +0 -20
- package/config/skills/orchestrator/recall/skill.json +0 -20
- package/config/skills/orchestrator/record-failure/skill.json +0 -20
- package/config/skills/orchestrator/record-learning/skill.json +0 -20
- package/config/skills/orchestrator/record-success/skill.json +0 -20
- package/config/skills/orchestrator/register-self/skill.json +0 -20
- package/config/skills/orchestrator/remember/skill.json +0 -20
- package/config/skills/orchestrator/reply-chat/skill.json +0 -20
- package/config/skills/orchestrator/reply-gchat/skill.json +0 -20
- package/config/skills/orchestrator/reply-slack/skill.json +0 -20
- package/config/skills/orchestrator/report-bug/skill.json +0 -20
- package/config/skills/orchestrator/restart-crewly/skill.json +0 -20
- package/config/skills/orchestrator/resume-session/skill.json +0 -20
- package/config/skills/orchestrator/schedule-check/skill.json +0 -20
- package/config/skills/orchestrator/send-key/skill.json +0 -20
- package/config/skills/orchestrator/send-message/skill.json +0 -20
- package/config/skills/orchestrator/send-pdf-to-slack/skill.json +0 -20
- package/config/skills/orchestrator/set-goal/skill.json +0 -20
- package/config/skills/orchestrator/start-agent/skill.json +0 -20
- package/config/skills/orchestrator/start-team/skill.json +0 -20
- package/config/skills/orchestrator/stop-agent/skill.json +0 -20
- package/config/skills/orchestrator/stop-team/instructions.md +0 -19
- package/config/skills/orchestrator/stop-team/skill.json +0 -20
- package/config/skills/orchestrator/subscribe-event/skill.json +0 -20
- package/config/skills/orchestrator/terminate-agent/skill.json +0 -20
- package/config/skills/orchestrator/unsubscribe-event/instructions.md +0 -19
- package/config/skills/orchestrator/unsubscribe-event/skill.json +0 -20
- package/config/skills/orchestrator/update-focus/skill.json +0 -20
- package/config/skills/orchestrator/update-team/skill.json +0 -20
- package/config/skills/team-leader/aggregate-results/skill.json +0 -20
- package/config/skills/team-leader/decompose-goal/skill.json +0 -20
- package/config/skills/team-leader/delegate-task/skill.json +0 -20
- package/config/skills/team-leader/handle-failure/skill.json +0 -20
- package/config/skills/team-leader/schedule-check/skill.json +0 -20
- package/config/skills/team-leader/start-agent/skill.json +0 -20
- package/config/skills/team-leader/stop-agent/skill.json +0 -20
- package/config/skills/team-leader/verify-output/skill.json +0 -20
- package/frontend/dist/assets/index-0e5673b0.css +0 -33
- package/frontend/dist/assets/index-e6d7db4a.js +0 -5213
package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js
CHANGED
|
@@ -1,197 +1,93 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Google Chat Messenger Adapter
|
|
3
3
|
*
|
|
4
|
-
* Messenger adapter for Google Chat
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 3. **Pub/Sub mode** — pull incoming messages from a Cloud Pub/Sub subscription
|
|
8
|
-
* and reply via the Chat API (bidirectional, thread-aware)
|
|
9
|
-
*
|
|
10
|
-
* In Pub/Sub mode, a Google Chat App is configured to publish events to a
|
|
11
|
-
* Pub/Sub topic. Crewly pulls from the subscription, processes MESSAGE events,
|
|
12
|
-
* and replies in the same thread via the Chat API.
|
|
4
|
+
* Messenger adapter for Google Chat using the Google Chat API (webhook or service account).
|
|
5
|
+
* Supports sending messages to Google Chat spaces via incoming webhooks or
|
|
6
|
+
* the Chat API with a service account.
|
|
13
7
|
*
|
|
14
8
|
* @module services/messaging/adapters/google-chat-messenger.adapter
|
|
15
9
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const logger = LoggerService.getInstance().createComponentLogger('GoogleChatPubSub');
|
|
10
|
+
/** Timeout for external Google Chat API calls (ms). */
|
|
11
|
+
const FETCH_TIMEOUT_MS = 15_000;
|
|
19
12
|
/**
|
|
20
|
-
* Messenger adapter for Google Chat
|
|
13
|
+
* Messenger adapter for Google Chat.
|
|
14
|
+
*
|
|
15
|
+
* Supports two modes:
|
|
16
|
+
* 1. **Webhook mode** (simpler): uses an incoming webhook URL to post messages
|
|
17
|
+
* 2. **Service account mode**: uses a service account key to call the Chat API
|
|
21
18
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* Webhook mode is used when `webhookUrl` is provided in config.
|
|
20
|
+
* Service account mode is used when `serviceAccountKey` is provided.
|
|
24
21
|
*/
|
|
25
22
|
export class GoogleChatMessengerAdapter {
|
|
26
23
|
platform = 'google-chat';
|
|
27
|
-
/** Current connection mode */
|
|
28
|
-
mode = 'none';
|
|
29
24
|
/** Webhook URL for posting messages (webhook mode) */
|
|
30
25
|
webhookUrl = null;
|
|
31
|
-
/** Service account key JSON
|
|
26
|
+
/** Service account key JSON (service account mode) */
|
|
32
27
|
serviceAccountKey = null;
|
|
33
|
-
/**
|
|
34
|
-
authMode = 'service_account';
|
|
35
|
-
/** ADC credentials (parsed from application_default_credentials.json) */
|
|
36
|
-
adcCredentials = null;
|
|
37
|
-
/** Access token obtained from service account or ADC (cached) */
|
|
28
|
+
/** Access token obtained from service account (cached) */
|
|
38
29
|
accessToken = null;
|
|
39
30
|
/** Access token expiry timestamp */
|
|
40
31
|
tokenExpiresAt = 0;
|
|
41
|
-
/** OAuth2 scopes for the current mode */
|
|
42
|
-
tokenScopes = GOOGLE_CHAT_PUBSUB_CONSTANTS.CHAT_SCOPE;
|
|
43
|
-
/** Pending token refresh promise to deduplicate concurrent requests (RL2) */
|
|
44
|
-
pendingTokenRefresh = null;
|
|
45
|
-
/** Full Pub/Sub subscription resource name (e.g. projects/PROJECT/subscriptions/SUB) */
|
|
46
|
-
subscriptionName = null;
|
|
47
|
-
/** GCP project ID (for Pub/Sub mode) */
|
|
48
|
-
projectId = null;
|
|
49
|
-
/** Pub/Sub pull interval timer */
|
|
50
|
-
pullIntervalTimer = null;
|
|
51
|
-
/** Callback for incoming messages */
|
|
52
|
-
onIncomingMessage = null;
|
|
53
|
-
/** Service account email for impersonation (ADC mode) */
|
|
54
|
-
serviceAccountEmail = null;
|
|
55
|
-
/** Impersonated SA token (separate from user ADC token) */
|
|
56
|
-
saAccessToken = null;
|
|
57
|
-
/** Impersonated SA token expiry timestamp */
|
|
58
|
-
saTokenExpiresAt = 0;
|
|
59
|
-
/**
|
|
60
|
-
* Recent send deduplication cache.
|
|
61
|
-
* Key: `${space}:${threadId}:${contentPrefix}`, value: timestamp (epoch ms).
|
|
62
|
-
* Prevents the same message being sent twice within DEDUP_WINDOW_MS (e.g. when
|
|
63
|
-
* both the auto-route and a manual reply-gchat call fire for the same response).
|
|
64
|
-
*/
|
|
65
|
-
recentSends = new Map();
|
|
66
|
-
/** Deduplication window in milliseconds */
|
|
67
|
-
static DEDUP_WINDOW_MS = 10_000;
|
|
68
|
-
/** Consecutive pull failure count */
|
|
69
|
-
consecutiveFailures = 0;
|
|
70
|
-
/** Whether the pull loop is paused due to failures */
|
|
71
|
-
pullPaused = false;
|
|
72
|
-
/** Timestamp of the last successful pull (epoch ms) */
|
|
73
|
-
lastPullAt = null;
|
|
74
32
|
/**
|
|
75
|
-
* Initialize the adapter
|
|
76
|
-
*
|
|
77
|
-
* Detects mode based on provided config fields:
|
|
78
|
-
* - `webhookUrl` → webhook mode
|
|
79
|
-
* - `serviceAccountKey` + `projectId` + `subscriptionName` → pubsub mode
|
|
80
|
-
* - `serviceAccountKey` alone → service-account mode
|
|
33
|
+
* Initialize the adapter by validating credentials.
|
|
81
34
|
*
|
|
82
|
-
* @param config -
|
|
83
|
-
* @throws Error if
|
|
35
|
+
* @param config - Must contain either `webhookUrl` string or `serviceAccountKey` string
|
|
36
|
+
* @throws Error if neither credential is provided or validation fails
|
|
84
37
|
*/
|
|
85
38
|
async initialize(config) {
|
|
86
39
|
const webhookUrl = config.webhookUrl;
|
|
87
40
|
const serviceAccountKey = config.serviceAccountKey;
|
|
88
|
-
const projectId = config.projectId;
|
|
89
|
-
const subscriptionName = config.subscriptionName;
|
|
90
|
-
const onIncomingMessage = config.onIncomingMessage;
|
|
91
|
-
const authMode = (config.authMode === 'adc' ? 'adc' : 'service_account');
|
|
92
|
-
// Webhook mode
|
|
93
41
|
if (typeof webhookUrl === 'string' && webhookUrl) {
|
|
42
|
+
// Webhook mode: validate the URL format
|
|
94
43
|
if (!webhookUrl.startsWith('https://chat.googleapis.com/')) {
|
|
95
44
|
throw new Error('Invalid Google Chat webhook URL. Must start with https://chat.googleapis.com/');
|
|
96
45
|
}
|
|
97
|
-
|
|
46
|
+
// Validate by sending a test (dry-run) - Google Chat webhooks don't have a validate endpoint,
|
|
47
|
+
// so we just validate the URL format and store it
|
|
98
48
|
this.webhookUrl = webhookUrl;
|
|
99
|
-
this.
|
|
49
|
+
this.serviceAccountKey = null;
|
|
50
|
+
this.accessToken = null;
|
|
100
51
|
return;
|
|
101
52
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// Store optional SA email for impersonation
|
|
109
|
-
if (typeof config.serviceAccountEmail === 'string' && config.serviceAccountEmail) {
|
|
110
|
-
this.serviceAccountEmail = config.serviceAccountEmail;
|
|
111
|
-
}
|
|
112
|
-
// Pub/Sub mode: requires projectId + subscriptionName
|
|
113
|
-
if (typeof projectId === 'string' && projectId &&
|
|
114
|
-
typeof subscriptionName === 'string' && subscriptionName) {
|
|
115
|
-
this.projectId = projectId;
|
|
116
|
-
this.subscriptionName = `projects/${projectId}/subscriptions/${subscriptionName}`;
|
|
117
|
-
this.tokenScopes = `${GOOGLE_CHAT_PUBSUB_CONSTANTS.CHAT_SCOPE} ${GOOGLE_CHAT_PUBSUB_CONSTANTS.PUBSUB_SCOPE}`;
|
|
118
|
-
this.mode = 'pubsub';
|
|
119
|
-
if (typeof onIncomingMessage === 'function') {
|
|
120
|
-
this.onIncomingMessage = onIncomingMessage;
|
|
53
|
+
if (typeof serviceAccountKey === 'string' && serviceAccountKey) {
|
|
54
|
+
// Service account mode: validate the key is valid JSON
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(serviceAccountKey);
|
|
57
|
+
if (!parsed.client_email || !parsed.private_key) {
|
|
58
|
+
throw new Error('Service account key must contain client_email and private_key');
|
|
121
59
|
}
|
|
122
|
-
this.startPubSubPull();
|
|
123
|
-
return;
|
|
124
60
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
// Service Account mode — requires a service account key
|
|
131
|
-
if (typeof serviceAccountKey === 'string' && serviceAccountKey) {
|
|
132
|
-
this.validateServiceAccountKey(serviceAccountKey);
|
|
133
|
-
this.resetState();
|
|
134
|
-
this.authMode = 'service_account';
|
|
135
|
-
this.serviceAccountKey = serviceAccountKey;
|
|
136
|
-
// Pub/Sub mode: requires projectId + subscriptionName
|
|
137
|
-
if (typeof projectId === 'string' && projectId &&
|
|
138
|
-
typeof subscriptionName === 'string' && subscriptionName) {
|
|
139
|
-
this.projectId = projectId;
|
|
140
|
-
this.subscriptionName = `projects/${projectId}/subscriptions/${subscriptionName}`;
|
|
141
|
-
this.tokenScopes = `${GOOGLE_CHAT_PUBSUB_CONSTANTS.CHAT_SCOPE} ${GOOGLE_CHAT_PUBSUB_CONSTANTS.PUBSUB_SCOPE}`;
|
|
142
|
-
this.mode = 'pubsub';
|
|
143
|
-
if (typeof onIncomingMessage === 'function') {
|
|
144
|
-
this.onIncomingMessage = onIncomingMessage;
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (err instanceof SyntaxError) {
|
|
63
|
+
throw new Error('Service account key must be valid JSON');
|
|
145
64
|
}
|
|
146
|
-
|
|
147
|
-
return;
|
|
65
|
+
throw err;
|
|
148
66
|
}
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
this.
|
|
67
|
+
this.serviceAccountKey = serviceAccountKey;
|
|
68
|
+
this.webhookUrl = null;
|
|
69
|
+
this.accessToken = null;
|
|
152
70
|
return;
|
|
153
71
|
}
|
|
154
|
-
throw new Error('Google Chat requires either a webhookUrl
|
|
72
|
+
throw new Error('Google Chat requires either a webhookUrl or serviceAccountKey');
|
|
155
73
|
}
|
|
156
74
|
/**
|
|
157
75
|
* Send a text message to a Google Chat space.
|
|
158
76
|
*
|
|
159
77
|
* In webhook mode, the `channel` parameter is ignored (webhook URL determines the space).
|
|
160
|
-
* In service
|
|
78
|
+
* In service account mode, `channel` is the space name (e.g., "spaces/AAAA...").
|
|
161
79
|
*
|
|
162
|
-
* @param channel - Google Chat space name (used in service
|
|
80
|
+
* @param channel - Google Chat space name (used in service account mode)
|
|
163
81
|
* @param text - Message content
|
|
164
82
|
* @param options - Optional send options (threadId for threaded replies)
|
|
165
83
|
* @throws Error if adapter is not initialized or send fails
|
|
166
84
|
*/
|
|
167
85
|
async sendMessage(channel, text, options) {
|
|
168
|
-
|
|
169
|
-
// This prevents double-sends when both the auto-route (googleChatResolve) and
|
|
170
|
-
// a manual reply-gchat API call fire for the same response.
|
|
171
|
-
const dedupKey = `${channel}:${options?.threadId || ''}:${text.substring(0, 200)}`;
|
|
172
|
-
const now = Date.now();
|
|
173
|
-
const lastSent = this.recentSends.get(dedupKey);
|
|
174
|
-
if (lastSent && (now - lastSent) < GoogleChatMessengerAdapter.DEDUP_WINDOW_MS) {
|
|
175
|
-
logger.info('Skipping duplicate send (same message sent within dedup window)', {
|
|
176
|
-
channel,
|
|
177
|
-
threadId: options?.threadId,
|
|
178
|
-
windowMs: GoogleChatMessengerAdapter.DEDUP_WINDOW_MS,
|
|
179
|
-
});
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
this.recentSends.set(dedupKey, now);
|
|
183
|
-
// Evict stale entries to prevent unbounded growth
|
|
184
|
-
for (const [key, ts] of this.recentSends) {
|
|
185
|
-
if (now - ts > GoogleChatMessengerAdapter.DEDUP_WINDOW_MS) {
|
|
186
|
-
this.recentSends.delete(key);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (this.mode === 'webhook' && this.webhookUrl) {
|
|
86
|
+
if (this.webhookUrl) {
|
|
190
87
|
await this.sendViaWebhook(text, options?.threadId);
|
|
191
88
|
return;
|
|
192
89
|
}
|
|
193
|
-
if (
|
|
194
|
-
(this.serviceAccountKey || this.adcCredentials)) {
|
|
90
|
+
if (this.serviceAccountKey) {
|
|
195
91
|
await this.sendViaApi(channel, text, options?.threadId);
|
|
196
92
|
return;
|
|
197
93
|
}
|
|
@@ -200,253 +96,64 @@ export class GoogleChatMessengerAdapter {
|
|
|
200
96
|
/**
|
|
201
97
|
* Get the current connection status.
|
|
202
98
|
*
|
|
203
|
-
* @returns Status object with connected flag
|
|
99
|
+
* @returns Status object with connected flag and platform identifier
|
|
204
100
|
*/
|
|
205
101
|
getStatus() {
|
|
102
|
+
const connected = Boolean(this.webhookUrl || this.serviceAccountKey);
|
|
206
103
|
return {
|
|
207
|
-
connected
|
|
104
|
+
connected,
|
|
208
105
|
platform: this.platform,
|
|
209
106
|
details: {
|
|
210
|
-
mode: this.
|
|
211
|
-
authMode: this.authMode,
|
|
212
|
-
...(this.serviceAccountEmail ? { serviceAccountEmail: this.serviceAccountEmail } : {}),
|
|
213
|
-
...(this.mode === 'pubsub' ? {
|
|
214
|
-
subscriptionName: this.subscriptionName,
|
|
215
|
-
projectId: this.projectId,
|
|
216
|
-
pullActive: Boolean(this.pullIntervalTimer) && !this.pullPaused,
|
|
217
|
-
pullPaused: this.pullPaused,
|
|
218
|
-
consecutiveFailures: this.consecutiveFailures,
|
|
219
|
-
lastPullAt: this.lastPullAt ? new Date(this.lastPullAt).toISOString() : null,
|
|
220
|
-
} : {}),
|
|
107
|
+
mode: this.webhookUrl ? 'webhook' : this.serviceAccountKey ? 'service-account' : 'none',
|
|
221
108
|
},
|
|
222
109
|
};
|
|
223
110
|
}
|
|
224
111
|
/**
|
|
225
|
-
* Disconnect by clearing stored credentials
|
|
112
|
+
* Disconnect by clearing stored credentials.
|
|
226
113
|
*/
|
|
227
114
|
async disconnect() {
|
|
228
|
-
this.
|
|
229
|
-
this.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
// Pub/Sub Pull Loop
|
|
233
|
-
// ===========================================================================
|
|
234
|
-
/**
|
|
235
|
-
* Start the Pub/Sub pull loop that periodically fetches messages.
|
|
236
|
-
*/
|
|
237
|
-
startPubSubPull() {
|
|
238
|
-
this.stopPubSubPull();
|
|
239
|
-
this.consecutiveFailures = 0;
|
|
240
|
-
this.pullPaused = false;
|
|
241
|
-
logger.info('Starting Pub/Sub pull loop', {
|
|
242
|
-
subscription: this.subscriptionName,
|
|
243
|
-
intervalMs: GOOGLE_CHAT_PUBSUB_CONSTANTS.PULL_INTERVAL_MS,
|
|
244
|
-
maxFailures: GOOGLE_CHAT_PUBSUB_CONSTANTS.MAX_CONSECUTIVE_FAILURES,
|
|
245
|
-
});
|
|
246
|
-
this.pullIntervalTimer = setInterval(async () => {
|
|
247
|
-
if (this.pullPaused)
|
|
248
|
-
return;
|
|
249
|
-
try {
|
|
250
|
-
await this.pullMessages();
|
|
251
|
-
this.consecutiveFailures = 0;
|
|
252
|
-
}
|
|
253
|
-
catch (error) {
|
|
254
|
-
// AbortError / TimeoutError from AbortSignal.timeout() is a normal
|
|
255
|
-
// "no messages within the timeout window" — not a real failure.
|
|
256
|
-
const isTimeout = error instanceof DOMException && (error.name === 'AbortError' || error.name === 'TimeoutError');
|
|
257
|
-
if (isTimeout) {
|
|
258
|
-
// Normal timeout — reset failure counter and skip error handling
|
|
259
|
-
this.consecutiveFailures = 0;
|
|
260
|
-
logger.debug('Pull timed out (no messages)', { subscription: this.subscriptionName });
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
this.consecutiveFailures++;
|
|
264
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
265
|
-
logger.error('Pull loop failure', {
|
|
266
|
-
subscription: this.subscriptionName,
|
|
267
|
-
consecutiveFailures: this.consecutiveFailures,
|
|
268
|
-
error: errorMsg,
|
|
269
|
-
});
|
|
270
|
-
if (this.consecutiveFailures >= GOOGLE_CHAT_PUBSUB_CONSTANTS.MAX_CONSECUTIVE_FAILURES) {
|
|
271
|
-
this.pullPaused = true;
|
|
272
|
-
logger.error('Pull loop PAUSED due to repeated failures', {
|
|
273
|
-
subscription: this.subscriptionName,
|
|
274
|
-
consecutiveFailures: this.consecutiveFailures,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}, GOOGLE_CHAT_PUBSUB_CONSTANTS.PULL_INTERVAL_MS);
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Stop the Pub/Sub pull loop.
|
|
282
|
-
*/
|
|
283
|
-
stopPubSubPull() {
|
|
284
|
-
if (this.pullIntervalTimer) {
|
|
285
|
-
logger.info('Stopping Pub/Sub pull loop', { subscription: this.subscriptionName });
|
|
286
|
-
clearInterval(this.pullIntervalTimer);
|
|
287
|
-
this.pullIntervalTimer = null;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Pull messages from the Pub/Sub subscription, process them, and acknowledge.
|
|
292
|
-
*
|
|
293
|
-
* Each message is a base64-encoded Google Chat event JSON. Only MESSAGE-type
|
|
294
|
-
* events are forwarded to the incoming message callback. All messages are
|
|
295
|
-
* acknowledged regardless of type to prevent redelivery.
|
|
296
|
-
*/
|
|
297
|
-
async pullMessages() {
|
|
298
|
-
if (!this.subscriptionName) {
|
|
299
|
-
throw new Error('Pub/Sub subscription not configured');
|
|
300
|
-
}
|
|
301
|
-
logger.debug('Pulling messages', { subscription: this.subscriptionName });
|
|
302
|
-
const token = await this.getAccessToken();
|
|
303
|
-
const pullUrl = `${GOOGLE_CHAT_PUBSUB_CONSTANTS.PUBSUB_API_BASE}/${this.subscriptionName}:pull`;
|
|
304
|
-
const resp = await fetch(pullUrl, {
|
|
305
|
-
method: 'POST',
|
|
306
|
-
headers: this.getAuthHeaders(token),
|
|
307
|
-
body: JSON.stringify({
|
|
308
|
-
maxMessages: GOOGLE_CHAT_PUBSUB_CONSTANTS.MAX_MESSAGES_PER_PULL,
|
|
309
|
-
returnImmediately: true,
|
|
310
|
-
}),
|
|
311
|
-
signal: AbortSignal.timeout(GOOGLE_CHAT_PUBSUB_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
312
|
-
});
|
|
313
|
-
if (!resp.ok) {
|
|
314
|
-
const details = await resp.text();
|
|
315
|
-
throw new Error(`Pub/Sub pull failed (${resp.status}): ${details}`);
|
|
316
|
-
}
|
|
317
|
-
const data = await resp.json();
|
|
318
|
-
this.lastPullAt = Date.now();
|
|
319
|
-
if (!data.receivedMessages || data.receivedMessages.length === 0) {
|
|
320
|
-
return 0;
|
|
321
|
-
}
|
|
322
|
-
const messageCount = data.receivedMessages.length;
|
|
323
|
-
const receivedAt = new Date().toISOString();
|
|
324
|
-
logger.info('Received messages from Pub/Sub', {
|
|
325
|
-
count: messageCount,
|
|
326
|
-
subscription: this.subscriptionName,
|
|
327
|
-
receivedAt,
|
|
328
|
-
});
|
|
329
|
-
const ackIds = [];
|
|
330
|
-
for (const received of data.receivedMessages) {
|
|
331
|
-
ackIds.push(received.ackId);
|
|
332
|
-
if (!received.message.data)
|
|
333
|
-
continue;
|
|
334
|
-
try {
|
|
335
|
-
const decoded = Buffer.from(received.message.data, 'base64').toString('utf-8');
|
|
336
|
-
logger.info('Decoded Pub/Sub payload', {
|
|
337
|
-
messageId: received.message.messageId,
|
|
338
|
-
snippet: decoded.slice(0, 200),
|
|
339
|
-
});
|
|
340
|
-
const event = JSON.parse(decoded);
|
|
341
|
-
logger.info('Parsed chat event', {
|
|
342
|
-
keys: Object.keys(event),
|
|
343
|
-
type: event.type,
|
|
344
|
-
hasMessage: Boolean(event.message),
|
|
345
|
-
hasText: Boolean(event.message?.text),
|
|
346
|
-
space: event.space?.name,
|
|
347
|
-
// v2 format detection
|
|
348
|
-
hasChat: Boolean(event.chat),
|
|
349
|
-
chatKeys: event.chat ? Object.keys(event.chat) : 'none',
|
|
350
|
-
hasCommonEventObject: Boolean(event.commonEventObject),
|
|
351
|
-
});
|
|
352
|
-
this.processChatEvent(event);
|
|
353
|
-
}
|
|
354
|
-
catch (err) {
|
|
355
|
-
logger.error('Failed to parse Pub/Sub message', {
|
|
356
|
-
messageId: received.message.messageId,
|
|
357
|
-
error: err instanceof Error ? err.message : String(err),
|
|
358
|
-
dataSnippet: received.message.data?.slice(0, 100),
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
// Acknowledge all messages (even non-MESSAGE types) to prevent redelivery
|
|
363
|
-
if (ackIds.length > 0) {
|
|
364
|
-
await this.acknowledgeMessages(ackIds);
|
|
365
|
-
}
|
|
366
|
-
return messageCount;
|
|
115
|
+
this.webhookUrl = null;
|
|
116
|
+
this.serviceAccountKey = null;
|
|
117
|
+
this.accessToken = null;
|
|
118
|
+
this.tokenExpiresAt = 0;
|
|
367
119
|
}
|
|
368
120
|
/**
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
* Supports two payload formats:
|
|
372
|
-
* - **Legacy (v1)**: `{ type: 'MESSAGE', message: { text, sender, thread }, space }`
|
|
373
|
-
* - **v2**: `{ commonEventObject: {...}, chat: { messagePayload: { message: {...}, space: {...} } } }`
|
|
121
|
+
* Add an emoji reaction to a Google Chat message.
|
|
374
122
|
*
|
|
375
|
-
*
|
|
123
|
+
* Only works in service account mode — webhook mode does not support the
|
|
124
|
+
* reactions API. Calls `spaces.messages.reactions.create`.
|
|
376
125
|
*
|
|
377
|
-
* @param
|
|
126
|
+
* @param messageName - Full message resource name (e.g., "spaces/xxx/messages/yyy")
|
|
127
|
+
* @param emoji - Unicode emoji character (e.g., "👀", "✅")
|
|
378
128
|
*/
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const msg = isV2 ? event.chat?.messagePayload?.message : event.message;
|
|
383
|
-
const space = isV2 ? event.chat?.messagePayload?.space : event.space;
|
|
384
|
-
// Legacy format: check type field. v2 format: check if messagePayload exists (implies MESSAGE)
|
|
385
|
-
const isMessage = isV2
|
|
386
|
-
? Boolean(msg?.text)
|
|
387
|
-
: (event.type === 'MESSAGE' && Boolean(msg?.text));
|
|
388
|
-
if (!isMessage || !msg?.text) {
|
|
389
|
-
logger.info('Skipping non-MESSAGE event', {
|
|
390
|
-
format: isV2 ? 'v2' : 'legacy',
|
|
391
|
-
type: event.type,
|
|
392
|
-
hasText: Boolean(msg?.text),
|
|
393
|
-
space: space?.name,
|
|
394
|
-
});
|
|
129
|
+
async addReaction(messageName, emoji) {
|
|
130
|
+
if (!this.serviceAccountKey) {
|
|
131
|
+
// Reactions require service account mode — silently skip in webhook mode
|
|
395
132
|
return;
|
|
396
133
|
}
|
|
397
|
-
if (!
|
|
398
|
-
logger.warn('MESSAGE event received but no onIncomingMessage callback set — message dropped', {
|
|
399
|
-
format: isV2 ? 'v2' : 'legacy',
|
|
400
|
-
space: space?.name,
|
|
401
|
-
textSnippet: msg.text.slice(0, 80),
|
|
402
|
-
});
|
|
134
|
+
if (!messageName || !messageName.includes('/messages/')) {
|
|
403
135
|
return;
|
|
404
136
|
}
|
|
405
|
-
const spaceName = space?.name || '';
|
|
406
|
-
const threadName = msg.thread?.name || '';
|
|
407
|
-
const senderName = msg.sender?.displayName || msg.sender?.name || '';
|
|
408
|
-
logger.info('Processing MESSAGE event', {
|
|
409
|
-
format: isV2 ? 'v2' : 'legacy',
|
|
410
|
-
space: spaceName,
|
|
411
|
-
sender: senderName,
|
|
412
|
-
textLength: msg.text.length,
|
|
413
|
-
thread: threadName ? threadName.slice(-20) : 'none',
|
|
414
|
-
});
|
|
415
|
-
const incomingMessage = {
|
|
416
|
-
platform: 'google-chat',
|
|
417
|
-
conversationId: spaceName,
|
|
418
|
-
channelId: spaceName,
|
|
419
|
-
userId: senderName,
|
|
420
|
-
text: msg.text,
|
|
421
|
-
threadId: threadName,
|
|
422
|
-
timestamp: msg.createTime || event.eventTime || new Date().toISOString(),
|
|
423
|
-
};
|
|
424
|
-
this.onIncomingMessage(incomingMessage);
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Acknowledge processed messages to prevent redelivery.
|
|
428
|
-
*
|
|
429
|
-
* @param ackIds - Array of ack IDs from the pull response
|
|
430
|
-
*/
|
|
431
|
-
async acknowledgeMessages(ackIds) {
|
|
432
|
-
if (!this.subscriptionName)
|
|
433
|
-
return;
|
|
434
137
|
const token = await this.getAccessToken();
|
|
435
|
-
const
|
|
436
|
-
const resp = await fetch(ackUrl, {
|
|
138
|
+
const resp = await fetch(`https://chat.googleapis.com/v1/${messageName}/reactions`, {
|
|
437
139
|
method: 'POST',
|
|
438
|
-
headers:
|
|
439
|
-
|
|
440
|
-
|
|
140
|
+
headers: {
|
|
141
|
+
Authorization: `Bearer ${token}`,
|
|
142
|
+
'Content-Type': 'application/json',
|
|
143
|
+
},
|
|
144
|
+
body: JSON.stringify({
|
|
145
|
+
emoji: { unicode: emoji },
|
|
146
|
+
}),
|
|
147
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
441
148
|
});
|
|
442
149
|
if (!resp.ok) {
|
|
443
150
|
const details = await resp.text();
|
|
444
|
-
|
|
151
|
+
// Non-critical — don't throw, just log
|
|
152
|
+
if (!details.includes('ALREADY_EXISTS')) {
|
|
153
|
+
throw new Error(`Google Chat reaction failed (${resp.status}): ${details}`);
|
|
154
|
+
}
|
|
445
155
|
}
|
|
446
156
|
}
|
|
447
|
-
// ===========================================================================
|
|
448
|
-
// Send Methods
|
|
449
|
-
// ===========================================================================
|
|
450
157
|
/**
|
|
451
158
|
* Send a message via incoming webhook URL.
|
|
452
159
|
*
|
|
@@ -471,7 +178,7 @@ export class GoogleChatMessengerAdapter {
|
|
|
471
178
|
method: 'POST',
|
|
472
179
|
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
|
|
473
180
|
body: JSON.stringify(body),
|
|
474
|
-
signal: AbortSignal.timeout(
|
|
181
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
475
182
|
});
|
|
476
183
|
if (!resp.ok) {
|
|
477
184
|
const details = await resp.text();
|
|
@@ -481,145 +188,59 @@ export class GoogleChatMessengerAdapter {
|
|
|
481
188
|
/**
|
|
482
189
|
* Send a message via the Google Chat REST API using service account credentials.
|
|
483
190
|
*
|
|
484
|
-
* When a threadId (thread name) is provided, the reply is posted to the same
|
|
485
|
-
* thread. This enables conversational thread tracking for Pub/Sub mode.
|
|
486
|
-
*
|
|
487
191
|
* @param space - Space name (e.g., "spaces/AAAA...")
|
|
488
192
|
* @param text - Message text
|
|
489
|
-
* @param
|
|
193
|
+
* @param threadKey - Optional thread key for threaded replies
|
|
490
194
|
*/
|
|
491
|
-
async sendViaApi(space, text,
|
|
492
|
-
if (!this.serviceAccountKey
|
|
493
|
-
throw new Error('
|
|
195
|
+
async sendViaApi(space, text, threadKey) {
|
|
196
|
+
if (!this.serviceAccountKey) {
|
|
197
|
+
throw new Error('Service account key not configured');
|
|
494
198
|
}
|
|
495
199
|
if (!space || !space.startsWith('spaces/')) {
|
|
496
200
|
throw new Error('Invalid Google Chat space name. Must start with "spaces/"');
|
|
497
201
|
}
|
|
498
|
-
// Split long messages into chunks that fit within the API limit
|
|
499
|
-
const maxLen = GOOGLE_CHAT_PUBSUB_CONSTANTS.MAX_MESSAGE_LENGTH;
|
|
500
|
-
const chunks = text.length > maxLen
|
|
501
|
-
? GoogleChatMessengerAdapter.splitMessage(text, maxLen - 96)
|
|
502
|
-
: [text];
|
|
503
202
|
const token = await this.getAccessToken();
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
body.thread = { name: threadName };
|
|
508
|
-
}
|
|
509
|
-
let url = `${GOOGLE_CHAT_PUBSUB_CONSTANTS.CHAT_API_BASE}/${space}/messages`;
|
|
510
|
-
if (threadName) {
|
|
511
|
-
url += '?messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD';
|
|
512
|
-
}
|
|
513
|
-
const resp = await fetch(url, {
|
|
514
|
-
method: 'POST',
|
|
515
|
-
headers: this.getAuthHeaders(token),
|
|
516
|
-
body: JSON.stringify(body),
|
|
517
|
-
signal: AbortSignal.timeout(GOOGLE_CHAT_PUBSUB_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
518
|
-
});
|
|
519
|
-
if (!resp.ok) {
|
|
520
|
-
const details = await resp.text();
|
|
521
|
-
throw new Error(`Google Chat API send failed (${resp.status}): ${details}`);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Split a message into chunks that fit within Google Chat's character limit.
|
|
527
|
-
*
|
|
528
|
-
* Splits on double-newline paragraph boundaries when possible. Falls back to
|
|
529
|
-
* single-newline, then hard truncation at maxLength.
|
|
530
|
-
*
|
|
531
|
-
* @param text - The full message text to split
|
|
532
|
-
* @param maxLength - Maximum characters per chunk (default 4000)
|
|
533
|
-
* @returns Array of text chunks, each within maxLength
|
|
534
|
-
*/
|
|
535
|
-
static splitMessage(text, maxLength = 4000) {
|
|
536
|
-
if (text.length <= maxLength) {
|
|
537
|
-
return [text];
|
|
203
|
+
const body = { text };
|
|
204
|
+
if (threadKey) {
|
|
205
|
+
body.thread = { name: `${space}/threads/${threadKey}` };
|
|
538
206
|
}
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}
|
|
552
|
-
// Hard cut if no newline found
|
|
553
|
-
if (splitIdx <= 0) {
|
|
554
|
-
splitIdx = maxLength;
|
|
555
|
-
}
|
|
556
|
-
chunks.push(remaining.slice(0, splitIdx));
|
|
557
|
-
remaining = remaining.slice(splitIdx).replace(/^\n+/, '');
|
|
207
|
+
const resp = await fetch(`https://chat.googleapis.com/v1/${space}/messages`, {
|
|
208
|
+
method: 'POST',
|
|
209
|
+
headers: {
|
|
210
|
+
Authorization: `Bearer ${token}`,
|
|
211
|
+
'Content-Type': 'application/json',
|
|
212
|
+
},
|
|
213
|
+
body: JSON.stringify(body),
|
|
214
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
215
|
+
});
|
|
216
|
+
if (!resp.ok) {
|
|
217
|
+
const details = await resp.text();
|
|
218
|
+
throw new Error(`Google Chat API send failed (${resp.status}): ${details}`);
|
|
558
219
|
}
|
|
559
|
-
return chunks;
|
|
560
220
|
}
|
|
561
|
-
// ===========================================================================
|
|
562
|
-
// Auth
|
|
563
|
-
// ===========================================================================
|
|
564
221
|
/**
|
|
565
222
|
* Get a valid access token, refreshing if needed.
|
|
566
223
|
*
|
|
567
|
-
* Uses JWT-based OAuth2 for service accounts
|
|
568
|
-
* The scope includes Pub/Sub when in pubsub mode.
|
|
224
|
+
* Uses a simplified JWT-based OAuth2 flow for service accounts.
|
|
569
225
|
*
|
|
570
226
|
* @returns Valid access token string
|
|
571
227
|
*/
|
|
572
228
|
async getAccessToken() {
|
|
573
|
-
// When SA impersonation is active, return cached SA token if valid
|
|
574
|
-
if (this.serviceAccountEmail && this.saAccessToken && Date.now() < this.saTokenExpiresAt - 60_000) {
|
|
575
|
-
return this.saAccessToken;
|
|
576
|
-
}
|
|
577
229
|
// Return cached token if still valid (with 60s buffer)
|
|
578
|
-
if (
|
|
230
|
+
if (this.accessToken && Date.now() < this.tokenExpiresAt - 60_000) {
|
|
579
231
|
return this.accessToken;
|
|
580
232
|
}
|
|
581
|
-
// Deduplicate concurrent refresh requests (RL2)
|
|
582
|
-
if (this.pendingTokenRefresh) {
|
|
583
|
-
return this.pendingTokenRefresh;
|
|
584
|
-
}
|
|
585
|
-
this.pendingTokenRefresh = this.refreshAccessToken();
|
|
586
|
-
try {
|
|
587
|
-
return await this.pendingTokenRefresh;
|
|
588
|
-
}
|
|
589
|
-
finally {
|
|
590
|
-
this.pendingTokenRefresh = null;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Perform the actual token refresh.
|
|
595
|
-
*
|
|
596
|
-
* Dispatches to the appropriate flow based on authMode:
|
|
597
|
-
* - `service_account`: JWT-based OAuth2 flow with SA private key
|
|
598
|
-
* - `adc`: Refresh token flow using ADC credentials
|
|
599
|
-
*
|
|
600
|
-
* @returns Fresh access token string
|
|
601
|
-
*/
|
|
602
|
-
async refreshAccessToken() {
|
|
603
|
-
if (this.authMode === 'adc') {
|
|
604
|
-
return this.refreshAccessTokenViaAdc();
|
|
605
|
-
}
|
|
606
|
-
return this.refreshAccessTokenViaJwt();
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* Refresh access token via JWT-based OAuth2 flow (service account).
|
|
610
|
-
*
|
|
611
|
-
* @returns Fresh access token string
|
|
612
|
-
*/
|
|
613
|
-
async refreshAccessTokenViaJwt() {
|
|
614
233
|
if (!this.serviceAccountKey) {
|
|
615
234
|
throw new Error('Service account key not configured');
|
|
616
235
|
}
|
|
236
|
+
// For service account auth, we need to create a JWT and exchange it for an access token.
|
|
237
|
+
// This is a simplified implementation — production use should use google-auth-library.
|
|
617
238
|
const key = JSON.parse(this.serviceAccountKey);
|
|
618
239
|
const now = Math.floor(Date.now() / 1000);
|
|
619
240
|
const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');
|
|
620
241
|
const payload = Buffer.from(JSON.stringify({
|
|
621
242
|
iss: key.client_email,
|
|
622
|
-
scope:
|
|
243
|
+
scope: 'https://www.googleapis.com/auth/chat.bot',
|
|
623
244
|
aud: 'https://oauth2.googleapis.com/token',
|
|
624
245
|
iat: now,
|
|
625
246
|
exp: now + 3600,
|
|
@@ -634,7 +255,7 @@ export class GoogleChatMessengerAdapter {
|
|
|
634
255
|
method: 'POST',
|
|
635
256
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
636
257
|
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`,
|
|
637
|
-
signal: AbortSignal.timeout(
|
|
258
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
638
259
|
});
|
|
639
260
|
if (!resp.ok) {
|
|
640
261
|
const details = await resp.text();
|
|
@@ -645,212 +266,5 @@ export class GoogleChatMessengerAdapter {
|
|
|
645
266
|
this.tokenExpiresAt = Date.now() + data.expires_in * 1000;
|
|
646
267
|
return this.accessToken;
|
|
647
268
|
}
|
|
648
|
-
/**
|
|
649
|
-
* Refresh access token via ADC (Application Default Credentials).
|
|
650
|
-
*
|
|
651
|
-
* Uses the refresh_token from the ADC JSON file to obtain a new access token
|
|
652
|
-
* from Google's OAuth2 token endpoint. This supports credentials created by
|
|
653
|
-
* `gcloud auth application-default login`.
|
|
654
|
-
*
|
|
655
|
-
* When `serviceAccountEmail` is configured, the ADC user token is used to
|
|
656
|
-
* impersonate the service account via the IAM Credentials API, producing a
|
|
657
|
-
* token with `chat.bot` and `pubsub` scopes that the Chat API accepts.
|
|
658
|
-
*
|
|
659
|
-
* @returns Fresh access token string (impersonated SA token if configured, else user token)
|
|
660
|
-
*/
|
|
661
|
-
async refreshAccessTokenViaAdc() {
|
|
662
|
-
if (!this.adcCredentials) {
|
|
663
|
-
throw new Error('ADC credentials not loaded');
|
|
664
|
-
}
|
|
665
|
-
const { client_id, client_secret, refresh_token } = this.adcCredentials;
|
|
666
|
-
const body = new URLSearchParams({
|
|
667
|
-
grant_type: 'refresh_token',
|
|
668
|
-
client_id,
|
|
669
|
-
client_secret,
|
|
670
|
-
refresh_token,
|
|
671
|
-
});
|
|
672
|
-
const resp = await fetch('https://oauth2.googleapis.com/token', {
|
|
673
|
-
method: 'POST',
|
|
674
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
675
|
-
body: body.toString(),
|
|
676
|
-
signal: AbortSignal.timeout(GOOGLE_CHAT_PUBSUB_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
677
|
-
});
|
|
678
|
-
if (!resp.ok) {
|
|
679
|
-
const details = await resp.text();
|
|
680
|
-
throw new Error(`ADC token refresh failed (${resp.status}): ${details}`);
|
|
681
|
-
}
|
|
682
|
-
const data = await resp.json();
|
|
683
|
-
this.accessToken = data.access_token;
|
|
684
|
-
this.tokenExpiresAt = Date.now() + data.expires_in * 1000;
|
|
685
|
-
// If SA impersonation is configured, exchange the user token for an SA token
|
|
686
|
-
if (this.serviceAccountEmail) {
|
|
687
|
-
return this.impersonateServiceAccount(this.accessToken);
|
|
688
|
-
}
|
|
689
|
-
return this.accessToken;
|
|
690
|
-
}
|
|
691
|
-
/**
|
|
692
|
-
* Impersonate a service account using the IAM Credentials API.
|
|
693
|
-
*
|
|
694
|
-
* Uses the user's ADC access token to call `generateAccessToken` on the
|
|
695
|
-
* target service account, producing a token with `chat.bot` and `pubsub`
|
|
696
|
-
* scopes. The user must have the `Service Account Token Creator` IAM role.
|
|
697
|
-
*
|
|
698
|
-
* @param userToken - ADC user access token for authorization
|
|
699
|
-
* @returns Impersonated service account access token
|
|
700
|
-
* @throws Error if impersonation fails (e.g., missing IAM role)
|
|
701
|
-
*/
|
|
702
|
-
async impersonateServiceAccount(userToken) {
|
|
703
|
-
// Return cached SA token if still valid (60s buffer)
|
|
704
|
-
if (this.saAccessToken && Date.now() < this.saTokenExpiresAt - 60_000) {
|
|
705
|
-
return this.saAccessToken;
|
|
706
|
-
}
|
|
707
|
-
const url = `https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${this.serviceAccountEmail}:generateAccessToken`;
|
|
708
|
-
const headers = {
|
|
709
|
-
Authorization: `Bearer ${userToken}`,
|
|
710
|
-
'Content-Type': 'application/json',
|
|
711
|
-
};
|
|
712
|
-
if (this.projectId) {
|
|
713
|
-
headers['x-goog-user-project'] = this.projectId;
|
|
714
|
-
}
|
|
715
|
-
const reqBody = {
|
|
716
|
-
scope: [
|
|
717
|
-
GOOGLE_CHAT_PUBSUB_CONSTANTS.CHAT_SCOPE,
|
|
718
|
-
GOOGLE_CHAT_PUBSUB_CONSTANTS.PUBSUB_SCOPE,
|
|
719
|
-
],
|
|
720
|
-
lifetime: '3600s',
|
|
721
|
-
};
|
|
722
|
-
const resp = await fetch(url, {
|
|
723
|
-
method: 'POST',
|
|
724
|
-
headers,
|
|
725
|
-
body: JSON.stringify(reqBody),
|
|
726
|
-
signal: AbortSignal.timeout(GOOGLE_CHAT_PUBSUB_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
727
|
-
});
|
|
728
|
-
if (!resp.ok) {
|
|
729
|
-
const details = await resp.text();
|
|
730
|
-
throw new Error(`SA impersonation failed (${resp.status}): ${details}`);
|
|
731
|
-
}
|
|
732
|
-
const result = await resp.json();
|
|
733
|
-
this.saAccessToken = result.accessToken;
|
|
734
|
-
this.saTokenExpiresAt = new Date(result.expireTime).getTime();
|
|
735
|
-
logger.info('Impersonated service account', {
|
|
736
|
-
serviceAccountEmail: this.serviceAccountEmail,
|
|
737
|
-
expiresAt: result.expireTime,
|
|
738
|
-
});
|
|
739
|
-
return this.saAccessToken;
|
|
740
|
-
}
|
|
741
|
-
// ===========================================================================
|
|
742
|
-
// Helpers
|
|
743
|
-
// ===========================================================================
|
|
744
|
-
/**
|
|
745
|
-
* Build auth headers for Google API requests.
|
|
746
|
-
*
|
|
747
|
-
* When using ADC auth mode, adds x-goog-user-project header to set the
|
|
748
|
-
* billing/quota project. Without this header, ADC requests fail with
|
|
749
|
-
* 403 PERMISSION_DENIED because Google cannot determine which project
|
|
750
|
-
* should be billed for the API usage.
|
|
751
|
-
*
|
|
752
|
-
* @param token - OAuth2 access token
|
|
753
|
-
* @returns Headers object with Authorization, Content-Type, and optional quota project
|
|
754
|
-
*/
|
|
755
|
-
getAuthHeaders(token) {
|
|
756
|
-
const headers = {
|
|
757
|
-
Authorization: `Bearer ${token}`,
|
|
758
|
-
'Content-Type': 'application/json',
|
|
759
|
-
};
|
|
760
|
-
if (this.authMode === 'adc' && this.projectId) {
|
|
761
|
-
headers['x-goog-user-project'] = this.projectId;
|
|
762
|
-
}
|
|
763
|
-
return headers;
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Validate a service account key JSON string.
|
|
767
|
-
*
|
|
768
|
-
* @param key - JSON string of the service account key
|
|
769
|
-
* @throws Error if the key is invalid
|
|
770
|
-
*/
|
|
771
|
-
validateServiceAccountKey(key) {
|
|
772
|
-
try {
|
|
773
|
-
const parsed = JSON.parse(key);
|
|
774
|
-
if (!parsed.client_email || !parsed.private_key) {
|
|
775
|
-
throw new Error('Service account key must contain client_email and private_key');
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
catch (err) {
|
|
779
|
-
if (err instanceof SyntaxError) {
|
|
780
|
-
throw new Error('Service account key must be valid JSON');
|
|
781
|
-
}
|
|
782
|
-
throw err;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* Load ADC (Application Default Credentials) from the filesystem.
|
|
787
|
-
*
|
|
788
|
-
* Checks (in order):
|
|
789
|
-
* 1. `GOOGLE_APPLICATION_CREDENTIALS` environment variable (custom path)
|
|
790
|
-
* 2. Default gcloud ADC path: `~/.config/gcloud/application_default_credentials.json`
|
|
791
|
-
*
|
|
792
|
-
* @returns Parsed ADC credentials
|
|
793
|
-
* @throws Error if the ADC file is not found or invalid
|
|
794
|
-
*/
|
|
795
|
-
async loadAdcCredentials() {
|
|
796
|
-
const { readFile } = await import('node:fs/promises');
|
|
797
|
-
const { join } = await import('node:path');
|
|
798
|
-
const { homedir } = await import('node:os');
|
|
799
|
-
const envPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
800
|
-
const defaultPath = join(homedir(), '.config', 'gcloud', 'application_default_credentials.json');
|
|
801
|
-
const credPath = envPath || defaultPath;
|
|
802
|
-
let raw;
|
|
803
|
-
try {
|
|
804
|
-
raw = await readFile(credPath, 'utf-8');
|
|
805
|
-
}
|
|
806
|
-
catch {
|
|
807
|
-
throw new Error(`ADC credentials file not found at ${credPath}. ` +
|
|
808
|
-
'Run: gcloud auth application-default login --scopes=' +
|
|
809
|
-
'https://www.googleapis.com/auth/chat.bot,' +
|
|
810
|
-
'https://www.googleapis.com/auth/pubsub,' +
|
|
811
|
-
'https://www.googleapis.com/auth/cloud-platform');
|
|
812
|
-
}
|
|
813
|
-
let parsed;
|
|
814
|
-
try {
|
|
815
|
-
parsed = JSON.parse(raw);
|
|
816
|
-
}
|
|
817
|
-
catch {
|
|
818
|
-
throw new Error('ADC credentials file is not valid JSON');
|
|
819
|
-
}
|
|
820
|
-
if (!parsed.client_id || !parsed.client_secret || !parsed.refresh_token) {
|
|
821
|
-
throw new Error('ADC credentials file must contain client_id, client_secret, and refresh_token. ' +
|
|
822
|
-
'Ensure you ran gcloud auth application-default login with the correct scopes.');
|
|
823
|
-
}
|
|
824
|
-
return {
|
|
825
|
-
client_id: parsed.client_id,
|
|
826
|
-
client_secret: parsed.client_secret,
|
|
827
|
-
refresh_token: parsed.refresh_token,
|
|
828
|
-
type: parsed.type || 'authorized_user',
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
/**
|
|
832
|
-
* Reset all internal state to defaults.
|
|
833
|
-
*/
|
|
834
|
-
resetState() {
|
|
835
|
-
this.stopPubSubPull();
|
|
836
|
-
this.webhookUrl = null;
|
|
837
|
-
this.serviceAccountKey = null;
|
|
838
|
-
this.authMode = 'service_account';
|
|
839
|
-
this.adcCredentials = null;
|
|
840
|
-
this.accessToken = null;
|
|
841
|
-
this.tokenExpiresAt = 0;
|
|
842
|
-
this.tokenScopes = GOOGLE_CHAT_PUBSUB_CONSTANTS.CHAT_SCOPE;
|
|
843
|
-
this.pendingTokenRefresh = null;
|
|
844
|
-
this.subscriptionName = null;
|
|
845
|
-
this.projectId = null;
|
|
846
|
-
this.serviceAccountEmail = null;
|
|
847
|
-
this.saAccessToken = null;
|
|
848
|
-
this.saTokenExpiresAt = 0;
|
|
849
|
-
this.onIncomingMessage = null;
|
|
850
|
-
this.consecutiveFailures = 0;
|
|
851
|
-
this.pullPaused = false;
|
|
852
|
-
this.lastPullAt = null;
|
|
853
|
-
this.mode = 'none';
|
|
854
|
-
}
|
|
855
269
|
}
|
|
856
270
|
//# sourceMappingURL=google-chat-messenger.adapter.js.map
|