crewly 1.6.3 → 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.
Files changed (27) hide show
  1. package/config/slack-app-manifest.json +1 -2
  2. package/dist/backend/backend/src/index.d.ts.map +1 -1
  3. package/dist/backend/backend/src/index.js +16 -0
  4. package/dist/backend/backend/src/index.js.map +1 -1
  5. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  6. package/dist/backend/backend/src/services/agent/agent-registration.service.js +30 -8
  7. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  8. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts +91 -0
  9. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts.map +1 -0
  10. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js +120 -0
  11. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js.map +1 -0
  12. package/dist/backend/backend/src/services/orchestrator/index.d.ts +1 -0
  13. package/dist/backend/backend/src/services/orchestrator/index.d.ts.map +1 -1
  14. package/dist/backend/backend/src/services/orchestrator/index.js +1 -0
  15. package/dist/backend/backend/src/services/orchestrator/index.js.map +1 -1
  16. package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.d.ts +114 -0
  17. package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.d.ts.map +1 -0
  18. package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.js +195 -0
  19. package/dist/backend/backend/src/services/orchestrator/orchestrator-setup.service.js.map +1 -0
  20. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -1
  21. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js +18 -6
  22. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -1
  23. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +23 -0
  24. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  25. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +79 -2
  26. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  27. package/package.json +1 -1
