devchain-cli 0.2.1 → 0.3.1
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/README.md +2 -0
- package/dist/cli.js +199 -42
- package/dist/drizzle/0018_whole_zodiak.sql +43 -0
- package/dist/drizzle/0019_flat_avengers.sql +3 -0
- package/dist/drizzle/0020_statuses_mcp_hidden.sql +1 -0
- package/dist/drizzle/meta/0018_snapshot.json +2920 -0
- package/dist/drizzle/meta/0019_snapshot.json +2943 -0
- package/dist/drizzle/meta/0020_snapshot.json +2951 -0
- package/dist/drizzle/meta/_journal.json +21 -0
- package/dist/server/app.module.js +11 -1
- package/dist/server/app.module.js.map +1 -1
- package/dist/server/common/config/env.config.d.ts +1 -0
- package/dist/server/common/config/env.config.js +4 -0
- package/dist/server/common/config/env.config.js.map +1 -1
- package/dist/server/common/filters/http-exception.filter.js +24 -1
- package/dist/server/common/filters/http-exception.filter.js.map +1 -1
- package/dist/server/common/logging/logger.js +4 -3
- package/dist/server/common/logging/logger.js.map +1 -1
- package/dist/server/main.js +0 -3
- package/dist/server/main.js.map +1 -1
- package/dist/server/modules/agents/agents.module.js +2 -1
- package/dist/server/modules/agents/agents.module.js.map +1 -1
- package/dist/server/modules/agents/controllers/agents.controller.d.ts +17 -2
- package/dist/server/modules/agents/controllers/agents.controller.js +84 -3
- package/dist/server/modules/agents/controllers/agents.controller.js.map +1 -1
- package/dist/server/modules/chat/dtos/chat.dto.d.ts +18 -18
- package/dist/server/modules/chat/services/invite-template.util.js +1 -1
- package/dist/server/modules/chat/services/invite-template.util.js.map +1 -1
- package/dist/server/modules/core/controllers/health.controller.d.ts +1 -0
- package/dist/server/modules/core/controllers/health.controller.js +23 -0
- package/dist/server/modules/core/controllers/health.controller.js.map +1 -1
- package/dist/server/modules/events/catalog/index.d.ts +40 -0
- package/dist/server/modules/events/catalog/index.js +2 -0
- package/dist/server/modules/events/catalog/index.js.map +1 -1
- package/dist/server/modules/events/catalog/terminal.watcher.triggered.d.ts +45 -0
- package/dist/server/modules/events/catalog/terminal.watcher.triggered.js +22 -0
- package/dist/server/modules/events/catalog/terminal.watcher.triggered.js.map +1 -0
- package/dist/server/modules/events/subscribers/chat-message-delivery.subscriber.d.ts +1 -0
- package/dist/server/modules/events/subscribers/chat-message-delivery.subscriber.js +30 -12
- package/dist/server/modules/events/subscribers/chat-message-delivery.subscriber.js.map +1 -1
- package/dist/server/modules/mcp/constants.js +5 -1
- package/dist/server/modules/mcp/constants.js.map +1 -1
- package/dist/server/modules/mcp/controllers/mcp-http.controller.js +78 -77
- package/dist/server/modules/mcp/controllers/mcp-http.controller.js.map +1 -1
- package/dist/server/modules/mcp/controllers/mcp-sdk.controller.js +78 -77
- package/dist/server/modules/mcp/controllers/mcp-sdk.controller.js.map +1 -1
- package/dist/server/modules/mcp/dtos/mcp.dto.d.ts +125 -97
- package/dist/server/modules/mcp/dtos/mcp.dto.js +23 -26
- package/dist/server/modules/mcp/dtos/mcp.dto.js.map +1 -1
- package/dist/server/modules/mcp/services/instructions-resolver.d.ts +3 -0
- package/dist/server/modules/mcp/services/instructions-resolver.js +83 -2
- package/dist/server/modules/mcp/services/instructions-resolver.js.map +1 -1
- package/dist/server/modules/mcp/services/mcp.service.d.ts +3 -2
- package/dist/server/modules/mcp/services/mcp.service.js +549 -263
- package/dist/server/modules/mcp/services/mcp.service.js.map +1 -1
- package/dist/server/modules/projects/controllers/projects.controller.d.ts +42 -0
- package/dist/server/modules/projects/controllers/projects.controller.js +11 -0
- package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
- package/dist/server/modules/projects/projects.module.js +2 -1
- package/dist/server/modules/projects/projects.module.js.map +1 -1
- package/dist/server/modules/projects/services/projects.service.d.ts +47 -1
- package/dist/server/modules/projects/services/projects.service.js +278 -22
- package/dist/server/modules/projects/services/projects.service.js.map +1 -1
- package/dist/server/modules/prompts/controllers/prompts.controller.d.ts +1 -1
- package/dist/server/modules/prompts/controllers/prompts.controller.js +26 -4
- package/dist/server/modules/prompts/controllers/prompts.controller.js.map +1 -1
- package/dist/server/modules/sessions/utils/template-renderer.js +1 -0
- package/dist/server/modules/sessions/utils/template-renderer.js.map +1 -1
- package/dist/server/modules/statuses/controllers/statuses.controller.js +2 -0
- package/dist/server/modules/statuses/controllers/statuses.controller.js.map +1 -1
- package/dist/server/modules/storage/db/schema.d.ts +613 -0
- package/dist/server/modules/storage/db/schema.js +50 -1
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +40 -2
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/local-storage.service.d.ts +18 -3
- package/dist/server/modules/storage/local/local-storage.service.js +407 -11
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +59 -1
- package/dist/server/modules/subscribers/actions/action.interface.d.ts +67 -0
- package/dist/server/modules/subscribers/actions/action.interface.js +3 -0
- package/dist/server/modules/subscribers/actions/action.interface.js.map +1 -0
- package/dist/server/modules/subscribers/actions/actions.registry.d.ts +7 -0
- package/dist/server/modules/subscribers/actions/actions.registry.js +37 -0
- package/dist/server/modules/subscribers/actions/actions.registry.js.map +1 -0
- package/dist/server/modules/subscribers/actions/restart-agent.action.d.ts +8 -0
- package/dist/server/modules/subscribers/actions/restart-agent.action.js +119 -0
- package/dist/server/modules/subscribers/actions/restart-agent.action.js.map +1 -0
- package/dist/server/modules/subscribers/actions/send-message.action.d.ts +2 -0
- package/dist/server/modules/subscribers/actions/send-message.action.js +83 -0
- package/dist/server/modules/subscribers/actions/send-message.action.js.map +1 -0
- package/dist/server/modules/subscribers/controllers/actions.controller.d.ts +6 -0
- package/dist/server/modules/subscribers/controllers/actions.controller.js +51 -0
- package/dist/server/modules/subscribers/controllers/actions.controller.js.map +1 -0
- package/dist/server/modules/subscribers/controllers/subscribers.controller.d.ts +17 -0
- package/dist/server/modules/subscribers/controllers/subscribers.controller.js +178 -0
- package/dist/server/modules/subscribers/controllers/subscribers.controller.js.map +1 -0
- package/dist/server/modules/subscribers/dtos/subscriber.dto.d.ts +251 -0
- package/dist/server/modules/subscribers/dtos/subscriber.dto.js +68 -0
- package/dist/server/modules/subscribers/dtos/subscriber.dto.js.map +1 -0
- package/dist/server/modules/subscribers/events/event-fields-catalog.d.ts +19 -0
- package/dist/server/modules/subscribers/events/event-fields-catalog.js +98 -0
- package/dist/server/modules/subscribers/events/event-fields-catalog.js.map +1 -0
- package/dist/server/modules/subscribers/services/automation-scheduler.service.d.ts +49 -0
- package/dist/server/modules/subscribers/services/automation-scheduler.service.js +300 -0
- package/dist/server/modules/subscribers/services/automation-scheduler.service.js.map +1 -0
- package/dist/server/modules/subscribers/services/subscriber-executor.service.d.ts +77 -0
- package/dist/server/modules/subscribers/services/subscriber-executor.service.js +576 -0
- package/dist/server/modules/subscribers/services/subscriber-executor.service.js.map +1 -0
- package/dist/server/modules/subscribers/services/subscribers.service.d.ts +14 -0
- package/dist/server/modules/subscribers/services/subscribers.service.js +70 -0
- package/dist/server/modules/subscribers/services/subscribers.service.js.map +1 -0
- package/dist/server/modules/subscribers/subscribers.module.d.ts +2 -0
- package/dist/server/modules/subscribers/subscribers.module.js +36 -0
- package/dist/server/modules/subscribers/subscribers.module.js.map +1 -0
- package/dist/server/modules/terminal/services/tmux.service.js +9 -6
- package/dist/server/modules/terminal/services/tmux.service.js.map +1 -1
- package/dist/server/modules/watchers/controllers/watchers.controller.d.ts +16 -0
- package/dist/server/modules/watchers/controllers/watchers.controller.js +180 -0
- package/dist/server/modules/watchers/controllers/watchers.controller.js.map +1 -0
- package/dist/server/modules/watchers/dtos/watcher.dto.d.ts +206 -0
- package/dist/server/modules/watchers/dtos/watcher.dto.js +54 -0
- package/dist/server/modules/watchers/dtos/watcher.dto.js.map +1 -0
- package/dist/server/modules/watchers/services/watcher-runner.service.d.ts +68 -0
- package/dist/server/modules/watchers/services/watcher-runner.service.js +477 -0
- package/dist/server/modules/watchers/services/watcher-runner.service.js.map +1 -0
- package/dist/server/modules/watchers/services/watchers.service.d.ts +29 -0
- package/dist/server/modules/watchers/services/watchers.service.js +98 -0
- package/dist/server/modules/watchers/services/watchers.service.js.map +1 -0
- package/dist/server/modules/watchers/watchers.module.d.ts +2 -0
- package/dist/server/modules/watchers/watchers.module.js +34 -0
- package/dist/server/modules/watchers/watchers.module.js.map +1 -0
- package/dist/server/templates/claude-codex-advanced.json +377 -0
- package/dist/server/templates/claude-opus.json +29 -25
- package/dist/server/templates/simple-codex.json +29 -25
- package/dist/server/test-setup-node.d.ts +1 -0
- package/dist/server/test-setup-node.js +8 -0
- package/dist/server/test-setup-node.js.map +1 -0
- package/dist/server/test-setup.js +2 -0
- package/dist/server/test-setup.js.map +1 -1
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/index-C9GXCjnF.js +700 -0
- package/dist/server/ui/assets/index-o0FbZg-1.css +32 -0
- package/dist/server/ui/index.html +2 -2
- package/dist/templates/claude-codex-advanced.json +377 -0
- package/dist/templates/claude-opus.json +29 -25
- package/dist/templates/simple-codex.json +29 -25
- package/package.json +58 -27
- package/dist/server/templates/codex-claude.json +0 -178
- package/dist/server/ui/assets/index-5Xb7jFMJ.js +0 -641
- package/dist/server/ui/assets/index-CbYIbCQV.css +0 -32
- package/dist/templates/codex-claude.json +0 -178
|
@@ -17,6 +17,8 @@ const common_1 = require("@nestjs/common");
|
|
|
17
17
|
const storage_interface_1 = require("../../storage/interfaces/storage.interface");
|
|
18
18
|
const sessions_service_1 = require("../../sessions/services/sessions.service");
|
|
19
19
|
const settings_service_1 = require("../../settings/services/settings.service");
|
|
20
|
+
const watchers_service_1 = require("../../watchers/services/watchers.service");
|
|
21
|
+
const watcher_runner_service_1 = require("../../watchers/services/watcher-runner.service");
|
|
20
22
|
const logger_1 = require("../../../common/logging/logger");
|
|
21
23
|
const error_types_1 = require("../../../common/errors/error-types");
|
|
22
24
|
const path_1 = require("path");
|
|
@@ -65,6 +67,7 @@ const ExportSchema = zod_1.z
|
|
|
65
67
|
label: zod_1.z.string().min(1),
|
|
66
68
|
color: zod_1.z.string().min(1),
|
|
67
69
|
position: zod_1.z.number().int(),
|
|
70
|
+
mcpHidden: zod_1.z.boolean().optional().default(false),
|
|
68
71
|
}))
|
|
69
72
|
.optional()
|
|
70
73
|
.default([]),
|
|
@@ -79,13 +82,66 @@ const ExportSchema = zod_1.z
|
|
|
79
82
|
epicAssignedTemplate: zod_1.z.string().optional(),
|
|
80
83
|
})
|
|
81
84
|
.optional(),
|
|
85
|
+
watchers: zod_1.z
|
|
86
|
+
.array(zod_1.z.object({
|
|
87
|
+
id: zod_1.z.string().uuid().optional(),
|
|
88
|
+
name: zod_1.z.string().min(1),
|
|
89
|
+
description: zod_1.z.string().nullable().optional(),
|
|
90
|
+
enabled: zod_1.z.boolean(),
|
|
91
|
+
scope: zod_1.z.enum(['all', 'agent', 'profile', 'provider']),
|
|
92
|
+
scopeFilterName: zod_1.z.string().nullable().optional(),
|
|
93
|
+
pollIntervalMs: zod_1.z.number().int(),
|
|
94
|
+
viewportLines: zod_1.z.number().int(),
|
|
95
|
+
condition: zod_1.z.object({
|
|
96
|
+
type: zod_1.z.enum(['contains', 'regex', 'not_contains']),
|
|
97
|
+
pattern: zod_1.z.string(),
|
|
98
|
+
flags: zod_1.z.string().optional(),
|
|
99
|
+
}),
|
|
100
|
+
cooldownMs: zod_1.z.number().int(),
|
|
101
|
+
cooldownMode: zod_1.z.enum(['time', 'until_clear']),
|
|
102
|
+
eventName: zod_1.z.string(),
|
|
103
|
+
}))
|
|
104
|
+
.optional()
|
|
105
|
+
.default([]),
|
|
106
|
+
subscribers: zod_1.z
|
|
107
|
+
.array(zod_1.z.object({
|
|
108
|
+
id: zod_1.z.string().uuid().optional(),
|
|
109
|
+
name: zod_1.z.string().min(1),
|
|
110
|
+
description: zod_1.z.string().nullable().optional(),
|
|
111
|
+
enabled: zod_1.z.boolean(),
|
|
112
|
+
eventName: zod_1.z.string(),
|
|
113
|
+
eventFilter: zod_1.z
|
|
114
|
+
.object({
|
|
115
|
+
field: zod_1.z.string(),
|
|
116
|
+
operator: zod_1.z.enum(['equals', 'contains', 'regex']),
|
|
117
|
+
value: zod_1.z.string(),
|
|
118
|
+
})
|
|
119
|
+
.nullable()
|
|
120
|
+
.optional(),
|
|
121
|
+
actionType: zod_1.z.string(),
|
|
122
|
+
actionInputs: zod_1.z.record(zod_1.z.string(), zod_1.z.object({
|
|
123
|
+
source: zod_1.z.enum(['event_field', 'custom']),
|
|
124
|
+
eventField: zod_1.z.string().optional(),
|
|
125
|
+
customValue: zod_1.z.string().optional(),
|
|
126
|
+
})),
|
|
127
|
+
delayMs: zod_1.z.number().int(),
|
|
128
|
+
cooldownMs: zod_1.z.number().int(),
|
|
129
|
+
retryOnError: zod_1.z.boolean(),
|
|
130
|
+
groupName: zod_1.z.string().nullable().optional(),
|
|
131
|
+
position: zod_1.z.number().int().optional().default(0),
|
|
132
|
+
priority: zod_1.z.number().int().optional().default(0),
|
|
133
|
+
}))
|
|
134
|
+
.optional()
|
|
135
|
+
.default([]),
|
|
82
136
|
})
|
|
83
137
|
.strict();
|
|
84
138
|
let ProjectsService = class ProjectsService {
|
|
85
|
-
constructor(storage, sessions, settings) {
|
|
139
|
+
constructor(storage, sessions, settings, watchersService, watcherRunner) {
|
|
86
140
|
this.storage = storage;
|
|
87
141
|
this.sessions = sessions;
|
|
88
142
|
this.settings = settings;
|
|
143
|
+
this.watchersService = watchersService;
|
|
144
|
+
this.watcherRunner = watcherRunner;
|
|
89
145
|
}
|
|
90
146
|
findTemplatesDirectory() {
|
|
91
147
|
const env = (0, env_config_1.getEnvConfig)();
|
|
@@ -97,11 +153,8 @@ let ProjectsService = class ProjectsService {
|
|
|
97
153
|
logger.warn({ path: env.TEMPLATES_DIR }, 'TEMPLATES_DIR set but path does not exist');
|
|
98
154
|
}
|
|
99
155
|
const possibleTemplatePaths = [
|
|
100
|
-
(0, path_1.join)(__dirname, '
|
|
101
|
-
(0, path_1.join)(__dirname, '../../../../templates'),
|
|
102
|
-
(0, path_1.join)(process.cwd(), 'dist', 'templates'),
|
|
156
|
+
(0, path_1.join)(__dirname, '..', '..', '..', '..', 'templates'),
|
|
103
157
|
(0, path_1.join)(process.cwd(), 'apps', 'local-app', 'templates'),
|
|
104
|
-
(0, path_1.join)(process.cwd(), 'templates'),
|
|
105
158
|
];
|
|
106
159
|
for (const path of possibleTemplatePaths) {
|
|
107
160
|
if ((0, fs_1.existsSync)(path)) {
|
|
@@ -139,6 +192,40 @@ let ProjectsService = class ProjectsService {
|
|
|
139
192
|
});
|
|
140
193
|
}
|
|
141
194
|
}
|
|
195
|
+
async getTemplateContent(templateId) {
|
|
196
|
+
logger.info({ templateId }, 'getTemplateContent');
|
|
197
|
+
const templatesDir = this.findTemplatesDirectory();
|
|
198
|
+
if (!templatesDir) {
|
|
199
|
+
throw new common_1.InternalServerErrorException({
|
|
200
|
+
message: 'Templates directory not found',
|
|
201
|
+
hint: 'Templates directory is not available in this deployment',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const TEMPLATE_ID_REGEX = /^[a-zA-Z0-9_-]+$/;
|
|
205
|
+
if (!TEMPLATE_ID_REGEX.test(templateId)) {
|
|
206
|
+
throw new error_types_1.ValidationError('Invalid template ID: must contain only alphanumeric characters, hyphens, and underscores', { templateId });
|
|
207
|
+
}
|
|
208
|
+
const resolvedTemplatesDir = (0, path_1.resolve)(templatesDir);
|
|
209
|
+
const templatePath = (0, path_1.resolve)(templatesDir, `${templateId}.json`);
|
|
210
|
+
if (!templatePath.startsWith(resolvedTemplatesDir + path_1.sep)) {
|
|
211
|
+
logger.warn({ templateId, templatePath, templatesDir: resolvedTemplatesDir }, 'Path traversal attempt detected');
|
|
212
|
+
throw new error_types_1.ValidationError('Invalid template ID: path traversal not allowed', { templateId });
|
|
213
|
+
}
|
|
214
|
+
if (!(0, fs_1.existsSync)(templatePath)) {
|
|
215
|
+
throw new error_types_1.NotFoundError('Template', templateId);
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const content = (0, fs_1.readFileSync)(templatePath, 'utf-8');
|
|
219
|
+
return JSON.parse(content);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
logger.error({ error, templatePath }, 'Failed to read template file');
|
|
223
|
+
throw new common_1.InternalServerErrorException({
|
|
224
|
+
message: 'Failed to read template file',
|
|
225
|
+
hint: 'Template file exists but cannot be read or parsed',
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
142
229
|
async createFromTemplate(input) {
|
|
143
230
|
logger.info({ input }, 'createFromTemplate');
|
|
144
231
|
const templatesDir = this.findTemplatesDirectory();
|
|
@@ -245,6 +332,7 @@ let ProjectsService = class ProjectsService {
|
|
|
245
332
|
label: s.label,
|
|
246
333
|
color: s.color,
|
|
247
334
|
position: s.position,
|
|
335
|
+
mcpHidden: s.mcpHidden,
|
|
248
336
|
})),
|
|
249
337
|
initialPrompt: payload.initialPrompt,
|
|
250
338
|
};
|
|
@@ -300,9 +388,11 @@ let ProjectsService = class ProjectsService {
|
|
|
300
388
|
})
|
|
301
389
|
.filter((id) => !!id);
|
|
302
390
|
if (autoCleanStatusIds.length > 0) {
|
|
391
|
+
const currentSettings = this.settings.getSettings();
|
|
392
|
+
const existingAutoClean = currentSettings.autoClean?.statusIds ?? {};
|
|
303
393
|
await this.settings.updateSettings({
|
|
304
394
|
autoClean: {
|
|
305
|
-
statusIds: { [result.project.id]: autoCleanStatusIds },
|
|
395
|
+
statusIds: { ...existingAutoClean, [result.project.id]: autoCleanStatusIds },
|
|
306
396
|
},
|
|
307
397
|
});
|
|
308
398
|
logger.info({ projectId: result.project.id, autoCleanStatusIds }, 'Applied autoClean statuses from projectSettings');
|
|
@@ -313,9 +403,11 @@ let ProjectsService = class ProjectsService {
|
|
|
313
403
|
if (archiveTemplateStatus?.id) {
|
|
314
404
|
const archiveNewId = result.mappings.statusIdMap[archiveTemplateStatus.id];
|
|
315
405
|
if (archiveNewId) {
|
|
406
|
+
const currentSettings = this.settings.getSettings();
|
|
407
|
+
const existingAutoClean = currentSettings.autoClean?.statusIds ?? {};
|
|
316
408
|
await this.settings.updateSettings({
|
|
317
409
|
autoClean: {
|
|
318
|
-
statusIds: { [result.project.id]: [archiveNewId] },
|
|
410
|
+
statusIds: { ...existingAutoClean, [result.project.id]: [archiveNewId] },
|
|
319
411
|
},
|
|
320
412
|
});
|
|
321
413
|
logger.info({ projectId: result.project.id, archiveStatusId: archiveNewId }, 'Auto-configured Archive status for auto-clean (fallback)');
|
|
@@ -336,9 +428,11 @@ let ProjectsService = class ProjectsService {
|
|
|
336
428
|
if (archiveTemplateStatus?.id) {
|
|
337
429
|
const archiveNewId = result.mappings.statusIdMap[archiveTemplateStatus.id];
|
|
338
430
|
if (archiveNewId) {
|
|
431
|
+
const currentSettings = this.settings.getSettings();
|
|
432
|
+
const existingAutoClean = currentSettings.autoClean?.statusIds ?? {};
|
|
339
433
|
await this.settings.updateSettings({
|
|
340
434
|
autoClean: {
|
|
341
|
-
statusIds: { [result.project.id]: [archiveNewId] },
|
|
435
|
+
statusIds: { ...existingAutoClean, [result.project.id]: [archiveNewId] },
|
|
342
436
|
},
|
|
343
437
|
});
|
|
344
438
|
logger.info({ projectId: result.project.id, archiveStatusId: archiveNewId }, 'Auto-configured Archive status for auto-clean');
|
|
@@ -356,13 +450,15 @@ let ProjectsService = class ProjectsService {
|
|
|
356
450
|
}
|
|
357
451
|
async exportProject(projectId) {
|
|
358
452
|
logger.info({ projectId }, 'exportProject');
|
|
359
|
-
const [promptsRes, profilesRes, agentsRes, statusesRes, initialPrompt, settings] = await Promise.all([
|
|
360
|
-
this.storage.listPrompts(projectId,
|
|
453
|
+
const [promptsRes, profilesRes, agentsRes, statusesRes, initialPrompt, settings, watchersRes, subscribersRes,] = await Promise.all([
|
|
454
|
+
this.storage.listPrompts({ projectId, limit: 1000, offset: 0 }),
|
|
361
455
|
this.storage.listAgentProfiles({ projectId, limit: 1000, offset: 0 }),
|
|
362
456
|
this.storage.listAgents(projectId, { limit: 1000, offset: 0 }),
|
|
363
457
|
this.storage.listStatuses(projectId, { limit: 1000, offset: 0 }),
|
|
364
458
|
this.storage.getInitialSessionPrompt(projectId),
|
|
365
459
|
Promise.resolve(this.settings.getSettings()),
|
|
460
|
+
this.storage.listWatchers(projectId),
|
|
461
|
+
this.storage.listSubscribers(projectId),
|
|
366
462
|
]);
|
|
367
463
|
const secretKeys = new Set([
|
|
368
464
|
'apikey',
|
|
@@ -410,7 +506,8 @@ let ProjectsService = class ProjectsService {
|
|
|
410
506
|
return null;
|
|
411
507
|
return options;
|
|
412
508
|
};
|
|
413
|
-
const
|
|
509
|
+
const fullPrompts = await Promise.all(promptsRes.items.map((p) => this.storage.getPrompt(p.id)));
|
|
510
|
+
const prompts = fullPrompts.map((p) => ({
|
|
414
511
|
id: p.id,
|
|
415
512
|
title: p.title,
|
|
416
513
|
content: p.content,
|
|
@@ -440,6 +537,7 @@ let ProjectsService = class ProjectsService {
|
|
|
440
537
|
label: s.label,
|
|
441
538
|
color: s.color,
|
|
442
539
|
position: s.position,
|
|
540
|
+
mcpHidden: s.mcpHidden,
|
|
443
541
|
}));
|
|
444
542
|
const projectSettings = {};
|
|
445
543
|
if (initialPrompt?.title) {
|
|
@@ -459,6 +557,63 @@ let ProjectsService = class ProjectsService {
|
|
|
459
557
|
if (epicAssignedTemplate) {
|
|
460
558
|
projectSettings.epicAssignedTemplate = epicAssignedTemplate;
|
|
461
559
|
}
|
|
560
|
+
const watchers = await Promise.all(watchersRes.map(async (w) => {
|
|
561
|
+
let scopeFilterName = null;
|
|
562
|
+
if (w.scopeFilterId) {
|
|
563
|
+
switch (w.scope) {
|
|
564
|
+
case 'agent': {
|
|
565
|
+
const agent = agentsRes.items.find((a) => a.id === w.scopeFilterId);
|
|
566
|
+
scopeFilterName = agent?.name ?? null;
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
case 'profile': {
|
|
570
|
+
const profile = profilesRes.items.find((p) => p.id === w.scopeFilterId);
|
|
571
|
+
scopeFilterName = profile?.name ?? null;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
case 'provider': {
|
|
575
|
+
try {
|
|
576
|
+
const provider = await this.storage.getProvider(w.scopeFilterId);
|
|
577
|
+
scopeFilterName = provider?.name ?? null;
|
|
578
|
+
}
|
|
579
|
+
catch {
|
|
580
|
+
scopeFilterName = null;
|
|
581
|
+
}
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
id: w.id,
|
|
588
|
+
name: w.name,
|
|
589
|
+
description: w.description,
|
|
590
|
+
enabled: w.enabled,
|
|
591
|
+
scope: w.scope,
|
|
592
|
+
scopeFilterName,
|
|
593
|
+
pollIntervalMs: w.pollIntervalMs,
|
|
594
|
+
viewportLines: w.viewportLines,
|
|
595
|
+
condition: w.condition,
|
|
596
|
+
cooldownMs: w.cooldownMs,
|
|
597
|
+
cooldownMode: w.cooldownMode,
|
|
598
|
+
eventName: w.eventName,
|
|
599
|
+
};
|
|
600
|
+
}));
|
|
601
|
+
const subscribers = subscribersRes.map((s) => ({
|
|
602
|
+
id: s.id,
|
|
603
|
+
name: s.name,
|
|
604
|
+
description: s.description,
|
|
605
|
+
enabled: s.enabled,
|
|
606
|
+
eventName: s.eventName,
|
|
607
|
+
eventFilter: s.eventFilter,
|
|
608
|
+
actionType: s.actionType,
|
|
609
|
+
actionInputs: s.actionInputs,
|
|
610
|
+
delayMs: s.delayMs,
|
|
611
|
+
cooldownMs: s.cooldownMs,
|
|
612
|
+
retryOnError: s.retryOnError,
|
|
613
|
+
groupName: s.groupName,
|
|
614
|
+
position: s.position,
|
|
615
|
+
priority: s.priority,
|
|
616
|
+
}));
|
|
462
617
|
const exportPayload = {
|
|
463
618
|
version: 1,
|
|
464
619
|
exportedAt: new Date().toISOString(),
|
|
@@ -470,6 +625,8 @@ let ProjectsService = class ProjectsService {
|
|
|
470
625
|
? { promptId: initialPrompt.id, title: initialPrompt.title }
|
|
471
626
|
: null,
|
|
472
627
|
...(Object.keys(projectSettings).length > 0 && { projectSettings }),
|
|
628
|
+
watchers,
|
|
629
|
+
subscribers,
|
|
473
630
|
};
|
|
474
631
|
return exportPayload;
|
|
475
632
|
}
|
|
@@ -484,11 +641,13 @@ let ProjectsService = class ProjectsService {
|
|
|
484
641
|
available.set(prov.name.trim().toLowerCase(), prov.id);
|
|
485
642
|
}
|
|
486
643
|
const missingProviders = Array.from(providerNames).filter((n) => !available.has(n));
|
|
487
|
-
const [existingPrompts, existingProfiles, existingAgents, existingStatuses] = await Promise.all([
|
|
488
|
-
this.storage.listPrompts(input.projectId,
|
|
644
|
+
const [existingPrompts, existingProfiles, existingAgents, existingStatuses, existingWatchers, existingSubscribers,] = await Promise.all([
|
|
645
|
+
this.storage.listPrompts({ projectId: input.projectId, limit: 10000, offset: 0 }),
|
|
489
646
|
this.storage.listAgentProfiles({ projectId: input.projectId, limit: 10000, offset: 0 }),
|
|
490
647
|
this.storage.listAgents(input.projectId, { limit: 10000, offset: 0 }),
|
|
491
648
|
this.storage.listStatuses(input.projectId, { limit: 10000, offset: 0 }),
|
|
649
|
+
this.storage.listWatchers(input.projectId),
|
|
650
|
+
this.storage.listSubscribers(input.projectId),
|
|
492
651
|
]);
|
|
493
652
|
const templateStatusLabels = new Set(payload.statuses.map((s) => s.label.trim().toLowerCase()));
|
|
494
653
|
const unmatchedStatuses = [];
|
|
@@ -521,12 +680,16 @@ let ProjectsService = class ProjectsService {
|
|
|
521
680
|
profiles: payload.profiles.length,
|
|
522
681
|
agents: payload.agents.length,
|
|
523
682
|
statuses: payload.statuses.length,
|
|
683
|
+
watchers: payload.watchers.length,
|
|
684
|
+
subscribers: payload.subscribers.length,
|
|
524
685
|
},
|
|
525
686
|
toDelete: {
|
|
526
687
|
prompts: existingPrompts.total,
|
|
527
688
|
profiles: existingProfiles.total,
|
|
528
689
|
agents: existingAgents.total,
|
|
529
690
|
statuses: existingStatuses.total,
|
|
691
|
+
watchers: existingWatchers.length,
|
|
692
|
+
subscribers: existingSubscribers.length,
|
|
530
693
|
},
|
|
531
694
|
},
|
|
532
695
|
};
|
|
@@ -560,6 +723,12 @@ let ProjectsService = class ProjectsService {
|
|
|
560
723
|
for (const pr of existingPrompts.items) {
|
|
561
724
|
await this.storage.deletePrompt(pr.id);
|
|
562
725
|
}
|
|
726
|
+
for (const w of existingWatchers) {
|
|
727
|
+
await this.watchersService.deleteWatcher(w.id);
|
|
728
|
+
}
|
|
729
|
+
for (const s of existingSubscribers) {
|
|
730
|
+
await this.storage.deleteSubscriber(s.id);
|
|
731
|
+
}
|
|
563
732
|
await this.settings.updateSettings({
|
|
564
733
|
projectId: input.projectId,
|
|
565
734
|
initialSessionPromptId: null,
|
|
@@ -572,6 +741,10 @@ let ProjectsService = class ProjectsService {
|
|
|
572
741
|
for (const s of existingStatuses.items) {
|
|
573
742
|
existingStatusByLabel.set(s.label.trim().toLowerCase(), s);
|
|
574
743
|
}
|
|
744
|
+
const TEMP_POSITION_OFFSET = 100000;
|
|
745
|
+
for (const s of existingStatuses.items) {
|
|
746
|
+
await this.storage.updateStatus(s.id, { position: s.position + TEMP_POSITION_OFFSET });
|
|
747
|
+
}
|
|
575
748
|
for (const s of payload.statuses.sort((a, b) => a.position - b.position)) {
|
|
576
749
|
const labelKey = s.label.trim().toLowerCase();
|
|
577
750
|
const existing = existingStatusByLabel.get(labelKey);
|
|
@@ -579,6 +752,7 @@ let ProjectsService = class ProjectsService {
|
|
|
579
752
|
const updated = await this.storage.updateStatus(existing.id, {
|
|
580
753
|
color: s.color,
|
|
581
754
|
position: s.position,
|
|
755
|
+
mcpHidden: s.mcpHidden,
|
|
582
756
|
});
|
|
583
757
|
if (s.id)
|
|
584
758
|
statusIdMap[s.id] = updated.id;
|
|
@@ -590,6 +764,7 @@ let ProjectsService = class ProjectsService {
|
|
|
590
764
|
label: s.label,
|
|
591
765
|
color: s.color,
|
|
592
766
|
position: s.position,
|
|
767
|
+
mcpHidden: s.mcpHidden,
|
|
593
768
|
});
|
|
594
769
|
if (s.id)
|
|
595
770
|
statusIdMap[s.id] = created.id;
|
|
@@ -629,6 +804,7 @@ let ProjectsService = class ProjectsService {
|
|
|
629
804
|
promptIdMap[p.id] = created.id;
|
|
630
805
|
createdPrompts.push({ id: created.id, title: created.title });
|
|
631
806
|
}
|
|
807
|
+
const profileNameToNewId = new Map();
|
|
632
808
|
for (const prof of payload.profiles) {
|
|
633
809
|
const providerId = available.get(prof.provider.name.trim().toLowerCase());
|
|
634
810
|
if (!providerId) {
|
|
@@ -658,7 +834,9 @@ let ProjectsService = class ProjectsService {
|
|
|
658
834
|
});
|
|
659
835
|
if (prof.id)
|
|
660
836
|
profileIdMap[prof.id] = created.id;
|
|
837
|
+
profileNameToNewId.set(prof.name.trim().toLowerCase(), created.id);
|
|
661
838
|
}
|
|
839
|
+
const agentNameToNewId = new Map();
|
|
662
840
|
for (const a of payload.agents) {
|
|
663
841
|
const oldProfileId = a.profileId ?? '';
|
|
664
842
|
const newProfileId = oldProfileId && profileIdMap[oldProfileId] ? profileIdMap[oldProfileId] : undefined;
|
|
@@ -676,14 +854,77 @@ let ProjectsService = class ProjectsService {
|
|
|
676
854
|
});
|
|
677
855
|
if (a.id)
|
|
678
856
|
agentIdMap[a.id] = created.id;
|
|
857
|
+
agentNameToNewId.set(a.name.trim().toLowerCase(), created.id);
|
|
679
858
|
}
|
|
680
|
-
const
|
|
681
|
-
for (const
|
|
682
|
-
|
|
683
|
-
if (
|
|
684
|
-
|
|
859
|
+
const watcherIdMap = {};
|
|
860
|
+
for (const w of payload.watchers) {
|
|
861
|
+
let scopeFilterId = null;
|
|
862
|
+
if (w.scopeFilterName && w.scope !== 'all') {
|
|
863
|
+
const scopeFilterNameLower = w.scopeFilterName.trim().toLowerCase();
|
|
864
|
+
switch (w.scope) {
|
|
865
|
+
case 'agent': {
|
|
866
|
+
scopeFilterId = agentNameToNewId.get(scopeFilterNameLower) ?? null;
|
|
867
|
+
break;
|
|
868
|
+
}
|
|
869
|
+
case 'profile': {
|
|
870
|
+
scopeFilterId = profileNameToNewId.get(scopeFilterNameLower) ?? null;
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
case 'provider': {
|
|
874
|
+
const provider = providers.items.find((p) => p.name.trim().toLowerCase() === scopeFilterNameLower);
|
|
875
|
+
scopeFilterId = provider?.id ?? null;
|
|
876
|
+
break;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (!scopeFilterId) {
|
|
880
|
+
logger.warn({ watcherName: w.name, scope: w.scope, scopeFilterName: w.scopeFilterName }, 'Could not resolve scope filter, setting scope to "all"');
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
const created = await this.storage.createWatcher({
|
|
884
|
+
projectId: input.projectId,
|
|
885
|
+
name: w.name,
|
|
886
|
+
description: w.description ?? null,
|
|
887
|
+
enabled: w.enabled,
|
|
888
|
+
scope: scopeFilterId ? w.scope : 'all',
|
|
889
|
+
scopeFilterId,
|
|
890
|
+
pollIntervalMs: w.pollIntervalMs,
|
|
891
|
+
viewportLines: w.viewportLines,
|
|
892
|
+
condition: w.condition,
|
|
893
|
+
cooldownMs: w.cooldownMs,
|
|
894
|
+
cooldownMode: w.cooldownMode,
|
|
895
|
+
eventName: w.eventName,
|
|
896
|
+
});
|
|
897
|
+
if (w.id)
|
|
898
|
+
watcherIdMap[w.id] = created.id;
|
|
899
|
+
if (created.enabled) {
|
|
900
|
+
await this.watcherRunner.startWatcher(created);
|
|
685
901
|
}
|
|
686
902
|
}
|
|
903
|
+
const subscriberIdMap = {};
|
|
904
|
+
for (const s of payload.subscribers) {
|
|
905
|
+
const created = await this.storage.createSubscriber({
|
|
906
|
+
projectId: input.projectId,
|
|
907
|
+
name: s.name,
|
|
908
|
+
description: s.description ?? null,
|
|
909
|
+
enabled: s.enabled,
|
|
910
|
+
eventName: s.eventName,
|
|
911
|
+
eventFilter: s.eventFilter ?? null,
|
|
912
|
+
actionType: s.actionType,
|
|
913
|
+
actionInputs: s.actionInputs,
|
|
914
|
+
delayMs: s.delayMs,
|
|
915
|
+
cooldownMs: s.cooldownMs,
|
|
916
|
+
retryOnError: s.retryOnError,
|
|
917
|
+
groupName: s.groupName ?? null,
|
|
918
|
+
position: s.position ?? 0,
|
|
919
|
+
priority: s.priority ?? 0,
|
|
920
|
+
});
|
|
921
|
+
if (s.id)
|
|
922
|
+
subscriberIdMap[s.id] = created.id;
|
|
923
|
+
}
|
|
924
|
+
logger.info({
|
|
925
|
+
watchersCreated: payload.watchers.length,
|
|
926
|
+
subscribersCreated: payload.subscribers.length,
|
|
927
|
+
}, 'Watchers and subscribers imported');
|
|
687
928
|
const existingEpics = await this.storage.listEpics(input.projectId, {
|
|
688
929
|
limit: 100000,
|
|
689
930
|
offset: 0,
|
|
@@ -694,7 +935,7 @@ let ProjectsService = class ProjectsService {
|
|
|
694
935
|
if (epic.agentId) {
|
|
695
936
|
const oldAgentName = oldAgentIdToName.get(epic.agentId);
|
|
696
937
|
if (oldAgentName) {
|
|
697
|
-
const newAgentId =
|
|
938
|
+
const newAgentId = agentNameToNewId.get(oldAgentName);
|
|
698
939
|
if (newAgentId) {
|
|
699
940
|
await this.storage.updateEpic(epic.id, { agentId: newAgentId }, epic.version);
|
|
700
941
|
epicsRemapped++;
|
|
@@ -748,9 +989,11 @@ let ProjectsService = class ProjectsService {
|
|
|
748
989
|
.map((label) => templateLabelToStatusId.get(label.toLowerCase()))
|
|
749
990
|
.filter((id) => !!id);
|
|
750
991
|
if (autoCleanStatusIds.length > 0) {
|
|
992
|
+
const currentSettings = this.settings.getSettings();
|
|
993
|
+
const existingAutoClean = currentSettings.autoClean?.statusIds ?? {};
|
|
751
994
|
await this.settings.updateSettings({
|
|
752
995
|
autoClean: {
|
|
753
|
-
statusIds: { [input.projectId]: autoCleanStatusIds },
|
|
996
|
+
statusIds: { ...existingAutoClean, [input.projectId]: autoCleanStatusIds },
|
|
754
997
|
},
|
|
755
998
|
});
|
|
756
999
|
logger.info({ projectId: input.projectId, autoCleanStatusIds }, 'Applied autoClean statuses from projectSettings');
|
|
@@ -776,12 +1019,16 @@ let ProjectsService = class ProjectsService {
|
|
|
776
1019
|
profiles: payload.profiles.length,
|
|
777
1020
|
agents: payload.agents.length,
|
|
778
1021
|
statuses: payload.statuses.length,
|
|
1022
|
+
watchers: payload.watchers.length,
|
|
1023
|
+
subscribers: payload.subscribers.length,
|
|
779
1024
|
},
|
|
780
1025
|
deleted: {
|
|
781
1026
|
prompts: existingPrompts.total,
|
|
782
1027
|
profiles: existingProfiles.total,
|
|
783
1028
|
agents: existingAgents.total,
|
|
784
1029
|
statuses: 0,
|
|
1030
|
+
watchers: existingWatchers.length,
|
|
1031
|
+
subscribers: existingSubscribers.length,
|
|
785
1032
|
},
|
|
786
1033
|
epics: {
|
|
787
1034
|
preserved: existingEpics.total,
|
|
@@ -789,7 +1036,14 @@ let ProjectsService = class ProjectsService {
|
|
|
789
1036
|
agentCleared: epicsCleared,
|
|
790
1037
|
},
|
|
791
1038
|
},
|
|
792
|
-
mappings: {
|
|
1039
|
+
mappings: {
|
|
1040
|
+
promptIdMap,
|
|
1041
|
+
profileIdMap,
|
|
1042
|
+
agentIdMap,
|
|
1043
|
+
statusIdMap,
|
|
1044
|
+
watcherIdMap,
|
|
1045
|
+
subscriberIdMap,
|
|
1046
|
+
},
|
|
793
1047
|
initialPromptSet,
|
|
794
1048
|
message: 'Project configuration replaced. Epics preserved.',
|
|
795
1049
|
};
|
|
@@ -828,6 +1082,8 @@ exports.ProjectsService = ProjectsService = __decorate([
|
|
|
828
1082
|
(0, common_1.Injectable)(),
|
|
829
1083
|
__param(0, (0, common_1.Inject)(storage_interface_1.STORAGE_SERVICE)),
|
|
830
1084
|
__metadata("design:paramtypes", [Object, sessions_service_1.SessionsService,
|
|
831
|
-
settings_service_1.SettingsService
|
|
1085
|
+
settings_service_1.SettingsService,
|
|
1086
|
+
watchers_service_1.WatchersService,
|
|
1087
|
+
watcher_runner_service_1.WatcherRunnerService])
|
|
832
1088
|
], ProjectsService);
|
|
833
1089
|
//# sourceMappingURL=projects.service.js.map
|