devchain-cli 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drizzle/0027_legal_malice.sql +17 -0
- package/dist/drizzle/0028_populate_provider_configs.sql +19 -0
- package/dist/drizzle/0029_merge_profiles_by_family_slug.sql +116 -0
- package/dist/drizzle/0030_set_agents_provider_config_id.sql +14 -0
- package/dist/drizzle/0031_remove_legacy_profile_columns.sql +68 -0
- package/dist/drizzle/0032_agents_provider_config_not_null.sql +52 -0
- package/dist/drizzle/0033_profile_provider_configs_name.sql +38 -0
- package/dist/drizzle/0034_sessions_agent_running_unique.sql +30 -0
- package/dist/drizzle/0035_provider_config_position.sql +26 -0
- package/dist/drizzle/PHASE2_MIGRATION_GUIDE.md +109 -0
- package/dist/drizzle/meta/0027_snapshot.json +3648 -0
- package/dist/drizzle/meta/0035_snapshot.json +3670 -0
- package/dist/drizzle/meta/_journal.json +64 -1
- package/dist/drizzle/migration-guard.sql +17 -0
- package/dist/drizzle/phase2-rollback.sql +44 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +101 -12
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts.map +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js +20 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js.map +1 -1
- package/dist/node_modules/@devchain/shared/tsconfig.tsbuildinfo +1 -1
- package/dist/server/modules/agents/controllers/agents.controller.d.ts +15 -0
- package/dist/server/modules/agents/controllers/agents.controller.js +120 -57
- package/dist/server/modules/agents/controllers/agents.controller.js.map +1 -1
- package/dist/server/modules/core/services/preflight.service.d.ts +6 -0
- package/dist/server/modules/core/services/preflight.service.js +143 -57
- package/dist/server/modules/core/services/preflight.service.js.map +1 -1
- package/dist/server/modules/epics/services/epics.service.d.ts +10 -4
- package/dist/server/modules/epics/services/epics.service.js +8 -5
- package/dist/server/modules/epics/services/epics.service.js.map +1 -1
- package/dist/server/modules/events/catalog/epic.created.d.ts +18 -0
- package/dist/server/modules/events/catalog/epic.created.js +8 -0
- package/dist/server/modules/events/catalog/epic.created.js.map +1 -1
- package/dist/server/modules/events/catalog/epic.updated.d.ts +18 -0
- package/dist/server/modules/events/catalog/epic.updated.js +8 -0
- package/dist/server/modules/events/catalog/epic.updated.js.map +1 -1
- package/dist/server/modules/events/catalog/index.d.ts +36 -0
- package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.d.ts +1 -0
- package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.js +33 -2
- package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.js.map +1 -1
- package/dist/server/modules/events/subscribers/review-comment-notifier.subscriber.js +12 -5
- package/dist/server/modules/events/subscribers/review-comment-notifier.subscriber.js.map +1 -1
- package/dist/server/modules/mcp/services/mcp.service.js +16 -2
- package/dist/server/modules/mcp/services/mcp.service.js.map +1 -1
- package/dist/server/modules/mcp/services/terminal-activity.service.d.ts +1 -1
- package/dist/server/modules/mcp/services/terminal-activity.service.js +22 -2
- package/dist/server/modules/mcp/services/terminal-activity.service.js.map +1 -1
- package/dist/server/modules/profiles/controllers/profiles.controller.d.ts +11 -8
- package/dist/server/modules/profiles/controllers/profiles.controller.js +88 -14
- package/dist/server/modules/profiles/controllers/profiles.controller.js.map +1 -1
- package/dist/server/modules/profiles/controllers/provider-configs.controller.d.ts +9 -0
- package/dist/server/modules/profiles/controllers/provider-configs.controller.js +94 -0
- package/dist/server/modules/profiles/controllers/provider-configs.controller.js.map +1 -0
- package/dist/server/modules/profiles/dto.d.ts +81 -6
- package/dist/server/modules/profiles/dto.js +45 -3
- package/dist/server/modules/profiles/dto.js.map +1 -1
- package/dist/server/modules/profiles/profiles.module.js +2 -1
- package/dist/server/modules/profiles/profiles.module.js.map +1 -1
- package/dist/server/modules/projects/controllers/projects.controller.d.ts +78 -19
- package/dist/server/modules/projects/controllers/projects.controller.js +243 -17
- package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
- package/dist/server/modules/projects/dtos/export.dto.d.ts +44 -0
- package/dist/server/modules/projects/dtos/export.dto.js +10 -0
- package/dist/server/modules/projects/dtos/export.dto.js.map +1 -1
- package/dist/server/modules/projects/services/projects.service.d.ts +48 -11
- package/dist/server/modules/projects/services/projects.service.js +359 -27
- package/dist/server/modules/projects/services/projects.service.js.map +1 -1
- package/dist/server/modules/providers/controllers/providers.controller.js +12 -7
- package/dist/server/modules/providers/controllers/providers.controller.js.map +1 -1
- package/dist/server/modules/registry/controllers/templates.controller.d.ts +2 -2
- package/dist/server/modules/registry/services/registry-orchestration.service.js +11 -0
- package/dist/server/modules/registry/services/registry-orchestration.service.js.map +1 -1
- package/dist/server/modules/registry/services/template-upgrade.service.js +6 -0
- package/dist/server/modules/registry/services/template-upgrade.service.js.map +1 -1
- package/dist/server/modules/registry/services/unified-template.service.d.ts +2 -1
- package/dist/server/modules/registry/services/unified-template.service.js +61 -0
- package/dist/server/modules/registry/services/unified-template.service.js.map +1 -1
- package/dist/server/modules/reviews/services/reviews.service.js +8 -0
- package/dist/server/modules/reviews/services/reviews.service.js.map +1 -1
- package/dist/server/modules/sessions/services/activity-tracker.service.d.ts +2 -0
- package/dist/server/modules/sessions/services/activity-tracker.service.js +20 -0
- package/dist/server/modules/sessions/services/activity-tracker.service.js.map +1 -1
- package/dist/server/modules/sessions/services/sessions-message-pool.service.js +2 -2
- package/dist/server/modules/sessions/services/sessions-message-pool.service.js.map +1 -1
- package/dist/server/modules/sessions/services/sessions.service.d.ts +3 -1
- package/dist/server/modules/sessions/services/sessions.service.js +275 -144
- package/dist/server/modules/sessions/services/sessions.service.js.map +1 -1
- package/dist/server/modules/sessions/utils/env-builder.d.ts +8 -0
- package/dist/server/modules/sessions/utils/env-builder.js +62 -0
- package/dist/server/modules/sessions/utils/env-builder.js.map +1 -0
- package/dist/server/modules/settings/dtos/settings.dto.d.ts +84 -8
- package/dist/server/modules/settings/dtos/settings.dto.js +15 -2
- package/dist/server/modules/settings/dtos/settings.dto.js.map +1 -1
- package/dist/server/modules/settings/services/settings.service.d.ts +10 -1
- package/dist/server/modules/settings/services/settings.service.js +275 -0
- package/dist/server/modules/settings/services/settings.service.js.map +1 -1
- package/dist/server/modules/storage/db/db.provider.js +2 -0
- package/dist/server/modules/storage/db/db.provider.js.map +1 -1
- package/dist/server/modules/storage/db/schema.d.ts +185 -28
- package/dist/server/modules/storage/db/schema.js +32 -6
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +17 -1
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/local-storage.service.d.ts +15 -1
- package/dist/server/modules/storage/local/local-storage.service.js +352 -21
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +26 -7
- package/dist/server/modules/subscribers/actions/restart-agent.action.js +17 -19
- package/dist/server/modules/subscribers/actions/restart-agent.action.js.map +1 -1
- package/dist/server/modules/subscribers/events/event-fields-catalog.js +4 -0
- package/dist/server/modules/subscribers/events/event-fields-catalog.js.map +1 -1
- package/dist/server/modules/terminal/services/pty.service.js +6 -1
- package/dist/server/modules/terminal/services/pty.service.js.map +1 -1
- package/dist/server/modules/watchers/services/watcher-runner.service.js +27 -8
- package/dist/server/modules/watchers/services/watcher-runner.service.js.map +1 -1
- package/dist/{templates/claude-opus.json → server/templates/dev-loop.json} +365 -209
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/{ReviewDetailPage-I54h-2L-.js → ReviewDetailPage-YlFGGJv7.js} +2 -2
- package/dist/server/ui/assets/ReviewsPage-Diegg4jt.js +19 -0
- package/dist/server/ui/assets/index-DuMIsIyY.css +32 -0
- package/dist/server/ui/assets/index-sEtQpiB4.js +868 -0
- package/dist/server/ui/assets/{useReviewSubscription-C0GEsiRw.js → useReviewSubscription-CMhQ2m0h.js} +22 -22
- package/dist/server/ui/index.html +2 -2
- package/dist/{server/templates/claude-opus.json → templates/dev-loop.json} +365 -209
- package/package.json +9 -4
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.d.ts +0 -2
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.d.ts.map +0 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.js +0 -88
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.js.map +0 -1
- package/dist/server/templates/claude-codex-advanced.json +0 -470
- package/dist/server/templates/simple-codex.json +0 -469
- package/dist/server/ui/assets/ReviewsPage-B4ua5hiX.js +0 -19
- package/dist/server/ui/assets/index-CqcmnFBh.css +0 -32
- package/dist/server/ui/assets/index-JbUMpbg7.js +0 -858
- package/dist/templates/claude-codex-advanced.json +0 -470
- package/dist/templates/simple-codex.json +0 -469
|
@@ -117,13 +117,26 @@ let ProjectsService = class ProjectsService {
|
|
|
117
117
|
}
|
|
118
118
|
async createFromTemplate(input) {
|
|
119
119
|
logger.info({ input }, 'createFromTemplate');
|
|
120
|
-
|
|
120
|
+
let templateResult;
|
|
121
|
+
let templateSlug;
|
|
122
|
+
if (input.templatePath) {
|
|
123
|
+
templateResult = this.unifiedTemplateService.getTemplateFromFilePath(input.templatePath);
|
|
124
|
+
const manifest = templateResult.content._manifest;
|
|
125
|
+
templateSlug = manifest?.slug ?? this.deriveSlugFromPath(input.templatePath);
|
|
126
|
+
}
|
|
127
|
+
else if (input.slug) {
|
|
128
|
+
templateResult = await this.unifiedTemplateService.getTemplate(input.slug, input.version ?? undefined);
|
|
129
|
+
templateSlug = input.slug;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
throw new error_types_1.ValidationError('Either slug or templatePath is required', {});
|
|
133
|
+
}
|
|
121
134
|
let payload;
|
|
122
135
|
try {
|
|
123
136
|
payload = shared_1.ExportSchema.parse(templateResult.content);
|
|
124
137
|
}
|
|
125
138
|
catch (error) {
|
|
126
|
-
logger.error({ error, slug:
|
|
139
|
+
logger.error({ error, slug: templateSlug, version: input.version }, 'Invalid template format');
|
|
127
140
|
throw new error_types_1.ValidationError('Invalid template format', {
|
|
128
141
|
hint: 'Template file does not match expected export schema',
|
|
129
142
|
});
|
|
@@ -199,6 +212,81 @@ let ProjectsService = class ProjectsService {
|
|
|
199
212
|
isTemplate: false,
|
|
200
213
|
}, templatePayload);
|
|
201
214
|
const { agentNameToId: agentNameToNewId, profileNameToId: profileNameToNewId } = this.buildNameToIdMaps(templatePayload, result.mappings);
|
|
215
|
+
const configLookupMap = new Map();
|
|
216
|
+
for (const prof of selectedProfilesByFamily.profilesToCreate) {
|
|
217
|
+
if (!prof.id)
|
|
218
|
+
continue;
|
|
219
|
+
const newProfileId = result.mappings.profileIdMap[prof.id];
|
|
220
|
+
if (!newProfileId)
|
|
221
|
+
continue;
|
|
222
|
+
const providerConfigs = prof.providerConfigs;
|
|
223
|
+
if (providerConfigs && providerConfigs.length > 0) {
|
|
224
|
+
for (const config of providerConfigs) {
|
|
225
|
+
const configProviderId = available.get(config.providerName.trim().toLowerCase());
|
|
226
|
+
if (!configProviderId) {
|
|
227
|
+
logger.warn({ profileName: prof.name, providerName: config.providerName }, 'Provider not found for config in createFromTemplate, skipping');
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const createdConfig = await this.storage.createProfileProviderConfig({
|
|
231
|
+
profileId: newProfileId,
|
|
232
|
+
providerId: configProviderId,
|
|
233
|
+
name: config.name,
|
|
234
|
+
options: config.options ?? null,
|
|
235
|
+
env: config.env ?? null,
|
|
236
|
+
});
|
|
237
|
+
const lookupKey = `${newProfileId}:${config.name.trim().toLowerCase()}`;
|
|
238
|
+
configLookupMap.set(lookupKey, createdConfig.id);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const profilesWithProviderConfigs = new Map();
|
|
243
|
+
for (const prof of selectedProfilesByFamily.profilesToCreate) {
|
|
244
|
+
if (!prof.id)
|
|
245
|
+
continue;
|
|
246
|
+
const newProfileId = result.mappings.profileIdMap[prof.id];
|
|
247
|
+
if (!newProfileId)
|
|
248
|
+
continue;
|
|
249
|
+
const providerConfigs = prof.providerConfigs;
|
|
250
|
+
if (providerConfigs && providerConfigs.length > 0) {
|
|
251
|
+
profilesWithProviderConfigs.set(newProfileId, {
|
|
252
|
+
profileName: prof.name,
|
|
253
|
+
configNames: new Set(providerConfigs.map((pc) => pc.name.trim().toLowerCase())),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
for (const a of payload.agents) {
|
|
258
|
+
const agentWithConfig = a;
|
|
259
|
+
if (!agentWithConfig.providerConfigName || !a.id)
|
|
260
|
+
continue;
|
|
261
|
+
const newAgentId = result.mappings.agentIdMap[a.id];
|
|
262
|
+
if (!newAgentId)
|
|
263
|
+
continue;
|
|
264
|
+
const remappedProfileId = selectedProfilesByFamily.agentProfileMap.get(a.id) ?? a.profileId;
|
|
265
|
+
const newProfileId = remappedProfileId
|
|
266
|
+
? result.mappings.profileIdMap[remappedProfileId]
|
|
267
|
+
: null;
|
|
268
|
+
if (!newProfileId)
|
|
269
|
+
continue;
|
|
270
|
+
const lookupKey = `${newProfileId}:${agentWithConfig.providerConfigName.trim().toLowerCase()}`;
|
|
271
|
+
const providerConfigId = configLookupMap.get(lookupKey);
|
|
272
|
+
if (providerConfigId) {
|
|
273
|
+
await this.storage.updateAgent(newAgentId, { providerConfigId });
|
|
274
|
+
logger.debug({ agentName: a.name, providerConfigId }, 'Updated agent with providerConfigId');
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
logger.warn({ agentName: a.name, providerConfigName: agentWithConfig.providerConfigName }, 'Provider config not found for agent in createFromTemplate');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const [newProfileId, { profileName, configNames }] of profilesWithProviderConfigs) {
|
|
281
|
+
const existingConfigs = await this.storage.listProfileProviderConfigsByProfile(newProfileId);
|
|
282
|
+
for (const existingConfig of existingConfigs) {
|
|
283
|
+
const isFromProviderConfigs = configNames.has(existingConfig.name.trim().toLowerCase());
|
|
284
|
+
if (!isFromProviderConfigs && existingConfig.name === profileName) {
|
|
285
|
+
await this.storage.deleteProfileProviderConfig(existingConfig.id);
|
|
286
|
+
logger.debug({ profileName, configId: existingConfig.id }, 'Deleted duplicate config created by storage layer');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
202
290
|
let mergedInitialPromptTitle;
|
|
203
291
|
if (payload.initialPrompt?.title) {
|
|
204
292
|
mergedInitialPromptTitle = payload.initialPrompt.title;
|
|
@@ -246,7 +334,7 @@ let ProjectsService = class ProjectsService {
|
|
|
246
334
|
const installedVersion = templateResult.version ?? manifestVersion;
|
|
247
335
|
const registryConfig = this.settings.getRegistryConfig();
|
|
248
336
|
await this.settings.setProjectTemplateMetadata(result.project.id, {
|
|
249
|
-
templateSlug
|
|
337
|
+
templateSlug,
|
|
250
338
|
source: templateResult.source,
|
|
251
339
|
installedVersion,
|
|
252
340
|
registryUrl: templateResult.source === 'registry' ? registryConfig.url : null,
|
|
@@ -254,10 +342,29 @@ let ProjectsService = class ProjectsService {
|
|
|
254
342
|
});
|
|
255
343
|
logger.info({
|
|
256
344
|
projectId: result.project.id,
|
|
257
|
-
slug:
|
|
345
|
+
slug: templateSlug,
|
|
258
346
|
source: templateResult.source,
|
|
259
347
|
version: installedVersion,
|
|
260
348
|
}, 'Template metadata set for project');
|
|
349
|
+
const rawPresets = payload.presets;
|
|
350
|
+
const templatePresets = Array.isArray(rawPresets) ? rawPresets : [];
|
|
351
|
+
if (templatePresets.length > 0) {
|
|
352
|
+
await this.settings.setProjectPresets(result.project.id, templatePresets);
|
|
353
|
+
logger.info({ projectId: result.project.id, presetCount: templatePresets.length }, 'Presets stored for project');
|
|
354
|
+
}
|
|
355
|
+
if (input.presetName) {
|
|
356
|
+
const selectedPreset = templatePresets.find((p) => typeof p === 'object' && p !== null && 'name' in p && p.name === input.presetName);
|
|
357
|
+
if (!selectedPreset) {
|
|
358
|
+
logger.warn({ projectId: result.project.id, presetName: input.presetName }, 'Selected preset not found in template');
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
await this.applyPreset(result.project.id, input.presetName, {
|
|
362
|
+
agentNameToId: agentNameToNewId,
|
|
363
|
+
configLookupMap,
|
|
364
|
+
});
|
|
365
|
+
logger.info({ projectId: result.project.id, presetName: input.presetName }, 'Applied preset to project');
|
|
366
|
+
}
|
|
367
|
+
}
|
|
261
368
|
return {
|
|
262
369
|
success: true,
|
|
263
370
|
project: result.project,
|
|
@@ -273,7 +380,7 @@ let ProjectsService = class ProjectsService {
|
|
|
273
380
|
}
|
|
274
381
|
async exportProject(projectId, opts) {
|
|
275
382
|
logger.info({ projectId }, 'exportProject');
|
|
276
|
-
const { manifestOverrides } = opts ?? {};
|
|
383
|
+
const { manifestOverrides, presets: presetsOverride } = opts ?? {};
|
|
277
384
|
const [project, promptsRes, profilesRes, agentsRes, statusesRes, initialPrompt, settings, watchersRes, subscribersRes,] = await Promise.all([
|
|
278
385
|
this.storage.getProject(projectId),
|
|
279
386
|
this.storage.listPrompts({ projectId, limit: 1000, offset: 0 }),
|
|
@@ -326,11 +433,6 @@ let ProjectsService = class ProjectsService {
|
|
|
326
433
|
}
|
|
327
434
|
return value;
|
|
328
435
|
};
|
|
329
|
-
const sanitizeOptionsString = (options) => {
|
|
330
|
-
if (!options)
|
|
331
|
-
return null;
|
|
332
|
-
return options;
|
|
333
|
-
};
|
|
334
436
|
const fullPrompts = await Promise.all(promptsRes.items.map((p) => this.storage.getPrompt(p.id)));
|
|
335
437
|
const prompts = fullPrompts.map((p) => ({
|
|
336
438
|
id: p.id,
|
|
@@ -339,25 +441,66 @@ let ProjectsService = class ProjectsService {
|
|
|
339
441
|
version: p.version,
|
|
340
442
|
tags: p.tags,
|
|
341
443
|
}));
|
|
342
|
-
const
|
|
343
|
-
|
|
444
|
+
const configIdToInfo = new Map();
|
|
445
|
+
const profileIds = profilesRes.items.map((p) => p.id);
|
|
446
|
+
const allConfigsByProfile = new Map();
|
|
447
|
+
await Promise.all(profileIds.map(async (profileId) => {
|
|
448
|
+
const configs = await this.storage.listProfileProviderConfigsByProfile(profileId);
|
|
449
|
+
allConfigsByProfile.set(profileId, configs);
|
|
450
|
+
}));
|
|
451
|
+
const allProviderIds = new Set();
|
|
452
|
+
for (const configs of allConfigsByProfile.values()) {
|
|
453
|
+
for (const config of configs) {
|
|
454
|
+
allProviderIds.add(config.providerId);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const providersArray = await this.storage.listProvidersByIds([...allProviderIds]);
|
|
458
|
+
const providersMap = new Map(providersArray.map((p) => [p.id, p]));
|
|
459
|
+
const profiles = profilesRes.items.map((prof) => {
|
|
460
|
+
const configs = allConfigsByProfile.get(prof.id) || [];
|
|
461
|
+
let primaryProvider = null;
|
|
462
|
+
const providerConfigs = configs.map((config) => {
|
|
463
|
+
const configProvider = providersMap.get(config.providerId);
|
|
464
|
+
if (!primaryProvider && configProvider) {
|
|
465
|
+
primaryProvider = { id: configProvider.id, name: configProvider.name };
|
|
466
|
+
}
|
|
467
|
+
const configName = config.name;
|
|
468
|
+
configIdToInfo.set(config.id, { name: configName, profileId: prof.id });
|
|
469
|
+
return {
|
|
470
|
+
name: configName,
|
|
471
|
+
providerName: configProvider?.name || 'unknown',
|
|
472
|
+
options: config.options,
|
|
473
|
+
env: config.env,
|
|
474
|
+
position: config.position,
|
|
475
|
+
};
|
|
476
|
+
});
|
|
344
477
|
return {
|
|
345
478
|
id: prof.id,
|
|
346
479
|
name: prof.name,
|
|
347
|
-
provider:
|
|
480
|
+
provider: primaryProvider,
|
|
348
481
|
familySlug: prof.familySlug,
|
|
349
|
-
options: sanitizeOptionsString(prof.options),
|
|
350
482
|
instructions: prof.instructions,
|
|
351
483
|
temperature: prof.temperature,
|
|
352
484
|
maxTokens: prof.maxTokens,
|
|
485
|
+
...(providerConfigs.length > 0 && { providerConfigs }),
|
|
353
486
|
};
|
|
354
|
-
})
|
|
355
|
-
const agents = agentsRes.items.map((a) =>
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
487
|
+
});
|
|
488
|
+
const agents = agentsRes.items.map((a) => {
|
|
489
|
+
let providerConfigName = null;
|
|
490
|
+
if (a.providerConfigId) {
|
|
491
|
+
const configInfo = configIdToInfo.get(a.providerConfigId);
|
|
492
|
+
if (configInfo) {
|
|
493
|
+
providerConfigName = configInfo.name;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
id: a.id,
|
|
498
|
+
name: a.name,
|
|
499
|
+
profileId: a.profileId,
|
|
500
|
+
description: a.description,
|
|
501
|
+
...(providerConfigName && { providerConfigName }),
|
|
502
|
+
};
|
|
503
|
+
});
|
|
361
504
|
const statuses = statusesRes.items.map((s) => ({
|
|
362
505
|
id: s.id,
|
|
363
506
|
label: s.label,
|
|
@@ -467,9 +610,114 @@ let ProjectsService = class ProjectsService {
|
|
|
467
610
|
...(Object.keys(projectSettings).length > 0 && { projectSettings }),
|
|
468
611
|
watchers,
|
|
469
612
|
subscribers,
|
|
613
|
+
...(presetsOverride !== undefined
|
|
614
|
+
? { presets: presetsOverride }
|
|
615
|
+
: this.settings.getProjectPresets(projectId).length > 0
|
|
616
|
+
? { presets: this.settings.getProjectPresets(projectId) }
|
|
617
|
+
: {}),
|
|
470
618
|
};
|
|
471
619
|
return exportPayload;
|
|
472
620
|
}
|
|
621
|
+
async doesProjectMatchPreset(projectId, preset) {
|
|
622
|
+
const agentsRes = await this.storage.listAgents(projectId, { limit: 1000, offset: 0 });
|
|
623
|
+
const agentsByName = new Map(agentsRes.items.map((a) => [a.name.toLowerCase(), a]));
|
|
624
|
+
const uniqueProviderConfigIds = new Set();
|
|
625
|
+
for (const agent of agentsRes.items) {
|
|
626
|
+
if (agent.providerConfigId) {
|
|
627
|
+
uniqueProviderConfigIds.add(agent.providerConfigId);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const allProviderConfigs = uniqueProviderConfigIds.size > 0
|
|
631
|
+
? await this.storage.listProfileProviderConfigsByIds(Array.from(uniqueProviderConfigIds))
|
|
632
|
+
: [];
|
|
633
|
+
const providerConfigNames = new Map(allProviderConfigs.map((c) => [c.id, c.name]));
|
|
634
|
+
for (const agentConfig of preset.agentConfigs) {
|
|
635
|
+
const agentNameLower = agentConfig.agentName.trim().toLowerCase();
|
|
636
|
+
const providerConfigNameLower = agentConfig.providerConfigName.trim().toLowerCase();
|
|
637
|
+
const agent = agentsByName.get(agentNameLower);
|
|
638
|
+
if (!agent) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
const currentProviderConfigName = providerConfigNames.get(agent.providerConfigId ?? '');
|
|
642
|
+
if (currentProviderConfigName?.toLowerCase() !== providerConfigNameLower) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return true;
|
|
647
|
+
}
|
|
648
|
+
async applyPreset(projectId, presetName, nameMaps) {
|
|
649
|
+
logger.info({ projectId, presetName }, 'applyPreset');
|
|
650
|
+
const warnings = [];
|
|
651
|
+
const presets = this.settings.getProjectPresets(projectId);
|
|
652
|
+
const selectedPreset = presets.find((p) => p.name === presetName);
|
|
653
|
+
if (!selectedPreset) {
|
|
654
|
+
throw new error_types_1.NotFoundError('Preset', presetName);
|
|
655
|
+
}
|
|
656
|
+
if (!selectedPreset.agentConfigs || !Array.isArray(selectedPreset.agentConfigs)) {
|
|
657
|
+
throw new error_types_1.ValidationError(`Preset "${presetName}" has invalid or missing agentConfigs`, {
|
|
658
|
+
presetName,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
const agentsRes = await this.storage.listAgents(projectId, { limit: 1000, offset: 0 });
|
|
662
|
+
let agentNameToId;
|
|
663
|
+
if (nameMaps?.agentNameToId) {
|
|
664
|
+
agentNameToId = nameMaps.agentNameToId;
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
agentNameToId = new Map();
|
|
668
|
+
for (const agent of agentsRes.items) {
|
|
669
|
+
agentNameToId.set(agent.name.toLowerCase(), agent.id);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
let configLookupMap;
|
|
673
|
+
if (nameMaps?.configLookupMap) {
|
|
674
|
+
configLookupMap = nameMaps.configLookupMap;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
configLookupMap = new Map();
|
|
678
|
+
const profilesRes = await this.storage.listAgentProfiles({
|
|
679
|
+
projectId,
|
|
680
|
+
limit: 1000,
|
|
681
|
+
offset: 0,
|
|
682
|
+
});
|
|
683
|
+
for (const profile of profilesRes.items) {
|
|
684
|
+
const configs = await this.storage.listProfileProviderConfigsByProfile(profile.id);
|
|
685
|
+
for (const config of configs) {
|
|
686
|
+
const lookupKey = `${profile.id}:${config.name.trim().toLowerCase()}`;
|
|
687
|
+
configLookupMap.set(lookupKey, config.id);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
let applied = 0;
|
|
692
|
+
const agentsById = new Map(agentsRes.items.map((a) => [a.id, a]));
|
|
693
|
+
for (const agentConfig of selectedPreset.agentConfigs) {
|
|
694
|
+
const agentId = agentNameToId.get(agentConfig.agentName.trim().toLowerCase());
|
|
695
|
+
if (!agentId) {
|
|
696
|
+
warnings.push(`Agent "${agentConfig.agentName}" not found in project`);
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
const agent = agentsById.get(agentId);
|
|
700
|
+
if (!agent)
|
|
701
|
+
continue;
|
|
702
|
+
const profileId = agent.profileId;
|
|
703
|
+
const lookupKey = `${profileId}:${agentConfig.providerConfigName.trim().toLowerCase()}`;
|
|
704
|
+
const providerConfigId = configLookupMap.get(lookupKey);
|
|
705
|
+
if (!providerConfigId) {
|
|
706
|
+
warnings.push(`Provider config "${agentConfig.providerConfigName}" not found for agent "${agentConfig.agentName}"`);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
await this.storage.updateAgent(agentId, { providerConfigId });
|
|
710
|
+
applied++;
|
|
711
|
+
logger.debug({ projectId, agentId, agentName: agentConfig.agentName, providerConfigId }, 'Applied preset: updated agent provider config');
|
|
712
|
+
}
|
|
713
|
+
const fullMatch = warnings.length === 0 && applied === selectedPreset.agentConfigs.length;
|
|
714
|
+
if (fullMatch) {
|
|
715
|
+
await this.settings.setProjectActivePreset(projectId, presetName);
|
|
716
|
+
logger.info({ projectId, presetName }, 'Active preset set (full match)');
|
|
717
|
+
}
|
|
718
|
+
logger.info({ projectId, presetName, applied, warnings: warnings.length }, 'Preset applied');
|
|
719
|
+
return { applied, warnings };
|
|
720
|
+
}
|
|
473
721
|
async importProject(input) {
|
|
474
722
|
logger.info({ projectId: input.projectId, dryRun: input.dryRun }, 'importProject');
|
|
475
723
|
const isDryRun = input.dryRun ?? false;
|
|
@@ -668,16 +916,10 @@ let ProjectsService = class ProjectsService {
|
|
|
668
916
|
createdPrompts.push({ id: created.id, title: created.title });
|
|
669
917
|
}
|
|
670
918
|
for (const prof of selectedProfilesByFamily.profilesToCreate) {
|
|
671
|
-
const providerId = available.get(prof.provider.name.trim().toLowerCase());
|
|
672
|
-
if (!providerId) {
|
|
673
|
-
throw new error_types_1.NotFoundError('Provider', prof.provider.name);
|
|
674
|
-
}
|
|
675
919
|
const created = await this.storage.createAgentProfile({
|
|
676
920
|
projectId: input.projectId,
|
|
677
921
|
name: prof.name,
|
|
678
|
-
providerId,
|
|
679
922
|
familySlug: prof.familySlug ?? null,
|
|
680
|
-
options: this.normalizeProfileOptions(prof.options),
|
|
681
923
|
systemPrompt: null,
|
|
682
924
|
instructions: prof.instructions ?? null,
|
|
683
925
|
temperature: prof.temperature ?? null,
|
|
@@ -686,6 +928,55 @@ let ProjectsService = class ProjectsService {
|
|
|
686
928
|
const profKey = prof.id || `name:${prof.name.trim().toLowerCase()}`;
|
|
687
929
|
profileIdMap[profKey] = created.id;
|
|
688
930
|
}
|
|
931
|
+
const configLookupMap = new Map();
|
|
932
|
+
const configIdMap = {};
|
|
933
|
+
for (const prof of selectedProfilesByFamily.profilesToCreate) {
|
|
934
|
+
const profKey = prof.id || `name:${prof.name.trim().toLowerCase()}`;
|
|
935
|
+
const newProfileId = profileIdMap[profKey];
|
|
936
|
+
if (!newProfileId)
|
|
937
|
+
continue;
|
|
938
|
+
const providerConfigs = prof.providerConfigs;
|
|
939
|
+
if (providerConfigs && providerConfigs.length > 0) {
|
|
940
|
+
for (const config of providerConfigs) {
|
|
941
|
+
const configProviderId = available.get(config.providerName.trim().toLowerCase());
|
|
942
|
+
if (!configProviderId) {
|
|
943
|
+
logger.warn({ profileName: prof.name, providerName: config.providerName }, 'Provider not found for config, skipping');
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
const createdConfig = await this.storage.createProfileProviderConfig({
|
|
947
|
+
profileId: newProfileId,
|
|
948
|
+
providerId: configProviderId,
|
|
949
|
+
name: config.name,
|
|
950
|
+
options: config.options ?? null,
|
|
951
|
+
env: config.env ?? null,
|
|
952
|
+
});
|
|
953
|
+
const lookupKey = `${newProfileId}:${config.name.trim().toLowerCase()}`;
|
|
954
|
+
configLookupMap.set(lookupKey, createdConfig.id);
|
|
955
|
+
configIdMap[`${profKey}:${config.name}`] = createdConfig.id;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
960
|
+
const configProviderId = available.get(providerName);
|
|
961
|
+
if (configProviderId) {
|
|
962
|
+
const options = prof.options != null
|
|
963
|
+
? typeof prof.options === 'string'
|
|
964
|
+
? prof.options
|
|
965
|
+
: JSON.stringify(prof.options)
|
|
966
|
+
: null;
|
|
967
|
+
const createdConfig = await this.storage.createProfileProviderConfig({
|
|
968
|
+
profileId: newProfileId,
|
|
969
|
+
providerId: configProviderId,
|
|
970
|
+
name: 'default',
|
|
971
|
+
options,
|
|
972
|
+
env: null,
|
|
973
|
+
});
|
|
974
|
+
const lookupKey = `${newProfileId}:default`;
|
|
975
|
+
configLookupMap.set(lookupKey, createdConfig.id);
|
|
976
|
+
configIdMap[`${profKey}:default`] = createdConfig.id;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
689
980
|
for (const a of payload.agents) {
|
|
690
981
|
const remappedProfileId = selectedProfilesByFamily.agentProfileMap.get(a.id ?? '');
|
|
691
982
|
const oldProfileId = remappedProfileId ?? a.profileId ?? '';
|
|
@@ -695,11 +986,33 @@ let ProjectsService = class ProjectsService {
|
|
|
695
986
|
profileId: oldProfileId || null,
|
|
696
987
|
});
|
|
697
988
|
}
|
|
989
|
+
let providerConfigId;
|
|
990
|
+
const agentWithConfig = a;
|
|
991
|
+
if (agentWithConfig.providerConfigName && newProfileId) {
|
|
992
|
+
const lookupKey = `${newProfileId}:${agentWithConfig.providerConfigName.trim().toLowerCase()}`;
|
|
993
|
+
providerConfigId = configLookupMap.get(lookupKey);
|
|
994
|
+
}
|
|
995
|
+
if (!providerConfigId && newProfileId) {
|
|
996
|
+
const profilePrefix = `${newProfileId}:`;
|
|
997
|
+
for (const [key, configId] of configLookupMap.entries()) {
|
|
998
|
+
if (key.startsWith(profilePrefix)) {
|
|
999
|
+
providerConfigId = configId;
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
if (!providerConfigId) {
|
|
1005
|
+
throw new error_types_1.ValidationError(`No provider config available for agent ${a.name}`, {
|
|
1006
|
+
profileId: newProfileId,
|
|
1007
|
+
providerConfigName: agentWithConfig.providerConfigName || null,
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
698
1010
|
const created = await this.storage.createAgent({
|
|
699
1011
|
projectId: input.projectId,
|
|
700
1012
|
name: a.name,
|
|
701
1013
|
profileId: newProfileId,
|
|
702
1014
|
description: a.description ?? null,
|
|
1015
|
+
providerConfigId,
|
|
703
1016
|
});
|
|
704
1017
|
const agentKey = a.id || `name:${a.name.trim().toLowerCase()}`;
|
|
705
1018
|
agentIdMap[agentKey] = created.id;
|
|
@@ -796,6 +1109,16 @@ let ProjectsService = class ProjectsService {
|
|
|
796
1109
|
});
|
|
797
1110
|
logger.info({ projectId: input.projectId, slug: payload._manifest.slug, source: templateSource }, 'Updated template metadata after import');
|
|
798
1111
|
}
|
|
1112
|
+
const rawPresets = payload.presets;
|
|
1113
|
+
const templatePresets = Array.isArray(rawPresets) ? rawPresets : [];
|
|
1114
|
+
if (templatePresets.length > 0) {
|
|
1115
|
+
await this.settings.setProjectPresets(input.projectId, templatePresets);
|
|
1116
|
+
logger.info({ projectId: input.projectId, presetCount: templatePresets.length }, 'Presets replaced from template during import');
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
await this.settings.clearProjectPresets(input.projectId);
|
|
1120
|
+
logger.info({ projectId: input.projectId }, 'Presets cleared during import (template has none)');
|
|
1121
|
+
}
|
|
799
1122
|
return {
|
|
800
1123
|
success: true,
|
|
801
1124
|
mode: 'replace',
|
|
@@ -1261,6 +1584,11 @@ let ProjectsService = class ProjectsService {
|
|
|
1261
1584
|
.replace(/[^a-z0-9]+/g, '-')
|
|
1262
1585
|
.replace(/(^-|-$)/g, '');
|
|
1263
1586
|
}
|
|
1587
|
+
deriveSlugFromPath(filePath) {
|
|
1588
|
+
const filename = (0, path_1.basename)(filePath);
|
|
1589
|
+
const nameWithoutExt = filename.replace(/\.json$/i, '');
|
|
1590
|
+
return this.slugify(nameWithoutExt);
|
|
1591
|
+
}
|
|
1264
1592
|
async getTemplateManifestForProject(projectId) {
|
|
1265
1593
|
const metadata = this.settings.getProjectTemplateMetadata(projectId);
|
|
1266
1594
|
if (!metadata?.templateSlug) {
|
|
@@ -1268,6 +1596,10 @@ let ProjectsService = class ProjectsService {
|
|
|
1268
1596
|
return null;
|
|
1269
1597
|
}
|
|
1270
1598
|
try {
|
|
1599
|
+
if (metadata.source === 'file') {
|
|
1600
|
+
logger.debug({ projectId, templateSlug: metadata.templateSlug }, 'File-based template - no manifest available');
|
|
1601
|
+
return null;
|
|
1602
|
+
}
|
|
1271
1603
|
if (metadata.source === 'bundled') {
|
|
1272
1604
|
const template = this.unifiedTemplateService.getBundledTemplate(metadata.templateSlug);
|
|
1273
1605
|
return template.content._manifest ?? null;
|