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.
- package/config/constants.ts +57 -0
- package/dist/backend/backend/src/constants.d.ts +39 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +22 -1
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +23 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/addon/addon-loader.service.d.ts +101 -0
- package/dist/backend/backend/src/services/addon/addon-loader.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/addon/addon-loader.service.js +253 -0
- package/dist/backend/backend/src/services/addon/addon-loader.service.js.map +1 -0
- package/dist/backend/backend/src/services/addon/addon.types.d.ts +62 -0
- package/dist/backend/backend/src/services/addon/addon.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/addon/addon.types.js +11 -0
- package/dist/backend/backend/src/services/addon/addon.types.js.map +1 -0
- package/dist/backend/backend/src/services/addon/index.d.ts +8 -0
- package/dist/backend/backend/src/services/addon/index.d.ts.map +1 -0
- package/dist/backend/backend/src/services/addon/index.js +7 -0
- package/dist/backend/backend/src/services/addon/index.js.map +1 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +2 -2
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +2 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +48 -31
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +16 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +67 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +34 -25
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +3 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +21 -6
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +2 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js +2 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +2 -2
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts +35 -0
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +156 -2
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/config/constants.d.ts +49 -0
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +50 -0
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +39 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +22 -1
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/cli/src/commands/upgrade.d.ts +20 -2
- package/dist/cli/cli/src/commands/upgrade.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/upgrade.js +84 -3
- package/dist/cli/cli/src/commands/upgrade.js.map +1 -1
- package/dist/cli/cli/src/index.js +3 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/config/constants.d.ts +49 -0
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +50 -0
- package/dist/cli/config/constants.js.map +1 -1
- package/frontend/dist/assets/{index-83869ca7.js → index-726a1859.js} +2 -2
- package/frontend/dist/index.html +1 -1
- 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 @@
|
|
|
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 @@
|
|
|
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:([^\]]+)
|
|
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.
|