@@ -0,0 +1,91 @@
1
+ /**
2
+ * In-Process Runtime Registry
3
+ *
4
+ * Module-level registry that tracks active in-process Crewly Agent runtimes
5
+ * by session name. Provides a lightweight lookup mechanism for callers (such
6
+ * as `orchestrator-status.service.ts`) that need to determine whether an
7
+ * in-process runtime is alive without holding a reference to the
8
+ * `AgentRegistrationService` instance.
9
+ *
10
+ * Why this exists (B0 hot-fix):
11
+ * The PTY-based `sessionExists()` check returns `false` for in-process
12
+ * Crewly Agent runtimes because they have no PTY session. Before this
13
+ * registry, the orchestrator-status service had no runtime-aware fallback,
14
+ * so `isActive` would report `false` for healthy in-process orchestrators
15
+ * — causing SlackBridge to incorrectly route messages to the offline path.
16
+ *
17
+ * The `AgentRegistrationService` already maintains an internal
18
+ * `inProcessRuntimes` map for in-process runtime routing. This module
19
+ * mirrors that knowledge at module scope so any caller can probe runtime
20
+ * health without a service-locator dance.
21
+ *
22
+ * @module services/agent/crewly-agent/in-process-runtime-registry
23
+ */
24
+ import type { CrewlyAgentRuntimeService } from './crewly-agent-runtime.service.js';
25
+ /**
26
+ * Register an in-process Crewly Agent runtime.
27
+ *
28
+ * Called by `AgentRegistrationService` after `initializeInProcess()`
29
+ * succeeds. If a runtime is already registered for the same session, it is
30
+ * replaced — the old reference is discarded but not shut down (the caller
31
+ * is responsible for the lifecycle).
32
+ *
33
+ * @param sessionName - Session name owning the runtime (e.g. 'crewly-orc')
34
+ * @param runtime - The initialized CrewlyAgentRuntimeService instance
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * registerInProcessRuntime('crewly-orc', crewlyRuntime);
39
+ * ```
40
+ */
41
+ export declare function registerInProcessRuntime(sessionName: string, runtime: CrewlyAgentRuntimeService): void;
42
+ /**
43
+ * Unregister an in-process runtime by session name.
44
+ *
45
+ * Called when a runtime is shut down or the session is destroyed.
46
+ * Idempotent — safe to call when the session is not registered.
47
+ *
48
+ * @param sessionName - Session name to remove
49
+ * @returns True if a runtime was removed, false if none was registered
50
+ */
51
+ export declare function unregisterInProcessRuntime(sessionName: string): boolean;
52
+ /**
53
+ * Look up an in-process runtime by session name.
54
+ *
55
+ * @param sessionName - Session name to look up
56
+ * @returns The CrewlyAgentRuntimeService if registered, undefined otherwise
57
+ */
58
+ export declare function getInProcessRuntime(sessionName: string): CrewlyAgentRuntimeService | undefined;
59
+ /**
60
+ * Check whether an in-process runtime exists and is ready to handle
61
+ * messages for the given session.
62
+ *
63
+ * Returns `true` only when both:
64
+ * - A runtime is registered for the session
65
+ * - The runtime's `isReady()` returns `true`
66
+ *
67
+ * This is the function callers should use when answering "is this
68
+ * session alive?" — it correctly handles both the worker-process and
69
+ * direct in-process modes of `CrewlyAgentRuntimeService`.
70
+ *
71
+ * @param sessionName - Session name to check
72
+ * @returns True when the runtime exists and is ready
73
+ */
74
+ export declare function isInProcessRuntimeActive(sessionName: string): boolean;
75
+ /**
76
+ * Reset the registry. Test-only helper.
77
+ *
78
+ * Leaves any actually-running runtimes untouched — only clears the
79
+ * registry's bookkeeping. Production code must never call this.
80
+ *
81
+ * @internal
82
+ */
83
+ export declare function _resetInProcessRuntimeRegistryForTesting(): void;
84
+ /**
85
+ * Get the current registry size. Test-only helper.
86
+ *
87
+ * @returns Number of registered runtimes
88
+ * @internal
89
+ */
90
+ export declare function _getInProcessRuntimeRegistrySize(): number;
91
+ //# sourceMappingURL=in-process-runtime-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-process-runtime-registry.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/in-process-runtime-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAWnF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAEN;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAClB,yBAAyB,GAAG,SAAS,CAEvC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAWrE;AAED;;;;;;;GAOG;AACH,wBAAgB,wCAAwC,IAAI,IAAI,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,IAAI,MAAM,CAEzD"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * In-Process Runtime Registry
3
+ *
4
+ * Module-level registry that tracks active in-process Crewly Agent runtimes
5
+ * by session name. Provides a lightweight lookup mechanism for callers (such
6
+ * as `orchestrator-status.service.ts`) that need to determine whether an
7
+ * in-process runtime is alive without holding a reference to the
8
+ * `AgentRegistrationService` instance.
9
+ *
10
+ * Why this exists (B0 hot-fix):
11
+ * The PTY-based `sessionExists()` check returns `false` for in-process
12
+ * Crewly Agent runtimes because they have no PTY session. Before this
13
+ * registry, the orchestrator-status service had no runtime-aware fallback,
14
+ * so `isActive` would report `false` for healthy in-process orchestrators
15
+ * — causing SlackBridge to incorrectly route messages to the offline path.
16
+ *
17
+ * The `AgentRegistrationService` already maintains an internal
18
+ * `inProcessRuntimes` map for in-process runtime routing. This module
19
+ * mirrors that knowledge at module scope so any caller can probe runtime
20
+ * health without a service-locator dance.
21
+ *
22
+ * @module services/agent/crewly-agent/in-process-runtime-registry
23
+ */
24
+ /**
25
+ * Module-level registry of active in-process runtimes keyed by session name.
26
+ *
27
+ * Mirrors `AgentRegistrationService.inProcessRuntimes`. Both maps must stay
28
+ * in sync — `AgentRegistrationService` writes to this registry whenever it
29
+ * registers/unregisters a runtime.
30
+ */
31
+ const registry = new Map();
32
+ /**
33
+ * Register an in-process Crewly Agent runtime.
34
+ *
35
+ * Called by `AgentRegistrationService` after `initializeInProcess()`
36
+ * succeeds. If a runtime is already registered for the same session, it is
37
+ * replaced — the old reference is discarded but not shut down (the caller
38
+ * is responsible for the lifecycle).
39
+ *
40
+ * @param sessionName - Session name owning the runtime (e.g. 'crewly-orc')
41
+ * @param runtime - The initialized CrewlyAgentRuntimeService instance
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * registerInProcessRuntime('crewly-orc', crewlyRuntime);
46
+ * ```
47
+ */
48
+ export function registerInProcessRuntime(sessionName, runtime) {
49
+ registry.set(sessionName, runtime);
50
+ }
51
+ /**
52
+ * Unregister an in-process runtime by session name.
53
+ *
54
+ * Called when a runtime is shut down or the session is destroyed.
55
+ * Idempotent — safe to call when the session is not registered.
56
+ *
57
+ * @param sessionName - Session name to remove
58
+ * @returns True if a runtime was removed, false if none was registered
59
+ */
60
+ export function unregisterInProcessRuntime(sessionName) {
61
+ return registry.delete(sessionName);
62
+ }
63
+ /**
64
+ * Look up an in-process runtime by session name.
65
+ *
66
+ * @param sessionName - Session name to look up
67
+ * @returns The CrewlyAgentRuntimeService if registered, undefined otherwise
68
+ */
69
+ export function getInProcessRuntime(sessionName) {
70
+ return registry.get(sessionName);
71
+ }
72
+ /**
73
+ * Check whether an in-process runtime exists and is ready to handle
74
+ * messages for the given session.
75
+ *
76
+ * Returns `true` only when both:
77
+ * - A runtime is registered for the session
78
+ * - The runtime's `isReady()` returns `true`
79
+ *
80
+ * This is the function callers should use when answering "is this
81
+ * session alive?" — it correctly handles both the worker-process and
82
+ * direct in-process modes of `CrewlyAgentRuntimeService`.
83
+ *
84
+ * @param sessionName - Session name to check
85
+ * @returns True when the runtime exists and is ready
86
+ */
87
+ export function isInProcessRuntimeActive(sessionName) {
88
+ const runtime = registry.get(sessionName);
89
+ if (!runtime) {
90
+ return false;
91
+ }
92
+ try {
93
+ return runtime.isReady();
94
+ }
95
+ catch {
96
+ // Defensive: a misbehaving isReady() must not break callers.
97
+ return false;
98
+ }
99
+ }
100
+ /**
101
+ * Reset the registry. Test-only helper.
102
+ *
103
+ * Leaves any actually-running runtimes untouched — only clears the
104
+ * registry's bookkeeping. Production code must never call this.
105
+ *
106
+ * @internal
107
+ */
108
+ export function _resetInProcessRuntimeRegistryForTesting() {
109
+ registry.clear();
110
+ }
111
+ /**
112
+ * Get the current registry size. Test-only helper.
113
+ *
114
+ * @returns Number of registered runtimes
115
+ * @internal
116
+ */
117
+ export function _getInProcessRuntimeRegistrySize() {
118
+ return registry.size;
119
+ }
120
+ //# sourceMappingURL=in-process-runtime-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-process-runtime-registry.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/in-process-runtime-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH;;;;;;GAMG;AACH,MAAM,QAAQ,GAA2C,IAAI,GAAG,EAAE,CAAC;AAEnE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,OAAkC;IAElC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAmB;IAC5D,OAAO,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAmB;IAEnB,OAAO,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAAmB;IAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wCAAwC;IACtD,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gCAAgC;IAC9C,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}
@@ -12,4 +12,5 @@ export { ImprovementMarkerService, getImprovementMarkerService, resetImprovement
12
12
  export { ImprovementStartupService, getImprovementStartupService, resetImprovementStartupService, type StartupResult, } from './improvement-startup.service.js';
13
13
  export { isOrchestratorActive, isAgentActive, getOrchestratorStatus, getOrchestratorOfflineMessage, type OrchestratorStatusResult, } from './orchestrator-status.service.js';
14
14
  export { OrchestratorRestartService, type RestartStats, } from './orchestrator-restart.service.js';
15
+ export { triggerOrchestratorSetup, setOrchestratorSetupDependencies, type OrchestratorSetupResult, type AgentRegistrationServiceLike, } from './orchestrator-setup.service.js';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,EAC3B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACrB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,EAC7B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,8BAA8B,EAC9B,KAAK,aAAa,GACnB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,6BAA6B,EAC7B,KAAK,wBAAwB,GAC9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,0BAA0B,EAC1B,KAAK,YAAY,GAClB,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,EAC3B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACrB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,EAC7B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,8BAA8B,EAC9B,KAAK,aAAa,GACnB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,6BAA6B,EAC7B,KAAK,wBAAwB,GAC9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,0BAA0B,EAC1B,KAAK,YAAY,GAClB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,wBAAwB,EACxB,gCAAgC,EAChC,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,GAClC,MAAM,iCAAiC,CAAC"}
@@ -12,4 +12,5 @@ export { ImprovementMarkerService, getImprovementMarkerService, resetImprovement
12
12
  export { ImprovementStartupService, getImprovementStartupService, resetImprovementStartupService, } from './improvement-startup.service.js';
13
13
  export { isOrchestratorActive, isAgentActive, getOrchestratorStatus, getOrchestratorOfflineMessage, } from './orchestrator-status.service.js';
14
14
  export { OrchestratorRestartService, } from './orchestrator-restart.service.js';
15
+ export { triggerOrchestratorSetup, setOrchestratorSetupDependencies, } from './orchestrator-setup.service.js';
15
16
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,GAGxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,GAI5B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,GAK9B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,8BAA8B,GAE/B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,6BAA6B,GAE9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,0BAA0B,GAE3B,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orchestrator/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,GAGxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,GAI5B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,GAK9B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,8BAA8B,GAE/B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,6BAA6B,GAE9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,0BAA0B,GAE3B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,wBAAwB,EACxB,gCAAgC,GAGjC,MAAM,iCAAiC,CAAC"}
@@ -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;AASH;;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,CAyI/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"}
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
- const cleanupSessionName = orchestratorStatus?.sessionName || CREWLY_CONSTANTS.SESSIONS.ORCHESTRATOR_NAME;
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
- const recoverySessionName = orchestratorStatus?.sessionName || CREWLY_CONSTANTS.SESSIONS.ORCHESTRATOR_NAME;
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