crewly 1.4.5 → 1.4.8

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 (68) hide show
  1. package/config/constants.ts +57 -0
  2. package/dist/backend/backend/src/constants.d.ts +39 -0
  3. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  4. package/dist/backend/backend/src/constants.js +22 -1
  5. package/dist/backend/backend/src/constants.js.map +1 -1
  6. package/dist/backend/backend/src/index.d.ts.map +1 -1
  7. package/dist/backend/backend/src/index.js +23 -0
  8. package/dist/backend/backend/src/index.js.map +1 -1
  9. package/dist/backend/backend/src/services/addon/addon-loader.service.d.ts +101 -0
  10. package/dist/backend/backend/src/services/addon/addon-loader.service.d.ts.map +1 -0
  11. package/dist/backend/backend/src/services/addon/addon-loader.service.js +253 -0
  12. package/dist/backend/backend/src/services/addon/addon-loader.service.js.map +1 -0
  13. package/dist/backend/backend/src/services/addon/addon.types.d.ts +62 -0
  14. package/dist/backend/backend/src/services/addon/addon.types.d.ts.map +1 -0
  15. package/dist/backend/backend/src/services/addon/addon.types.js +11 -0
  16. package/dist/backend/backend/src/services/addon/addon.types.js.map +1 -0
  17. package/dist/backend/backend/src/services/addon/index.d.ts +8 -0
  18. package/dist/backend/backend/src/services/addon/index.d.ts.map +1 -0
  19. package/dist/backend/backend/src/services/addon/index.js +7 -0
  20. package/dist/backend/backend/src/services/addon/index.js.map +1 -0
  21. package/dist/backend/backend/src/services/agent/agent-registration.service.js +2 -2
  22. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  23. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +2 -0
  24. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
  25. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +48 -31
  26. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
  27. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +16 -0
  28. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +1 -1
  29. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +67 -2
  30. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +1 -1
  31. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +34 -25
  33. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
  34. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +3 -1
  35. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +1 -1
  36. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +21 -6
  37. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +1 -1
  38. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +2 -0
  39. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/agent/crewly-agent/types.js +2 -0
  41. package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
  42. package/dist/backend/backend/src/services/messaging/queue-processor.service.js +2 -2
  43. package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
  44. package/dist/backend/backend/src/services/slack/slack.service.d.ts +35 -0
  45. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/slack/slack.service.js +156 -2
  47. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  48. package/dist/backend/config/constants.d.ts +49 -0
  49. package/dist/backend/config/constants.d.ts.map +1 -1
  50. package/dist/backend/config/constants.js +50 -0
  51. package/dist/backend/config/constants.js.map +1 -1
  52. package/dist/cli/backend/src/constants.d.ts +39 -0
  53. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  54. package/dist/cli/backend/src/constants.js +22 -1
  55. package/dist/cli/backend/src/constants.js.map +1 -1
  56. package/dist/cli/cli/src/commands/upgrade.d.ts +20 -2
  57. package/dist/cli/cli/src/commands/upgrade.d.ts.map +1 -1
  58. package/dist/cli/cli/src/commands/upgrade.js +84 -3
  59. package/dist/cli/cli/src/commands/upgrade.js.map +1 -1
  60. package/dist/cli/cli/src/index.js +3 -0
  61. package/dist/cli/cli/src/index.js.map +1 -1
  62. package/dist/cli/config/constants.d.ts +49 -0
  63. package/dist/cli/config/constants.d.ts.map +1 -1
  64. package/dist/cli/config/constants.js +50 -0
  65. package/dist/cli/config/constants.js.map +1 -1
  66. package/frontend/dist/assets/{index-83869ca7.js → index-726a1859.js} +2 -2
  67. package/frontend/dist/index.html +1 -1
  68. package/package.json +1 -1
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Addon Loader Service
3
+ *
4
+ * Scans ~/.crewly/addons/ on server startup, loads each addon's
5
+ * manifest.json, dynamically imports its entrypoint, and calls
6
+ * addon.register(app, server) so addons can attach routes, WS
7
+ * servers, and middleware to the running Crewly instance.
8
+ *
9
+ * Singleton pattern matching other Crewly services.
10
+ *
11
+ * @module services/addon/addon-loader.service
12
+ */
13
+ import type { Application } from 'express';
14
+ import type { Server as HttpServer } from 'http';
15
+ import type { LoadedAddon } from './addon.types.js';
16
+ /**
17
+ * AddonLoaderService discovers and loads addons from the file system.
18
+ *
19
+ * On server startup, call `loadAddons(app, server)` to scan the
20
+ * addons directory and register all valid addons. On shutdown, call
21
+ * `unloadAddons()` to invoke each addon's cleanup hook.
22
+ */
23
+ export declare class AddonLoaderService {
24
+ private static instance;
25
+ /** Successfully loaded addons indexed by name */
26
+ private addons;
27
+ private logger;
28
+ private constructor();
29
+ /**
30
+ * Get the singleton instance.
31
+ *
32
+ * @returns The singleton AddonLoaderService instance
33
+ */
34
+ static getInstance(): AddonLoaderService;
35
+ /**
36
+ * Clear the singleton instance (for testing).
37
+ */
38
+ static clearInstance(): void;
39
+ /**
40
+ * Scan the addons directory and load all valid addons.
41
+ *
42
+ * Each addon directory must contain a manifest.json with name,
43
+ * version, and entrypoint fields. The entrypoint module must
44
+ * export a `register(app, server)` function.
45
+ *
46
+ * Errors in one addon do not prevent others from loading.
47
+ *
48
+ * @param app - The Express application instance
49
+ * @param server - The HTTP server instance
50
+ * @returns Array of successfully loaded addon names
51
+ */
52
+ loadAddons(app: Application, server: HttpServer): Promise<string[]>;
53
+ /**
54
+ * Unload all loaded addons, calling their unregister hooks.
55
+ * Called during server shutdown.
56
+ */
57
+ unloadAddons(): Promise<void>;
58
+ /**
59
+ * Get a loaded addon by name.
60
+ *
61
+ * @param name - The addon name from its manifest
62
+ * @returns The loaded addon record, or undefined
63
+ */
64
+ getAddon(name: string): LoadedAddon | undefined;
65
+ /**
66
+ * List all loaded addons.
67
+ *
68
+ * @returns Array of loaded addon records
69
+ */
70
+ listAddons(): LoadedAddon[];
71
+ /**
72
+ * Get the number of loaded addons.
73
+ *
74
+ * @returns Count of loaded addons
75
+ */
76
+ getAddonCount(): number;
77
+ /**
78
+ * Get the absolute path to the addons directory.
79
+ *
80
+ * @returns Path to ~/.crewly/addons/
81
+ */
82
+ getAddonsDir(): string;
83
+ /**
84
+ * Load a single addon from its directory.
85
+ *
86
+ * @param addonPath - Absolute path to the addon directory
87
+ * @param app - Express app
88
+ * @param server - HTTP server
89
+ * @throws If manifest is invalid or entrypoint fails to load
90
+ */
91
+ private loadSingleAddon;
92
+ /**
93
+ * Validate that a manifest has all required fields.
94
+ *
95
+ * @param manifest - The parsed manifest object
96
+ * @param manifestPath - Path to the manifest file (for error messages)
97
+ * @throws If any required field is missing or invalid
98
+ */
99
+ private validateManifest;
100
+ }
101
+ //# sourceMappingURL=addon-loader.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addon-loader.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/addon/addon-loader.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAA8B,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQhF;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmC;IAE1D,iDAAiD;IACjD,OAAO,CAAC,MAAM,CAAuC;IAErD,OAAO,CAAC,MAAM,CAAgB;IAE9B,OAAO;IAIP;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,kBAAkB;IAOxC;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;IAQ5B;;;;;;;;;;;;OAYG;IACG,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA4DzE;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI/C;;;;OAIG;IACH,UAAU,IAAI,WAAW,EAAE;IAI3B;;;;OAIG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;OAIG;IACH,YAAY,IAAI,MAAM;IAatB;;;;;;;OAOG;YACW,eAAe;IAkE7B;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;CAWxB"}
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Addon Loader Service
3
+ *
4
+ * Scans ~/.crewly/addons/ on server startup, loads each addon's
5
+ * manifest.json, dynamically imports its entrypoint, and calls
6
+ * addon.register(app, server) so addons can attach routes, WS
7
+ * servers, and middleware to the running Crewly instance.
8
+ *
9
+ * Singleton pattern matching other Crewly services.
10
+ *
11
+ * @module services/addon/addon-loader.service
12
+ */
13
+ import { promises as fs } from 'fs';
14
+ import path from 'path';
15
+ import os from 'os';
16
+ import { pathToFileURL } from 'url';
17
+ import { ADDON_CONSTANTS } from '../../constants.js';
18
+ import { LoggerService } from '../core/logger.service.js';
19
+ // =============================================================================
20
+ // Service
21
+ // =============================================================================
22
+ /**
23
+ * AddonLoaderService discovers and loads addons from the file system.
24
+ *
25
+ * On server startup, call `loadAddons(app, server)` to scan the
26
+ * addons directory and register all valid addons. On shutdown, call
27
+ * `unloadAddons()` to invoke each addon's cleanup hook.
28
+ */
29
+ export class AddonLoaderService {
30
+ static instance = null;
31
+ /** Successfully loaded addons indexed by name */
32
+ addons = new Map();
33
+ logger;
34
+ constructor() {
35
+ this.logger = LoggerService.getInstance();
36
+ }
37
+ /**
38
+ * Get the singleton instance.
39
+ *
40
+ * @returns The singleton AddonLoaderService instance
41
+ */
42
+ static getInstance() {
43
+ if (!AddonLoaderService.instance) {
44
+ AddonLoaderService.instance = new AddonLoaderService();
45
+ }
46
+ return AddonLoaderService.instance;
47
+ }
48
+ /**
49
+ * Clear the singleton instance (for testing).
50
+ */
51
+ static clearInstance() {
52
+ AddonLoaderService.instance = null;
53
+ }
54
+ // =========================================================================
55
+ // Public API
56
+ // =========================================================================
57
+ /**
58
+ * Scan the addons directory and load all valid addons.
59
+ *
60
+ * Each addon directory must contain a manifest.json with name,
61
+ * version, and entrypoint fields. The entrypoint module must
62
+ * export a `register(app, server)` function.
63
+ *
64
+ * Errors in one addon do not prevent others from loading.
65
+ *
66
+ * @param app - The Express application instance
67
+ * @param server - The HTTP server instance
68
+ * @returns Array of successfully loaded addon names
69
+ */
70
+ async loadAddons(app, server) {
71
+ const addonsDir = this.getAddonsDir();
72
+ // Ensure addons directory exists
73
+ try {
74
+ await fs.mkdir(addonsDir, { recursive: true });
75
+ }
76
+ catch {
77
+ // Directory likely already exists
78
+ }
79
+ // List subdirectories
80
+ let entries;
81
+ try {
82
+ const dirEntries = await fs.readdir(addonsDir, { withFileTypes: true });
83
+ entries = dirEntries
84
+ .filter(e => e.isDirectory())
85
+ .map(e => e.name);
86
+ }
87
+ catch (error) {
88
+ this.logger.warn('Failed to read addons directory', {
89
+ path: addonsDir,
90
+ error: error instanceof Error ? error.message : String(error),
91
+ });
92
+ return [];
93
+ }
94
+ if (entries.length === 0) {
95
+ this.logger.info('No addons found', { path: addonsDir });
96
+ return [];
97
+ }
98
+ this.logger.info('Discovered addon directories', {
99
+ count: entries.length,
100
+ names: entries,
101
+ });
102
+ const loaded = [];
103
+ for (const dirName of entries) {
104
+ const addonPath = path.join(addonsDir, dirName);
105
+ try {
106
+ await this.loadSingleAddon(addonPath, app, server);
107
+ loaded.push(dirName);
108
+ }
109
+ catch (error) {
110
+ this.logger.error('Failed to load addon', {
111
+ addon: dirName,
112
+ path: addonPath,
113
+ error: error instanceof Error ? error.message : String(error),
114
+ });
115
+ }
116
+ }
117
+ this.logger.info('Addon loading complete', {
118
+ loaded: loaded.length,
119
+ total: entries.length,
120
+ names: loaded,
121
+ });
122
+ return loaded;
123
+ }
124
+ /**
125
+ * Unload all loaded addons, calling their unregister hooks.
126
+ * Called during server shutdown.
127
+ */
128
+ async unloadAddons() {
129
+ for (const [name, addon] of this.addons) {
130
+ try {
131
+ if (addon.module.unregister) {
132
+ await addon.module.unregister();
133
+ }
134
+ this.logger.info('Unloaded addon', { addon: name });
135
+ }
136
+ catch (error) {
137
+ this.logger.error('Error unloading addon', {
138
+ addon: name,
139
+ error: error instanceof Error ? error.message : String(error),
140
+ });
141
+ }
142
+ }
143
+ this.addons.clear();
144
+ }
145
+ /**
146
+ * Get a loaded addon by name.
147
+ *
148
+ * @param name - The addon name from its manifest
149
+ * @returns The loaded addon record, or undefined
150
+ */
151
+ getAddon(name) {
152
+ return this.addons.get(name);
153
+ }
154
+ /**
155
+ * List all loaded addons.
156
+ *
157
+ * @returns Array of loaded addon records
158
+ */
159
+ listAddons() {
160
+ return Array.from(this.addons.values());
161
+ }
162
+ /**
163
+ * Get the number of loaded addons.
164
+ *
165
+ * @returns Count of loaded addons
166
+ */
167
+ getAddonCount() {
168
+ return this.addons.size;
169
+ }
170
+ /**
171
+ * Get the absolute path to the addons directory.
172
+ *
173
+ * @returns Path to ~/.crewly/addons/
174
+ */
175
+ getAddonsDir() {
176
+ return path.join(os.homedir(), ADDON_CONSTANTS.PATHS.ADDONS_DIR === 'addons'
177
+ ? `.crewly/${ADDON_CONSTANTS.PATHS.ADDONS_DIR}`
178
+ : ADDON_CONSTANTS.PATHS.ADDONS_DIR);
179
+ }
180
+ // =========================================================================
181
+ // Internal
182
+ // =========================================================================
183
+ /**
184
+ * Load a single addon from its directory.
185
+ *
186
+ * @param addonPath - Absolute path to the addon directory
187
+ * @param app - Express app
188
+ * @param server - HTTP server
189
+ * @throws If manifest is invalid or entrypoint fails to load
190
+ */
191
+ async loadSingleAddon(addonPath, app, server) {
192
+ // Read and validate manifest
193
+ const manifestPath = path.join(addonPath, ADDON_CONSTANTS.MANIFEST_FILE);
194
+ const manifestRaw = await fs.readFile(manifestPath, 'utf-8');
195
+ const manifest = JSON.parse(manifestRaw);
196
+ this.validateManifest(manifest, manifestPath);
197
+ // Resolve entrypoint path
198
+ const entrypointPath = path.join(addonPath, manifest.entrypoint);
199
+ // Verify entrypoint file exists
200
+ try {
201
+ await fs.access(entrypointPath);
202
+ }
203
+ catch {
204
+ throw new Error(`Addon entrypoint not found: ${entrypointPath} (from manifest.entrypoint: "${manifest.entrypoint}")`);
205
+ }
206
+ // Dynamic import — use file:// URL for ESM compatibility
207
+ const entrypointUrl = pathToFileURL(entrypointPath).href;
208
+ const mod = await import(entrypointUrl);
209
+ // Handle both default export and named export patterns
210
+ const addonModule = 'default' in mod && typeof mod.default?.register === 'function'
211
+ ? mod.default
212
+ : mod;
213
+ if (typeof addonModule.register !== 'function') {
214
+ throw new Error(`Addon "${manifest.name}" entrypoint does not export a register() function`);
215
+ }
216
+ // Call register with timeout
217
+ await Promise.race([
218
+ addonModule.register(app, server),
219
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Addon "${manifest.name}" register() timed out`)), ADDON_CONSTANTS.TIMEOUTS.LOAD_TIMEOUT_MS)),
220
+ ]);
221
+ // Store loaded addon
222
+ this.addons.set(manifest.name, {
223
+ manifest,
224
+ module: addonModule,
225
+ path: addonPath,
226
+ loadedAt: new Date(),
227
+ });
228
+ this.logger.info('Loaded addon', {
229
+ name: manifest.name,
230
+ version: manifest.version,
231
+ entrypoint: manifest.entrypoint,
232
+ });
233
+ }
234
+ /**
235
+ * Validate that a manifest has all required fields.
236
+ *
237
+ * @param manifest - The parsed manifest object
238
+ * @param manifestPath - Path to the manifest file (for error messages)
239
+ * @throws If any required field is missing or invalid
240
+ */
241
+ validateManifest(manifest, manifestPath) {
242
+ if (!manifest.name || typeof manifest.name !== 'string') {
243
+ throw new Error(`Invalid manifest at ${manifestPath}: missing or invalid "name" field`);
244
+ }
245
+ if (!manifest.version || typeof manifest.version !== 'string') {
246
+ throw new Error(`Invalid manifest at ${manifestPath}: missing or invalid "version" field`);
247
+ }
248
+ if (!manifest.entrypoint || typeof manifest.entrypoint !== 'string') {
249
+ throw new Error(`Invalid manifest at ${manifestPath}: missing or invalid "entrypoint" field`);
250
+ }
251
+ }
252
+ }
253
+ //# sourceMappingURL=addon-loader.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addon-loader.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/addon/addon-loader.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Addon System Types
3
+ *
4
+ * Defines the manifest format, addon interface, and registration
5
+ * contract for the Crewly addon/plugin system. Pro and third-party
6
+ * extensions implement these interfaces to hook into the server.
7
+ *
8
+ * @module services/addon/addon.types
9
+ */
10
+ import type { Application } from 'express';
11
+ import type { Server as HttpServer } from 'http';
12
+ /**
13
+ * Schema for an addon's manifest.json file.
14
+ * Every addon directory must contain a manifest.json matching this shape.
15
+ */
16
+ export interface AddonManifest {
17
+ /** Unique addon identifier (e.g. "crewly-pro") */
18
+ name: string;
19
+ /** Semver version string */
20
+ version: string;
21
+ /** Path to the compiled entrypoint relative to the addon directory */
22
+ entrypoint: string;
23
+ /** Human-readable description */
24
+ description?: string;
25
+ /** Author name or organization */
26
+ author?: string;
27
+ /** SPDX license identifier */
28
+ license?: string;
29
+ }
30
+ /**
31
+ * The export contract for an addon's entrypoint module.
32
+ * The addon loader calls `register()` on startup and optionally
33
+ * `unregister()` on shutdown.
34
+ */
35
+ export interface AddonModule {
36
+ /**
37
+ * Called during server startup to let the addon attach routes,
38
+ * WebSocket servers, middleware, or other functionality.
39
+ *
40
+ * @param app - The Express application instance
41
+ * @param server - The underlying HTTP server (for WS upgrades)
42
+ */
43
+ register(app: Application, server: HttpServer): void | Promise<void>;
44
+ /**
45
+ * Optional cleanup hook called during server shutdown.
46
+ */
47
+ unregister?(): void | Promise<void>;
48
+ }
49
+ /**
50
+ * Internal record of a successfully loaded addon.
51
+ */
52
+ export interface LoadedAddon {
53
+ /** Parsed manifest data */
54
+ manifest: AddonManifest;
55
+ /** The imported module */
56
+ module: AddonModule;
57
+ /** Absolute path to the addon directory */
58
+ path: string;
59
+ /** Timestamp when the addon was loaded */
60
+ loadedAt: Date;
61
+ }
62
+ //# sourceMappingURL=addon.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addon.types.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/addon/addon.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AAMjD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE;;OAEG;IACH,UAAU,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAMD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,2BAA2B;IAC3B,QAAQ,EAAE,aAAa,CAAC;IACxB,0BAA0B;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,QAAQ,EAAE,IAAI,CAAC;CACf"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Addon System Types
3
+ *
4
+ * Defines the manifest format, addon interface, and registration
5
+ * contract for the Crewly addon/plugin system. Pro and third-party
6
+ * extensions implement these interfaces to hook into the server.
7
+ *
8
+ * @module services/addon/addon.types
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=addon.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addon.types.js","sourceRoot":"","sources":["../../../../../../backend/src/services/addon/addon.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Addon service barrel exports
3
+ *
4
+ * @module services/addon
5
+ */
6
+ export { AddonLoaderService } from './addon-loader.service.js';
7
+ export type { AddonManifest, AddonModule, LoadedAddon } from './addon.types.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/addon/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Addon service barrel exports
3
+ *
4
+ * @module services/addon
5
+ */
6
+ export { AddonLoaderService } from './addon-loader.service.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../backend/src/services/addon/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -2007,8 +2007,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
2007
2007
  error: `Crewly Agent runtime for '${sessionName}' is not initialized`,
2008
2008
  };
2009
2009
  }
2010
- // Extract conversationId from [CHAT:xxx] prefix for response routing
2011
- const chatPrefixMatch = message.match(/^\[CHAT:([^\]]+)\]\s*/);
2010
+ // Extract conversationId from [CHAT:xxx] or [GCHAT:xxx ...] prefix for response routing
2011
+ const chatPrefixMatch = message.match(/^\[(?:G?CHAT):([^\]\s]+)[^\]]*\]\s*/);
2012
2012
  const incomingConversationId = chatPrefixMatch?.[1];
2013
2013
  // Extract Slack context from [SLACK:channelId:threadTs] marker if present (Bug 5).
2014
2014
  // This allows crewly-agent to auto-fill reply_slack with the correct thread.