devchain-cli 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/drizzle/0027_legal_malice.sql +17 -0
  2. package/dist/drizzle/0028_populate_provider_configs.sql +19 -0
  3. package/dist/drizzle/0029_merge_profiles_by_family_slug.sql +116 -0
  4. package/dist/drizzle/0030_set_agents_provider_config_id.sql +14 -0
  5. package/dist/drizzle/0031_remove_legacy_profile_columns.sql +68 -0
  6. package/dist/drizzle/0032_agents_provider_config_not_null.sql +52 -0
  7. package/dist/drizzle/0033_profile_provider_configs_name.sql +38 -0
  8. package/dist/drizzle/0034_sessions_agent_running_unique.sql +30 -0
  9. package/dist/drizzle/0035_provider_config_position.sql +26 -0
  10. package/dist/drizzle/PHASE2_MIGRATION_GUIDE.md +109 -0
  11. package/dist/drizzle/meta/0027_snapshot.json +3648 -0
  12. package/dist/drizzle/meta/0035_snapshot.json +3670 -0
  13. package/dist/drizzle/meta/_journal.json +64 -1
  14. package/dist/drizzle/migration-guard.sql +17 -0
  15. package/dist/drizzle/phase2-rollback.sql +44 -0
  16. package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +101 -12
  17. package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts.map +1 -1
  18. package/dist/node_modules/@devchain/shared/schemas/export-schema.js +20 -0
  19. package/dist/node_modules/@devchain/shared/schemas/export-schema.js.map +1 -1
  20. package/dist/node_modules/@devchain/shared/tsconfig.tsbuildinfo +1 -1
  21. package/dist/server/modules/agents/controllers/agents.controller.d.ts +15 -0
  22. package/dist/server/modules/agents/controllers/agents.controller.js +120 -57
  23. package/dist/server/modules/agents/controllers/agents.controller.js.map +1 -1
  24. package/dist/server/modules/core/services/preflight.service.d.ts +6 -0
  25. package/dist/server/modules/core/services/preflight.service.js +143 -57
  26. package/dist/server/modules/core/services/preflight.service.js.map +1 -1
  27. package/dist/server/modules/epics/services/epics.service.d.ts +10 -4
  28. package/dist/server/modules/epics/services/epics.service.js +8 -5
  29. package/dist/server/modules/epics/services/epics.service.js.map +1 -1
  30. package/dist/server/modules/events/catalog/epic.created.d.ts +18 -0
  31. package/dist/server/modules/events/catalog/epic.created.js +8 -0
  32. package/dist/server/modules/events/catalog/epic.created.js.map +1 -1
  33. package/dist/server/modules/events/catalog/epic.updated.d.ts +18 -0
  34. package/dist/server/modules/events/catalog/epic.updated.js +8 -0
  35. package/dist/server/modules/events/catalog/epic.updated.js.map +1 -1
  36. package/dist/server/modules/events/catalog/index.d.ts +36 -0
  37. package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.d.ts +1 -0
  38. package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.js +33 -2
  39. package/dist/server/modules/events/subscribers/epic-assignment-notifier.subscriber.js.map +1 -1
  40. package/dist/server/modules/events/subscribers/review-comment-notifier.subscriber.js +12 -5
  41. package/dist/server/modules/events/subscribers/review-comment-notifier.subscriber.js.map +1 -1
  42. package/dist/server/modules/mcp/services/mcp.service.js +16 -2
  43. package/dist/server/modules/mcp/services/mcp.service.js.map +1 -1
  44. package/dist/server/modules/mcp/services/terminal-activity.service.d.ts +1 -1
  45. package/dist/server/modules/mcp/services/terminal-activity.service.js +22 -2
  46. package/dist/server/modules/mcp/services/terminal-activity.service.js.map +1 -1
  47. package/dist/server/modules/profiles/controllers/profiles.controller.d.ts +11 -8
  48. package/dist/server/modules/profiles/controllers/profiles.controller.js +88 -14
  49. package/dist/server/modules/profiles/controllers/profiles.controller.js.map +1 -1
  50. package/dist/server/modules/profiles/controllers/provider-configs.controller.d.ts +9 -0
  51. package/dist/server/modules/profiles/controllers/provider-configs.controller.js +94 -0
  52. package/dist/server/modules/profiles/controllers/provider-configs.controller.js.map +1 -0
  53. package/dist/server/modules/profiles/dto.d.ts +81 -6
  54. package/dist/server/modules/profiles/dto.js +45 -3
  55. package/dist/server/modules/profiles/dto.js.map +1 -1
  56. package/dist/server/modules/profiles/profiles.module.js +2 -1
  57. package/dist/server/modules/profiles/profiles.module.js.map +1 -1
  58. package/dist/server/modules/projects/controllers/projects.controller.d.ts +78 -19
  59. package/dist/server/modules/projects/controllers/projects.controller.js +243 -17
  60. package/dist/server/modules/projects/controllers/projects.controller.js.map +1 -1
  61. package/dist/server/modules/projects/dtos/export.dto.d.ts +44 -0
  62. package/dist/server/modules/projects/dtos/export.dto.js +10 -0
  63. package/dist/server/modules/projects/dtos/export.dto.js.map +1 -1
  64. package/dist/server/modules/projects/services/projects.service.d.ts +48 -11
  65. package/dist/server/modules/projects/services/projects.service.js +359 -27
  66. package/dist/server/modules/projects/services/projects.service.js.map +1 -1
  67. package/dist/server/modules/providers/controllers/providers.controller.js +12 -7
  68. package/dist/server/modules/providers/controllers/providers.controller.js.map +1 -1
  69. package/dist/server/modules/registry/controllers/templates.controller.d.ts +2 -2
  70. package/dist/server/modules/registry/services/registry-orchestration.service.js +11 -0
  71. package/dist/server/modules/registry/services/registry-orchestration.service.js.map +1 -1
  72. package/dist/server/modules/registry/services/template-upgrade.service.js +6 -0
  73. package/dist/server/modules/registry/services/template-upgrade.service.js.map +1 -1
  74. package/dist/server/modules/registry/services/unified-template.service.d.ts +2 -1
  75. package/dist/server/modules/registry/services/unified-template.service.js +61 -0
  76. package/dist/server/modules/registry/services/unified-template.service.js.map +1 -1
  77. package/dist/server/modules/reviews/services/reviews.service.js +8 -0
  78. package/dist/server/modules/reviews/services/reviews.service.js.map +1 -1
  79. package/dist/server/modules/sessions/services/activity-tracker.service.d.ts +2 -0
  80. package/dist/server/modules/sessions/services/activity-tracker.service.js +20 -0
  81. package/dist/server/modules/sessions/services/activity-tracker.service.js.map +1 -1
  82. package/dist/server/modules/sessions/services/sessions-message-pool.service.js +2 -2
  83. package/dist/server/modules/sessions/services/sessions-message-pool.service.js.map +1 -1
  84. package/dist/server/modules/sessions/services/sessions.service.d.ts +3 -1
  85. package/dist/server/modules/sessions/services/sessions.service.js +275 -144
  86. package/dist/server/modules/sessions/services/sessions.service.js.map +1 -1
  87. package/dist/server/modules/sessions/utils/env-builder.d.ts +8 -0
  88. package/dist/server/modules/sessions/utils/env-builder.js +62 -0
  89. package/dist/server/modules/sessions/utils/env-builder.js.map +1 -0
  90. package/dist/server/modules/settings/dtos/settings.dto.d.ts +84 -8
  91. package/dist/server/modules/settings/dtos/settings.dto.js +15 -2
  92. package/dist/server/modules/settings/dtos/settings.dto.js.map +1 -1
  93. package/dist/server/modules/settings/services/settings.service.d.ts +10 -1
  94. package/dist/server/modules/settings/services/settings.service.js +275 -0
  95. package/dist/server/modules/settings/services/settings.service.js.map +1 -1
  96. package/dist/server/modules/storage/db/db.provider.js +2 -0
  97. package/dist/server/modules/storage/db/db.provider.js.map +1 -1
  98. package/dist/server/modules/storage/db/schema.d.ts +185 -28
  99. package/dist/server/modules/storage/db/schema.js +32 -6
  100. package/dist/server/modules/storage/db/schema.js.map +1 -1
  101. package/dist/server/modules/storage/interfaces/storage.interface.d.ts +17 -1
  102. package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
  103. package/dist/server/modules/storage/local/local-storage.service.d.ts +15 -1
  104. package/dist/server/modules/storage/local/local-storage.service.js +352 -21
  105. package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
  106. package/dist/server/modules/storage/models/domain.models.d.ts +26 -7
  107. package/dist/server/modules/subscribers/actions/restart-agent.action.js +17 -19
  108. package/dist/server/modules/subscribers/actions/restart-agent.action.js.map +1 -1
  109. package/dist/server/modules/subscribers/events/event-fields-catalog.js +4 -0
  110. package/dist/server/modules/subscribers/events/event-fields-catalog.js.map +1 -1
  111. package/dist/server/modules/terminal/services/pty.service.js +6 -1
  112. package/dist/server/modules/terminal/services/pty.service.js.map +1 -1
  113. package/dist/server/modules/watchers/services/watcher-runner.service.js +27 -8
  114. package/dist/server/modules/watchers/services/watcher-runner.service.js.map +1 -1
  115. package/dist/{templates/claude-opus.json → server/templates/dev-loop.json} +365 -209
  116. package/dist/server/tsconfig.tsbuildinfo +1 -1
  117. package/dist/server/ui/assets/{ReviewDetailPage-I54h-2L-.js → ReviewDetailPage-YlFGGJv7.js} +2 -2
  118. package/dist/server/ui/assets/ReviewsPage-Diegg4jt.js +19 -0
  119. package/dist/server/ui/assets/index-DuMIsIyY.css +32 -0
  120. package/dist/server/ui/assets/index-sEtQpiB4.js +868 -0
  121. package/dist/server/ui/assets/{useReviewSubscription-C0GEsiRw.js → useReviewSubscription-CMhQ2m0h.js} +22 -22
  122. package/dist/server/ui/index.html +2 -2
  123. package/dist/{server/templates/claude-opus.json → templates/dev-loop.json} +365 -209
  124. package/package.json +9 -4
  125. package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.d.ts +0 -2
  126. package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.d.ts.map +0 -1
  127. package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.js +0 -88
  128. package/dist/node_modules/@devchain/shared/schemas/export-schema.spec.js.map +0 -1
  129. package/dist/server/templates/claude-codex-advanced.json +0 -470
  130. package/dist/server/templates/simple-codex.json +0 -469
  131. package/dist/server/ui/assets/ReviewsPage-B4ua5hiX.js +0 -19
  132. package/dist/server/ui/assets/index-CqcmnFBh.css +0 -32
  133. package/dist/server/ui/assets/index-JbUMpbg7.js +0 -858
  134. package/dist/templates/claude-codex-advanced.json +0 -470
  135. package/dist/templates/simple-codex.json +0 -469
