crewly 1.6.2 → 1.6.4
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/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.js +76 -15
- package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +3 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +16 -0
- package/dist/backend/backend/src/index.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 +58 -9
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts +91 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js +120 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js.map +1 -0
- package/dist/backend/backend/src/services/core/storage.service.d.ts +15 -0
- package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.js +42 -0
- package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/index.d.ts +1 -0
- package/dist/backend/backend/src/services/orchestrator/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/index.js +1 -0
- package/dist/backend/backend/src/services/orchestrator/index.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.d.ts +114 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.js +195 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.js.map +1 -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 +18 -6
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +23 -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 +79 -2
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.d.ts +15 -0
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.js +42 -0
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator Setup Service
|
|
3
|
+
*
|
|
4
|
+
* Provides a service-level entrypoint for triggering orchestrator setup,
|
|
5
|
+
* mirroring the logic behind `POST /api/orchestrator/setup`. Used by the
|
|
6
|
+
* SlackBridge auto-recovery path so it can reattempt setup without going
|
|
7
|
+
* through HTTP.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - Dependencies are injected via `setOrchestratorSetupDependencies()` from
|
|
11
|
+
* the bootstrap layer (`backend/src/index.ts`), keeping this service
|
|
12
|
+
* decoupled from the API context shape.
|
|
13
|
+
* - Concurrent calls are deduplicated via an in-flight promise — if a
|
|
14
|
+
* setup is already running, the second caller awaits the same result.
|
|
15
|
+
* - Callers should impose their own timeout on the returned promise; this
|
|
16
|
+
* service does not enforce a timeout because setup duration varies per
|
|
17
|
+
* runtime type.
|
|
18
|
+
*
|
|
19
|
+
* @module services/orchestrator/orchestrator-setup.service
|
|
20
|
+
*/
|
|
21
|
+
import { type RuntimeType } from '../../constants.js';
|
|
22
|
+
import type { StorageService } from '../core/storage.service.js';
|
|
23
|
+
/**
|
|
24
|
+
* Minimal contract expected from the agent registration service.
|
|
25
|
+
*
|
|
26
|
+
* Defined as an inline structural type rather than imported to avoid a
|
|
27
|
+
* circular module graph (agent-registration → orchestrator → bridge →
|
|
28
|
+
* agent-registration). Matches `AgentRegistrationService.createAgentSession`.
|
|
29
|
+
*/
|
|
30
|
+
export interface AgentRegistrationServiceLike {
|
|
31
|
+
createAgentSession(config: {
|
|
32
|
+
sessionName: string;
|
|
33
|
+
role: string;
|
|
34
|
+
projectPath: string;
|
|
35
|
+
windowName: string;
|
|
36
|
+
runtimeType: RuntimeType;
|
|
37
|
+
forceRecreate?: boolean;
|
|
38
|
+
additionalAllowlistPaths?: string[];
|
|
39
|
+
}): Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
sessionName?: string;
|
|
42
|
+
message?: string;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of `triggerOrchestratorSetup()`.
|
|
48
|
+
*/
|
|
49
|
+
export interface OrchestratorSetupResult {
|
|
50
|
+
/** Whether the setup attempt succeeded (or the orchestrator was already healthy). */
|
|
51
|
+
success: boolean;
|
|
52
|
+
/** Session name if setup succeeded. */
|
|
53
|
+
sessionName?: string;
|
|
54
|
+
/** Human-readable status message. */
|
|
55
|
+
message?: string;
|
|
56
|
+
/** Error message if setup failed. */
|
|
57
|
+
error?: string;
|
|
58
|
+
/** True when setup was skipped because the orchestrator was already healthy. */
|
|
59
|
+
skipped?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Injected dependencies wired by the bootstrap layer.
|
|
63
|
+
*/
|
|
64
|
+
interface SetupDependencies {
|
|
65
|
+
agentRegistrationService: AgentRegistrationServiceLike;
|
|
66
|
+
storageService: StorageService;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Wire the dependencies needed to trigger setup from any caller.
|
|
70
|
+
*
|
|
71
|
+
* Must be called once during bootstrap, after the agent registration service
|
|
72
|
+
* is created. Passing the same dependencies twice is safe (last write wins).
|
|
73
|
+
*
|
|
74
|
+
* @param deps - Required service dependencies
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* setOrchestratorSetupDependencies({
|
|
79
|
+
* agentRegistrationService,
|
|
80
|
+
* storageService,
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function setOrchestratorSetupDependencies(deps: SetupDependencies): void;
|
|
85
|
+
/**
|
|
86
|
+
* Reset injected dependencies. Test-only helper.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export declare function _resetOrchestratorSetupDependenciesForTesting(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Trigger orchestrator setup if it is not already healthy.
|
|
93
|
+
*
|
|
94
|
+
* Steps:
|
|
95
|
+
* 1. Health-check via `getOrchestratorStatus()` — if active, return early.
|
|
96
|
+
* 2. Resolve runtime type from persisted orchestrator status (default: claude-code).
|
|
97
|
+
* 3. Call `createAgentSession()` with `forceRecreate: true`.
|
|
98
|
+
* 4. Initialize memory and start chat monitoring (best-effort).
|
|
99
|
+
*
|
|
100
|
+
* Concurrent callers receive the same in-flight promise — at most one setup
|
|
101
|
+
* runs at a time across the process.
|
|
102
|
+
*
|
|
103
|
+
* The orchestrator's conversation history (`AgentRunner.state.messages`) is
|
|
104
|
+
* left empty after this call. The registration path skips the activation
|
|
105
|
+
* kickoff message for the orchestrator session — this preserves the B1
|
|
106
|
+
* `messageCount === 0` cold-start invariant.
|
|
107
|
+
*
|
|
108
|
+
* @returns Setup result. `skipped: true` if the orchestrator was already healthy.
|
|
109
|
+
*
|
|
110
|
+
* @throws Never — errors are returned in the result object instead.
|
|
111
|
+
*/
|
|
112
|
+
export declare function triggerOrchestratorSetup(): Promise<OrchestratorSetupResult>;
|
|
113
|
+
export {};
|
|
114
|
+
//# sourceMappingURL=orchestrator-setup.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator-setup.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/orchestrator-setup.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAKN,KAAK,WAAW,EAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAKjE;;;;;;GAMG;AACH,MAAM,WAAW,4BAA4B;IAC5C,kBAAkB,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,WAAW,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;KACpC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAC;IACjB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,UAAU,iBAAiB;IAC1B,wBAAwB,EAAE,4BAA4B,CAAC;IACvD,cAAc,EAAE,cAAc,CAAC;CAC/B;AAQD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAE9E;AAED;;;;GAIG;AACH,wBAAgB,6CAA6C,IAAI,IAAI,CAGpE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAiBjF"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator Setup Service
|
|
3
|
+
*
|
|
4
|
+
* Provides a service-level entrypoint for triggering orchestrator setup,
|
|
5
|
+
* mirroring the logic behind `POST /api/orchestrator/setup`. Used by the
|
|
6
|
+
* SlackBridge auto-recovery path so it can reattempt setup without going
|
|
7
|
+
* through HTTP.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - Dependencies are injected via `setOrchestratorSetupDependencies()` from
|
|
11
|
+
* the bootstrap layer (`backend/src/index.ts`), keeping this service
|
|
12
|
+
* decoupled from the API context shape.
|
|
13
|
+
* - Concurrent calls are deduplicated via an in-flight promise — if a
|
|
14
|
+
* setup is already running, the second caller awaits the same result.
|
|
15
|
+
* - Callers should impose their own timeout on the returned promise; this
|
|
16
|
+
* service does not enforce a timeout because setup duration varies per
|
|
17
|
+
* runtime type.
|
|
18
|
+
*
|
|
19
|
+
* @module services/orchestrator/orchestrator-setup.service
|
|
20
|
+
*/
|
|
21
|
+
import { ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_WINDOW_NAME, ORCHESTRATOR_ROLE, RUNTIME_TYPES, } from '../../constants.js';
|
|
22
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
23
|
+
import { formatError } from '../../utils/format-error.js';
|
|
24
|
+
import { MemoryService } from '../memory/memory.service.js';
|
|
25
|
+
import { getTerminalGateway } from '../../websocket/terminal.gateway.js';
|
|
26
|
+
import { getOrchestratorStatus } from './orchestrator-status.service.js';
|
|
27
|
+
let dependencies = null;
|
|
28
|
+
let setupInFlight = null;
|
|
29
|
+
const getLogger = () => LoggerService.getInstance().createComponentLogger('OrchestratorSetup');
|
|
30
|
+
/**
|
|
31
|
+
* Wire the dependencies needed to trigger setup from any caller.
|
|
32
|
+
*
|
|
33
|
+
* Must be called once during bootstrap, after the agent registration service
|
|
34
|
+
* is created. Passing the same dependencies twice is safe (last write wins).
|
|
35
|
+
*
|
|
36
|
+
* @param deps - Required service dependencies
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* setOrchestratorSetupDependencies({
|
|
41
|
+
* agentRegistrationService,
|
|
42
|
+
* storageService,
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function setOrchestratorSetupDependencies(deps) {
|
|
47
|
+
dependencies = deps;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Reset injected dependencies. Test-only helper.
|
|
51
|
+
*
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export function _resetOrchestratorSetupDependenciesForTesting() {
|
|
55
|
+
dependencies = null;
|
|
56
|
+
setupInFlight = null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Trigger orchestrator setup if it is not already healthy.
|
|
60
|
+
*
|
|
61
|
+
* Steps:
|
|
62
|
+
* 1. Health-check via `getOrchestratorStatus()` — if active, return early.
|
|
63
|
+
* 2. Resolve runtime type from persisted orchestrator status (default: claude-code).
|
|
64
|
+
* 3. Call `createAgentSession()` with `forceRecreate: true`.
|
|
65
|
+
* 4. Initialize memory and start chat monitoring (best-effort).
|
|
66
|
+
*
|
|
67
|
+
* Concurrent callers receive the same in-flight promise — at most one setup
|
|
68
|
+
* runs at a time across the process.
|
|
69
|
+
*
|
|
70
|
+
* The orchestrator's conversation history (`AgentRunner.state.messages`) is
|
|
71
|
+
* left empty after this call. The registration path skips the activation
|
|
72
|
+
* kickoff message for the orchestrator session — this preserves the B1
|
|
73
|
+
* `messageCount === 0` cold-start invariant.
|
|
74
|
+
*
|
|
75
|
+
* @returns Setup result. `skipped: true` if the orchestrator was already healthy.
|
|
76
|
+
*
|
|
77
|
+
* @throws Never — errors are returned in the result object instead.
|
|
78
|
+
*/
|
|
79
|
+
export async function triggerOrchestratorSetup() {
|
|
80
|
+
if (setupInFlight) {
|
|
81
|
+
// Concurrent call — caller waits on the existing setup.
|
|
82
|
+
return setupInFlight;
|
|
83
|
+
}
|
|
84
|
+
if (!dependencies) {
|
|
85
|
+
const error = 'Orchestrator setup dependencies not initialized';
|
|
86
|
+
getLogger().error(error);
|
|
87
|
+
return { success: false, error };
|
|
88
|
+
}
|
|
89
|
+
setupInFlight = _runSetup(dependencies).finally(() => {
|
|
90
|
+
setupInFlight = null;
|
|
91
|
+
});
|
|
92
|
+
return setupInFlight;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Internal setup runner. Extracted for clarity — `triggerOrchestratorSetup`
|
|
96
|
+
* just guards concurrency.
|
|
97
|
+
*/
|
|
98
|
+
async function _runSetup(deps) {
|
|
99
|
+
const logger = getLogger();
|
|
100
|
+
try {
|
|
101
|
+
// 1. Skip when already healthy. Avoids hammering setup when SlackBridge's
|
|
102
|
+
// auto-recovery races with another caller.
|
|
103
|
+
try {
|
|
104
|
+
const currentStatus = await getOrchestratorStatus();
|
|
105
|
+
if (currentStatus.isActive) {
|
|
106
|
+
logger.info('Orchestrator is already healthy — skipping setup', {
|
|
107
|
+
agentStatus: currentStatus.agentStatus,
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
success: true,
|
|
111
|
+
skipped: true,
|
|
112
|
+
message: 'Orchestrator is already running (setup skipped)',
|
|
113
|
+
sessionName: ORCHESTRATOR_SESSION_NAME,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (healthErr) {
|
|
118
|
+
logger.warn('Health check failed, proceeding with setup', {
|
|
119
|
+
error: formatError(healthErr),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// 2. Resolve runtime type. Falls back to claude-code if unknown.
|
|
123
|
+
let runtimeType = RUNTIME_TYPES.CLAUDE_CODE;
|
|
124
|
+
try {
|
|
125
|
+
const orchestratorStatus = await deps.storageService.getOrchestratorStatus();
|
|
126
|
+
const stored = orchestratorStatus?.runtimeType;
|
|
127
|
+
if (stored && Object.values(RUNTIME_TYPES).includes(stored)) {
|
|
128
|
+
runtimeType = stored;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (lookupErr) {
|
|
132
|
+
logger.warn('Failed to read runtime type from storage; defaulting to claude-code', {
|
|
133
|
+
error: formatError(lookupErr),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// 3. For Gemini CLI we'd normally collect project paths for the
|
|
137
|
+
// allowlist. The auto-recovery path is best-effort and the controller
|
|
138
|
+
// already does this on the explicit setup endpoint, so we keep it
|
|
139
|
+
// simple here. The createAgentSession contract treats the parameter
|
|
140
|
+
// as optional.
|
|
141
|
+
logger.info('Triggering createAgentSession from auto-recovery', {
|
|
142
|
+
sessionName: ORCHESTRATOR_SESSION_NAME,
|
|
143
|
+
runtimeType,
|
|
144
|
+
});
|
|
145
|
+
const result = await deps.agentRegistrationService.createAgentSession({
|
|
146
|
+
sessionName: ORCHESTRATOR_SESSION_NAME,
|
|
147
|
+
role: ORCHESTRATOR_ROLE,
|
|
148
|
+
projectPath: process.cwd(),
|
|
149
|
+
windowName: ORCHESTRATOR_WINDOW_NAME,
|
|
150
|
+
runtimeType,
|
|
151
|
+
forceRecreate: true,
|
|
152
|
+
});
|
|
153
|
+
if (!result.success) {
|
|
154
|
+
logger.error('createAgentSession returned failure', { error: result.error });
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
error: result.error || 'Failed to create orchestrator session',
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// 4. Best-effort memory init + chat monitoring. Failures here do not
|
|
161
|
+
// block setup success — the session is created, these are auxiliary.
|
|
162
|
+
try {
|
|
163
|
+
await MemoryService.getInstance().initializeForSession(ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, process.cwd());
|
|
164
|
+
}
|
|
165
|
+
catch (memErr) {
|
|
166
|
+
logger.warn('Memory initialization failed (non-fatal)', {
|
|
167
|
+
error: formatError(memErr),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const terminalGateway = getTerminalGateway();
|
|
172
|
+
if (terminalGateway) {
|
|
173
|
+
terminalGateway.startOrchestratorChatMonitoring(ORCHESTRATOR_SESSION_NAME);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (monitorErr) {
|
|
177
|
+
logger.warn('Failed to start chat monitoring (non-fatal)', {
|
|
178
|
+
error: formatError(monitorErr),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
success: true,
|
|
183
|
+
sessionName: result.sessionName ?? ORCHESTRATOR_SESSION_NAME,
|
|
184
|
+
message: result.message ?? 'Orchestrator session created and registered',
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
logger.error('Auto-recovery setup failed', { error: formatError(error) });
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
error: error instanceof Error ? error.message : 'Failed to setup orchestrator session',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=orchestrator-setup.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator-setup.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/orchestrator-setup.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator-status.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/orchestrator-status.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"orchestrator-status.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/orchestrator-status.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAG7D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAqJ/E;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAczE;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,UAAO,GAAG,MAAM,CAMvE"}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
import { StorageService } from '../core/storage.service.js';
|
|
11
11
|
import { CREWLY_CONSTANTS, WEB_CONSTANTS } from '../../../../config/index.js';
|
|
12
12
|
import { getSessionBackendSync } from '../session/index.js';
|
|
13
|
+
import { isInProcessRuntimeActive } from '../agent/crewly-agent/in-process-runtime-registry.js';
|
|
14
|
+
import { RUNTIME_TYPES } from '../../constants.js';
|
|
13
15
|
/** Dashboard URL for user-facing messages */
|
|
14
16
|
const DASHBOARD_URL = `http://localhost:${WEB_CONSTANTS.PORTS.FRONTEND}`;
|
|
15
17
|
/**
|
|
@@ -58,9 +60,9 @@ export async function getOrchestratorStatus() {
|
|
|
58
60
|
// aligning with how the teams controller checks session existence.
|
|
59
61
|
let sessionExists = false;
|
|
60
62
|
let sessionCheckPerformed = false;
|
|
63
|
+
const sessionName = orchestratorStatus?.sessionName || CREWLY_CONSTANTS.SESSIONS.ORCHESTRATOR_NAME;
|
|
61
64
|
try {
|
|
62
65
|
const sessionBackend = getSessionBackendSync();
|
|
63
|
-
const sessionName = orchestratorStatus?.sessionName || CREWLY_CONSTANTS.SESSIONS.ORCHESTRATOR_NAME;
|
|
64
66
|
if (sessionBackend && sessionName) {
|
|
65
67
|
sessionExists = sessionBackend.sessionExists(sessionName);
|
|
66
68
|
sessionCheckPerformed = true;
|
|
@@ -69,6 +71,19 @@ export async function getOrchestratorStatus() {
|
|
|
69
71
|
catch {
|
|
70
72
|
// Ignore session check errors - fall back to storage-based status
|
|
71
73
|
}
|
|
74
|
+
// Runtime-aware fallback (B0 hot-fix):
|
|
75
|
+
// The PTY-based `sessionExists()` returns false for in-process Crewly
|
|
76
|
+
// Agent runtimes because they have no PTY session. Treat the session as
|
|
77
|
+
// alive when the runtime type is `crewly-agent` AND the in-process
|
|
78
|
+
// registry confirms a ready runtime is registered. The PTY path is
|
|
79
|
+
// untouched for `claude-code` / other runtimes.
|
|
80
|
+
if (!sessionExists
|
|
81
|
+
&& orchestratorStatus?.runtimeType === RUNTIME_TYPES.CREWLY_AGENT
|
|
82
|
+
&& sessionName
|
|
83
|
+
&& isInProcessRuntimeActive(sessionName)) {
|
|
84
|
+
sessionExists = true;
|
|
85
|
+
sessionCheckPerformed = true;
|
|
86
|
+
}
|
|
72
87
|
if (!orchestratorStatus) {
|
|
73
88
|
return {
|
|
74
89
|
isActive: false,
|
|
@@ -99,8 +114,7 @@ export async function getOrchestratorStatus() {
|
|
|
99
114
|
if (sessionCheckPerformed && !sessionExists && agentStatus === CREWLY_CONSTANTS.AGENT_STATUSES.ACTIVE) {
|
|
100
115
|
try {
|
|
101
116
|
const storageServiceForCleanup = StorageService.getInstance();
|
|
102
|
-
|
|
103
|
-
await storageServiceForCleanup.updateAgentStatus(cleanupSessionName, CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE);
|
|
117
|
+
await storageServiceForCleanup.updateAgentStatus(sessionName, CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE);
|
|
104
118
|
}
|
|
105
119
|
catch {
|
|
106
120
|
// Best-effort cleanup — don't let it break the status check
|
|
@@ -125,7 +139,6 @@ export async function getOrchestratorStatus() {
|
|
|
125
139
|
let childProcessAlive = false;
|
|
126
140
|
try {
|
|
127
141
|
const sessionBackend = getSessionBackendSync();
|
|
128
|
-
const sessionName = orchestratorStatus?.sessionName || CREWLY_CONSTANTS.SESSIONS.ORCHESTRATOR_NAME;
|
|
129
142
|
childProcessAlive = !!sessionBackend?.isChildProcessAlive?.(sessionName);
|
|
130
143
|
}
|
|
131
144
|
catch {
|
|
@@ -135,8 +148,7 @@ export async function getOrchestratorStatus() {
|
|
|
135
148
|
// Best-effort: persist the recovered status but return active regardless
|
|
136
149
|
try {
|
|
137
150
|
const storageServiceForRecovery = StorageService.getInstance();
|
|
138
|
-
|
|
139
|
-
await storageServiceForRecovery.updateAgentStatus(recoverySessionName, CREWLY_CONSTANTS.AGENT_STATUSES.ACTIVE);
|
|
151
|
+
await storageServiceForRecovery.updateAgentStatus(sessionName, CREWLY_CONSTANTS.AGENT_STATUSES.ACTIVE);
|
|
140
152
|
}
|
|
141
153
|
catch {
|
|
142
154
|
// Best-effort — don't let persist failure block recovery
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator-status.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/orchestrator-status.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"orchestrator-status.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/orchestrator-status.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -173,6 +173,29 @@ export declare class SlackOrchestratorBridge extends EventEmitter {
|
|
|
173
173
|
* @returns Control response
|
|
174
174
|
*/
|
|
175
175
|
private handleControlCommand;
|
|
176
|
+
/**
|
|
177
|
+
* Attempt to auto-recover the orchestrator with a hard timeout.
|
|
178
|
+
*
|
|
179
|
+
* Calls `triggerOrchestratorSetup()` from the orchestrator service module
|
|
180
|
+
* directly (bypassing HTTP). Wraps the attempt in a 5-second deadline so
|
|
181
|
+
* a wedged setup cannot stall the Slack message ingress thread.
|
|
182
|
+
*
|
|
183
|
+
* Behavior:
|
|
184
|
+
* - Timeout: rejects with a TimeoutError-like message after 5s.
|
|
185
|
+
* - Setup error: rejects with the underlying error.
|
|
186
|
+
* - Setup returning `success: false`: rejects with the recorded error
|
|
187
|
+
* (the caller treats this the same as a thrown error and falls
|
|
188
|
+
* through to the offline path).
|
|
189
|
+
*
|
|
190
|
+
* Caller is expected to wrap the call in try/catch and continue down
|
|
191
|
+
* the offline path on rejection — auto-recovery is best-effort.
|
|
192
|
+
*
|
|
193
|
+
* @returns Resolves when setup completes successfully (or was skipped
|
|
194
|
+
* because the orc was already healthy)
|
|
195
|
+
* @throws Error on timeout or setup failure
|
|
196
|
+
* @internal Visible for tests via class member access.
|
|
197
|
+
*/
|
|
198
|
+
private attemptAutoRecovery;
|
|
176
199
|
/**
|
|
177
200
|
* Send message to orchestrator via the message queue and wait for response.
|
|
178
201
|
*
|
|
@@ -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;
|
|
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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"}
|
|
@@ -15,7 +15,7 @@ import { pipeline } from 'stream/promises';
|
|
|
15
15
|
import { PDFParse } from 'pdf-parse';
|
|
16
16
|
import { getSlackService } from './slack.service.js';
|
|
17
17
|
import { getChatService } from '../chat/chat.service.js';
|
|
18
|
-
import { isOrchestratorActive, isAgentActive, getOrchestratorOfflineMessage, } from '../orchestrator/index.js';
|
|
18
|
+
import { isOrchestratorActive, isAgentActive, getOrchestratorOfflineMessage, triggerOrchestratorSetup, } from '../orchestrator/index.js';
|
|
19
19
|
import { parseCommandIntent, } from '../../types/slack.types.js';
|
|
20
20
|
import { ContentApprovalService } from '../onboarding/content-approval.service.js';
|
|
21
21
|
import { getSlackImageService } from './slack-image.service.js';
|
|
@@ -34,6 +34,12 @@ const DEFAULT_CONFIG = {
|
|
|
34
34
|
responseTimeoutMs: (MESSAGE_QUEUE_CONSTANTS?.DEFAULT_MESSAGE_TIMEOUT ?? 120000) + 5000,
|
|
35
35
|
skillDeliveryWaitMs: SLACK_BRIDGE_CONSTANTS?.SKILL_DELIVERY_WAIT_MS ?? 3000,
|
|
36
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Maximum time to wait for an auto-recovery setup attempt before giving
|
|
39
|
+
* up and falling through to the offline path. Capped tight to avoid
|
|
40
|
+
* blocking the message ingress thread when setup is wedged.
|
|
41
|
+
*/
|
|
42
|
+
const AUTO_RECOVERY_TIMEOUT_MS = 5_000;
|
|
37
43
|
/**
|
|
38
44
|
* Slack-Orchestrator Bridge singleton
|
|
39
45
|
*/
|
|
@@ -521,6 +527,49 @@ Just type naturally to chat with the orchestrator!`;
|
|
|
521
527
|
const target = command.parameters.target || command.parameters.mention || 'all agents';
|
|
522
528
|
return await this.sendToOrchestrator(`${action} ${target}.`, context);
|
|
523
529
|
}
|
|
530
|
+
/**
|
|
531
|
+
* Attempt to auto-recover the orchestrator with a hard timeout.
|
|
532
|
+
*
|
|
533
|
+
* Calls `triggerOrchestratorSetup()` from the orchestrator service module
|
|
534
|
+
* directly (bypassing HTTP). Wraps the attempt in a 5-second deadline so
|
|
535
|
+
* a wedged setup cannot stall the Slack message ingress thread.
|
|
536
|
+
*
|
|
537
|
+
* Behavior:
|
|
538
|
+
* - Timeout: rejects with a TimeoutError-like message after 5s.
|
|
539
|
+
* - Setup error: rejects with the underlying error.
|
|
540
|
+
* - Setup returning `success: false`: rejects with the recorded error
|
|
541
|
+
* (the caller treats this the same as a thrown error and falls
|
|
542
|
+
* through to the offline path).
|
|
543
|
+
*
|
|
544
|
+
* Caller is expected to wrap the call in try/catch and continue down
|
|
545
|
+
* the offline path on rejection — auto-recovery is best-effort.
|
|
546
|
+
*
|
|
547
|
+
* @returns Resolves when setup completes successfully (or was skipped
|
|
548
|
+
* because the orc was already healthy)
|
|
549
|
+
* @throws Error on timeout or setup failure
|
|
550
|
+
* @internal Visible for tests via class member access.
|
|
551
|
+
*/
|
|
552
|
+
async attemptAutoRecovery() {
|
|
553
|
+
let timeoutHandle;
|
|
554
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
555
|
+
timeoutHandle = setTimeout(() => {
|
|
556
|
+
reject(new Error(`auto-recovery setup timed out after ${AUTO_RECOVERY_TIMEOUT_MS}ms`));
|
|
557
|
+
}, AUTO_RECOVERY_TIMEOUT_MS);
|
|
558
|
+
// Don't keep the process alive just for this timer
|
|
559
|
+
timeoutHandle.unref?.();
|
|
560
|
+
});
|
|
561
|
+
try {
|
|
562
|
+
const result = await Promise.race([triggerOrchestratorSetup(), timeoutPromise]);
|
|
563
|
+
if (!result.success) {
|
|
564
|
+
throw new Error(result.error || 'orchestrator setup returned success=false');
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
finally {
|
|
568
|
+
if (timeoutHandle) {
|
|
569
|
+
clearTimeout(timeoutHandle);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
524
573
|
/**
|
|
525
574
|
* Send message to orchestrator via the message queue and wait for response.
|
|
526
575
|
*
|
|
@@ -534,7 +583,35 @@ Just type naturally to chat with the orchestrator!`;
|
|
|
534
583
|
async sendToOrchestrator(message, context) {
|
|
535
584
|
try {
|
|
536
585
|
// Check if orchestrator is active before attempting to send
|
|
537
|
-
|
|
586
|
+
let isActive = await isOrchestratorActive();
|
|
587
|
+
// Auto-recovery (B0 hot-fix, defense-in-depth):
|
|
588
|
+
// ESTestNode regression — `isActive` falsely reports offline when the
|
|
589
|
+
// orchestrator is an in-process Crewly Agent runtime that has lost its
|
|
590
|
+
// status registration but is otherwise healthy. Before falling
|
|
591
|
+
// through to the offline path, attempt one synchronous setup call.
|
|
592
|
+
// This is intentionally once-per-message (not retry-loop). On
|
|
593
|
+
// success we re-check isActive and proceed normally; on failure we
|
|
594
|
+
// continue down the existing offline branch (Auditor + queue).
|
|
595
|
+
if (!isActive) {
|
|
596
|
+
const recoveryStart = Date.now();
|
|
597
|
+
this.logger.info('Orchestrator offline — attempting auto-recovery via triggerOrchestratorSetup', {
|
|
598
|
+
timeoutMs: AUTO_RECOVERY_TIMEOUT_MS,
|
|
599
|
+
});
|
|
600
|
+
try {
|
|
601
|
+
await this.attemptAutoRecovery();
|
|
602
|
+
isActive = await isOrchestratorActive();
|
|
603
|
+
this.logger.info('Auto-recovery setup attempt complete', {
|
|
604
|
+
elapsedMs: Date.now() - recoveryStart,
|
|
605
|
+
isActiveAfter: isActive,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
catch (err) {
|
|
609
|
+
this.logger.warn('Auto-recovery setup attempt failed (falling through to offline path)', {
|
|
610
|
+
elapsedMs: Date.now() - recoveryStart,
|
|
611
|
+
error: err instanceof Error ? err.message : String(err),
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
538
615
|
if (!isActive) {
|
|
539
616
|
// Fallback: route to Auditor agent if it's active
|
|
540
617
|
const auditorSession = AUDITOR_SCHEDULER_CONSTANTS.AUDITOR_SESSION_NAME;
|