devchain-cli 0.4.6 → 0.5.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/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 +59 -11
- package/dist/server/modules/projects/controllers/projects.controller.js +70 -2
- package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
- package/dist/server/modules/projects/services/projects.service.d.ts +63 -10
- package/dist/server/modules/projects/services/projects.service.js +310 -20
- 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/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-BkGGbapJ.css → index-BoDZOB7c.css} +1 -1
- package/dist/server/ui/assets/index-CvNs6-rV.js +735 -0
- 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 +6 -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
|
@@ -15,12 +15,31 @@ export interface CreateFromTemplateInput {
|
|
|
15
15
|
rootPath: string;
|
|
16
16
|
slug: string;
|
|
17
17
|
version?: string | null;
|
|
18
|
+
familyProviderMappings?: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export interface ProviderMappingRequired {
|
|
21
|
+
missingProviders: string[];
|
|
22
|
+
familyAlternatives: FamilyAlternative[];
|
|
23
|
+
canImport: boolean;
|
|
18
24
|
}
|
|
19
25
|
export interface ImportProjectInput {
|
|
20
26
|
projectId: string;
|
|
21
27
|
payload: unknown;
|
|
22
28
|
dryRun?: boolean;
|
|
23
29
|
statusMappings?: Record<string, string>;
|
|
30
|
+
familyProviderMappings?: Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
export interface FamilyAlternative {
|
|
33
|
+
familySlug: string;
|
|
34
|
+
defaultProvider: string;
|
|
35
|
+
defaultProviderAvailable: boolean;
|
|
36
|
+
availableProviders: string[];
|
|
37
|
+
hasAlternatives: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface FamilyAlternativesResult {
|
|
40
|
+
alternatives: FamilyAlternative[];
|
|
41
|
+
missingProviders: string[];
|
|
42
|
+
canImport: boolean;
|
|
24
43
|
}
|
|
25
44
|
export declare class ProjectsService {
|
|
26
45
|
private readonly storage;
|
|
@@ -34,6 +53,18 @@ export declare class ProjectsService {
|
|
|
34
53
|
listTemplates(): Promise<TemplateInfo[]>;
|
|
35
54
|
getTemplateContent(templateId: string): Promise<unknown>;
|
|
36
55
|
createFromTemplate(input: CreateFromTemplateInput): Promise<{
|
|
56
|
+
success: boolean;
|
|
57
|
+
providerMappingRequired: {
|
|
58
|
+
missingProviders: string[];
|
|
59
|
+
familyAlternatives: FamilyAlternative[];
|
|
60
|
+
canImport: boolean;
|
|
61
|
+
};
|
|
62
|
+
project?: undefined;
|
|
63
|
+
imported?: undefined;
|
|
64
|
+
mappings?: undefined;
|
|
65
|
+
initialPromptSet?: undefined;
|
|
66
|
+
message?: undefined;
|
|
67
|
+
} | {
|
|
37
68
|
success: boolean;
|
|
38
69
|
project: import("../../storage/models/domain.models").Project;
|
|
39
70
|
imported: {
|
|
@@ -52,6 +83,7 @@ export declare class ProjectsService {
|
|
|
52
83
|
};
|
|
53
84
|
initialPromptSet: boolean;
|
|
54
85
|
message: string;
|
|
86
|
+
providerMappingRequired?: undefined;
|
|
55
87
|
}>;
|
|
56
88
|
exportProject(projectId: string, opts?: {
|
|
57
89
|
manifestOverrides?: Partial<ManifestData>;
|
|
@@ -128,6 +160,7 @@ export declare class ProjectsService {
|
|
|
128
160
|
id: string;
|
|
129
161
|
name: string;
|
|
130
162
|
};
|
|
163
|
+
familySlug: string | null;
|
|
131
164
|
options: string | null;
|
|
132
165
|
instructions: string | null;
|
|
133
166
|
temperature: number | null;
|
|
@@ -152,7 +185,7 @@ export declare class ProjectsService {
|
|
|
152
185
|
} | null;
|
|
153
186
|
}>;
|
|
154
187
|
importProject(input: ImportProjectInput): Promise<{
|
|
155
|
-
dryRun:
|
|
188
|
+
dryRun: true;
|
|
156
189
|
missingProviders: string[];
|
|
157
190
|
unmatchedStatuses: {
|
|
158
191
|
id: string;
|
|
@@ -164,6 +197,11 @@ export declare class ProjectsService {
|
|
|
164
197
|
label: string;
|
|
165
198
|
color: string;
|
|
166
199
|
}[];
|
|
200
|
+
providerMappingRequired?: {
|
|
201
|
+
missingProviders: string[];
|
|
202
|
+
familyAlternatives: FamilyAlternative[];
|
|
203
|
+
canImport: boolean;
|
|
204
|
+
};
|
|
167
205
|
counts: {
|
|
168
206
|
toImport: {
|
|
169
207
|
prompts: number;
|
|
@@ -181,13 +219,18 @@ export declare class ProjectsService {
|
|
|
181
219
|
watchers: number;
|
|
182
220
|
subscribers: number;
|
|
183
221
|
};
|
|
184
|
-
imported?: undefined;
|
|
185
|
-
deleted?: undefined;
|
|
186
|
-
epics?: undefined;
|
|
187
222
|
};
|
|
188
|
-
|
|
223
|
+
} | {
|
|
224
|
+
success: boolean;
|
|
225
|
+
providerMappingRequired: {
|
|
226
|
+
missingProviders: string[];
|
|
227
|
+
familyAlternatives: FamilyAlternative[];
|
|
228
|
+
canImport: boolean;
|
|
229
|
+
};
|
|
189
230
|
mode?: undefined;
|
|
190
231
|
replaced?: undefined;
|
|
232
|
+
missingProviders?: undefined;
|
|
233
|
+
counts?: undefined;
|
|
191
234
|
mappings?: undefined;
|
|
192
235
|
initialPromptSet?: undefined;
|
|
193
236
|
message?: undefined;
|
|
@@ -218,8 +261,6 @@ export declare class ProjectsService {
|
|
|
218
261
|
agentRemapped: number;
|
|
219
262
|
agentCleared: number;
|
|
220
263
|
};
|
|
221
|
-
toImport?: undefined;
|
|
222
|
-
toDelete?: undefined;
|
|
223
264
|
};
|
|
224
265
|
mappings: {
|
|
225
266
|
promptIdMap: Record<string, string>;
|
|
@@ -231,11 +272,22 @@ export declare class ProjectsService {
|
|
|
231
272
|
};
|
|
232
273
|
initialPromptSet: boolean;
|
|
233
274
|
message: string;
|
|
234
|
-
|
|
235
|
-
unmatchedStatuses?: undefined;
|
|
236
|
-
templateStatuses?: undefined;
|
|
275
|
+
providerMappingRequired?: undefined;
|
|
237
276
|
}>;
|
|
238
277
|
private resolveProviders;
|
|
278
|
+
computeFamilyAlternatives(templateProfiles: Array<{
|
|
279
|
+
id?: string;
|
|
280
|
+
name: string;
|
|
281
|
+
provider: {
|
|
282
|
+
name: string;
|
|
283
|
+
};
|
|
284
|
+
familySlug?: string | null;
|
|
285
|
+
}>, templateAgents: Array<{
|
|
286
|
+
id?: string;
|
|
287
|
+
name: string;
|
|
288
|
+
profileId?: string;
|
|
289
|
+
}>): Promise<FamilyAlternativesResult>;
|
|
290
|
+
private selectProfilesForFamilies;
|
|
239
291
|
private buildNameToIdMaps;
|
|
240
292
|
private createWatchersFromPayload;
|
|
241
293
|
private createSubscribersFromPayload;
|
|
@@ -243,4 +295,5 @@ export declare class ProjectsService {
|
|
|
243
295
|
private normalizeProfileOptions;
|
|
244
296
|
private getImportErrorMessage;
|
|
245
297
|
private slugify;
|
|
298
|
+
getTemplateManifestForProject(projectId: string): Promise<ManifestData | null>;
|
|
246
299
|
}
|
|
@@ -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,6 +239,7 @@ 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);
|
|
226
245
|
const registryConfig = this.settings.getRegistryConfig();
|
|
@@ -324,6 +343,7 @@ let ProjectsService = class ProjectsService {
|
|
|
324
343
|
id: prof.id,
|
|
325
344
|
name: prof.name,
|
|
326
345
|
provider: { id: provider.id, name: provider.name },
|
|
346
|
+
familySlug: prof.familySlug,
|
|
327
347
|
options: sanitizeOptionsString(prof.options),
|
|
328
348
|
instructions: prof.instructions,
|
|
329
349
|
temperature: prof.temperature,
|
|
@@ -452,8 +472,11 @@ let ProjectsService = class ProjectsService {
|
|
|
452
472
|
logger.info({ projectId: input.projectId, dryRun: input.dryRun }, 'importProject');
|
|
453
473
|
const isDryRun = input.dryRun ?? false;
|
|
454
474
|
const payload = shared_1.ExportSchema.parse(input.payload ?? {});
|
|
475
|
+
const familyResult = await this.computeFamilyAlternatives(payload.profiles, payload.agents);
|
|
476
|
+
const needsMapping = familyResult.alternatives.some((alt) => !alt.defaultProviderAvailable);
|
|
455
477
|
const providerNames = new Set((payload.profiles ?? []).map((p) => p.provider.name.trim().toLowerCase()));
|
|
456
478
|
const { available, missing: missingProviders } = await this.resolveProviders(providerNames);
|
|
479
|
+
const selectedProfilesByFamily = this.selectProfilesForFamilies(payload.profiles, payload.agents, input.familyProviderMappings, available);
|
|
457
480
|
const [existingPrompts, existingProfiles, existingAgents, existingStatuses, existingWatchers, existingSubscribers,] = await Promise.all([
|
|
458
481
|
this.storage.listPrompts({ projectId: input.projectId, limit: 10000, offset: 0 }),
|
|
459
482
|
this.storage.listAgentProfiles({ projectId: input.projectId, limit: 10000, offset: 0 }),
|
|
@@ -479,7 +502,7 @@ let ProjectsService = class ProjectsService {
|
|
|
479
502
|
}
|
|
480
503
|
}
|
|
481
504
|
if (isDryRun) {
|
|
482
|
-
|
|
505
|
+
const dryRunResponse = {
|
|
483
506
|
dryRun: true,
|
|
484
507
|
missingProviders,
|
|
485
508
|
unmatchedStatuses,
|
|
@@ -490,7 +513,7 @@ let ProjectsService = class ProjectsService {
|
|
|
490
513
|
counts: {
|
|
491
514
|
toImport: {
|
|
492
515
|
prompts: payload.prompts.length,
|
|
493
|
-
profiles:
|
|
516
|
+
profiles: selectedProfilesByFamily.profilesToCreate.length,
|
|
494
517
|
agents: payload.agents.length,
|
|
495
518
|
statuses: payload.statuses.length,
|
|
496
519
|
watchers: payload.watchers.length,
|
|
@@ -506,10 +529,37 @@ let ProjectsService = class ProjectsService {
|
|
|
506
529
|
},
|
|
507
530
|
},
|
|
508
531
|
};
|
|
532
|
+
if (needsMapping && !input.familyProviderMappings) {
|
|
533
|
+
dryRunResponse.providerMappingRequired = {
|
|
534
|
+
missingProviders: familyResult.missingProviders,
|
|
535
|
+
familyAlternatives: familyResult.alternatives,
|
|
536
|
+
canImport: familyResult.canImport,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return dryRunResponse;
|
|
540
|
+
}
|
|
541
|
+
if (needsMapping && !input.familyProviderMappings) {
|
|
542
|
+
return {
|
|
543
|
+
success: false,
|
|
544
|
+
providerMappingRequired: {
|
|
545
|
+
missingProviders: familyResult.missingProviders,
|
|
546
|
+
familyAlternatives: familyResult.alternatives,
|
|
547
|
+
canImport: familyResult.canImport,
|
|
548
|
+
},
|
|
549
|
+
};
|
|
509
550
|
}
|
|
510
|
-
if (
|
|
551
|
+
if (!familyResult.canImport) {
|
|
552
|
+
throw new error_types_1.ValidationError('Cannot import: some profile families have no available providers', {
|
|
553
|
+
hint: 'Install the required providers or use a different template',
|
|
554
|
+
missingProviders: familyResult.missingProviders,
|
|
555
|
+
familyAlternatives: familyResult.alternatives,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
const selectedProviderNames = new Set(selectedProfilesByFamily.profilesToCreate.map((p) => p.provider.name.trim().toLowerCase()));
|
|
559
|
+
const unavailableSelectedProviders = Array.from(selectedProviderNames).filter((name) => !available.has(name));
|
|
560
|
+
if (unavailableSelectedProviders.length > 0) {
|
|
511
561
|
throw new error_types_1.ValidationError('Import aborted: missing providers', {
|
|
512
|
-
missingProviders,
|
|
562
|
+
missingProviders: unavailableSelectedProviders,
|
|
513
563
|
hint: 'Install/configure providers by name before importing profiles.',
|
|
514
564
|
});
|
|
515
565
|
}
|
|
@@ -615,7 +665,7 @@ let ProjectsService = class ProjectsService {
|
|
|
615
665
|
promptIdMap[p.id] = created.id;
|
|
616
666
|
createdPrompts.push({ id: created.id, title: created.title });
|
|
617
667
|
}
|
|
618
|
-
for (const prof of
|
|
668
|
+
for (const prof of selectedProfilesByFamily.profilesToCreate) {
|
|
619
669
|
const providerId = available.get(prof.provider.name.trim().toLowerCase());
|
|
620
670
|
if (!providerId) {
|
|
621
671
|
throw new error_types_1.NotFoundError('Provider', prof.provider.name);
|
|
@@ -624,6 +674,7 @@ let ProjectsService = class ProjectsService {
|
|
|
624
674
|
projectId: input.projectId,
|
|
625
675
|
name: prof.name,
|
|
626
676
|
providerId,
|
|
677
|
+
familySlug: prof.familySlug ?? null,
|
|
627
678
|
options: this.normalizeProfileOptions(prof.options),
|
|
628
679
|
systemPrompt: null,
|
|
629
680
|
instructions: prof.instructions ?? null,
|
|
@@ -634,7 +685,8 @@ let ProjectsService = class ProjectsService {
|
|
|
634
685
|
profileIdMap[profKey] = created.id;
|
|
635
686
|
}
|
|
636
687
|
for (const a of payload.agents) {
|
|
637
|
-
const
|
|
688
|
+
const remappedProfileId = selectedProfilesByFamily.agentProfileMap.get(a.id ?? '');
|
|
689
|
+
const oldProfileId = remappedProfileId ?? a.profileId ?? '';
|
|
638
690
|
const newProfileId = oldProfileId && profileIdMap[oldProfileId] ? profileIdMap[oldProfileId] : undefined;
|
|
639
691
|
if (!newProfileId) {
|
|
640
692
|
throw new error_types_1.ValidationError(`Profile mapping missing for agent ${a.name}`, {
|
|
@@ -655,7 +707,7 @@ let ProjectsService = class ProjectsService {
|
|
|
655
707
|
...a,
|
|
656
708
|
id: a.id || `name:${a.name.trim().toLowerCase()}`,
|
|
657
709
|
})),
|
|
658
|
-
profiles:
|
|
710
|
+
profiles: selectedProfilesByFamily.profilesToCreate.map((p) => ({
|
|
659
711
|
...p,
|
|
660
712
|
id: p.id || `name:${p.name.trim().toLowerCase()}`,
|
|
661
713
|
})),
|
|
@@ -665,6 +717,7 @@ let ProjectsService = class ProjectsService {
|
|
|
665
717
|
agentNameToId: agentNameToNewId,
|
|
666
718
|
profileNameToId: profileNameToNewId,
|
|
667
719
|
providerNameToId: available,
|
|
720
|
+
profileNameRemapMap: selectedProfilesByFamily.profileNameRemapMap,
|
|
668
721
|
});
|
|
669
722
|
const { subscriberIdMap } = await this.createSubscribersFromPayload(input.projectId, payload.subscribers);
|
|
670
723
|
logger.info({
|
|
@@ -723,6 +776,24 @@ let ProjectsService = class ProjectsService {
|
|
|
723
776
|
const archiveStatusId = templateLabelToStatusId.get('archive') ?? null;
|
|
724
777
|
const settingsResult = await this.applyProjectSettings(input.projectId, mergedSettings, { promptTitleToId, statusLabelToId: templateLabelToStatusId }, archiveStatusId);
|
|
725
778
|
const initialPromptSet = settingsResult.initialPromptSet;
|
|
779
|
+
if (payload._manifest?.slug) {
|
|
780
|
+
let templateSource = 'registry';
|
|
781
|
+
try {
|
|
782
|
+
this.unifiedTemplateService.getBundledTemplate(payload._manifest.slug);
|
|
783
|
+
templateSource = 'bundled';
|
|
784
|
+
}
|
|
785
|
+
catch {
|
|
786
|
+
templateSource = 'registry';
|
|
787
|
+
}
|
|
788
|
+
await this.settings.setProjectTemplateMetadata(input.projectId, {
|
|
789
|
+
templateSlug: payload._manifest.slug,
|
|
790
|
+
source: templateSource,
|
|
791
|
+
installedVersion: payload._manifest.version ?? null,
|
|
792
|
+
registryUrl: null,
|
|
793
|
+
installedAt: new Date().toISOString(),
|
|
794
|
+
});
|
|
795
|
+
logger.info({ projectId: input.projectId, slug: payload._manifest.slug, source: templateSource }, 'Updated template metadata after import');
|
|
796
|
+
}
|
|
726
797
|
return {
|
|
727
798
|
success: true,
|
|
728
799
|
mode: 'replace',
|
|
@@ -778,6 +849,181 @@ let ProjectsService = class ProjectsService {
|
|
|
778
849
|
const missing = Array.from(providerNames).filter((n) => !available.has(n));
|
|
779
850
|
return { available, missing };
|
|
780
851
|
}
|
|
852
|
+
async computeFamilyAlternatives(templateProfiles, templateAgents) {
|
|
853
|
+
const localProviders = await this.storage.listProviders();
|
|
854
|
+
const availableProviderNames = new Set(localProviders.items.map((p) => p.name.trim().toLowerCase()));
|
|
855
|
+
const profileById = new Map();
|
|
856
|
+
for (const prof of templateProfiles) {
|
|
857
|
+
if (prof.id) {
|
|
858
|
+
profileById.set(prof.id, prof);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
const usedFamilySlugs = new Set();
|
|
862
|
+
for (const agent of templateAgents) {
|
|
863
|
+
if (agent.profileId) {
|
|
864
|
+
const profile = profileById.get(agent.profileId);
|
|
865
|
+
if (profile?.familySlug) {
|
|
866
|
+
usedFamilySlugs.add(profile.familySlug);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
const familyProviders = new Map();
|
|
871
|
+
for (const prof of templateProfiles) {
|
|
872
|
+
const familySlug = prof.familySlug;
|
|
873
|
+
if (!familySlug)
|
|
874
|
+
continue;
|
|
875
|
+
if (!familyProviders.has(familySlug)) {
|
|
876
|
+
familyProviders.set(familySlug, new Map());
|
|
877
|
+
}
|
|
878
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
879
|
+
const familyMap = familyProviders.get(familySlug);
|
|
880
|
+
if (!familyMap.has(providerName)) {
|
|
881
|
+
familyMap.set(providerName, []);
|
|
882
|
+
}
|
|
883
|
+
familyMap.get(providerName).push(prof.name);
|
|
884
|
+
}
|
|
885
|
+
const alternatives = [];
|
|
886
|
+
const allMissingProviders = new Set();
|
|
887
|
+
let canImport = true;
|
|
888
|
+
for (const familySlug of usedFamilySlugs) {
|
|
889
|
+
const providersForFamily = familyProviders.get(familySlug);
|
|
890
|
+
if (!providersForFamily || providersForFamily.size === 0) {
|
|
891
|
+
logger.warn({ familySlug }, 'Family used by agent has no profiles');
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
const providerNamesForFamily = Array.from(providersForFamily.keys());
|
|
895
|
+
const defaultProvider = providerNamesForFamily[0];
|
|
896
|
+
const defaultProviderAvailable = availableProviderNames.has(defaultProvider);
|
|
897
|
+
const availableForFamily = providerNamesForFamily.filter((name) => availableProviderNames.has(name));
|
|
898
|
+
for (const provName of providerNamesForFamily) {
|
|
899
|
+
if (!availableProviderNames.has(provName)) {
|
|
900
|
+
allMissingProviders.add(provName);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
const hasAlternatives = availableForFamily.length > 0;
|
|
904
|
+
if (!hasAlternatives) {
|
|
905
|
+
canImport = false;
|
|
906
|
+
}
|
|
907
|
+
alternatives.push({
|
|
908
|
+
familySlug,
|
|
909
|
+
defaultProvider,
|
|
910
|
+
defaultProviderAvailable,
|
|
911
|
+
availableProviders: availableForFamily.sort(),
|
|
912
|
+
hasAlternatives,
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
return {
|
|
916
|
+
alternatives,
|
|
917
|
+
missingProviders: Array.from(allMissingProviders).sort(),
|
|
918
|
+
canImport,
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
selectProfilesForFamilies(templateProfiles, templateAgents, familyProviderMappings, availableProviders) {
|
|
922
|
+
const profileById = new Map();
|
|
923
|
+
for (const prof of templateProfiles) {
|
|
924
|
+
if (prof.id) {
|
|
925
|
+
profileById.set(prof.id, prof);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
const profilesByFamilyAndProvider = new Map();
|
|
929
|
+
for (const prof of templateProfiles) {
|
|
930
|
+
if (!prof.familySlug)
|
|
931
|
+
continue;
|
|
932
|
+
const family = prof.familySlug;
|
|
933
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
934
|
+
if (!profilesByFamilyAndProvider.has(family)) {
|
|
935
|
+
profilesByFamilyAndProvider.set(family, new Map());
|
|
936
|
+
}
|
|
937
|
+
const familyMap = profilesByFamilyAndProvider.get(family);
|
|
938
|
+
if (!familyMap.has(providerName)) {
|
|
939
|
+
familyMap.set(providerName, prof);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
const familyOriginalProviders = new Map();
|
|
943
|
+
for (const agent of templateAgents) {
|
|
944
|
+
if (!agent.profileId)
|
|
945
|
+
continue;
|
|
946
|
+
const profile = profileById.get(agent.profileId);
|
|
947
|
+
if (!profile?.familySlug)
|
|
948
|
+
continue;
|
|
949
|
+
const providerName = profile.provider.name.trim().toLowerCase();
|
|
950
|
+
familyOriginalProviders.set(profile.familySlug, providerName);
|
|
951
|
+
}
|
|
952
|
+
const selectedProfileIdsByFamily = new Map();
|
|
953
|
+
for (const [familySlug, providerMap] of profilesByFamilyAndProvider) {
|
|
954
|
+
let selectedProvider;
|
|
955
|
+
if (familyProviderMappings?.[familySlug]) {
|
|
956
|
+
selectedProvider = familyProviderMappings[familySlug].trim().toLowerCase();
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
const originalProvider = familyOriginalProviders.get(familySlug);
|
|
960
|
+
if (originalProvider &&
|
|
961
|
+
availableProviders.has(originalProvider) &&
|
|
962
|
+
providerMap.has(originalProvider)) {
|
|
963
|
+
selectedProvider = originalProvider;
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
for (const provName of providerMap.keys()) {
|
|
967
|
+
if (availableProviders.has(provName)) {
|
|
968
|
+
selectedProvider = provName;
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
if (selectedProvider && providerMap.has(selectedProvider)) {
|
|
975
|
+
const profile = providerMap.get(selectedProvider);
|
|
976
|
+
if (profile.id) {
|
|
977
|
+
selectedProfileIdsByFamily.set(familySlug, profile.id);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
const profilesToCreate = [];
|
|
982
|
+
const usedProfileIds = new Set();
|
|
983
|
+
for (const prof of templateProfiles) {
|
|
984
|
+
if (!prof.id || usedProfileIds.has(prof.id))
|
|
985
|
+
continue;
|
|
986
|
+
const providerName = prof.provider.name.trim().toLowerCase();
|
|
987
|
+
if (availableProviders.has(providerName)) {
|
|
988
|
+
usedProfileIds.add(prof.id);
|
|
989
|
+
profilesToCreate.push(prof);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
const agentProfileMap = new Map();
|
|
993
|
+
for (const agent of templateAgents) {
|
|
994
|
+
if (!agent.id || !agent.profileId)
|
|
995
|
+
continue;
|
|
996
|
+
const originalProfile = profileById.get(agent.profileId);
|
|
997
|
+
if (!originalProfile) {
|
|
998
|
+
agentProfileMap.set(agent.id, agent.profileId);
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
if (originalProfile.familySlug) {
|
|
1002
|
+
const selectedProfileId = selectedProfileIdsByFamily.get(originalProfile.familySlug);
|
|
1003
|
+
agentProfileMap.set(agent.id, selectedProfileId ?? agent.profileId);
|
|
1004
|
+
}
|
|
1005
|
+
else {
|
|
1006
|
+
agentProfileMap.set(agent.id, agent.profileId);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
const profileNameRemapMap = new Map();
|
|
1010
|
+
for (const [familySlug, providerMap] of profilesByFamilyAndProvider) {
|
|
1011
|
+
const selectedProfileId = selectedProfileIdsByFamily.get(familySlug);
|
|
1012
|
+
const selectedProfile = selectedProfileId
|
|
1013
|
+
? templateProfiles.find((p) => p.id === selectedProfileId)
|
|
1014
|
+
: undefined;
|
|
1015
|
+
if (selectedProfile) {
|
|
1016
|
+
const selectedNameLower = selectedProfile.name.trim().toLowerCase();
|
|
1017
|
+
for (const profile of providerMap.values()) {
|
|
1018
|
+
const profileNameLower = profile.name.trim().toLowerCase();
|
|
1019
|
+
if (profileNameLower !== selectedNameLower) {
|
|
1020
|
+
profileNameRemapMap.set(profileNameLower, selectedNameLower);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return { profilesToCreate, agentProfileMap, profileNameRemapMap };
|
|
1026
|
+
}
|
|
781
1027
|
buildNameToIdMaps(payload, mappings) {
|
|
782
1028
|
const agentNameToId = new Map();
|
|
783
1029
|
for (const a of payload.agents) {
|
|
@@ -823,6 +1069,20 @@ let ProjectsService = class ProjectsService {
|
|
|
823
1069
|
}
|
|
824
1070
|
case 'profile': {
|
|
825
1071
|
scopeFilterId = maps.profileNameToId.get(scopeFilterNameLower) ?? null;
|
|
1072
|
+
if (!scopeFilterId && maps.profileNameRemapMap) {
|
|
1073
|
+
const remappedName = maps.profileNameRemapMap.get(scopeFilterNameLower);
|
|
1074
|
+
if (remappedName) {
|
|
1075
|
+
scopeFilterId = maps.profileNameToId.get(remappedName) ?? null;
|
|
1076
|
+
if (scopeFilterId) {
|
|
1077
|
+
logger.info({
|
|
1078
|
+
projectId,
|
|
1079
|
+
watcherName: w.name,
|
|
1080
|
+
originalProfile: w.scopeFilterName,
|
|
1081
|
+
remappedProfile: remappedName,
|
|
1082
|
+
}, 'Watcher profile scope remapped due to provider family selection');
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
826
1086
|
break;
|
|
827
1087
|
}
|
|
828
1088
|
case 'provider': {
|
|
@@ -999,6 +1259,36 @@ let ProjectsService = class ProjectsService {
|
|
|
999
1259
|
.replace(/[^a-z0-9]+/g, '-')
|
|
1000
1260
|
.replace(/(^-|-$)/g, '');
|
|
1001
1261
|
}
|
|
1262
|
+
async getTemplateManifestForProject(projectId) {
|
|
1263
|
+
const metadata = this.settings.getProjectTemplateMetadata(projectId);
|
|
1264
|
+
if (!metadata?.templateSlug) {
|
|
1265
|
+
logger.debug({ projectId }, 'No template metadata for project');
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
try {
|
|
1269
|
+
if (metadata.source === 'bundled') {
|
|
1270
|
+
const template = this.unifiedTemplateService.getBundledTemplate(metadata.templateSlug);
|
|
1271
|
+
return template.content._manifest ?? null;
|
|
1272
|
+
}
|
|
1273
|
+
else {
|
|
1274
|
+
const template = await this.unifiedTemplateService.getTemplate(metadata.templateSlug, metadata.installedVersion ?? undefined);
|
|
1275
|
+
if (template.source !== 'registry') {
|
|
1276
|
+
logger.debug({
|
|
1277
|
+
projectId,
|
|
1278
|
+
templateSlug: metadata.templateSlug,
|
|
1279
|
+
expectedSource: 'registry',
|
|
1280
|
+
actualSource: template.source,
|
|
1281
|
+
}, 'Template source mismatch - registry template not available, rejecting bundled fallback');
|
|
1282
|
+
return null;
|
|
1283
|
+
}
|
|
1284
|
+
return template.content._manifest ?? null;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
catch (error) {
|
|
1288
|
+
logger.debug({ projectId, templateSlug: metadata.templateSlug, error }, 'Failed to fetch template manifest for project');
|
|
1289
|
+
return null;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1002
1292
|
};
|
|
1003
1293
|
exports.ProjectsService = ProjectsService;
|
|
1004
1294
|
exports.ProjectsService = ProjectsService = __decorate([
|