@@ -62,6 +62,32 @@ let LocalStorageService = class LocalStorageService {
62
62
  getFeatureFlags() {
63
63
  return { ...feature_flags_1.DEFAULT_FEATURE_FLAGS };
64
64
  }
65
+ parseProviderConfigEnv(envJson, configId, profileId) {
66
+ if (!envJson) {
67
+ return null;
68
+ }
69
+ try {
70
+ const parsed = JSON.parse(envJson);
71
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
72
+ throw new Error('env must be an object');
73
+ }
74
+ for (const [key, value] of Object.entries(parsed)) {
75
+ if (typeof value !== 'string') {
76
+ throw new Error(`env["${key}"] must be a string, got ${typeof value}`);
77
+ }
78
+ }
79
+ return parsed;
80
+ }
81
+ catch (error) {
82
+ const message = error instanceof Error ? error.message : String(error);
83
+ logger.warn({ configId, profileId, error: message }, 'Failed to parse provider config env JSON');
84
+ throw new error_types_1.ValidationError(`Invalid JSON in provider config env field: ${message}`, {
85
+ configId,
86
+ profileId,
87
+ rawValue: envJson.slice(0, 100) + (envJson.length > 100 ? '...' : ''),
88
+ });
89
+ }
90
+ }
65
91
  async ensureValidEpicParent(projectId, parentId, childId) {
66
92
  if (!parentId) {
67
93
  return;
@@ -181,10 +207,11 @@ let LocalStorageService = class LocalStorageService {
181
207
  createdAt: now,
182
208
  updatedAt: now,
183
209
  };
184
- const { projects, statuses, prompts, agentProfiles, agents, tags, promptTags } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
210
+ const { projects, statuses, prompts, agentProfiles, agents, tags, promptTags, profileProviderConfigs, providers, } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
185
211
  const statusIdMap = {};
186
212
  const promptIdMap = {};
187
213
  const profileIdMap = {};
214
+ const configIdMap = {};
188
215
  const agentIdMap = {};
189
216
  const createdPrompts = [];
190
217
  const sqlite = (0, sqlite_raw_1.getRawSqliteClient)(this.db);
@@ -266,9 +293,7 @@ let LocalStorageService = class LocalStorageService {
266
293
  id: profileId,
267
294
  projectId: project.id,
268
295
  name: prof.name,
269
- providerId: prof.providerId,
270
296
  familySlug: prof.familySlug ?? null,
271
- options: prof.options,
272
297
  systemPrompt: null,
273
298
  instructions: prof.instructions,
274
299
  temperature: prof.temperature != null ? Math.round(prof.temperature * 100) : null,
@@ -278,6 +303,53 @@ let LocalStorageService = class LocalStorageService {
278
303
  });
279
304
  if (prof.id)
280
305
  profileIdMap[prof.id] = profileId;
306
+ if (prof.providerConfigs && prof.providerConfigs.length > 0) {
307
+ const sortedConfigs = [...prof.providerConfigs].sort((a, b) => {
308
+ const posA = a.position ?? 0;
309
+ const posB = b.position ?? 0;
310
+ return posA - posB;
311
+ });
312
+ for (const config of sortedConfigs) {
313
+ const provider = await this.db
314
+ .select()
315
+ .from(providers)
316
+ .where(eq(providers.name, config.providerName))
317
+ .limit(1);
318
+ if (!provider[0]) {
319
+ throw new error_types_1.ValidationError(`Provider not found: ${config.providerName}`);
320
+ }
321
+ const configId = randomUUID();
322
+ await this.db.insert(profileProviderConfigs).values({
323
+ id: configId,
324
+ profileId: profileId,
325
+ providerId: provider[0].id,
326
+ name: config.name,
327
+ options: config.options ?? null,
328
+ env: config.env ? JSON.stringify(config.env) : null,
329
+ position: config.position ?? sortedConfigs.indexOf(config),
330
+ createdAt: now,
331
+ updatedAt: now,
332
+ });
333
+ if (!configIdMap[profileId]) {
334
+ configIdMap[profileId] = configId;
335
+ }
336
+ }
337
+ }
338
+ else {
339
+ const configId = randomUUID();
340
+ await this.db.insert(profileProviderConfigs).values({
341
+ id: configId,
342
+ profileId: profileId,
343
+ providerId: prof.providerId,
344
+ name: prof.name,
345
+ options: prof.options ?? null,
346
+ env: null,
347
+ position: 0,
348
+ createdAt: now,
349
+ updatedAt: now,
350
+ });
351
+ configIdMap[profileId] = configId;
352
+ }
281
353
  }
282
354
  for (const a of template.agents) {
283
355
  const oldProfileId = a.profileId ?? '';
@@ -287,12 +359,19 @@ let LocalStorageService = class LocalStorageService {
287
359
  profileId: oldProfileId || null,
288
360
  });
289
361
  }
