crewly 1.4.61 → 1.4.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/skills/agent/content-calendar/execute.sh +2 -2
- package/config/skills/agent/marketing/brand-onboarding/SKILL.md +76 -0
- package/config/skills/agent/marketing/brand-onboarding/execute.sh +312 -0
- package/config/skills/agent/marketing/submit-for-approval/SKILL.md +73 -0
- package/config/skills/agent/marketing/submit-for-approval/execute.sh +138 -0
- package/config/skills/agent/marketing/weekly-content-planning/SKILL.md +52 -0
- package/config/skills/agent/marketing/weekly-content-planning/execute.sh +202 -0
- package/config/skills/agent/marketing/weekly-content-planning/execute.test.sh +151 -0
- package/config/skills/agent/marketing/weekly-marketing-report/SKILL.md +51 -0
- package/config/skills/agent/marketing/weekly-marketing-report/execute.sh +190 -0
- package/config/skills/agent/marketing/weekly-marketing-report/execute.test.sh +241 -0
- package/config/skills/orchestrator/send-to-remote/SKILL.md +51 -0
- package/config/skills/orchestrator/send-to-remote/execute.sh +114 -0
- package/config/templates/marketing-team/README.md +42 -0
- package/config/templates/marketing-team/goals.md +21 -0
- package/config/templates/marketing-team/knowledge/docs/brand-voice-guide.md +61 -0
- package/config/templates/marketing-team/knowledge/docs/content-best-practices.md +64 -0
- package/config/templates/marketing-team/knowledge/index.json +24 -0
- package/config/templates/marketing-team/learned-patterns.json +5 -0
- package/config/templates/marketing-team/norms/brand-consistency.md +40 -0
- package/config/templates/marketing-team/norms/content-quality-checklist.md +45 -0
- package/config/templates/marketing-team/quality-gates.yaml +47 -0
- package/config/templates/marketing-team/roles/analyst.md +63 -0
- package/config/templates/marketing-team/roles/strategist.md +26 -0
- package/config/templates/marketing-team/roles/writer.md +58 -0
- package/config/templates/marketing-team/template.json +90 -0
- package/config/templates/marketing-team/workflows/weekly-content-cycle.yaml +48 -0
- package/dist/backend/backend/src/constants.d.ts +9 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +9 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/cross-machine/cross-machine.controller.d.ts +16 -0
- package/dist/backend/backend/src/controllers/cross-machine/cross-machine.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cross-machine/cross-machine.controller.js +140 -0
- package/dist/backend/backend/src/controllers/cross-machine/cross-machine.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cross-machine/index.d.ts +7 -0
- package/dist/backend/backend/src/controllers/cross-machine/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cross-machine/index.js +7 -0
- package/dist/backend/backend/src/controllers/cross-machine/index.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 +3 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- 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 +46 -6
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +13 -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 +50 -5
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts +8 -0
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js +52 -3
- package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts +5 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.js +14 -2
- package/dist/backend/backend/src/services/cloud/relay-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/index.d.ts +2 -0
- package/dist/backend/backend/src/services/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/index.js +2 -0
- package/dist/backend/backend/src/services/index.js.map +1 -1
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.service.d.ts +155 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.service.js +469 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.service.js.map +1 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.types.d.ts +107 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.types.js +104 -0
- package/dist/backend/backend/src/services/onboarding/brand-onboarding.types.js.map +1 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.service.d.ts +124 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.service.js +256 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.service.js.map +1 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.types.d.ts +80 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.types.js +16 -0
- package/dist/backend/backend/src/services/onboarding/content-approval.types.js.map +1 -0
- package/dist/backend/backend/src/services/onboarding/index.d.ts +12 -0
- package/dist/backend/backend/src/services/onboarding/index.d.ts.map +1 -0
- package/dist/backend/backend/src/services/onboarding/index.js +10 -0
- package/dist/backend/backend/src/services/onboarding/index.js.map +1 -0
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.d.ts +147 -0
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.js +306 -0
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +7 -0
- 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 +76 -0
- 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.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +8 -2
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/types/cross-machine.types.d.ts +103 -0
- package/dist/backend/backend/src/types/cross-machine.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/cross-machine.types.js +47 -0
- package/dist/backend/backend/src/types/cross-machine.types.js.map +1 -0
- package/dist/cli/backend/src/constants.d.ts +9 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +9 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/cli/src/commands/cloud.d.ts +18 -2
- package/dist/cli/cli/src/commands/cloud.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/cloud.js +72 -16
- package/dist/cli/cli/src/commands/cloud.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Content Approval workflow.
|
|
3
|
+
*
|
|
4
|
+
* Used by marketing team agents to submit content for human review
|
|
5
|
+
* via Slack. The approval flow is: draft → submitted → approved/rejected.
|
|
6
|
+
*
|
|
7
|
+
* @module content-approval-types
|
|
8
|
+
*/
|
|
9
|
+
/** Approval status for a content item. */
|
|
10
|
+
export type ContentApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired';
|
|
11
|
+
/** A content item submitted for approval. */
|
|
12
|
+
export interface ContentApprovalRequest {
|
|
13
|
+
/** Unique approval request ID */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Team ID this approval belongs to */
|
|
16
|
+
teamId: string;
|
|
17
|
+
/** Agent session that submitted the content */
|
|
18
|
+
submittedBy: string;
|
|
19
|
+
/** Platform the content is for */
|
|
20
|
+
platform: string;
|
|
21
|
+
/** Content type (post, article, newsletter, etc.) */
|
|
22
|
+
contentType: string;
|
|
23
|
+
/** The actual content text */
|
|
24
|
+
content: string;
|
|
25
|
+
/** Suggested hashtags */
|
|
26
|
+
hashtags?: string[];
|
|
27
|
+
/** Suggested visual direction */
|
|
28
|
+
visualDirection?: string;
|
|
29
|
+
/** Suggested posting time */
|
|
30
|
+
scheduledTime?: string;
|
|
31
|
+
/** Current approval status */
|
|
32
|
+
status: ContentApprovalStatus;
|
|
33
|
+
/** Submission timestamp */
|
|
34
|
+
submittedAt: string;
|
|
35
|
+
/** Resolution timestamp */
|
|
36
|
+
resolvedAt?: string;
|
|
37
|
+
/** Who resolved (user ID or 'auto') */
|
|
38
|
+
resolvedBy?: string;
|
|
39
|
+
/** Rejection reason or edit notes */
|
|
40
|
+
feedback?: string;
|
|
41
|
+
/** Slack message timestamp for the approval message */
|
|
42
|
+
slackMessageTs?: string;
|
|
43
|
+
/** Slack channel ID where approval was posted */
|
|
44
|
+
slackChannelId?: string;
|
|
45
|
+
}
|
|
46
|
+
/** Options for submitting content for approval. */
|
|
47
|
+
export interface SubmitForApprovalOptions {
|
|
48
|
+
/** Team ID */
|
|
49
|
+
teamId: string;
|
|
50
|
+
/** Agent session name */
|
|
51
|
+
submittedBy: string;
|
|
52
|
+
/** Target platform */
|
|
53
|
+
platform: string;
|
|
54
|
+
/** Content type */
|
|
55
|
+
contentType: string;
|
|
56
|
+
/** Content text */
|
|
57
|
+
content: string;
|
|
58
|
+
/** Optional hashtags */
|
|
59
|
+
hashtags?: string[];
|
|
60
|
+
/** Optional visual direction */
|
|
61
|
+
visualDirection?: string;
|
|
62
|
+
/** Optional scheduled time */
|
|
63
|
+
scheduledTime?: string;
|
|
64
|
+
}
|
|
65
|
+
/** Result of resolving an approval request. */
|
|
66
|
+
export interface ApprovalResolution {
|
|
67
|
+
/** Approval ID that was resolved */
|
|
68
|
+
approvalId: string;
|
|
69
|
+
/** New status */
|
|
70
|
+
status: 'approved' | 'rejected';
|
|
71
|
+
/** Who resolved */
|
|
72
|
+
resolvedBy: string;
|
|
73
|
+
/** Optional feedback/notes */
|
|
74
|
+
feedback?: string;
|
|
75
|
+
}
|
|
76
|
+
/** How long an approval request stays active before expiring (ms). */
|
|
77
|
+
export declare const CONTENT_APPROVAL_TTL_MS: number;
|
|
78
|
+
/** Maximum pending approvals per team. */
|
|
79
|
+
export declare const MAX_PENDING_APPROVALS = 50;
|
|
80
|
+
//# sourceMappingURL=content-approval.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-approval.types.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/onboarding/content-approval.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,0CAA0C;AAC1C,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,UAAU,GACV,UAAU,GACV,SAAS,CAAC;AAEd,6CAA6C;AAC7C,MAAM,WAAW,sBAAsB;IACrC,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,iCAAiC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8BAA8B;IAC9B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,mDAAmD;AACnD,MAAM,WAAW,wBAAwB;IACvC,cAAc;IACd,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB;IACjB,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;IAChC,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,QAAsB,CAAC;AAE3D,0CAA0C;AAC1C,eAAO,MAAM,qBAAqB,KAAK,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Content Approval workflow.
|
|
3
|
+
*
|
|
4
|
+
* Used by marketing team agents to submit content for human review
|
|
5
|
+
* via Slack. The approval flow is: draft → submitted → approved/rejected.
|
|
6
|
+
*
|
|
7
|
+
* @module content-approval-types
|
|
8
|
+
*/
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Constants
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/** How long an approval request stays active before expiring (ms). */
|
|
13
|
+
export const CONTENT_APPROVAL_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
14
|
+
/** Maximum pending approvals per team. */
|
|
15
|
+
export const MAX_PENDING_APPROVALS = 50;
|
|
16
|
+
//# sourceMappingURL=content-approval.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-approval.types.js","sourceRoot":"","sources":["../../../../../../backend/src/services/onboarding/content-approval.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiFH,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;AAEvE,0CAA0C;AAC1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding service exports.
|
|
3
|
+
*
|
|
4
|
+
* @module onboarding
|
|
5
|
+
*/
|
|
6
|
+
export { BrandOnboardingService } from './brand-onboarding.service.js';
|
|
7
|
+
export { ONBOARDING_QUESTIONS, DEFAULT_CONTENT_MIX, } from './brand-onboarding.types.js';
|
|
8
|
+
export type { OnboardingQuestion, OnboardingAnswer, OnboardingSession, OnboardingStatus, BrandProfile, GenerateGuideOptions, } from './brand-onboarding.types.js';
|
|
9
|
+
export { ContentApprovalService } from './content-approval.service.js';
|
|
10
|
+
export { CONTENT_APPROVAL_TTL_MS, MAX_PENDING_APPROVALS, } from './content-approval.types.js';
|
|
11
|
+
export type { ContentApprovalRequest, ContentApprovalStatus, SubmitForApprovalOptions, ApprovalResolution, } from './content-approval.types.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/onboarding/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding service exports.
|
|
3
|
+
*
|
|
4
|
+
* @module onboarding
|
|
5
|
+
*/
|
|
6
|
+
export { BrandOnboardingService } from './brand-onboarding.service.js';
|
|
7
|
+
export { ONBOARDING_QUESTIONS, DEFAULT_CONTENT_MIX, } from './brand-onboarding.types.js';
|
|
8
|
+
export { ContentApprovalService } from './content-approval.service.js';
|
|
9
|
+
export { CONTENT_APPROVAL_TTL_MS, MAX_PENDING_APPROVALS, } from './content-approval.types.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../backend/src/services/onboarding/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,6BAA6B,CAAC;AAUrC,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Machine Message Service
|
|
3
|
+
*
|
|
4
|
+
* Enables Crewly instances on different machines to communicate
|
|
5
|
+
* through a shared Slack channel. Uses Slack as the transport layer,
|
|
6
|
+
* replacing the Cloud Relay WebSocket approach with a simpler HTTP-based
|
|
7
|
+
* mechanism that leverages Slack's built-in auth, delivery, and persistence.
|
|
8
|
+
*
|
|
9
|
+
* @module services/slack/cross-machine-message
|
|
10
|
+
*/
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
import { type SlackService } from './slack.service.js';
|
|
13
|
+
import { DeviceIdentityService, type DeviceIdentity } from '../cloud/device-identity.service.js';
|
|
14
|
+
import type { SlackIncomingMessage } from '../../types/slack.types.js';
|
|
15
|
+
import { type CrossMachineMessage, type CrossMachineMessageType, type CrossMachineConfig, type CrossMachineSendResult } from '../../types/cross-machine.types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Events emitted by CrossMachineMessageService.
|
|
18
|
+
*/
|
|
19
|
+
export interface CrossMachineEvents {
|
|
20
|
+
/** Fired when a cross-machine message addressed to this machine is received */
|
|
21
|
+
message: (message: CrossMachineMessage) => void;
|
|
22
|
+
/** Fired when a broadcast message is received */
|
|
23
|
+
broadcast: (message: CrossMachineMessage) => void;
|
|
24
|
+
/** Fired on errors */
|
|
25
|
+
error: (error: Error) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* CrossMachineMessageService
|
|
29
|
+
*
|
|
30
|
+
* Singleton service managing cross-machine communication via Slack.
|
|
31
|
+
* On send: serializes a CrossMachineMessage with a recognizable prefix
|
|
32
|
+
* and posts it to the configured Slack channel.
|
|
33
|
+
* On receive: the SlackOrchestratorBridge detects the prefix and calls
|
|
34
|
+
* handleIncomingMessage(), which filters by target and emits events.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const service = getCrossMachineMessageService();
|
|
39
|
+
* await service.initialize();
|
|
40
|
+
*
|
|
41
|
+
* // Send a task to another machine
|
|
42
|
+
* await service.sendMessage('device-uuid-of-remote', 'delegate-task', {
|
|
43
|
+
* task: 'Run tests on feature branch',
|
|
44
|
+
* priority: 'high',
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // Listen for incoming messages
|
|
48
|
+
* service.on('message', (msg) => {
|
|
49
|
+
* console.log(`Received ${msg.type} from ${msg.fromName}`);
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare class CrossMachineMessageService extends EventEmitter {
|
|
54
|
+
private readonly logger;
|
|
55
|
+
private slackService;
|
|
56
|
+
private deviceIdentity;
|
|
57
|
+
private config;
|
|
58
|
+
private identity;
|
|
59
|
+
private initialized;
|
|
60
|
+
/** Track processed message IDs to prevent duplicate handling */
|
|
61
|
+
private processedMessageIds;
|
|
62
|
+
/** Maximum number of tracked message IDs before pruning */
|
|
63
|
+
private readonly maxTrackedMessages;
|
|
64
|
+
/**
|
|
65
|
+
* Create a new CrossMachineMessageService.
|
|
66
|
+
*
|
|
67
|
+
* @param slackService - Optional SlackService override (for testing)
|
|
68
|
+
* @param deviceIdentity - Optional DeviceIdentityService override (for testing)
|
|
69
|
+
*/
|
|
70
|
+
constructor(slackService?: SlackService, deviceIdentity?: DeviceIdentityService);
|
|
71
|
+
/**
|
|
72
|
+
* Initialize the service.
|
|
73
|
+
* Loads device identity and cross-machine config from disk.
|
|
74
|
+
*
|
|
75
|
+
* @returns Promise that resolves when initialized
|
|
76
|
+
*/
|
|
77
|
+
initialize(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Check if the service is initialized and enabled.
|
|
80
|
+
*
|
|
81
|
+
* @returns True if ready to send/receive messages
|
|
82
|
+
*/
|
|
83
|
+
isEnabled(): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Get the current configuration.
|
|
86
|
+
*
|
|
87
|
+
* @returns Cross-machine config or null
|
|
88
|
+
*/
|
|
89
|
+
getConfig(): CrossMachineConfig | null;
|
|
90
|
+
/**
|
|
91
|
+
* Get the local device identity.
|
|
92
|
+
*
|
|
93
|
+
* @returns Device identity or null if not initialized
|
|
94
|
+
*/
|
|
95
|
+
getIdentity(): DeviceIdentity | null;
|
|
96
|
+
/**
|
|
97
|
+
* Configure cross-machine messaging.
|
|
98
|
+
* Persists the config to ~/.crewly/cross-machine.json.
|
|
99
|
+
*
|
|
100
|
+
* @param config - Configuration with Slack channel ID
|
|
101
|
+
* @returns Promise that resolves when saved
|
|
102
|
+
*/
|
|
103
|
+
configure(config: CrossMachineConfig): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Send a cross-machine message via Slack.
|
|
106
|
+
*
|
|
107
|
+
* @param targetDeviceId - Target machine's device ID (or "*" for broadcast)
|
|
108
|
+
* @param type - Message type
|
|
109
|
+
* @param payload - Message payload
|
|
110
|
+
* @returns Send result with success status
|
|
111
|
+
*/
|
|
112
|
+
sendMessage(targetDeviceId: string, type: CrossMachineMessageType, payload?: Record<string, unknown>): Promise<CrossMachineSendResult>;
|
|
113
|
+
/**
|
|
114
|
+
* Handle an incoming Slack message that has been identified as a
|
|
115
|
+
* cross-machine message by the SlackOrchestratorBridge.
|
|
116
|
+
*
|
|
117
|
+
* Checks if the message is addressed to this machine, deduplicates,
|
|
118
|
+
* and emits appropriate events.
|
|
119
|
+
*
|
|
120
|
+
* @param slackMessage - The raw Slack incoming message
|
|
121
|
+
* @returns True if the message was handled (addressed to us), false if ignored
|
|
122
|
+
*/
|
|
123
|
+
handleIncomingMessage(slackMessage: SlackIncomingMessage): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Load cross-machine config from disk.
|
|
126
|
+
*
|
|
127
|
+
* @returns Config or null if not configured
|
|
128
|
+
*/
|
|
129
|
+
private loadConfig;
|
|
130
|
+
/**
|
|
131
|
+
* Save cross-machine config to disk.
|
|
132
|
+
*
|
|
133
|
+
* @param config - Configuration to persist
|
|
134
|
+
*/
|
|
135
|
+
private saveConfig;
|
|
136
|
+
/**
|
|
137
|
+
* Reset the singleton instance (for testing).
|
|
138
|
+
*/
|
|
139
|
+
static resetInstance(): void;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the singleton CrossMachineMessageService instance.
|
|
143
|
+
*
|
|
144
|
+
* @returns The service instance
|
|
145
|
+
*/
|
|
146
|
+
export declare function getCrossMachineMessageService(): CrossMachineMessageService;
|
|
147
|
+
//# sourceMappingURL=cross-machine-message.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-machine-message.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/slack/cross-machine-message.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMtC,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACjG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAG5B,MAAM,oCAAoC,CAAC;AAI5C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,OAAO,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChD,iDAAiD;IACjD,SAAS,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD,sBAAsB;IACtB,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,WAAW,CAAS;IAE5B,gEAAgE;IAChE,OAAO,CAAC,mBAAmB,CAAqB;IAChD,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAE5C;;;;;OAKG;gBACS,YAAY,CAAC,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,qBAAqB;IAQ/E;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAejC;;;;OAIG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACH,SAAS,IAAI,kBAAkB,GAAG,IAAI;IAItC;;;;OAIG;IACH,WAAW,IAAI,cAAc,GAAG,IAAI;IAIpC;;;;;;OAMG;IACG,SAAS,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM1D;;;;;;;OAOG;IACG,WAAW,CACf,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,uBAAuB,EAC7B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,OAAO,CAAC,sBAAsB,CAAC;IAgDlC;;;;;;;;;OASG;IACH,qBAAqB,CAAC,YAAY,EAAE,oBAAoB,GAAG,OAAO;IAqElE;;;;OAIG;YACW,UAAU;IAexB;;;;OAIG;YACW,UAAU;IAgBxB;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;CAG7B;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,0BAA0B,CAK1E"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Machine Message Service
|
|
3
|
+
*
|
|
4
|
+
* Enables Crewly instances on different machines to communicate
|
|
5
|
+
* through a shared Slack channel. Uses Slack as the transport layer,
|
|
6
|
+
* replacing the Cloud Relay WebSocket approach with a simpler HTTP-based
|
|
7
|
+
* mechanism that leverages Slack's built-in auth, delivery, and persistence.
|
|
8
|
+
*
|
|
9
|
+
* @module services/slack/cross-machine-message
|
|
10
|
+
*/
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
13
|
+
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
14
|
+
import { existsSync } from 'fs';
|
|
15
|
+
import { join } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
import { getSlackService } from './slack.service.js';
|
|
18
|
+
import { DeviceIdentityService } from '../cloud/device-identity.service.js';
|
|
19
|
+
import { parseCrossMachineMessage, serializeCrossMachineMessage, } from '../../types/cross-machine.types.js';
|
|
20
|
+
import { CROSS_MACHINE_CONSTANTS } from '../../constants.js';
|
|
21
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
22
|
+
/** Config file path relative to ~/.crewly/ */
|
|
23
|
+
const CONFIG_FILE = 'cross-machine.json';
|
|
24
|
+
/** Singleton instance */
|
|
25
|
+
let serviceInstance = null;
|
|
26
|
+
/**
|
|
27
|
+
* CrossMachineMessageService
|
|
28
|
+
*
|
|
29
|
+
* Singleton service managing cross-machine communication via Slack.
|
|
30
|
+
* On send: serializes a CrossMachineMessage with a recognizable prefix
|
|
31
|
+
* and posts it to the configured Slack channel.
|
|
32
|
+
* On receive: the SlackOrchestratorBridge detects the prefix and calls
|
|
33
|
+
* handleIncomingMessage(), which filters by target and emits events.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const service = getCrossMachineMessageService();
|
|
38
|
+
* await service.initialize();
|
|
39
|
+
*
|
|
40
|
+
* // Send a task to another machine
|
|
41
|
+
* await service.sendMessage('device-uuid-of-remote', 'delegate-task', {
|
|
42
|
+
* task: 'Run tests on feature branch',
|
|
43
|
+
* priority: 'high',
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Listen for incoming messages
|
|
47
|
+
* service.on('message', (msg) => {
|
|
48
|
+
* console.log(`Received ${msg.type} from ${msg.fromName}`);
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export class CrossMachineMessageService extends EventEmitter {
|
|
53
|
+
logger;
|
|
54
|
+
slackService;
|
|
55
|
+
deviceIdentity;
|
|
56
|
+
config = null;
|
|
57
|
+
identity = null;
|
|
58
|
+
initialized = false;
|
|
59
|
+
/** Track processed message IDs to prevent duplicate handling */
|
|
60
|
+
processedMessageIds = new Set();
|
|
61
|
+
/** Maximum number of tracked message IDs before pruning */
|
|
62
|
+
maxTrackedMessages;
|
|
63
|
+
/**
|
|
64
|
+
* Create a new CrossMachineMessageService.
|
|
65
|
+
*
|
|
66
|
+
* @param slackService - Optional SlackService override (for testing)
|
|
67
|
+
* @param deviceIdentity - Optional DeviceIdentityService override (for testing)
|
|
68
|
+
*/
|
|
69
|
+
constructor(slackService, deviceIdentity) {
|
|
70
|
+
super();
|
|
71
|
+
this.logger = LoggerService.getInstance().createComponentLogger('CrossMachineMsg');
|
|
72
|
+
this.slackService = slackService || getSlackService();
|
|
73
|
+
this.deviceIdentity = deviceIdentity || DeviceIdentityService.getInstance();
|
|
74
|
+
this.maxTrackedMessages = CROSS_MACHINE_CONSTANTS.MAX_TRACKED_MESSAGE_IDS;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Initialize the service.
|
|
78
|
+
* Loads device identity and cross-machine config from disk.
|
|
79
|
+
*
|
|
80
|
+
* @returns Promise that resolves when initialized
|
|
81
|
+
*/
|
|
82
|
+
async initialize() {
|
|
83
|
+
if (this.initialized)
|
|
84
|
+
return;
|
|
85
|
+
this.identity = await this.deviceIdentity.getOrCreateIdentity();
|
|
86
|
+
this.config = await this.loadConfig();
|
|
87
|
+
this.initialized = true;
|
|
88
|
+
this.logger.info('Initialized', {
|
|
89
|
+
deviceId: this.identity.deviceId,
|
|
90
|
+
deviceName: this.identity.deviceName,
|
|
91
|
+
enabled: this.config?.enabled ?? false,
|
|
92
|
+
channelId: this.config?.channelId ?? 'not configured',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if the service is initialized and enabled.
|
|
97
|
+
*
|
|
98
|
+
* @returns True if ready to send/receive messages
|
|
99
|
+
*/
|
|
100
|
+
isEnabled() {
|
|
101
|
+
return this.initialized && !!this.config?.enabled && !!this.config?.channelId;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get the current configuration.
|
|
105
|
+
*
|
|
106
|
+
* @returns Cross-machine config or null
|
|
107
|
+
*/
|
|
108
|
+
getConfig() {
|
|
109
|
+
return this.config ? { ...this.config } : null;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get the local device identity.
|
|
113
|
+
*
|
|
114
|
+
* @returns Device identity or null if not initialized
|
|
115
|
+
*/
|
|
116
|
+
getIdentity() {
|
|
117
|
+
return this.identity ? { ...this.identity } : null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Configure cross-machine messaging.
|
|
121
|
+
* Persists the config to ~/.crewly/cross-machine.json.
|
|
122
|
+
*
|
|
123
|
+
* @param config - Configuration with Slack channel ID
|
|
124
|
+
* @returns Promise that resolves when saved
|
|
125
|
+
*/
|
|
126
|
+
async configure(config) {
|
|
127
|
+
this.config = config;
|
|
128
|
+
await this.saveConfig(config);
|
|
129
|
+
this.logger.info('Configuration updated', { enabled: config.enabled, channelId: config.channelId });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Send a cross-machine message via Slack.
|
|
133
|
+
*
|
|
134
|
+
* @param targetDeviceId - Target machine's device ID (or "*" for broadcast)
|
|
135
|
+
* @param type - Message type
|
|
136
|
+
* @param payload - Message payload
|
|
137
|
+
* @returns Send result with success status
|
|
138
|
+
*/
|
|
139
|
+
async sendMessage(targetDeviceId, type, payload = {}) {
|
|
140
|
+
if (!this.isEnabled()) {
|
|
141
|
+
return { success: false, error: 'Cross-machine messaging is not enabled or configured' };
|
|
142
|
+
}
|
|
143
|
+
if (!this.identity) {
|
|
144
|
+
return { success: false, error: 'Device identity not initialized' };
|
|
145
|
+
}
|
|
146
|
+
if (!this.slackService.isConnected()) {
|
|
147
|
+
return { success: false, error: 'Slack is not connected' };
|
|
148
|
+
}
|
|
149
|
+
const message = {
|
|
150
|
+
protocol: 'crewly-x-machine',
|
|
151
|
+
version: 1,
|
|
152
|
+
from: this.identity.deviceId,
|
|
153
|
+
fromName: this.identity.deviceName,
|
|
154
|
+
to: targetDeviceId,
|
|
155
|
+
type,
|
|
156
|
+
payload,
|
|
157
|
+
timestamp: new Date().toISOString(),
|
|
158
|
+
messageId: uuidv4(),
|
|
159
|
+
};
|
|
160
|
+
const serialized = serializeCrossMachineMessage(message);
|
|
161
|
+
try {
|
|
162
|
+
const ts = await this.slackService.sendMessage({
|
|
163
|
+
channelId: this.config.channelId,
|
|
164
|
+
text: serialized,
|
|
165
|
+
});
|
|
166
|
+
this.logger.info('Sent cross-machine message', {
|
|
167
|
+
to: targetDeviceId,
|
|
168
|
+
type,
|
|
169
|
+
messageId: message.messageId,
|
|
170
|
+
slackTs: ts,
|
|
171
|
+
});
|
|
172
|
+
return { success: true, slackTs: ts };
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
176
|
+
this.logger.error('Failed to send cross-machine message', { error: errorMsg, to: targetDeviceId, type });
|
|
177
|
+
return { success: false, error: errorMsg };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Handle an incoming Slack message that has been identified as a
|
|
182
|
+
* cross-machine message by the SlackOrchestratorBridge.
|
|
183
|
+
*
|
|
184
|
+
* Checks if the message is addressed to this machine, deduplicates,
|
|
185
|
+
* and emits appropriate events.
|
|
186
|
+
*
|
|
187
|
+
* @param slackMessage - The raw Slack incoming message
|
|
188
|
+
* @returns True if the message was handled (addressed to us), false if ignored
|
|
189
|
+
*/
|
|
190
|
+
handleIncomingMessage(slackMessage) {
|
|
191
|
+
const parsed = parseCrossMachineMessage(slackMessage.text);
|
|
192
|
+
if (!parsed) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
// Ignore messages from ourselves
|
|
196
|
+
if (this.identity && parsed.from === this.identity.deviceId) {
|
|
197
|
+
this.logger.debug('Ignoring own message', { messageId: parsed.messageId });
|
|
198
|
+
return true; // Handled (by ignoring)
|
|
199
|
+
}
|
|
200
|
+
// Deduplicate
|
|
201
|
+
if (this.processedMessageIds.has(parsed.messageId)) {
|
|
202
|
+
this.logger.debug('Ignoring duplicate message', { messageId: parsed.messageId });
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
// Track message ID
|
|
206
|
+
this.processedMessageIds.add(parsed.messageId);
|
|
207
|
+
if (this.processedMessageIds.size > this.maxTrackedMessages) {
|
|
208
|
+
// Prune oldest entries (Set preserves insertion order)
|
|
209
|
+
const iterator = this.processedMessageIds.values();
|
|
210
|
+
const halfSize = Math.floor(this.maxTrackedMessages / 2);
|
|
211
|
+
for (let i = 0; i < halfSize; i++) {
|
|
212
|
+
const val = iterator.next().value;
|
|
213
|
+
if (val !== undefined) {
|
|
214
|
+
this.processedMessageIds.delete(val);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Check if addressed to us or broadcast
|
|
219
|
+
const isForUs = this.identity && (parsed.to === this.identity.deviceId ||
|
|
220
|
+
parsed.to === '*');
|
|
221
|
+
if (!isForUs) {
|
|
222
|
+
this.logger.debug('Ignoring message addressed to another machine', {
|
|
223
|
+
to: parsed.to,
|
|
224
|
+
ourId: this.identity?.deviceId,
|
|
225
|
+
});
|
|
226
|
+
return true; // Handled (by ignoring — not for us)
|
|
227
|
+
}
|
|
228
|
+
this.logger.info('Received cross-machine message', {
|
|
229
|
+
from: parsed.fromName,
|
|
230
|
+
fromId: parsed.from,
|
|
231
|
+
type: parsed.type,
|
|
232
|
+
messageId: parsed.messageId,
|
|
233
|
+
});
|
|
234
|
+
// Handle ping/pong automatically
|
|
235
|
+
if (parsed.type === 'ping') {
|
|
236
|
+
this.sendMessage(parsed.from, 'pong', { inResponseTo: parsed.messageId }).catch(err => {
|
|
237
|
+
this.logger.warn('Failed to send pong', { error: err instanceof Error ? err.message : String(err) });
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
// Emit events
|
|
241
|
+
if (parsed.to === '*') {
|
|
242
|
+
this.emit('broadcast', parsed);
|
|
243
|
+
}
|
|
244
|
+
this.emit('message', parsed);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Load cross-machine config from disk.
|
|
249
|
+
*
|
|
250
|
+
* @returns Config or null if not configured
|
|
251
|
+
*/
|
|
252
|
+
async loadConfig() {
|
|
253
|
+
const configPath = join(homedir(), '.crewly', CONFIG_FILE);
|
|
254
|
+
try {
|
|
255
|
+
if (existsSync(configPath)) {
|
|
256
|
+
const content = await readFile(configPath, 'utf-8');
|
|
257
|
+
return JSON.parse(content);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
this.logger.warn('Failed to load cross-machine config', {
|
|
262
|
+
error: error instanceof Error ? error.message : String(error),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Save cross-machine config to disk.
|
|
269
|
+
*
|
|
270
|
+
* @param config - Configuration to persist
|
|
271
|
+
*/
|
|
272
|
+
async saveConfig(config) {
|
|
273
|
+
const crewlyHome = join(homedir(), '.crewly');
|
|
274
|
+
const configPath = join(crewlyHome, CONFIG_FILE);
|
|
275
|
+
try {
|
|
276
|
+
if (!existsSync(crewlyHome)) {
|
|
277
|
+
await mkdir(crewlyHome, { recursive: true });
|
|
278
|
+
}
|
|
279
|
+
await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
this.logger.error('Failed to save cross-machine config', {
|
|
283
|
+
error: error instanceof Error ? error.message : String(error),
|
|
284
|
+
});
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Reset the singleton instance (for testing).
|
|
290
|
+
*/
|
|
291
|
+
static resetInstance() {
|
|
292
|
+
serviceInstance = null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Get the singleton CrossMachineMessageService instance.
|
|
297
|
+
*
|
|
298
|
+
* @returns The service instance
|
|
299
|
+
*/
|
|
300
|
+
export function getCrossMachineMessageService() {
|
|
301
|
+
if (!serviceInstance) {
|
|
302
|
+
serviceInstance = new CrossMachineMessageService();
|
|
303
|
+
}
|
|
304
|
+
return serviceInstance;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=cross-machine-message.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-machine-message.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/slack/cross-machine-message.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -111,6 +111,13 @@ export declare class SlackOrchestratorBridge extends EventEmitter {
|
|
|
111
111
|
* @param message - Incoming Slack message
|
|
112
112
|
*/
|
|
113
113
|
private handleSlackMessage;
|
|
114
|
+
/**
|
|
115
|
+
* Handle an incoming cross-machine message.
|
|
116
|
+
* Routes the message payload to the local orchestrator via the message queue.
|
|
117
|
+
*
|
|
118
|
+
* @param msg - Parsed cross-machine message
|
|
119
|
+
*/
|
|
120
|
+
private handleCrossMachineMessage;
|
|
114
121
|
/**
|
|
115
122
|
* Parse command from message text
|
|
116
123
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-orchestrator-bridge.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/slack/slack-orchestrator-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AActC,OAAO,EAEL,iBAAiB,EAKjB,kBAAkB,EAEnB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"slack-orchestrator-bridge.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/slack/slack-orchestrator-bridge.ts"],"names":[],"mappings":"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"}
|