devchain-cli 0.9.0 → 0.9.2
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/0041_community_skill_sources.sql +12 -0
- package/dist/drizzle/0042_nice_flatman.sql +10 -0
- package/dist/drizzle/0043_majestic_starhawk.sql +10 -0
- package/dist/drizzle/meta/0041_snapshot.json +4102 -0
- package/dist/drizzle/meta/0042_snapshot.json +4171 -0
- package/dist/drizzle/meta/0043_snapshot.json +4231 -0
- package/dist/drizzle/meta/_journal.json +21 -0
- package/dist/server/modules/seeders/seeders/0003_seed_preseed_jeffallan_claude_skills.d.ts +3 -0
- package/dist/server/modules/seeders/seeders/0003_seed_preseed_jeffallan_claude_skills.js +41 -0
- package/dist/server/modules/seeders/seeders/0003_seed_preseed_jeffallan_claude_skills.js.map +1 -0
- package/dist/server/modules/seeders/seeders/0004_seed_disable_microsoft_source_default.d.ts +3 -0
- package/dist/server/modules/seeders/seeders/0004_seed_disable_microsoft_source_default.js +48 -0
- package/dist/server/modules/seeders/seeders/0004_seed_disable_microsoft_source_default.js.map +1 -0
- package/dist/server/modules/seeders/services/data-seeder.service.js +4 -0
- package/dist/server/modules/seeders/services/data-seeder.service.js.map +1 -1
- package/dist/server/modules/skills/adapters/community-skill-source.adapter.d.ts +11 -0
- package/dist/server/modules/skills/adapters/community-skill-source.adapter.js +181 -0
- package/dist/server/modules/skills/adapters/community-skill-source.adapter.js.map +1 -0
- package/dist/server/modules/skills/adapters/github-skill-source.base.d.ts +2 -5
- package/dist/server/modules/skills/adapters/github-skill-source.base.js +31 -100
- package/dist/server/modules/skills/adapters/github-skill-source.base.js.map +1 -1
- package/dist/server/modules/skills/adapters/local-skill-source.adapter.d.ts +16 -0
- package/dist/server/modules/skills/adapters/local-skill-source.adapter.js +265 -0
- package/dist/server/modules/skills/adapters/local-skill-source.adapter.js.map +1 -0
- package/dist/server/modules/skills/adapters/skill-parsing.utils.d.ts +32 -0
- package/dist/server/modules/skills/adapters/skill-parsing.utils.js +169 -0
- package/dist/server/modules/skills/adapters/skill-parsing.utils.js.map +1 -0
- package/dist/server/modules/skills/controllers/community-sources.controller.d.ts +12 -0
- package/dist/server/modules/skills/controllers/community-sources.controller.js +71 -0
- package/dist/server/modules/skills/controllers/community-sources.controller.js.map +1 -0
- package/dist/server/modules/skills/controllers/local-sources.controller.d.ts +12 -0
- package/dist/server/modules/skills/controllers/local-sources.controller.js +71 -0
- package/dist/server/modules/skills/controllers/local-sources.controller.js.map +1 -0
- package/dist/server/modules/skills/controllers/skills.controller.d.ts +11 -1
- package/dist/server/modules/skills/controllers/skills.controller.js +35 -3
- package/dist/server/modules/skills/controllers/skills.controller.js.map +1 -1
- package/dist/server/modules/skills/dtos/community-sources.dto.d.ts +100 -0
- package/dist/server/modules/skills/dtos/community-sources.dto.js +138 -0
- package/dist/server/modules/skills/dtos/community-sources.dto.js.map +1 -0
- package/dist/server/modules/skills/dtos/local-sources.dto.d.ts +42 -0
- package/dist/server/modules/skills/dtos/local-sources.dto.js +30 -0
- package/dist/server/modules/skills/dtos/local-sources.dto.js.map +1 -0
- package/dist/server/modules/skills/dtos/skill.dto.d.ts +16 -0
- package/dist/server/modules/skills/dtos/skill.dto.js +7 -1
- package/dist/server/modules/skills/dtos/skill.dto.js.map +1 -1
- package/dist/server/modules/skills/services/community-sources.service.d.ts +18 -0
- package/dist/server/modules/skills/services/community-sources.service.js +158 -0
- package/dist/server/modules/skills/services/community-sources.service.js.map +1 -0
- package/dist/server/modules/skills/services/local-sources.service.d.ts +20 -0
- package/dist/server/modules/skills/services/local-sources.service.js +206 -0
- package/dist/server/modules/skills/services/local-sources.service.js.map +1 -0
- package/dist/server/modules/skills/services/skill-source-registry.service.d.ts +20 -0
- package/dist/server/modules/skills/services/skill-source-registry.service.js +142 -0
- package/dist/server/modules/skills/services/skill-source-registry.service.js.map +1 -0
- package/dist/server/modules/skills/services/skill-sync.service.d.ts +7 -3
- package/dist/server/modules/skills/services/skill-sync.service.js +102 -11
- package/dist/server/modules/skills/services/skill-sync.service.js.map +1 -1
- package/dist/server/modules/skills/services/skills.service.d.ts +16 -4
- package/dist/server/modules/skills/services/skills.service.js +141 -36
- package/dist/server/modules/skills/services/skills.service.js.map +1 -1
- package/dist/server/modules/skills/skills.module.js +10 -1
- package/dist/server/modules/skills/skills.module.js.map +1 -1
- package/dist/server/modules/storage/db/schema.d.ts +342 -0
- package/dist/server/modules/storage/db/schema.js +30 -1
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/interfaces/storage.interface.d.ts +18 -1
- package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
- package/dist/server/modules/storage/local/local-storage.service.d.ts +28 -1
- package/dist/server/modules/storage/local/local-storage.service.js +452 -2
- package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +20 -0
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/{ReviewDetailPage-D_-bS1MK.js → ReviewDetailPage-BvSckWKj.js} +1 -1
- package/dist/server/ui/assets/{ReviewsPage-BE1gxYlC.js → ReviewsPage-MKT-vv59.js} +1 -1
- package/dist/server/ui/assets/index-BtUq-Qxb.css +32 -0
- package/dist/server/ui/assets/{index-C094CE5I.js → index-kTb634Zp.js} +197 -197
- package/dist/server/ui/assets/{useReviewSubscription-Bs-17h-m.js → useReviewSubscription-Dc58i6Bk.js} +1 -1
- package/dist/server/ui/index.html +2 -2
- package/package.json +8 -1
- package/dist/server/ui/assets/index-CbtpBUHu.css +0 -32
|
@@ -54,6 +54,14 @@ const logger_1 = require("../../../common/logging/logger");
|
|
|
54
54
|
const sqlite_raw_1 = require("../db/sqlite-raw");
|
|
55
55
|
const feature_flags_1 = require("../../../common/config/feature-flags");
|
|
56
56
|
const logger = (0, logger_1.createLogger)('LocalStorageService');
|
|
57
|
+
const COMMUNITY_SOURCE_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
58
|
+
const RESERVED_COMMUNITY_SOURCE_NAMES = new Set([
|
|
59
|
+
'anthropic',
|
|
60
|
+
'openai',
|
|
61
|
+
'microsoft',
|
|
62
|
+
'trailofbits',
|
|
63
|
+
'vercel',
|
|
64
|
+
]);
|
|
57
65
|
let LocalStorageService = class LocalStorageService {
|
|
58
66
|
constructor(db) {
|
|
59
67
|
this.db = db;
|
|
@@ -121,6 +129,97 @@ let LocalStorageService = class LocalStorageService {
|
|
|
121
129
|
}
|
|
122
130
|
return JSON.stringify(skillsRequired);
|
|
123
131
|
}
|
|
132
|
+
normalizeCommunitySourceName(name) {
|
|
133
|
+
const normalized = name.trim().toLowerCase();
|
|
134
|
+
if (!normalized) {
|
|
135
|
+
throw new error_types_1.ValidationError('name is required.', { fieldName: 'name' });
|
|
136
|
+
}
|
|
137
|
+
if (!COMMUNITY_SOURCE_NAME_PATTERN.test(normalized)) {
|
|
138
|
+
throw new error_types_1.ValidationError('Invalid community source name. Use lowercase letters, numbers, and hyphens only.', { name: normalized });
|
|
139
|
+
}
|
|
140
|
+
if (RESERVED_COMMUNITY_SOURCE_NAMES.has(normalized)) {
|
|
141
|
+
throw new error_types_1.ValidationError('Community source name conflicts with a built-in source.', {
|
|
142
|
+
name: normalized,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return normalized;
|
|
146
|
+
}
|
|
147
|
+
normalizeCommunitySourceNameForLookup(name) {
|
|
148
|
+
const normalized = name.trim().toLowerCase();
|
|
149
|
+
if (!normalized) {
|
|
150
|
+
throw new error_types_1.ValidationError('name is required.', { fieldName: 'name' });
|
|
151
|
+
}
|
|
152
|
+
if (!COMMUNITY_SOURCE_NAME_PATTERN.test(normalized)) {
|
|
153
|
+
throw new error_types_1.ValidationError('Invalid community source name. Use lowercase letters, numbers, and hyphens only.', { name: normalized });
|
|
154
|
+
}
|
|
155
|
+
return normalized;
|
|
156
|
+
}
|
|
157
|
+
normalizeCommunityRepoPart(value, fieldName) {
|
|
158
|
+
const normalized = value.trim().toLowerCase();
|
|
159
|
+
if (!normalized) {
|
|
160
|
+
throw new error_types_1.ValidationError(`${fieldName} is required.`, { fieldName });
|
|
161
|
+
}
|
|
162
|
+
return normalized;
|
|
163
|
+
}
|
|
164
|
+
normalizeCommunityBranch(branch) {
|
|
165
|
+
const normalized = (branch ?? 'main').trim();
|
|
166
|
+
if (!normalized) {
|
|
167
|
+
throw new error_types_1.ValidationError('branch is required.', { fieldName: 'branch' });
|
|
168
|
+
}
|
|
169
|
+
return normalized;
|
|
170
|
+
}
|
|
171
|
+
normalizeLocalSkillSourceFolderPath(folderPath) {
|
|
172
|
+
const normalized = folderPath.trim();
|
|
173
|
+
if (!normalized) {
|
|
174
|
+
throw new error_types_1.ValidationError('folderPath is required.', { fieldName: 'folderPath' });
|
|
175
|
+
}
|
|
176
|
+
return normalized;
|
|
177
|
+
}
|
|
178
|
+
async assertLocalSourceNameAvailableAcrossTypes(sourceName) {
|
|
179
|
+
if (RESERVED_COMMUNITY_SOURCE_NAMES.has(sourceName)) {
|
|
180
|
+
throw new error_types_1.ValidationError('Local source name conflicts with a built-in source.', {
|
|
181
|
+
name: sourceName,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const { communitySkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
185
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
186
|
+
const existingCommunitySource = await this.db
|
|
187
|
+
.select({ id: communitySkillSources.id })
|
|
188
|
+
.from(communitySkillSources)
|
|
189
|
+
.where(eq(communitySkillSources.name, sourceName))
|
|
190
|
+
.limit(1);
|
|
191
|
+
if (existingCommunitySource.length > 0) {
|
|
192
|
+
throw new error_types_1.ConflictError('Local source name conflicts with an existing community source.', {
|
|
193
|
+
name: sourceName,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
normalizeProjectIdForSourceEnablement(projectId) {
|
|
198
|
+
const normalized = projectId.trim();
|
|
199
|
+
if (!normalized) {
|
|
200
|
+
throw new error_types_1.ValidationError('projectId is required.', { fieldName: 'projectId' });
|
|
201
|
+
}
|
|
202
|
+
return normalized;
|
|
203
|
+
}
|
|
204
|
+
normalizeSourceNameForSourceEnablement(sourceName) {
|
|
205
|
+
const normalized = sourceName.trim().toLowerCase();
|
|
206
|
+
if (!normalized) {
|
|
207
|
+
throw new error_types_1.ValidationError('sourceName is required.', { fieldName: 'sourceName' });
|
|
208
|
+
}
|
|
209
|
+
return normalized;
|
|
210
|
+
}
|
|
211
|
+
isSqliteUniqueConstraint(error) {
|
|
212
|
+
if (typeof error !== 'object' || error === null) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
const code = 'code' in error ? error.code : undefined;
|
|
216
|
+
const message = 'message' in error ? error.message : undefined;
|
|
217
|
+
const normalizedMessage = typeof message === 'string' ? message : '';
|
|
218
|
+
return (code === 'SQLITE_CONSTRAINT' ||
|
|
219
|
+
code === 'SQLITE_CONSTRAINT_UNIQUE' ||
|
|
220
|
+
code === 19 ||
|
|
221
|
+
normalizedMessage.includes('UNIQUE constraint failed'));
|
|
222
|
+
}
|
|
124
223
|
async ensureValidEpicParent(projectId, parentId, childId) {
|
|
125
224
|
if (!parentId) {
|
|
126
225
|
return;
|
|
@@ -187,6 +286,39 @@ let LocalStorageService = class LocalStorageService {
|
|
|
187
286
|
});
|
|
188
287
|
}
|
|
189
288
|
}
|
|
289
|
+
async listSeedableSourceNamesForNewProject() {
|
|
290
|
+
const { communitySkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
291
|
+
const communitySourceRows = await this.db
|
|
292
|
+
.select({ name: communitySkillSources.name })
|
|
293
|
+
.from(communitySkillSources);
|
|
294
|
+
const sourceNames = communitySourceRows
|
|
295
|
+
.map((row) => row.name.trim().toLowerCase())
|
|
296
|
+
.filter((name) => name.length > 0);
|
|
297
|
+
const sqlite = (0, sqlite_raw_1.getRawSqliteClient)(this.db);
|
|
298
|
+
if (sqlite && typeof sqlite.prepare === 'function') {
|
|
299
|
+
try {
|
|
300
|
+
const localRows = sqlite.prepare('SELECT name FROM local_skill_sources').all();
|
|
301
|
+
for (const row of localRows) {
|
|
302
|
+
if (typeof row.name !== 'string') {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const normalized = row.name.trim().toLowerCase();
|
|
306
|
+
if (normalized.length > 0) {
|
|
307
|
+
sourceNames.push(normalized);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
313
|
+
if (!message.includes('no such table: local_skill_sources')) {
|
|
314
|
+
throw new error_types_1.StorageError('Failed to list local skill sources for project source seeding.', {
|
|
315
|
+
cause: message,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return [...new Set(sourceNames)];
|
|
321
|
+
}
|
|
190
322
|
async createProject(data) {
|
|
191
323
|
const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
192
324
|
const now = new Date().toISOString();
|
|
@@ -197,7 +329,8 @@ let LocalStorageService = class LocalStorageService {
|
|
|
197
329
|
createdAt: now,
|
|
198
330
|
updatedAt: now,
|
|
199
331
|
};
|
|
200
|
-
const
|
|
332
|
+
const seedableSourceNames = await this.listSeedableSourceNamesForNewProject();
|
|
333
|
+
const { projects, statuses, sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
201
334
|
await this.db.transaction(async (tx) => {
|
|
202
335
|
await tx.insert(projects).values({
|
|
203
336
|
id: project.id,
|
|
@@ -226,6 +359,15 @@ let LocalStorageService = class LocalStorageService {
|
|
|
226
359
|
updatedAt: now,
|
|
227
360
|
});
|
|
228
361
|
}
|
|
362
|
+
if (seedableSourceNames.length > 0) {
|
|
363
|
+
await tx.insert(sourceProjectEnabled).values(seedableSourceNames.map((sourceName) => ({
|
|
364
|
+
id: randomUUID(),
|
|
365
|
+
projectId: project.id,
|
|
366
|
+
sourceName,
|
|
367
|
+
enabled: false,
|
|
368
|
+
createdAt: now,
|
|
369
|
+
})));
|
|
370
|
+
}
|
|
229
371
|
});
|
|
230
372
|
logger.info({ projectId: project.id }, 'Created project with default statuses (transactional)');
|
|
231
373
|
return project;
|
|
@@ -240,7 +382,8 @@ let LocalStorageService = class LocalStorageService {
|
|
|
240
382
|
createdAt: now,
|
|
241
383
|
updatedAt: now,
|
|
242
384
|
};
|
|
243
|
-
const
|
|
385
|
+
const seedableSourceNames = await this.listSeedableSourceNamesForNewProject();
|
|
386
|
+
const { projects, statuses, prompts, agentProfiles, agents, tags, promptTags, profileProviderConfigs, providers, sourceProjectEnabled, } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
244
387
|
const statusIdMap = {};
|
|
245
388
|
const promptIdMap = {};
|
|
246
389
|
const profileIdMap = {};
|
|
@@ -277,6 +420,15 @@ let LocalStorageService = class LocalStorageService {
|
|
|
277
420
|
if (s.id)
|
|
278
421
|
statusIdMap[s.id] = statusId;
|
|
279
422
|
}
|
|
423
|
+
if (seedableSourceNames.length > 0) {
|
|
424
|
+
await this.db.insert(sourceProjectEnabled).values(seedableSourceNames.map((sourceName) => ({
|
|
425
|
+
id: randomUUID(),
|
|
426
|
+
projectId: project.id,
|
|
427
|
+
sourceName,
|
|
428
|
+
enabled: false,
|
|
429
|
+
createdAt: now,
|
|
430
|
+
})));
|
|
431
|
+
}
|
|
280
432
|
const { eq, and, or, isNull } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
281
433
|
for (const p of template.prompts) {
|
|
282
434
|
const promptId = randomUUID();
|
|
@@ -1901,6 +2053,304 @@ let LocalStorageService = class LocalStorageService {
|
|
|
1901
2053
|
}
|
|
1902
2054
|
return this.updateProvider(id, update);
|
|
1903
2055
|
}
|
|
2056
|
+
async getSourceProjectEnabled(projectId, sourceName) {
|
|
2057
|
+
const normalizedProjectId = this.normalizeProjectIdForSourceEnablement(projectId);
|
|
2058
|
+
const normalizedSourceName = this.normalizeSourceNameForSourceEnablement(sourceName);
|
|
2059
|
+
const { sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2060
|
+
const { and, eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2061
|
+
const rows = await this.db
|
|
2062
|
+
.select({ enabled: sourceProjectEnabled.enabled })
|
|
2063
|
+
.from(sourceProjectEnabled)
|
|
2064
|
+
.where(and(eq(sourceProjectEnabled.projectId, normalizedProjectId), eq(sourceProjectEnabled.sourceName, normalizedSourceName)))
|
|
2065
|
+
.limit(1);
|
|
2066
|
+
return rows[0] ? Boolean(rows[0].enabled) : null;
|
|
2067
|
+
}
|
|
2068
|
+
async setSourceProjectEnabled(projectId, sourceName, enabled) {
|
|
2069
|
+
const normalizedProjectId = this.normalizeProjectIdForSourceEnablement(projectId);
|
|
2070
|
+
const normalizedSourceName = this.normalizeSourceNameForSourceEnablement(sourceName);
|
|
2071
|
+
const { sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2072
|
+
const { and, eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2073
|
+
const existing = await this.db
|
|
2074
|
+
.select({ id: sourceProjectEnabled.id })
|
|
2075
|
+
.from(sourceProjectEnabled)
|
|
2076
|
+
.where(and(eq(sourceProjectEnabled.projectId, normalizedProjectId), eq(sourceProjectEnabled.sourceName, normalizedSourceName)))
|
|
2077
|
+
.limit(1);
|
|
2078
|
+
if (existing[0]) {
|
|
2079
|
+
await this.db
|
|
2080
|
+
.update(sourceProjectEnabled)
|
|
2081
|
+
.set({ enabled })
|
|
2082
|
+
.where(eq(sourceProjectEnabled.id, existing[0].id));
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
2086
|
+
await this.db.insert(sourceProjectEnabled).values({
|
|
2087
|
+
id: randomUUID(),
|
|
2088
|
+
projectId: normalizedProjectId,
|
|
2089
|
+
sourceName: normalizedSourceName,
|
|
2090
|
+
enabled,
|
|
2091
|
+
createdAt: new Date().toISOString(),
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
async listSourceProjectEnabled(projectId) {
|
|
2095
|
+
const normalizedProjectId = this.normalizeProjectIdForSourceEnablement(projectId);
|
|
2096
|
+
const { sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2097
|
+
const { asc, eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2098
|
+
const rows = await this.db
|
|
2099
|
+
.select({
|
|
2100
|
+
sourceName: sourceProjectEnabled.sourceName,
|
|
2101
|
+
enabled: sourceProjectEnabled.enabled,
|
|
2102
|
+
})
|
|
2103
|
+
.from(sourceProjectEnabled)
|
|
2104
|
+
.where(eq(sourceProjectEnabled.projectId, normalizedProjectId))
|
|
2105
|
+
.orderBy(asc(sourceProjectEnabled.sourceName));
|
|
2106
|
+
return rows.map((row) => ({
|
|
2107
|
+
sourceName: row.sourceName,
|
|
2108
|
+
enabled: Boolean(row.enabled),
|
|
2109
|
+
}));
|
|
2110
|
+
}
|
|
2111
|
+
async seedSourceProjectDisabled(projectId, sourceNames) {
|
|
2112
|
+
const normalizedProjectId = this.normalizeProjectIdForSourceEnablement(projectId);
|
|
2113
|
+
const normalizedSourceNames = [
|
|
2114
|
+
...new Set(sourceNames.map((name) => name.trim().toLowerCase())),
|
|
2115
|
+
].filter((name) => name.length > 0);
|
|
2116
|
+
if (normalizedSourceNames.length === 0) {
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
const sqlite = (0, sqlite_raw_1.getRawSqliteClient)(this.db);
|
|
2120
|
+
if (!sqlite || typeof sqlite.exec !== 'function') {
|
|
2121
|
+
throw new error_types_1.StorageError('Unable to access underlying SQLite client');
|
|
2122
|
+
}
|
|
2123
|
+
sqlite.exec('BEGIN IMMEDIATE TRANSACTION');
|
|
2124
|
+
try {
|
|
2125
|
+
const { sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2126
|
+
const { and, eq, inArray } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2127
|
+
const existingRows = await this.db
|
|
2128
|
+
.select({ sourceName: sourceProjectEnabled.sourceName })
|
|
2129
|
+
.from(sourceProjectEnabled)
|
|
2130
|
+
.where(and(eq(sourceProjectEnabled.projectId, normalizedProjectId), inArray(sourceProjectEnabled.sourceName, normalizedSourceNames)));
|
|
2131
|
+
const existingSourceNames = new Set(existingRows.map((row) => row.sourceName));
|
|
2132
|
+
const sourceNamesToInsert = normalizedSourceNames.filter((sourceName) => !existingSourceNames.has(sourceName));
|
|
2133
|
+
if (sourceNamesToInsert.length > 0) {
|
|
2134
|
+
const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
2135
|
+
const now = new Date().toISOString();
|
|
2136
|
+
await this.db.insert(sourceProjectEnabled).values(sourceNamesToInsert.map((sourceName) => ({
|
|
2137
|
+
id: randomUUID(),
|
|
2138
|
+
projectId: normalizedProjectId,
|
|
2139
|
+
sourceName,
|
|
2140
|
+
enabled: false,
|
|
2141
|
+
createdAt: now,
|
|
2142
|
+
})));
|
|
2143
|
+
}
|
|
2144
|
+
sqlite.exec('COMMIT');
|
|
2145
|
+
}
|
|
2146
|
+
catch (error) {
|
|
2147
|
+
try {
|
|
2148
|
+
sqlite.exec('ROLLBACK');
|
|
2149
|
+
}
|
|
2150
|
+
catch (rollbackError) {
|
|
2151
|
+
logger.error({ rollbackError }, 'Failed to rollback seedSourceProjectDisabled transaction');
|
|
2152
|
+
}
|
|
2153
|
+
throw error;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
async deleteSourceProjectEnabledBySource(sourceName) {
|
|
2157
|
+
const normalizedSourceName = this.normalizeSourceNameForSourceEnablement(sourceName);
|
|
2158
|
+
const { sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2159
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2160
|
+
await this.db
|
|
2161
|
+
.delete(sourceProjectEnabled)
|
|
2162
|
+
.where(eq(sourceProjectEnabled.sourceName, normalizedSourceName));
|
|
2163
|
+
}
|
|
2164
|
+
async listCommunitySkillSources() {
|
|
2165
|
+
const { communitySkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2166
|
+
const { asc } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2167
|
+
const rows = await this.db
|
|
2168
|
+
.select()
|
|
2169
|
+
.from(communitySkillSources)
|
|
2170
|
+
.orderBy(asc(communitySkillSources.name));
|
|
2171
|
+
return rows;
|
|
2172
|
+
}
|
|
2173
|
+
async getCommunitySkillSource(id) {
|
|
2174
|
+
const normalizedId = id.trim();
|
|
2175
|
+
if (!normalizedId) {
|
|
2176
|
+
throw new error_types_1.ValidationError('id is required.', { fieldName: 'id' });
|
|
2177
|
+
}
|
|
2178
|
+
const { communitySkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2179
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2180
|
+
const rows = await this.db
|
|
2181
|
+
.select()
|
|
2182
|
+
.from(communitySkillSources)
|
|
2183
|
+
.where(eq(communitySkillSources.id, normalizedId))
|
|
2184
|
+
.limit(1);
|
|
2185
|
+
if (!rows[0]) {
|
|
2186
|
+
throw new error_types_1.NotFoundError('Community skill source', normalizedId);
|
|
2187
|
+
}
|
|
2188
|
+
return rows[0];
|
|
2189
|
+
}
|
|
2190
|
+
async getCommunitySkillSourceByName(name) {
|
|
2191
|
+
const normalizedName = this.normalizeCommunitySourceNameForLookup(name);
|
|
2192
|
+
const { communitySkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2193
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2194
|
+
const rows = await this.db
|
|
2195
|
+
.select()
|
|
2196
|
+
.from(communitySkillSources)
|
|
2197
|
+
.where(eq(communitySkillSources.name, normalizedName))
|
|
2198
|
+
.limit(1);
|
|
2199
|
+
return rows[0] ?? null;
|
|
2200
|
+
}
|
|
2201
|
+
async createCommunitySkillSource(data) {
|
|
2202
|
+
const normalizedName = this.normalizeCommunitySourceName(data.name);
|
|
2203
|
+
const normalizedRepoOwner = this.normalizeCommunityRepoPart(data.repoOwner, 'repoOwner');
|
|
2204
|
+
const normalizedRepoName = this.normalizeCommunityRepoPart(data.repoName, 'repoName');
|
|
2205
|
+
const normalizedBranch = this.normalizeCommunityBranch(data.branch);
|
|
2206
|
+
const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
2207
|
+
const now = new Date().toISOString();
|
|
2208
|
+
const record = {
|
|
2209
|
+
id: randomUUID(),
|
|
2210
|
+
name: normalizedName,
|
|
2211
|
+
repoOwner: normalizedRepoOwner,
|
|
2212
|
+
repoName: normalizedRepoName,
|
|
2213
|
+
branch: normalizedBranch,
|
|
2214
|
+
createdAt: now,
|
|
2215
|
+
updatedAt: now,
|
|
2216
|
+
};
|
|
2217
|
+
const { communitySkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2218
|
+
try {
|
|
2219
|
+
await this.db.insert(communitySkillSources).values({
|
|
2220
|
+
id: record.id,
|
|
2221
|
+
name: record.name,
|
|
2222
|
+
repoOwner: record.repoOwner,
|
|
2223
|
+
repoName: record.repoName,
|
|
2224
|
+
branch: record.branch,
|
|
2225
|
+
createdAt: record.createdAt,
|
|
2226
|
+
updatedAt: record.updatedAt,
|
|
2227
|
+
});
|
|
2228
|
+
}
|
|
2229
|
+
catch (error) {
|
|
2230
|
+
if (this.isSqliteUniqueConstraint(error)) {
|
|
2231
|
+
const rawMessage = typeof error === 'object' && error !== null && 'message' in error
|
|
2232
|
+
? String(error.message ?? '')
|
|
2233
|
+
: '';
|
|
2234
|
+
if (rawMessage.includes('community_skill_sources.name')) {
|
|
2235
|
+
throw new error_types_1.ConflictError('Community skill source name already exists.', {
|
|
2236
|
+
name: normalizedName,
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
throw new error_types_1.ConflictError('Community skill source repository already exists.', {
|
|
2240
|
+
repoOwner: normalizedRepoOwner,
|
|
2241
|
+
repoName: normalizedRepoName,
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
throw new error_types_1.StorageError('Failed to create community skill source.', {
|
|
2245
|
+
name: normalizedName,
|
|
2246
|
+
repoOwner: normalizedRepoOwner,
|
|
2247
|
+
repoName: normalizedRepoName,
|
|
2248
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
logger.info({ communitySkillSourceId: record.id, name: record.name }, 'Created community skill source');
|
|
2252
|
+
return record;
|
|
2253
|
+
}
|
|
2254
|
+
async deleteCommunitySkillSource(id) {
|
|
2255
|
+
const source = await this.getCommunitySkillSource(id);
|
|
2256
|
+
const { communitySkillSources, skills, sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2257
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2258
|
+
await this.db.transaction(async (tx) => {
|
|
2259
|
+
await tx.delete(skills).where(eq(skills.source, source.name));
|
|
2260
|
+
await tx.delete(sourceProjectEnabled).where(eq(sourceProjectEnabled.sourceName, source.name));
|
|
2261
|
+
await tx.delete(communitySkillSources).where(eq(communitySkillSources.id, source.id));
|
|
2262
|
+
});
|
|
2263
|
+
logger.info({ communitySkillSourceId: source.id, sourceName: source.name }, 'Deleted community skill source and related skills');
|
|
2264
|
+
}
|
|
2265
|
+
async listLocalSkillSources() {
|
|
2266
|
+
const { localSkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2267
|
+
const { asc } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2268
|
+
const rows = await this.db
|
|
2269
|
+
.select()
|
|
2270
|
+
.from(localSkillSources)
|
|
2271
|
+
.orderBy(asc(localSkillSources.name));
|
|
2272
|
+
return rows;
|
|
2273
|
+
}
|
|
2274
|
+
async getLocalSkillSource(id) {
|
|
2275
|
+
const normalizedId = id.trim();
|
|
2276
|
+
if (!normalizedId) {
|
|
2277
|
+
throw new error_types_1.ValidationError('id is required.', { fieldName: 'id' });
|
|
2278
|
+
}
|
|
2279
|
+
const { localSkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2280
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2281
|
+
const rows = await this.db
|
|
2282
|
+
.select()
|
|
2283
|
+
.from(localSkillSources)
|
|
2284
|
+
.where(eq(localSkillSources.id, normalizedId))
|
|
2285
|
+
.limit(1);
|
|
2286
|
+
return rows[0] ?? null;
|
|
2287
|
+
}
|
|
2288
|
+
async createLocalSkillSource(data) {
|
|
2289
|
+
const normalizedName = this.normalizeCommunitySourceNameForLookup(data.name);
|
|
2290
|
+
const normalizedFolderPath = this.normalizeLocalSkillSourceFolderPath(data.folderPath);
|
|
2291
|
+
await this.assertLocalSourceNameAvailableAcrossTypes(normalizedName);
|
|
2292
|
+
const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
2293
|
+
const now = new Date().toISOString();
|
|
2294
|
+
const record = {
|
|
2295
|
+
id: randomUUID(),
|
|
2296
|
+
name: normalizedName,
|
|
2297
|
+
folderPath: normalizedFolderPath,
|
|
2298
|
+
createdAt: now,
|
|
2299
|
+
updatedAt: now,
|
|
2300
|
+
};
|
|
2301
|
+
const { localSkillSources } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2302
|
+
try {
|
|
2303
|
+
await this.db.insert(localSkillSources).values({
|
|
2304
|
+
id: record.id,
|
|
2305
|
+
name: record.name,
|
|
2306
|
+
folderPath: record.folderPath,
|
|
2307
|
+
createdAt: record.createdAt,
|
|
2308
|
+
updatedAt: record.updatedAt,
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
catch (error) {
|
|
2312
|
+
if (this.isSqliteUniqueConstraint(error)) {
|
|
2313
|
+
const rawMessage = typeof error === 'object' && error !== null && 'message' in error
|
|
2314
|
+
? String(error.message ?? '')
|
|
2315
|
+
: '';
|
|
2316
|
+
if (rawMessage.includes('local_skill_sources.name')) {
|
|
2317
|
+
throw new error_types_1.ConflictError('Local skill source name already exists.', {
|
|
2318
|
+
name: normalizedName,
|
|
2319
|
+
});
|
|
2320
|
+
}
|
|
2321
|
+
if (rawMessage.includes('local_skill_sources.folder_path')) {
|
|
2322
|
+
throw new error_types_1.ConflictError('Local skill source folder path already exists.', {
|
|
2323
|
+
folderPath: normalizedFolderPath,
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
throw new error_types_1.ConflictError('Local skill source already exists.', {
|
|
2327
|
+
name: normalizedName,
|
|
2328
|
+
folderPath: normalizedFolderPath,
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
throw new error_types_1.StorageError('Failed to create local skill source.', {
|
|
2332
|
+
name: normalizedName,
|
|
2333
|
+
folderPath: normalizedFolderPath,
|
|
2334
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
logger.info({ localSkillSourceId: record.id, name: record.name }, 'Created local skill source');
|
|
2338
|
+
return record;
|
|
2339
|
+
}
|
|
2340
|
+
async deleteLocalSkillSource(id) {
|
|
2341
|
+
const source = await this.getLocalSkillSource(id);
|
|
2342
|
+
if (!source) {
|
|
2343
|
+
throw new error_types_1.NotFoundError('Local skill source', id.trim());
|
|
2344
|
+
}
|
|
2345
|
+
const { localSkillSources, skills, sourceProjectEnabled } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
|
|
2346
|
+
const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
|
|
2347
|
+
await this.db.transaction(async (tx) => {
|
|
2348
|
+
await tx.delete(skills).where(eq(skills.source, source.name));
|
|
2349
|
+
await tx.delete(sourceProjectEnabled).where(eq(sourceProjectEnabled.sourceName, source.name));
|
|
2350
|
+
await tx.delete(localSkillSources).where(eq(localSkillSources.id, source.id));
|
|
2351
|
+
});
|
|
2352
|
+
logger.info({ localSkillSourceId: source.id, sourceName: source.name }, 'Deleted local skill source and related skills');
|
|
2353
|
+
}
|
|
1904
2354
|
async createAgentProfile(data) {
|
|
1905
2355
|
const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
1906
2356
|
const now = new Date().toISOString();
|