362
+ const configId = configIdMap[newProfileId];
363
+ if (!configId) {
364
+ throw new error_types_1.ValidationError(`Config mapping missing for agent ${a.name}`, {
365
+ profileId: newProfileId,
366
+ });
367
+ }
290
368
  const agentId = randomUUID();
291
369
  await this.db.insert(agents).values({
292
370
  id: agentId,
293
371
  projectId: project.id,
294
372
  name: a.name,
295
373
  profileId: newProfileId,
374
+ providerConfigId: configId,
296
375
  description: a.description ?? null,
297
376
  createdAt: now,
298
377
  updatedAt: now,
@@ -1731,6 +1810,15 @@ let LocalStorageService = class LocalStorageService {
1731
1810
  offset,
1732
1811
  };
1733
1812
  }
1813
+ async listProvidersByIds(ids) {
1814
+ if (ids.length === 0) {
1815
+ return [];
1816
+ }
1817
+ const { providers } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
1818
+ const { inArray } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
1819
+ const results = await this.db.select().from(providers).where(inArray(providers.id, ids));
1820
+ return results;
1821
+ }
1734
1822
  async updateProvider(id, data) {
1735
1823
  const { providers } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
1736
1824
  const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
@@ -1778,9 +1866,7 @@ let LocalStorageService = class LocalStorageService {
1778
1866
  id: randomUUID(),
1779
1867
  projectId: data.projectId ?? null,
1780
1868
  name: data.name,
1781
- providerId: data.providerId,
1782
1869
  familySlug: data.familySlug ?? null,
1783
- options: data.options ?? null,
1784
1870
  systemPrompt: data.systemPrompt ?? null,
1785
1871
  instructions: data.instructions ?? null,
1786
1872
  temperature: data.temperature ?? null,
@@ -1792,9 +1878,7 @@ let LocalStorageService = class LocalStorageService {
1792
1878
  id: profile.id,
1793
1879
  projectId: profile.projectId,
1794
1880
  name: profile.name,
1795
- providerId: profile.providerId,
1796
1881
  familySlug: profile.familySlug,
1797
- options: profile.options,
1798
1882
  systemPrompt: profile.systemPrompt,
1799
1883
  instructions: profile.instructions,
1800
1884
  temperature: profile.temperature != null ? Math.round(profile.temperature * 100) : null,
@@ -1819,7 +1903,6 @@ let LocalStorageService = class LocalStorageService {
1819
1903
  return {
1820
1904
  ...profile,
1821
1905
  temperature: profile.temperature != null ? profile.temperature / 100 : null,
1822
- options: profile.options ?? null,
1823
1906
  };
1824
1907
  }
1825
1908
  async listAgentProfiles(options = {}) {
@@ -1844,7 +1927,6 @@ let LocalStorageService = class LocalStorageService {
1844
1927
  items: items.map((p) => ({
1845
1928
  ...p,
1846
1929
  temperature: p.temperature != null ? p.temperature / 100 : null,
1847
- options: p.options ?? null,
1848
1930
  })),
1849
1931
  total: items.length,
1850
1932
  limit,
@@ -1865,9 +1947,6 @@ let LocalStorageService = class LocalStorageService {
1865
1947
  if (data.instructions !== undefined) {
1866
1948
  updateData.instructions = data.instructions ?? null;
1867
1949
  }
1868
- if (data.options !== undefined) {
1869
- updateData.options = data.options ?? null;
1870
- }
1871
1950
  if (data.familySlug !== undefined) {
1872
1951
  updateData.familySlug = data.familySlug ?? null;
1873
1952
  }
@@ -1953,9 +2032,9 @@ let LocalStorageService = class LocalStorageService {
1953
2032
  if (!base.items.length)
1954
2033
  return { ...base, items: [] };
1955
2034
  const ids = base.items.map((p) => p.id);
1956
- const { agentProfilePrompts, prompts } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2035
+ const { agentProfilePrompts, prompts, profileProviderConfigs, providers } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
1957
2036
  const { inArray, asc, eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
1958
- const rows = await this.db
2037
+ const promptRows = await this.db
1959
2038
  .select({
1960
2039
  profileId: agentProfilePrompts.profileId,
1961
2040
  promptId: agentProfilePrompts.promptId,
@@ -1966,28 +2045,259 @@ let LocalStorageService = class LocalStorageService {
1966
2045
  .innerJoin(prompts, eq(agentProfilePrompts.promptId, prompts.id))
1967
2046
  .where(inArray(agentProfilePrompts.profileId, ids))
1968
2047
  .orderBy(asc(agentProfilePrompts.profileId), asc(agentProfilePrompts.createdAt));
1969
- const grouped = new Map();
1970
- for (const r of rows) {
2048
+ const groupedPrompts = new Map();
2049
+ for (const r of promptRows) {
1971
2050
  const pid = r.profileId;
1972
- const arr = grouped.get(pid) ?? [];
2051
+ const arr = groupedPrompts.get(pid) ?? [];
1973
2052
  arr.push({
1974
2053
  promptId: r.promptId,
1975
2054
  title: r.title,
1976
2055
  createdAt: r.createdAt,
1977
2056
  });
1978
- grouped.set(pid, arr);
2057
+ groupedPrompts.set(pid, arr);
2058
+ }
2059
+ const configRows = await this.db
2060
+ .select({
2061
+ profileId: profileProviderConfigs.profileId,
2062
+ providerId: profileProviderConfigs.providerId,
2063
+ createdAt: profileProviderConfigs.createdAt,
2064
+ })
2065
+ .from(profileProviderConfigs)
2066
+ .where(inArray(profileProviderConfigs.profileId, ids))
2067
+ .orderBy(asc(profileProviderConfigs.profileId), asc(profileProviderConfigs.createdAt));
2068
+ const providerIds = [...new Set(configRows.map((r) => r.providerId))];
2069
+ const providerMap = new Map();
2070
+ if (providerIds.length > 0) {
2071
+ const providerRows = await this.db
2072
+ .select({ id: providers.id, name: providers.name })
2073
+ .from(providers)
2074
+ .where(inArray(providers.id, providerIds));
2075
+ for (const p of providerRows) {
2076
+ providerMap.set(p.id, { id: p.id, name: p.name });
2077
+ }
2078
+ }
2079
+ const firstProviderByProfile = new Map();
2080
+ for (const r of configRows) {
2081
+ const pid = r.profileId;
2082
+ if (!firstProviderByProfile.has(pid)) {
2083
+ const provider = providerMap.get(r.providerId);
2084
+ if (provider) {
2085
+ firstProviderByProfile.set(pid, provider);
2086
+ }
2087
+ }
1979
2088
  }
1980
2089
  const items = base.items.map((p) => {
1981
- const arr = grouped.get(p.id) ?? [];
2090
+ const arr = groupedPrompts.get(p.id) ?? [];
1982
2091
  const promptsDetailed = arr.map((row, idx) => ({
1983
2092
  promptId: row.promptId,
1984
2093
  title: row.title,
1985
2094
  order: idx + 1,
1986
2095
  }));
1987
- return { ...p, prompts: promptsDetailed };
2096
+ const provider = firstProviderByProfile.get(p.id);
2097
+ return { ...p, prompts: promptsDetailed, ...(provider && { provider }) };
1988
2098
  });
1989
2099
  return { ...base, items };
1990
2100
  }
2101
+ async createProfileProviderConfig(data) {
2102
+ const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
2103
+ const now = new Date().toISOString();
2104
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2105
+ const { eq, sql } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2106
+ let position = data.position;
2107
+ if (position === undefined) {
2108
+ const maxResult = await this.db
2109
+ .select({ maxPos: sql `COALESCE(MAX(${profileProviderConfigs.position}), -1)` })
2110
+ .from(profileProviderConfigs)
2111
+ .where(eq(profileProviderConfigs.profileId, data.profileId));
2112
+ position = (maxResult[0]?.maxPos ?? -1) + 1;
2113
+ }
2114
+ const config = {
2115
+ id: randomUUID(),
2116
+ profileId: data.profileId,
2117
+ providerId: data.providerId,
2118
+ name: data.name,
2119
+ options: data.options ?? null,
2120
+ env: data.env ?? null,
2121
+ position,
2122
+ createdAt: now,
2123
+ updatedAt: now,
2124
+ };
2125
+ await this.db.insert(profileProviderConfigs).values({
2126
+ id: config.id,
2127
+ profileId: config.profileId,
2128
+ providerId: config.providerId,
2129
+ name: config.name,
2130
+ options: config.options,
2131
+ env: config.env ? JSON.stringify(config.env) : null,
2132
+ position: config.position,
2133
+ createdAt: config.createdAt,
2134
+ updatedAt: config.updatedAt,
2135
+ });
2136
+ logger.info({ configId: config.id, profileId: config.profileId, position }, 'Created profile provider config');
2137
+ return config;
2138
+ }
2139
+ async getProfileProviderConfig(id) {
2140
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2141
+ const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2142
+ const result = await this.db
2143
+ .select()
2144
+ .from(profileProviderConfigs)
2145
+ .where(eq(profileProviderConfigs.id, id))
2146
+ .limit(1);
2147
+ if (!result[0]) {
2148
+ throw new error_types_1.NotFoundError('ProfileProviderConfig', id);
2149
+ }
2150
+ const row = result[0];
2151
+ return {
2152
+ id: row.id,
2153
+ profileId: row.profileId,
2154
+ providerId: row.providerId,
2155
+ name: row.name,
2156
+ options: row.options,
2157
+ env: this.parseProviderConfigEnv(row.env, row.id, row.profileId),
2158
+ position: row.position,
2159
+ createdAt: row.createdAt,
2160
+ updatedAt: row.updatedAt,
2161
+ };
2162
+ }
2163
+ async listProfileProviderConfigsByProfile(profileId) {
2164
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2165
+ const { eq, asc } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2166
+ const results = await this.db
2167
+ .select()
2168
+ .from(profileProviderConfigs)
2169
+ .where(eq(profileProviderConfigs.profileId, profileId))
2170
+ .orderBy(asc(profileProviderConfigs.position), asc(profileProviderConfigs.id));
2171
+ return results.map((row) => ({
2172
+ id: row.id,
2173
+ profileId: row.profileId,
2174
+ providerId: row.providerId,
2175
+ name: row.name,
2176
+ options: row.options,
2177
+ env: this.parseProviderConfigEnv(row.env, row.id, row.profileId),
2178
+ position: row.position,
2179
+ createdAt: row.createdAt,
2180
+ updatedAt: row.updatedAt,
2181
+ }));
2182
+ }
2183
+ async listProfileProviderConfigsByIds(ids) {
2184
+ if (ids.length === 0) {
2185
+ return [];
2186
+ }
2187
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2188
+ const { inArray } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2189
+ const results = await this.db
2190
+ .select()
2191
+ .from(profileProviderConfigs)
2192
+ .where(inArray(profileProviderConfigs.id, ids));
2193
+ return results.map((row) => ({
2194
+ id: row.id,
2195
+ profileId: row.profileId,
2196
+ providerId: row.providerId,
2197
+ name: row.name,
2198
+ options: row.options,
2199
+ env: this.parseProviderConfigEnv(row.env, row.id, row.profileId),
2200
+ position: row.position,
2201
+ createdAt: row.createdAt,
2202
+ updatedAt: row.updatedAt,
2203
+ }));
2204
+ }
2205
+ async listAllProfileProviderConfigs() {
2206
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2207
+ const results = await this.db.select().from(profileProviderConfigs);
2208
+ return results.map((row) => ({
2209
+ id: row.id,
2210
+ profileId: row.profileId,
2211
+ providerId: row.providerId,
2212
+ name: row.name,
2213
+ options: row.options,
2214
+ env: this.parseProviderConfigEnv(row.env, row.id, row.profileId),
2215
+ position: row.position,
2216
+ createdAt: row.createdAt,
2217
+ updatedAt: row.updatedAt,
2218
+ }));
2219
+ }
2220
+ async updateProfileProviderConfig(id, data) {
2221
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2222
+ const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2223
+ const now = new Date().toISOString();
2224
+ const updateData = { updatedAt: now };
2225
+ if (data.providerId !== undefined) {
2226
+ updateData.providerId = data.providerId;
2227
+ }
2228
+ if (data.name !== undefined) {
2229
+ updateData.name = data.name;
2230
+ }
2231
+ if (data.options !== undefined) {
2232
+ updateData.options = data.options;
2233
+ }
2234
+ if (data.env !== undefined) {
2235
+ updateData.env = data.env ? JSON.stringify(data.env) : null;
2236
+ }
2237
+ if (data.position !== undefined) {
2238
+ updateData.position = data.position;
2239
+ }
2240
+ await this.db
2241
+ .update(profileProviderConfigs)
2242
+ .set(updateData)
2243
+ .where(eq(profileProviderConfigs.id, id));
2244
+ logger.info({ configId: id }, 'Updated profile provider config');
2245
+ return this.getProfileProviderConfig(id);
2246
+ }
2247
+ async deleteProfileProviderConfig(id) {
2248
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2249
+ const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2250
+ const { agents } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2251
+ const agentRefs = await this.db
2252
+ .select({ id: agents.id })
2253
+ .from(agents)
2254
+ .where(eq(agents.providerConfigId, id))
2255
+ .limit(1);
2256
+ if (agentRefs.length > 0) {
2257
+ throw new error_types_1.ValidationError('Cannot delete provider config: still referenced by agents', {
2258
+ configId: id,
2259
+ referencingAgentId: agentRefs[0].id,
2260
+ });
2261
+ }
2262
+ await this.db.delete(profileProviderConfigs).where(eq(profileProviderConfigs.id, id));
2263
+ logger.info({ configId: id }, 'Deleted profile provider config');
2264
+ }
2265
+ async reorderProfileProviderConfigs(profileId, configIds) {
2266
+ const { profileProviderConfigs } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2267
+ const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2268
+ const sqlite = (0, sqlite_raw_1.getRawSqliteClient)(this.db);
2269
+ if (!sqlite || typeof sqlite.exec !== 'function') {
2270
+ throw new error_types_1.StorageError('Unable to access underlying SQLite client for transaction control');
2271
+ }
2272
+ try {
2273
+ sqlite.exec('BEGIN IMMEDIATE TRANSACTION');
2274
+ const configs = await this.db
2275
+ .select({ position: profileProviderConfigs.position })
2276
+ .from(profileProviderConfigs)
2277
+ .where(eq(profileProviderConfigs.profileId, profileId));
2278
+ const maxPosition = Math.max(0, ...configs.map((c) => c.position ?? 0));
2279
+ const tempBase = maxPosition + 1000;
2280
+ for (let i = 0; i < configIds.length; i++) {
2281
+ await this.db
2282
+ .update(profileProviderConfigs)
2283
+ .set({ position: tempBase + i })
2284
+ .where(eq(profileProviderConfigs.id, configIds[i]));
2285
+ }
2286
+ for (let i = 0; i < configIds.length; i++) {
2287
+ await this.db
2288
+ .update(profileProviderConfigs)
2289
+ .set({ position: i })
2290
+ .where(eq(profileProviderConfigs.id, configIds[i]));
2291
+ }
2292
+ sqlite.exec('COMMIT');
2293
+ logger.info({ profileId, configIds }, 'Reordered provider configs');
2294
+ }
2295
+ catch (error) {
2296
+ sqlite.exec('ROLLBACK');
2297
+ logger.error({ error, profileId, configIds }, 'Failed to reorder provider configs, rolled back');
2298
+ throw error;
2299
+ }
2300
+ }
1991
2301
  async createAgent(data) {
1992
2302
  const { randomUUID } = await Promise.resolve().then(() => __importStar(require('crypto')));
1993
2303
  const now = new Date().toISOString();
@@ -1996,6 +2306,7 @@ let LocalStorageService = class LocalStorageService {
1996
2306
  id: randomUUID(),
1997
2307
  ...data,
1998
2308
  description: data.description ?? null,
2309
+ providerConfigId: data.providerConfigId,
1999
2310
  createdAt: now,
2000
2311
  updatedAt: now,
2001
2312
  };
@@ -2007,10 +2318,19 @@ let LocalStorageService = class LocalStorageService {
2007
2318
  profileId: agent.profileId,
2008
2319
  });
2009
2320
  }
2321
+ const config = await this.getProfileProviderConfig(agent.providerConfigId);
2322
+ if (config.profileId !== agent.profileId) {
2323
+ throw new error_types_1.ValidationError('Provider config does not belong to the specified profile.', {
2324
+ providerConfigId: agent.providerConfigId,
2325
+ configProfileId: config.profileId,
2326
+ expectedProfileId: agent.profileId,
2327
+ });
2328
+ }
2010
2329
  await this.db.insert(agents).values({
2011
2330
  id: agent.id,
2012
2331
  projectId: agent.projectId,
2013
2332
  profileId: agent.profileId,
2333
+ providerConfigId: agent.providerConfigId,
2014
2334
  name: agent.name,
2015
2335
  description: agent.description,
2016
2336
  createdAt: agent.createdAt,
@@ -2067,10 +2387,13 @@ let LocalStorageService = class LocalStorageService {
2067
2387
  const { agents } = await Promise.resolve().then(() => __importStar(require('../db/schema')));
2068
2388
  const { eq } = await Promise.resolve().then(() => __importStar(require('drizzle-orm')));
2069
2389
  const now = new Date().toISOString();
2070
- if (data.projectId !== undefined || data.profileId !== undefined) {
2390
+ if (data.projectId !== undefined ||
2391
+ data.profileId !== undefined ||
2392
+ data.providerConfigId !== undefined) {
2071
2393
  const current = await this.getAgent(id);
2072
2394
  const newProjectId = data.projectId ?? current.projectId;
2073
2395
  const newProfileId = data.profileId ?? current.profileId;
2396
+ const newProviderConfigId = data.providerConfigId ?? current.providerConfigId;
2074
2397
  const profile = await this.getAgentProfile(newProfileId);
2075
2398
  if (profile.projectId !== newProjectId) {
2076
2399
  throw new error_types_1.ValidationError('Agent.profileId must belong to the same project as the agent.', {
@@ -2079,6 +2402,14 @@ let LocalStorageService = class LocalStorageService {
2079
2402
  profileId: newProfileId,
2080
2403
  });
2081
2404
  }
2405
+ const config = await this.getProfileProviderConfig(newProviderConfigId);
2406
+ if (config.profileId !== newProfileId) {
2407
+ throw new error_types_1.ValidationError('Provider config does not belong to the specified profile.', {
2408
+ providerConfigId: newProviderConfigId,
2409
+ configProfileId: config.profileId,
2410
+ expectedProfileId: newProfileId,
2411
+ });
2412
+ }
2082
2413
  }
2083
2414
  await this.db
2084
2415
  .update(agents)