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.
Files changed (80) hide show
  1. package/dist/drizzle/0041_community_skill_sources.sql +12 -0
  2. package/dist/drizzle/0042_nice_flatman.sql +10 -0
  3. package/dist/drizzle/0043_majestic_starhawk.sql +10 -0
  4. package/dist/drizzle/meta/0041_snapshot.json +4102 -0
  5. package/dist/drizzle/meta/0042_snapshot.json +4171 -0
  6. package/dist/drizzle/meta/0043_snapshot.json +4231 -0
  7. package/dist/drizzle/meta/_journal.json +21 -0
  8. package/dist/server/modules/seeders/seeders/0003_seed_preseed_jeffallan_claude_skills.d.ts +3 -0
  9. package/dist/server/modules/seeders/seeders/0003_seed_preseed_jeffallan_claude_skills.js +41 -0
  10. package/dist/server/modules/seeders/seeders/0003_seed_preseed_jeffallan_claude_skills.js.map +1 -0
  11. package/dist/server/modules/seeders/seeders/0004_seed_disable_microsoft_source_default.d.ts +3 -0
  12. package/dist/server/modules/seeders/seeders/0004_seed_disable_microsoft_source_default.js +48 -0
  13. package/dist/server/modules/seeders/seeders/0004_seed_disable_microsoft_source_default.js.map +1 -0
  14. package/dist/server/modules/seeders/services/data-seeder.service.js +4 -0
  15. package/dist/server/modules/seeders/services/data-seeder.service.js.map +1 -1
  16. package/dist/server/modules/skills/adapters/community-skill-source.adapter.d.ts +11 -0
  17. package/dist/server/modules/skills/adapters/community-skill-source.adapter.js +181 -0
  18. package/dist/server/modules/skills/adapters/community-skill-source.adapter.js.map +1 -0
  19. package/dist/server/modules/skills/adapters/github-skill-source.base.d.ts +2 -5
  20. package/dist/server/modules/skills/adapters/github-skill-source.base.js +31 -100
  21. package/dist/server/modules/skills/adapters/github-skill-source.base.js.map +1 -1
  22. package/dist/server/modules/skills/adapters/local-skill-source.adapter.d.ts +16 -0
  23. package/dist/server/modules/skills/adapters/local-skill-source.adapter.js +265 -0
  24. package/dist/server/modules/skills/adapters/local-skill-source.adapter.js.map +1 -0
  25. package/dist/server/modules/skills/adapters/skill-parsing.utils.d.ts +32 -0
  26. package/dist/server/modules/skills/adapters/skill-parsing.utils.js +169 -0
  27. package/dist/server/modules/skills/adapters/skill-parsing.utils.js.map +1 -0
  28. package/dist/server/modules/skills/controllers/community-sources.controller.d.ts +12 -0
  29. package/dist/server/modules/skills/controllers/community-sources.controller.js +71 -0
  30. package/dist/server/modules/skills/controllers/community-sources.controller.js.map +1 -0
  31. package/dist/server/modules/skills/controllers/local-sources.controller.d.ts +12 -0
  32. package/dist/server/modules/skills/controllers/local-sources.controller.js +71 -0
  33. package/dist/server/modules/skills/controllers/local-sources.controller.js.map +1 -0
  34. package/dist/server/modules/skills/controllers/skills.controller.d.ts +11 -1
  35. package/dist/server/modules/skills/controllers/skills.controller.js +35 -3
  36. package/dist/server/modules/skills/controllers/skills.controller.js.map +1 -1
  37. package/dist/server/modules/skills/dtos/community-sources.dto.d.ts +100 -0
  38. package/dist/server/modules/skills/dtos/community-sources.dto.js +138 -0
  39. package/dist/server/modules/skills/dtos/community-sources.dto.js.map +1 -0
  40. package/dist/server/modules/skills/dtos/local-sources.dto.d.ts +42 -0
  41. package/dist/server/modules/skills/dtos/local-sources.dto.js +30 -0
  42. package/dist/server/modules/skills/dtos/local-sources.dto.js.map +1 -0
  43. package/dist/server/modules/skills/dtos/skill.dto.d.ts +16 -0
  44. package/dist/server/modules/skills/dtos/skill.dto.js +7 -1
  45. package/dist/server/modules/skills/dtos/skill.dto.js.map +1 -1
  46. package/dist/server/modules/skills/services/community-sources.service.d.ts +18 -0
  47. package/dist/server/modules/skills/services/community-sources.service.js +158 -0
  48. package/dist/server/modules/skills/services/community-sources.service.js.map +1 -0
  49. package/dist/server/modules/skills/services/local-sources.service.d.ts +20 -0
  50. package/dist/server/modules/skills/services/local-sources.service.js +206 -0
  51. package/dist/server/modules/skills/services/local-sources.service.js.map +1 -0
  52. package/dist/server/modules/skills/services/skill-source-registry.service.d.ts +20 -0
  53. package/dist/server/modules/skills/services/skill-source-registry.service.js +142 -0
  54. package/dist/server/modules/skills/services/skill-source-registry.service.js.map +1 -0
  55. package/dist/server/modules/skills/services/skill-sync.service.d.ts +7 -3
  56. package/dist/server/modules/skills/services/skill-sync.service.js +102 -11
  57. package/dist/server/modules/skills/services/skill-sync.service.js.map +1 -1
  58. package/dist/server/modules/skills/services/skills.service.d.ts +16 -4
  59. package/dist/server/modules/skills/services/skills.service.js +141 -36
  60. package/dist/server/modules/skills/services/skills.service.js.map +1 -1
  61. package/dist/server/modules/skills/skills.module.js +10 -1
  62. package/dist/server/modules/skills/skills.module.js.map +1 -1
  63. package/dist/server/modules/storage/db/schema.d.ts +342 -0
  64. package/dist/server/modules/storage/db/schema.js +30 -1
  65. package/dist/server/modules/storage/db/schema.js.map +1 -1
  66. package/dist/server/modules/storage/interfaces/storage.interface.d.ts +18 -1
  67. package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
  68. package/dist/server/modules/storage/local/local-storage.service.d.ts +28 -1
  69. package/dist/server/modules/storage/local/local-storage.service.js +452 -2
  70. package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
  71. package/dist/server/modules/storage/models/domain.models.d.ts +20 -0
  72. package/dist/server/tsconfig.tsbuildinfo +1 -1
  73. package/dist/server/ui/assets/{ReviewDetailPage-D_-bS1MK.js → ReviewDetailPage-BvSckWKj.js} +1 -1
  74. package/dist/server/ui/assets/{ReviewsPage-BE1gxYlC.js → ReviewsPage-MKT-vv59.js} +1 -1
  75. package/dist/server/ui/assets/index-BtUq-Qxb.css +32 -0
  76. package/dist/server/ui/assets/{index-C094CE5I.js → index-kTb634Zp.js} +197 -197
  77. package/dist/server/ui/assets/{useReviewSubscription-Bs-17h-m.js → useReviewSubscription-Dc58i6Bk.js} +1 -1
  78. package/dist/server/ui/index.html +2 -2
  79. package/package.json +8 -1
  80. 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 { projects, statuses } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
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 { projects, statuses, prompts, agentProfiles, agents, tags, promptTags, profileProviderConfigs, providers, } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
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();