devchain-cli 0.4.6 → 0.5.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/dist/cli.js +7 -4
- package/dist/drizzle/0021_agent_profiles_family_slug.sql +3 -0
- package/dist/drizzle/meta/0021_snapshot.json +2968 -0
- package/dist/drizzle/meta/_journal.json +8 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +5 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts.map +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js +1 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.js.map +1 -1
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.d.ts +2 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.d.ts.map +1 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.js +88 -0
- package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.js.map +1 -0
- package/dist/node_modules/@devchain/shared/tsconfig.tsbuildinfo +1 -1
- package/dist/server/common/errors/error-types.d.ts +4 -0
- package/dist/server/common/errors/error-types.js +8 -1
- package/dist/server/common/errors/error-types.js.map +1 -1
- package/dist/server/modules/core/core.module.js +2 -1
- package/dist/server/modules/core/core.module.js.map +1 -1
- package/dist/server/modules/core/services/preflight.service.d.ts +4 -1
- package/dist/server/modules/core/services/preflight.service.js +8 -3
- package/dist/server/modules/core/services/preflight.service.js.map +1 -1
- package/dist/server/modules/epics/services/epics.service.js +0 -51
- package/dist/server/modules/epics/services/epics.service.js.map +1 -1
- package/dist/server/modules/events/catalog/epic.created.d.ts +2 -2
- package/dist/server/modules/events/catalog/index.d.ts +2 -27
- package/dist/server/modules/events/catalog/index.js +0 -2
- package/dist/server/modules/events/catalog/index.js.map +1 -1
- package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.d.ts +3 -0
- package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.js +87 -0
- package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.js.map +1 -1
- package/dist/server/modules/mcp/dtos/mcp.dto.d.ts +2 -2
- package/dist/server/modules/mcp/mcp.module.js +2 -34
- package/dist/server/modules/mcp/mcp.module.js.map +1 -1
- package/dist/server/modules/mcp/services/mcp-provider-registration.service.js +75 -31
- package/dist/server/modules/mcp/services/mcp-provider-registration.service.js.map +1 -1
- package/dist/server/modules/profiles/controllers/profiles.controller.d.ts +1 -0
- package/dist/server/modules/profiles/controllers/profiles.controller.js +13 -0
- package/dist/server/modules/profiles/controllers/profiles.controller.js.map +1 -1
- package/dist/server/modules/profiles/dto.d.ts +3 -0
- package/dist/server/modules/profiles/dto.js +1 -0
- package/dist/server/modules/profiles/dto.js.map +1 -1
- package/dist/server/modules/projects/controllers/projects.controller.d.ts +61 -11
- package/dist/server/modules/projects/controllers/projects.controller.js +81 -2
- package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
- package/dist/server/modules/projects/services/projects.service.d.ts +70 -10
- package/dist/server/modules/projects/services/projects.service.js +380 -22
- package/dist/server/modules/projects/services/projects.service.js.map +1 -1
- package/dist/server/modules/providers/adapters/claude.adapter.js +12 -2
- package/dist/server/modules/providers/adapters/claude.adapter.js.map +1 -1
- package/dist/server/modules/providers/adapters/codex.adapter.js +12 -2
- package/dist/server/modules/providers/adapters/codex.adapter.js.map +1 -1
- package/dist/server/modules/providers/adapters/gemini.adapter.d.ts +9 -0
- package/dist/server/modules/providers/adapters/gemini.adapter.js +56 -0
- package/dist/server/modules/providers/adapters/gemini.adapter.js.map +1 -0
- package/dist/server/modules/providers/adapters/index.d.ts +2 -0
- package/dist/server/modules/providers/adapters/index.js +2 -0
- package/dist/server/modules/providers/adapters/index.js.map +1 -1
- package/dist/server/modules/providers/adapters/provider-adapter.factory.d.ts +4 -1
- package/dist/server/modules/providers/adapters/provider-adapter.factory.js +13 -7
- package/dist/server/modules/providers/adapters/provider-adapter.factory.js.map +1 -1
- package/dist/server/modules/providers/adapters/provider-adapters.module.d.ts +2 -0
- package/dist/server/modules/providers/adapters/provider-adapters.module.js +24 -0
- package/dist/server/modules/providers/adapters/provider-adapters.module.js.map +1 -0
- package/dist/server/modules/providers/controllers/providers.controller.js +3 -4
- package/dist/server/modules/providers/controllers/providers.controller.js.map +1 -1
- package/dist/server/modules/providers/providers.module.js +1 -3
- package/dist/server/modules/providers/providers.module.js.map +1 -1
- package/dist/server/modules/registry/services/template-upgrade.service.d.ts +3 -1
- package/dist/server/modules/registry/services/template-upgrade.service.js +66 -17
- package/dist/server/modules/registry/services/template-upgrade.service.js.map +1 -1
- package/dist/server/modules/registry/services/unified-template.service.d.ts +1 -1
- package/dist/server/modules/registry/services/unified-template.service.js +17 -2
- package/dist/server/modules/registry/services/unified-template.service.js.map +1 -1
- package/dist/server/modules/sessions/services/sessions.service.js +1 -1
- package/dist/server/modules/storage/db/schema.d.ts +19 -0
- package/dist/server/modules/storage/db/schema.js +1 -0
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +1 -0
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/local-storage.service.js +10 -4
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +3 -1
- package/dist/server/templates/claude-codex-advanced.json +150 -120
- package/dist/server/templates/claude-opus.json +182 -79
- package/dist/server/templates/simple-codex.json +288 -74
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/index-Bgulh8ua.js +735 -0
- package/dist/server/ui/assets/{index-BkGGbapJ.css → index-BoDZOB7c.css} +1 -1
- package/dist/server/ui/index.html +2 -2
- package/dist/templates/claude-codex-advanced.json +150 -120
- package/dist/templates/claude-opus.json +182 -79
- package/dist/templates/simple-codex.json +288 -74
- package/package.json +10 -1
- package/dist/server/modules/events/catalog/epic.assigned.d.ts +0 -32
- package/dist/server/modules/events/catalog/epic.assigned.js +0 -19
- package/dist/server/modules/events/catalog/epic.assigned.js.map +0 -1
- package/dist/server/ui/assets/index-DLpDwHdv.js +0 -733
|
@@ -128,14 +128,28 @@ let ProjectsService = class ProjectsService {
|
|
|
128
128
|
hint: 'Template file does not match expected export schema',
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
const familyResult = await this.computeFamilyAlternatives(payload.profiles, payload.agents);
|
|
132
|
+
const needsMapping = familyResult.alternatives.some((alt) => !alt.defaultProviderAvailable);
|
|
133
|
+
if (needsMapping && !input.familyProviderMappings) {
|
|
134
|
+
return {
|
|
135
|
+
success: false,
|
|
136
|
+
providerMappingRequired: {
|
|
137
|
+
missingProviders: familyResult.missingProviders,
|
|
138
|
+
familyAlternatives: familyResult.alternatives,
|
|
139
|
+
canImport: familyResult.canImport,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (!familyResult.canImport) {
|
|
144
|
+
throw new error_types_1.ValidationError('Cannot import: some profile families have no available providers', {
|
|
145
|
+
hint: 'Install the required providers or use a different template',
|
|
146
|
+
missingProviders: familyResult.missingProviders,
|
|
147
|
+
familyAlternatives: familyResult.alternatives,
|
|
137
148
|
});
|
|
138
149
|
}
|
|
150
|
+
const providerNames = new Set((payload.profiles ?? []).map((p) => p.provider.name.trim().toLowerCase()));
|
|
151
|
+
const { available } = await this.resolveProviders(providerNames);
|
|
152
|
+
const selectedProfilesByFamily = this.selectProfilesForFamilies(payload.profiles, payload.agents, input.familyProviderMappings, available);
|
|
139
153
|
const templatePayload = {
|
|
140
154
|
prompts: payload.prompts.map((p) => ({
|
|
141
155
|
id: p.id,
|
|
@@ -144,7 +158,7 @@ let ProjectsService = class ProjectsService {
|
|
|
144
158
|
version: p.version,
|
|
145
159
|
tags: p.tags,
|
|
146
160
|
})),
|
|
147
|
-
profiles:
|
|
161
|
+
profiles: selectedProfilesByFamily.profilesToCreate.map((prof) => {
|
|
148
162
|
const providerId = available.get(prof.provider.name.trim().toLowerCase());
|
|
149
163
|
if (!providerId) {
|
|
150
164
|
throw new error_types_1.NotFoundError('Provider', prof.provider.name);
|
|
@@ -153,18 +167,22 @@ let ProjectsService = class ProjectsService {
|
|
|
153
167
|
id: prof.id,
|
|
154
168
|
name: prof.name,
|
|
155
169
|
providerId,
|
|
170
|
+
familySlug: prof.familySlug ?? null,
|
|
156
171
|
options: this.normalizeProfileOptions(prof.options),
|
|
157
172
|
instructions: prof.instructions ?? null,
|
|
158
173
|
temperature: prof.temperature ?? null,
|
|
159
174
|
maxTokens: prof.maxTokens ?? null,
|
|
160
175
|
};
|
|
161
176
|
}),
|
|
162
|
-
agents: payload.agents.map((a) =>
|
|
163
|
-
id
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
177
|
+
agents: payload.agents.map((a) => {
|
|
178
|
+
const remappedProfileId = selectedProfilesByFamily.agentProfileMap.get(a.id ?? '') ?? a.profileId;
|
|
179
|
+
return {
|
|
180
|
+
id: a.id,
|
|
181
|
+
name: a.name,
|
|
182
|
+
profileId: remappedProfileId,
|
|
183
|
+
description: a.description,
|
|
184
|
+
};
|
|
185
|
+
}),
|
|
168
186
|
statuses: payload.statuses.map((s) => ({
|
|
169
187
|
id: s.id,
|
|
170
188
|
label: s.label,
|
|
@@ -221,13 +239,16 @@ let ProjectsService = class ProjectsService {
|
|
|
221
239
|
agentNameToId: agentNameToNewId,
|
|
222
240
|
profileNameToId: profileNameToNewId,
|
|
223
241
|
providerNameToId: available,
|
|
242
|
+
profileNameRemapMap: selectedProfilesByFamily.profileNameRemapMap,
|
|
224
243
|
});
|
|
225
244
|
const { created: subscribersCreated } = await this.createSubscribersFromPayload(result.project.id, payload.subscribers);
|
|
245
|
+
const manifestVersion = payload._manifest?.version ?? null;
|
|
246
|
+
const installedVersion = templateResult.version ?? manifestVersion;
|
|
226
247
|
const registryConfig = this.settings.getRegistryConfig();
|
|
227
248
|
await this.settings.setProjectTemplateMetadata(result.project.id, {
|
|
228
249
|
templateSlug: input.slug,
|
|
229
250
|
source: templateResult.source,
|
|
230
|
-
installedVersion
|
|
251
|
+
installedVersion,
|
|
231
252
|
registryUrl: templateResult.source === 'registry' ? registryConfig.url : null,
|
|
232
253
|
installedAt: new Date().toISOString(),
|
|
233
254
|
});
|
|
@@ -235,7 +256,7 @@ let ProjectsService = class ProjectsService {
|
|
|
235
256
|
projectId: result.project.id,
|
|
236
257
|
slug: input.slug,
|
|
237
258
|
source: templateResult.source,
|
|
238
|
-
version:
|
|
259
|
+
version: installedVersion,
|
|
239
260
|
}, 'Template metadata set for project');
|
|
240
261
|
return {
|
|
241
262
|
success: true,
|
|
@@ -324,6 +345,7 @@ let ProjectsService = class ProjectsService {
|
|
|
324
345
|
id: prof.id,
|
|
325
346
|
name: prof.name,
|
|
326
347
|
provider: { id: provider.id, name: provider.name },
|
|
348
|
+
familySlug: prof.familySlug,
|
|
327
349
|
options: sanitizeOptionsString(prof.options),
|
|
328
350
|
instructions: prof.instructions,
|
|
329
351
|
temperature: prof.temperature,
|
|
@@ -452,8 +474,11 @@ let ProjectsService = class ProjectsService {
|
|
|
452
474
|
logger.info({ projectId: input.projectId, dryRun: input.dryRun }, 'importProject');
|
|
453
475
|
const isDryRun = input.dryRun ?? false;
|
|
454
476
|
const payload = shared_1.ExportSchema.parse(input.payload ?? {});
|
|
477
|
+
const familyResult = await this.computeFamilyAlternatives(payload.profiles, payload.agents);
|
|
478
|
+
const needsMapping = familyResult.alternatives.some((alt) => !alt.defaultProviderAvailable);
|
|
455
479
|
const providerNames = new Set((payload.profiles ?? []).map((p) => p.provider.name.trim().toLowerCase()));
|
|
456
480
|
const { available, missing: missingProviders } = await this.resolveProviders(providerNames);
|
|
481
|
+
const selectedProfilesByFamily = this.selectProfilesForFamilies(payload.profiles, payload.agents, input.familyProviderMappings, available);
|
|
457
482
|
const [existingPrompts, existingProfiles, existingAgents, existingStatuses, existingWatchers, existingSubscribers,] = await Promise.all([
|
|
458
483
|
this.storage.listPrompts({ projectId: input.projectId, limit: 10000, offset: 0 }),
|
|
459
484
|
this.storage.listAgentProfiles({ projectId: input.projectId, limit: 10000, offset: 0 }),
|
|
@@ -479,7 +504,7 @@ let ProjectsService = class ProjectsService {
|
|
|
479
504
|
}
|
|
480
505
|
}
|
|
481
506
|
if (isDryRun) {
|
|
482
|
-
|
|
507
|
+
const dryRunResponse = {
|
|
483
508
|
dryRun: true,
|
|
484
509
|
missingProviders,
|
|
485
510
|
unmatchedStatuses,
|
|
@@ -490,7 +515,7 @@ let ProjectsService = class ProjectsService {
|
|
|
490
515
|
counts: {
|
|
491
516
|
toImport: {
|
|
492
517
|
prompts: payload.prompts.length,
|
|
493
|
-
profiles:
|
|
518
|
+
profiles: selectedProfilesByFamily.profilesToCreate.length,
|
|
494
519
|
agents: payload.agents.length,
|
|
495
520
|
statuses: payload.statuses.length,
|
|
496
521
|
watchers: payload.watchers.length,
|
|
@@ -506,10 +531,37 @@ let ProjectsService = class ProjectsService {
|
|
|
506
531
|
},
|
|
507
532
|
},
|
|
508
533
|
};
|
|
534
|
+
if (needsMapping && !input.familyProviderMappings) {
|
|
535
|
+
dryRunResponse.providerMappingRequired = {
|
|
536
|
+
missingProviders: familyResult.missingProviders,
|
|
537
|
+
familyAlternatives: familyResult.alternatives,
|
|
538
|
+
canImport: familyResult.canImport,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
return dryRunResponse;
|
|
509
542
|
}
|
|
510
|
-
if (
|
|
543
|
+
if (needsMapping && !input.familyProviderMappings) {
|
|
544
|
+
return {
|
|
545
|
+
success: false,
|
|
546
|
+
providerMappingRequired: {
|
|
547
|
+
missingProviders: familyResult.missingProviders,
|
|
548
|
+
familyAlternatives: familyResult.alternatives,
|
|
549
|
+
canImport: familyResult.canImport,
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
if (!familyResult.canImport) {
|
|
554
|
+
throw new error_types_1.ValidationError('Cannot import: some profile families have no available providers', {
|
|
555
|
+
hint: 'Install the required providers or use a different template',
|
|
556
|
+
missingProviders: familyResult.missingProviders,
|
|
557
|
+
familyAlternatives: familyResult.alternatives,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
const selectedProviderNames = new Set(selectedProfilesByFamily.profilesToCreate.map((p) => p.provider.name.trim().toLowerCase()));
|
|
561
|
+
const unavailableSelectedProviders = Array.from(selectedProviderNames).filter((name) => !available.has(name));
|
|
562
|
+
if (unavailableSelectedProviders.length > 0) {
|
|
511
563
|
throw new error_types_1.ValidationError('Import aborted: missing providers', {
|
|
512
|
-
missingProviders,
|
|
564
|
+
missingProviders: unavailableSelectedProviders,
|
|
513
565
|
hint: 'Install/configure providers by name before importing profiles.',
|
|
514
566
|
});
|
|
515
567
|
}
|
|
@@ -615,7 +667,7 @@ let ProjectsService = class ProjectsService {
|
|
|
615
667
|
promptIdMap[p.id] = created.id;
|
|
616
668
|
createdPrompts.push({ id: created.id, title: created.title });
|
|
617
669
|
}
|
|
618
|
-
for (const prof of
|
|
670
|
+
for (const prof of selectedProfilesByFamily.profilesToCreate) {
|
|
619
671
|
const providerId = available.get(prof.provider.name.trim().toLowerCase());
|
|
620
672
|
if (!providerId) {
|
|
621
673
|
throw new error_types_1.NotFoundError('Provider', prof.provider.name);
|
|
@@ -624,6 +676,7 @@ let ProjectsService = class ProjectsService {
|
|
|
624
676
|
projectId: input.projectId,
|
|
625
677
|
name: prof.name,
|
|
626
678
|
providerId,
|
|
679
|
+
familySlug: prof.familySlug ?? null,
|
|
627
680
|
options: this.normalizeProfileOptions(prof.options),
|
|
628
681
|
systemPrompt: null,
|
|
629
682
|
instructions: prof.instructions ?? null,
|
|
@@ -634,7 +687,8 @@ let ProjectsService = class ProjectsService {
|
|
|
634
687
|
profileIdMap[profKey] = created.id;
|
|
635
688
|
}
|
|
636
689
|
for (const a of payload.agents) {
|
|
637
|
-
const
|
|
690
|
+
const remappedProfileId = selectedProfilesByFamily.agentProfileMap.get(a.id ?? '');
|
|
691
|
+
const oldProfileId = remappedProfileId ?? a.profileId ?? '';
|
|
638
692
|
const newProfileId = oldProfileId && profileIdMap[oldProfileId] ? profileIdMap[oldProfileId] : undefined;
|
|
639
693
|
if (!newProfileId) {
|
|
640
694
|
throw new error_types_1.ValidationError(`Profile mapping missing for agent ${a.name}`, {
|
|
@@ -655,7 +709,7 @@ let ProjectsService = class ProjectsService {
|
|
|
655
709
|
...a,
|
|
656
710
|
id: a.id || `name:${a.name.trim().toLowerCase()}`,
|
|
657
711
|
})),
|
|
658
|
-
profiles:
|
|
712
|
+
profiles: selectedProfilesByFamily.profilesToCreate.map((p) => ({
|
|
659
713
|
...p,
|
|
660
714
|
id: p.id || `name:${p.name.trim().toLowerCase()}`,
|
|
661
715
|
})),
|
|
@@ -665,6 +719,7 @@ let ProjectsService = class ProjectsService {
|
|
|
665
719
|
agentNameToId: agentNameToNewId,
|
|
666
720
|
profileNameToId: profileNameToNewId,
|
|
667
721
|
providerNameToId: available,
|
|
722
|
+
profileNameRemapMap: selectedProfilesByFamily.profileNameRemapMap,
|
|
668
723
|
});
|
|
669
724
|
const { subscriberIdMap } = await this.createSubscribersFromPayload(input.projectId, payload.subscribers);
|
|
670
725
|
logger.info({
|
|
@@ -723,6 +778,24 @@ let ProjectsService = class ProjectsService {
|
|
|
723
778
|
const archiveStatusId = templateLabelToStatusId.get('archive') ?? null;
|
|
724
779
|
const settingsResult = await this.applyProjectSettings(input.projectId, mergedSettings, { promptTitleToId, statusLabelToId: templateLabelToStatusId }, archiveStatusId);
|
|
725
780
|
const initialPromptSet = settingsResult.initialPromptSet;
|
|
781
|
+
if (payload._manifest?.slug) {
|
|
782
|
+
let templateSource = 'registry';
|
|
783
|
+
try {
|
|
784
|
+
this.unifiedTemplateService.getBundledTemplate(payload._manifest.slug);
|
|
785
|
+
templateSource = 'bundled';
|
|
786
|
+
}
|
|
787
|
+
catch {
|
|
788
|
+
templateSource = 'registry';
|
|
789
|
+
}
|
|
790
|
+
await this.settings.setProjectTemplateMetadata(input.projectId, {
|
|
791
|
+
templateSlug: payload._manifest.slug,
|
|
792
|
+
source: templateSource,
|
|
793
|
+
installedVersion: payload._manifest.version ?? null,
|
|
794
|
+
registryUrl: null,
|
|
795
|
+
installedAt: new Date().toISOString(),
|
|
796
|
+
});
|
|
797
|
+
logger.info({ projectId: input.projectId, slug: payload._manifest.slug, source: templateSource }, 'Updated template metadata after import');
|
|
798
|
+
}
|
|
726
799
|
return {
|
|
727
800
|
success: true,
|
|
728
801
|
mode: 'replace',
|
|
@@ -778,6 +851,181 @@ let ProjectsService = class ProjectsService {
|
|
|
778
851
|
const missing = Array.from(providerNames).filter((n) => !available.has(n));
|
|
779
852
|
return { available, missing };
|
|
780
853
|
}
|
|
854
|
+
async computeFamilyAlternatives(templateProfiles, templateAgents) {
|
|
855
|
+
const localProviders = await this.storage.listProviders();
|
|
856
|
+
const availableProviderNames = new Set(localProviders.items.map((p) => p.name.trim().toLowerCase()));
|
|
857
|
+
const profileById = new Map();
|
|
858
|
+
for (const prof of templateProfiles) {
|
|
859
|
+
if (prof.id) {
|
|
860
|
+
profileById.set(prof.id, prof);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const usedFamilySlugs = new Set();
|
|
864
|
+
for (const agent of templateAgents) {
|
|
865
|
+
if (agent.profileId) {
|
|
866
|
+
const profile = profileById.get(agent.profileId);
|
|
867
|
+
if (profile?.familySlug) {
|
|
868
|
+
usedFamilySlugs.add(profile.familySlug);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const familyProviders = new Map();
|
|
873
|
+
for (const prof of templateProfiles) {
|
|
874
|
+
const familySlug = prof.familySlug;
|
|
875
|
+
if (!familySlug)
|
|
876
|
+
continue;
|
|
877
|
+
if (!familyProviders.has(familySlug)) {
|
|
878
|
+
familyProviders.set(familySlug, new Map());
|
|
879
|
+
}
|
|
880
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
881
|
+
const familyMap = familyProviders.get(familySlug);
|
|
882
|
+
if (!familyMap.has(providerName)) {
|
|
883
|
+
familyMap.set(providerName, []);
|
|
884
|
+
}
|
|
885
|
+
familyMap.get(providerName).push(prof.name);
|
|
886
|
+
}
|
|
887
|
+
const alternatives = [];
|
|
888
|
+
const allMissingProviders = new Set();
|
|
889
|
+
let canImport = true;
|
|
890
|
+
for (const familySlug of usedFamilySlugs) {
|
|
891
|
+
const providersForFamily = familyProviders.get(familySlug);
|
|
892
|
+
if (!providersForFamily || providersForFamily.size === 0) {
|
|
893
|
+
logger.warn({ familySlug }, 'Family used by agent has no profiles');
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
const providerNamesForFamily = Array.from(providersForFamily.keys());
|
|
897
|
+
const defaultProvider = providerNamesForFamily[0];
|
|
898
|
+
const defaultProviderAvailable = availableProviderNames.has(defaultProvider);
|
|
899
|
+
const availableForFamily = providerNamesForFamily.filter((name) => availableProviderNames.has(name));
|
|
900
|
+
for (const provName of providerNamesForFamily) {
|
|
901
|
+
if (!availableProviderNames.has(provName)) {
|
|
902
|
+
allMissingProviders.add(provName);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const hasAlternatives = availableForFamily.length > 0;
|
|
906
|
+
if (!hasAlternatives) {
|
|
907
|
+
canImport = false;
|
|
908
|
+
}
|
|
909
|
+
alternatives.push({
|
|
910
|
+
familySlug,
|
|
911
|
+
defaultProvider,
|
|
912
|
+
defaultProviderAvailable,
|
|
913
|
+
availableProviders: availableForFamily.sort(),
|
|
914
|
+
hasAlternatives,
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
return {
|
|
918
|
+
alternatives,
|
|
919
|
+
missingProviders: Array.from(allMissingProviders).sort(),
|
|
920
|
+
canImport,
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
selectProfilesForFamilies(templateProfiles, templateAgents, familyProviderMappings, availableProviders) {
|
|
924
|
+
const profileById = new Map();
|
|
925
|
+
for (const prof of templateProfiles) {
|
|
926
|
+
if (prof.id) {
|
|
927
|
+
profileById.set(prof.id, prof);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const profilesByFamilyAndProvider = new Map();
|
|
931
|
+
for (const prof of templateProfiles) {
|
|
932
|
+
if (!prof.familySlug)
|
|
933
|
+
continue;
|
|
934
|
+
const family = prof.familySlug;
|
|
935
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
936
|
+
if (!profilesByFamilyAndProvider.has(family)) {
|
|
937
|
+
profilesByFamilyAndProvider.set(family, new Map());
|
|
938
|
+
}
|
|
939
|
+
const familyMap = profilesByFamilyAndProvider.get(family);
|
|
940
|
+
if (!familyMap.has(providerName)) {
|
|
941
|
+
familyMap.set(providerName, prof);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
const familyOriginalProviders = new Map();
|
|
945
|
+
for (const agent of templateAgents) {
|
|
946
|
+
if (!agent.profileId)
|
|
947
|
+
continue;
|
|
948
|
+
const profile = profileById.get(agent.profileId);
|
|
949
|
+
if (!profile?.familySlug)
|
|
950
|
+
continue;
|
|
951
|
+
const providerName = profile.provider.name.trim().toLowerCase();
|
|
952
|
+
familyOriginalProviders.set(profile.familySlug, providerName);
|
|
953
|
+
}
|
|
954
|
+
const selectedProfileIdsByFamily = new Map();
|
|
955
|
+
for (const [familySlug, providerMap] of profilesByFamilyAndProvider) {
|
|
956
|
+
let selectedProvider;
|
|
957
|
+
if (familyProviderMappings?.[familySlug]) {
|
|
958
|
+
selectedProvider = familyProviderMappings[familySlug].trim().toLowerCase();
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
const originalProvider = familyOriginalProviders.get(familySlug);
|
|
962
|
+
if (originalProvider &&
|
|
963
|
+
availableProviders.has(originalProvider) &&
|
|
964
|
+
providerMap.has(originalProvider)) {
|
|
965
|
+
selectedProvider = originalProvider;
|
|
966
|
+
}
|
|
967
|
+
else {
|
|
968
|
+
for (const provName of providerMap.keys()) {
|
|
969
|
+
if (availableProviders.has(provName)) {
|
|
970
|
+
selectedProvider = provName;
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (selectedProvider && providerMap.has(selectedProvider)) {
|
|
977
|
+
const profile = providerMap.get(selectedProvider);
|
|
978
|
+
if (profile.id) {
|
|
979
|
+
selectedProfileIdsByFamily.set(familySlug, profile.id);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
const profilesToCreate = [];
|
|
984
|
+
const usedProfileIds = new Set();
|
|
985
|
+
for (const prof of templateProfiles) {
|
|
986
|
+
if (!prof.id || usedProfileIds.has(prof.id))
|
|
987
|
+
continue;
|
|
988
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
989
|
+
if (availableProviders.has(providerName)) {
|
|
990
|
+
usedProfileIds.add(prof.id);
|
|
991
|
+
profilesToCreate.push(prof);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
const agentProfileMap = new Map();
|
|
995
|
+
for (const agent of templateAgents) {
|
|
996
|
+
if (!agent.id || !agent.profileId)
|
|
997
|
+
continue;
|
|
998
|
+
const originalProfile = profileById.get(agent.profileId);
|
|
999
|
+
if (!originalProfile) {
|
|
1000
|
+
agentProfileMap.set(agent.id, agent.profileId);
|
|
1001
|
+
continue;
|
|
1002
|
+
}
|
|
1003
|
+
if (originalProfile.familySlug) {
|
|
1004
|
+
const selectedProfileId = selectedProfileIdsByFamily.get(originalProfile.familySlug);
|
|
1005
|
+
agentProfileMap.set(agent.id, selectedProfileId ?? agent.profileId);
|
|
1006
|
+
}
|
|
1007
|
+
else {
|
|
1008
|
+
agentProfileMap.set(agent.id, agent.profileId);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
const profileNameRemapMap = new Map();
|
|
1012
|
+
for (const [familySlug, providerMap] of profilesByFamilyAndProvider) {
|
|
1013
|
+
const selectedProfileId = selectedProfileIdsByFamily.get(familySlug);
|
|
1014
|
+
const selectedProfile = selectedProfileId
|
|
1015
|
+
? templateProfiles.find((p) => p.id === selectedProfileId)
|
|
1016
|
+
: undefined;
|
|
1017
|
+
if (selectedProfile) {
|
|
1018
|
+
const selectedNameLower = selectedProfile.name.trim().toLowerCase();
|
|
1019
|
+
for (const profile of providerMap.values()) {
|
|
1020
|
+
const profileNameLower = profile.name.trim().toLowerCase();
|
|
1021
|
+
if (profileNameLower !== selectedNameLower) {
|
|
1022
|
+
profileNameRemapMap.set(profileNameLower, selectedNameLower);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return { profilesToCreate, agentProfileMap, profileNameRemapMap };
|
|
1028
|
+
}
|
|
781
1029
|
buildNameToIdMaps(payload, mappings) {
|
|
782
1030
|
const agentNameToId = new Map();
|
|
783
1031
|
for (const a of payload.agents) {
|
|
@@ -823,6 +1071,20 @@ let ProjectsService = class ProjectsService {
|
|
|
823
1071
|
}
|
|
824
1072
|
case 'profile': {
|
|
825
1073
|
scopeFilterId = maps.profileNameToId.get(scopeFilterNameLower) ?? null;
|
|
1074
|
+
if (!scopeFilterId && maps.profileNameRemapMap) {
|
|
1075
|
+
const remappedName = maps.profileNameRemapMap.get(scopeFilterNameLower);
|
|
1076
|
+
if (remappedName) {
|
|
1077
|
+
scopeFilterId = maps.profileNameToId.get(remappedName) ?? null;
|
|
1078
|
+
if (scopeFilterId) {
|
|
1079
|
+
logger.info({
|
|
1080
|
+
projectId,
|
|
1081
|
+
watcherName: w.name,
|
|
1082
|
+
originalProfile: w.scopeFilterName,
|
|
1083
|
+
remappedProfile: remappedName,
|
|
1084
|
+
}, 'Watcher profile scope remapped due to provider family selection');
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
826
1088
|
break;
|
|
827
1089
|
}
|
|
828
1090
|
case 'provider': {
|
|
@@ -999,6 +1261,102 @@ let ProjectsService = class ProjectsService {
|
|
|
999
1261
|
.replace(/[^a-z0-9]+/g, '-')
|
|
1000
1262
|
.replace(/(^-|-$)/g, '');
|
|
1001
1263
|
}
|
|
1264
|
+
async getTemplateManifestForProject(projectId) {
|
|
1265
|
+
const metadata = this.settings.getProjectTemplateMetadata(projectId);
|
|
1266
|
+
if (!metadata?.templateSlug) {
|
|
1267
|
+
logger.debug({ projectId }, 'No template metadata for project');
|
|
1268
|
+
return null;
|
|
1269
|
+
}
|
|
1270
|
+
try {
|
|
1271
|
+
if (metadata.source === 'bundled') {
|
|
1272
|
+
const template = this.unifiedTemplateService.getBundledTemplate(metadata.templateSlug);
|
|
1273
|
+
return template.content._manifest ?? null;
|
|
1274
|
+
}
|
|
1275
|
+
else {
|
|
1276
|
+
const template = await this.unifiedTemplateService.getTemplate(metadata.templateSlug, metadata.installedVersion ?? undefined);
|
|
1277
|
+
if (template.source !== 'registry') {
|
|
1278
|
+
logger.debug({
|
|
1279
|
+
projectId,
|
|
1280
|
+
templateSlug: metadata.templateSlug,
|
|
1281
|
+
expectedSource: 'registry',
|
|
1282
|
+
actualSource: template.source,
|
|
1283
|
+
}, 'Template source mismatch - registry template not available, rejecting bundled fallback');
|
|
1284
|
+
return null;
|
|
1285
|
+
}
|
|
1286
|
+
return template.content._manifest ?? null;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
catch (error) {
|
|
1290
|
+
logger.debug({ projectId, templateSlug: metadata.templateSlug, error }, 'Failed to fetch template manifest for project');
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
getBundledUpgradeVersion(templateSlug, installedVersion) {
|
|
1295
|
+
if (!installedVersion) {
|
|
1296
|
+
return null;
|
|
1297
|
+
}
|
|
1298
|
+
try {
|
|
1299
|
+
const bundled = this.unifiedTemplateService.getBundledTemplate(templateSlug);
|
|
1300
|
+
const manifest = bundled.content._manifest;
|
|
1301
|
+
const bundledVersion = manifest?.version;
|
|
1302
|
+
if (!bundledVersion) {
|
|
1303
|
+
return null;
|
|
1304
|
+
}
|
|
1305
|
+
if (!(0, shared_1.isValidSemVer)(installedVersion) || !(0, shared_1.isValidSemVer)(bundledVersion)) {
|
|
1306
|
+
logger.warn({ templateSlug, installedVersion, bundledVersion }, 'Invalid semver version detected, skipping upgrade check');
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
if ((0, shared_1.isLessThan)(installedVersion, bundledVersion)) {
|
|
1310
|
+
return bundledVersion;
|
|
1311
|
+
}
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
catch {
|
|
1315
|
+
return null;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
getBundledUpgradesForProjects(projects) {
|
|
1319
|
+
const result = new Map();
|
|
1320
|
+
const bundledVersionCache = new Map();
|
|
1321
|
+
for (const project of projects) {
|
|
1322
|
+
if (project.source !== 'bundled' || !project.templateSlug) {
|
|
1323
|
+
result.set(project.projectId, null);
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
if (!bundledVersionCache.has(project.templateSlug)) {
|
|
1327
|
+
try {
|
|
1328
|
+
const bundled = this.unifiedTemplateService.getBundledTemplate(project.templateSlug);
|
|
1329
|
+
const manifest = bundled.content._manifest;
|
|
1330
|
+
bundledVersionCache.set(project.templateSlug, manifest?.version ?? null);
|
|
1331
|
+
}
|
|
1332
|
+
catch {
|
|
1333
|
+
bundledVersionCache.set(project.templateSlug, null);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
const bundledVersion = bundledVersionCache.get(project.templateSlug);
|
|
1337
|
+
if (!bundledVersion || !project.installedVersion) {
|
|
1338
|
+
result.set(project.projectId, null);
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
if (!(0, shared_1.isValidSemVer)(project.installedVersion) || !(0, shared_1.isValidSemVer)(bundledVersion)) {
|
|
1342
|
+
logger.warn({
|
|
1343
|
+
projectId: project.projectId,
|
|
1344
|
+
templateSlug: project.templateSlug,
|
|
1345
|
+
installedVersion: project.installedVersion,
|
|
1346
|
+
bundledVersion,
|
|
1347
|
+
}, 'Invalid semver version detected, skipping upgrade check');
|
|
1348
|
+
result.set(project.projectId, null);
|
|
1349
|
+
continue;
|
|
1350
|
+
}
|
|
1351
|
+
if ((0, shared_1.isLessThan)(project.installedVersion, bundledVersion)) {
|
|
1352
|
+
result.set(project.projectId, bundledVersion);
|
|
1353
|
+
}
|
|
1354
|
+
else {
|
|
1355
|
+
result.set(project.projectId, null);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
return result;
|
|
1359
|
+
}
|
|
1002
1360
|
};
|
|
1003
1361
|
exports.ProjectsService = ProjectsService;
|
|
1004
1362
|
exports.ProjectsService = ProjectsService = __decorate([
|