@vibe-forge/tsconfigs 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/cli/__tests__/clear.spec.d.ts +1 -0
- package/dist/apps/cli/__tests__/clear.spec.js +72 -0
- package/dist/apps/cli/src/commands/clear.d.ts +4 -0
- package/dist/apps/cli/src/commands/clear.js +62 -39
- package/dist/apps/client/src/main.d.ts +1 -0
- package/dist/apps/client/src/main.js +1 -0
- package/dist/apps/server/__tests__/db/connection.spec.d.ts +1 -0
- package/dist/apps/server/__tests__/db/connection.spec.js +58 -0
- package/dist/apps/server/__tests__/db/index.spec.js +129 -5
- package/dist/apps/server/__tests__/db/schema.spec.js +3 -6
- package/dist/apps/server/__tests__/db/sqlite.spec.d.ts +1 -0
- package/dist/apps/server/__tests__/db/sqlite.spec.js +51 -0
- package/dist/apps/server/__tests__/services/session-start.spec.js +3 -3
- package/dist/apps/server/src/db/automation/repo.d.ts +2 -2
- package/dist/apps/server/src/db/channelSessions/repo.d.ts +2 -2
- package/dist/apps/server/src/db/connection.d.ts +2 -2
- package/dist/apps/server/src/db/connection.js +2 -2
- package/dist/apps/server/src/db/index.d.ts +2 -2
- package/dist/apps/server/src/db/schema.d.ts +3 -3
- package/dist/apps/server/src/db/sessions/messages.repo.d.ts +2 -2
- package/dist/apps/server/src/db/sessions/repo.d.ts +2 -2
- package/dist/apps/server/src/db/sessions/repo.js +1 -1
- package/dist/apps/server/src/db/sessions/tags.repo.d.ts +2 -2
- package/dist/apps/server/src/db/sqlite.d.ts +44 -0
- package/dist/apps/server/src/db/sqlite.js +83 -0
- package/dist/apps/server/src/index.js +1 -1
- package/dist/apps/server/src/routes/config.js +1 -1
- package/dist/apps/server/src/services/config/index.d.ts +2 -8
- package/dist/apps/server/src/services/config/index.js +3 -39
- package/dist/apps/server/src/services/session/index.js +1 -1
- package/dist/apps/server/src/services/session/notification.js +1 -1
- package/dist/packages/adapters/claude-code/__tests__/default-config.spec.js +15 -0
- package/dist/packages/adapters/claude-code/__tests__/prepare.spec.js +61 -1
- package/dist/packages/adapters/claude-code/__tests__/router-daemon.spec.d.ts +1 -0
- package/dist/packages/adapters/claude-code/__tests__/router-daemon.spec.js +183 -0
- package/dist/packages/adapters/claude-code/src/adapter-config.d.ts +1 -0
- package/dist/packages/adapters/claude-code/src/runtime/init.js +0 -45
- package/dist/packages/adapters/claude-code/src/runtime/prepare.d.ts +6 -9
- package/dist/packages/adapters/claude-code/src/runtime/prepare.js +25 -27
- package/dist/packages/adapters/claude-code/src/runtime/router-daemon.d.ts +19 -0
- package/dist/packages/adapters/claude-code/src/runtime/router-daemon.js +189 -0
- package/dist/packages/channels/lark/src/index.d.ts +4 -4
- package/dist/packages/config/__tests__/load.spec.js +219 -2
- package/dist/packages/config/__tests__/merge.spec.d.ts +1 -0
- package/dist/packages/config/__tests__/merge.spec.js +92 -0
- package/dist/packages/config/src/index.d.ts +1 -0
- package/dist/packages/config/src/index.js +1 -0
- package/dist/packages/config/src/load.d.ts +1 -1
- package/dist/packages/config/src/load.js +167 -53
- package/dist/packages/config/src/merge.d.ts +7 -0
- package/dist/packages/config/src/merge.js +92 -0
- package/dist/packages/tsconfigs/tsconfig.bundler.test.tsbuildinfo +1 -1
- package/dist/packages/tsconfigs/tsconfig.bundler.tsbuildinfo +1 -1
- package/dist/packages/tsconfigs/tsconfig.bundler.web.test.tsbuildinfo +1 -1
- package/dist/packages/tsconfigs/tsconfig.bundler.web.tsbuildinfo +1 -1
- package/dist/packages/tsconfigs/tsconfig.node.test.tsbuildinfo +1 -1
- package/dist/packages/tsconfigs/tsconfig.node.tsbuildinfo +1 -1
- package/dist/packages/types/src/config.d.ts +1 -0
- package/dist/packages/workspace-assets/__tests__/adapter-asset-plan.spec.d.ts +1 -0
- package/dist/packages/workspace-assets/__tests__/adapter-asset-plan.spec.js +121 -0
- package/dist/packages/workspace-assets/__tests__/bundle.spec.d.ts +1 -0
- package/dist/packages/workspace-assets/__tests__/bundle.spec.js +61 -0
- package/dist/packages/workspace-assets/__tests__/prompt-selection.spec.d.ts +1 -0
- package/dist/packages/workspace-assets/__tests__/prompt-selection.spec.js +29 -0
- package/dist/packages/workspace-assets/__tests__/snapshot.d.ts +15 -0
- package/dist/packages/workspace-assets/__tests__/snapshot.js +203 -0
- package/dist/packages/workspace-assets/__tests__/test-helpers.d.ts +2 -0
- package/dist/packages/workspace-assets/__tests__/test-helpers.js +17 -0
- package/dist/packages/workspace-assets/__tests__/workspace-assets.snapshot.spec.d.ts +1 -0
- package/dist/packages/workspace-assets/__tests__/workspace-assets.snapshot.spec.js +172 -0
- package/package.json +1 -1
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { dirname, extname, resolve } from 'node:path';
|
|
4
5
|
import process from 'node:process';
|
|
5
6
|
import { load } from 'js-yaml';
|
|
7
|
+
import { mergeConfigs } from './merge';
|
|
8
|
+
const CONFIG_FILE_EXTENSIONS = new Set([
|
|
9
|
+
'.json',
|
|
10
|
+
'.yaml',
|
|
11
|
+
'.yml'
|
|
12
|
+
]);
|
|
13
|
+
const PACKAGE_DEFAULT_CONFIG_FILES = [
|
|
14
|
+
'.ai.config.json',
|
|
15
|
+
'.ai.config.yaml',
|
|
16
|
+
'.ai.config.yml'
|
|
17
|
+
];
|
|
6
18
|
const serializeJsonVariables = (value) => (JSON.stringify(Object.entries(value)
|
|
7
19
|
.sort(([left], [right]) => left.localeCompare(right))));
|
|
8
20
|
const resolveConfigCacheKey = (options) => {
|
|
@@ -12,54 +24,160 @@ const resolveConfigCacheKey = (options) => {
|
|
|
12
24
|
return `${cwd}\n${disableDevConfig}\n${jsonVariables}`;
|
|
13
25
|
};
|
|
14
26
|
const resolveConfigPath = (cwd, filePath) => resolve(cwd, filePath);
|
|
27
|
+
const isExistingFilePath = (filePath) => {
|
|
28
|
+
if (!existsSync(filePath))
|
|
29
|
+
return false;
|
|
30
|
+
try {
|
|
31
|
+
return statSync(filePath).isFile();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const replaceJsonVariables = (content, jsonVariables) => (content.replace(/\$\{(\w+)\}/g, (_, key) => jsonVariables[key] ?? `$\{${key}}`));
|
|
15
38
|
export const buildConfigJsonVariables = (cwd, env = process.env) => ({
|
|
16
39
|
...env,
|
|
17
40
|
WORKSPACE_FOLDER: cwd,
|
|
18
41
|
__VF_PROJECT_WORKSPACE_FOLDER__: cwd
|
|
19
42
|
});
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
const isRecord = (value) => (value != null &&
|
|
44
|
+
typeof value === 'object' &&
|
|
45
|
+
!Array.isArray(value));
|
|
46
|
+
const toExtendPaths = (value) => {
|
|
47
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
48
|
+
return [value.trim()];
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(value))
|
|
51
|
+
return [];
|
|
52
|
+
return value
|
|
53
|
+
.filter((item) => typeof item === 'string' && item.trim() !== '')
|
|
54
|
+
.map(item => item.trim());
|
|
55
|
+
};
|
|
56
|
+
const omitExtendField = (value) => {
|
|
57
|
+
const { extend: _extend, ...rest } = value;
|
|
58
|
+
return rest;
|
|
59
|
+
};
|
|
60
|
+
const resolveExtendCandidates = (configPath, extendPath) => {
|
|
61
|
+
const resolvedPath = resolve(dirname(configPath), extendPath);
|
|
62
|
+
if (extname(resolvedPath) !== '')
|
|
63
|
+
return [resolvedPath];
|
|
64
|
+
return [
|
|
65
|
+
resolvedPath,
|
|
66
|
+
`${resolvedPath}.json`,
|
|
67
|
+
`${resolvedPath}.yaml`,
|
|
68
|
+
`${resolvedPath}.yml`
|
|
69
|
+
];
|
|
70
|
+
};
|
|
71
|
+
const parsePackageSpecifier = (specifier) => {
|
|
72
|
+
if (specifier.trim() === '' ||
|
|
73
|
+
specifier.startsWith('.') ||
|
|
74
|
+
specifier.startsWith('/') ||
|
|
75
|
+
/^[A-Za-z]:[\\/]/.test(specifier)) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const segments = specifier.split('/');
|
|
79
|
+
if (segments.length === 0)
|
|
80
|
+
return undefined;
|
|
81
|
+
if (specifier.startsWith('@')) {
|
|
82
|
+
const [scope, name, ...rest] = segments;
|
|
83
|
+
if (!scope || !name)
|
|
84
|
+
return undefined;
|
|
85
|
+
return {
|
|
86
|
+
packageName: `${scope}/${name}`,
|
|
87
|
+
subpath: rest.length > 0 ? rest.join('/') : undefined
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const [name, ...rest] = segments;
|
|
91
|
+
if (!name)
|
|
92
|
+
return undefined;
|
|
93
|
+
return {
|
|
94
|
+
packageName: name,
|
|
95
|
+
subpath: rest.length > 0 ? rest.join('/') : undefined
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const resolveConfigCandidatesFromBasePath = (basePath) => (extname(basePath) !== ''
|
|
99
|
+
? [basePath]
|
|
100
|
+
: [
|
|
101
|
+
basePath,
|
|
102
|
+
`${basePath}.json`,
|
|
103
|
+
`${basePath}.yaml`,
|
|
104
|
+
`${basePath}.yml`
|
|
105
|
+
]);
|
|
106
|
+
const resolveDependencyExtendPath = (configPath, extendPath) => {
|
|
107
|
+
const resolver = createRequire(configPath);
|
|
108
|
+
try {
|
|
109
|
+
const directResolvedPath = resolver.resolve(extendPath);
|
|
110
|
+
if (isExistingFilePath(directResolvedPath) &&
|
|
111
|
+
CONFIG_FILE_EXTENSIONS.has(extname(directResolvedPath).toLowerCase())) {
|
|
112
|
+
return directResolvedPath;
|
|
29
113
|
}
|
|
30
|
-
|
|
31
|
-
|
|
114
|
+
}
|
|
115
|
+
catch { }
|
|
116
|
+
const parsed = parsePackageSpecifier(extendPath);
|
|
117
|
+
if (parsed == null)
|
|
118
|
+
return undefined;
|
|
119
|
+
try {
|
|
120
|
+
const packageJsonPath = resolver.resolve(`${parsed.packageName}/package.json`);
|
|
121
|
+
const packageRoot = dirname(packageJsonPath);
|
|
122
|
+
if (parsed.subpath == null) {
|
|
123
|
+
return PACKAGE_DEFAULT_CONFIG_FILES
|
|
124
|
+
.map(fileName => resolve(packageRoot, fileName))
|
|
125
|
+
.find(candidate => isExistingFilePath(candidate));
|
|
32
126
|
}
|
|
127
|
+
return resolveConfigCandidatesFromBasePath(resolve(packageRoot, parsed.subpath))
|
|
128
|
+
.find(candidate => isExistingFilePath(candidate));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return undefined;
|
|
33
132
|
}
|
|
34
133
|
};
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
134
|
+
const resolveExistingExtendPath = (configPath, extendPath) => (resolveExtendCandidates(configPath, extendPath)
|
|
135
|
+
.find(candidate => isExistingFilePath(candidate)) ??
|
|
136
|
+
resolveDependencyExtendPath(configPath, extendPath));
|
|
137
|
+
const readConfigFile = async (configPath, jsonVariables) => {
|
|
138
|
+
const configContent = await readFile(configPath, 'utf-8');
|
|
139
|
+
const configResolvedContent = replaceJsonVariables(configContent, jsonVariables);
|
|
140
|
+
const extension = extname(configPath).toLowerCase();
|
|
141
|
+
if (extension === '.json') {
|
|
142
|
+
return JSON.parse(configResolvedContent);
|
|
143
|
+
}
|
|
144
|
+
if (extension === '.yaml' || extension === '.yml') {
|
|
145
|
+
return load(configResolvedContent);
|
|
146
|
+
}
|
|
147
|
+
throw new Error(`Unsupported config file extension "${extension || '<none>'}"`);
|
|
148
|
+
};
|
|
149
|
+
const loadResolvedConfigFile = async (configPath, jsonVariables, loadingStack) => {
|
|
150
|
+
if (loadingStack.has(configPath)) {
|
|
151
|
+
throw new Error(`Circular config extend detected: ${[
|
|
152
|
+
...loadingStack,
|
|
153
|
+
configPath
|
|
154
|
+
].join(' -> ')}`);
|
|
155
|
+
}
|
|
156
|
+
const rawConfig = await readConfigFile(configPath, jsonVariables);
|
|
157
|
+
if (!isRecord(rawConfig)) {
|
|
158
|
+
throw new Error(`Config file "${configPath}" must resolve to an object`);
|
|
159
|
+
}
|
|
160
|
+
const nextLoadingStack = new Set(loadingStack);
|
|
161
|
+
nextLoadingStack.add(configPath);
|
|
162
|
+
let mergedExtendedConfig;
|
|
163
|
+
for (const extendPath of toExtendPaths(rawConfig.extend)) {
|
|
164
|
+
const extendedConfigPath = resolveExistingExtendPath(configPath, extendPath);
|
|
165
|
+
if (extendedConfigPath == null) {
|
|
166
|
+
throw new Error(`Extended config "${extendPath}" not found from "${configPath}"`);
|
|
49
167
|
}
|
|
168
|
+
const extendedConfig = await loadResolvedConfigFile(extendedConfigPath, jsonVariables, nextLoadingStack);
|
|
169
|
+
mergedExtendedConfig = mergeConfigs(mergedExtendedConfig, extendedConfig);
|
|
50
170
|
}
|
|
171
|
+
return mergeConfigs(mergedExtendedConfig, omitExtendField(rawConfig));
|
|
51
172
|
};
|
|
52
|
-
const
|
|
173
|
+
const loadConfigFromPaths = async (cwd, paths, jsonVariables) => {
|
|
53
174
|
for (const path of paths) {
|
|
54
175
|
try {
|
|
55
176
|
const configPath = resolveConfigPath(cwd, path);
|
|
56
|
-
if (!
|
|
177
|
+
if (!isExistingFilePath(configPath)) {
|
|
57
178
|
continue;
|
|
58
179
|
}
|
|
59
|
-
|
|
60
|
-
const configResolvedContent = configContent
|
|
61
|
-
.replace(/\$\{(\w+)\}/g, (_, key) => jsonVariables[key] ?? `$\{${key}}`);
|
|
62
|
-
return load(configResolvedContent);
|
|
180
|
+
return await loadResolvedConfigFile(configPath, jsonVariables, new Set());
|
|
63
181
|
}
|
|
64
182
|
catch (e) {
|
|
65
183
|
console.error(`Failed to load config file ${path}: ${e}`);
|
|
@@ -86,30 +204,26 @@ export const loadConfig = (options = {}) => {
|
|
|
86
204
|
return cachedConfig;
|
|
87
205
|
}
|
|
88
206
|
const cwd = options.cwd ?? process.cwd();
|
|
89
|
-
const shouldLoadDevConfig =
|
|
90
|
-
process.env[DISABLE_DEV_CONFIG_ENV] !== '1'
|
|
207
|
+
const shouldLoadDevConfig = options.disableDevConfig !== true &&
|
|
208
|
+
process.env[DISABLE_DEV_CONFIG_ENV] !== '1';
|
|
91
209
|
const nextConfig = (async () => [
|
|
92
|
-
await
|
|
210
|
+
await loadConfigFromPaths(cwd, [
|
|
93
211
|
'./.ai.config.json',
|
|
94
|
-
'./infra/.ai.config.json'
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
'./infra/.ai.config.yml'
|
|
101
|
-
], options.jsonVariables ?? {}),
|
|
212
|
+
'./infra/.ai.config.json',
|
|
213
|
+
'./.ai.config.yaml',
|
|
214
|
+
'./.ai.config.yml',
|
|
215
|
+
'./infra/.ai.config.yaml',
|
|
216
|
+
'./infra/.ai.config.yml'
|
|
217
|
+
], options.jsonVariables ?? {}),
|
|
102
218
|
shouldLoadDevConfig
|
|
103
|
-
? await
|
|
219
|
+
? await loadConfigFromPaths(cwd, [
|
|
104
220
|
'./.ai.dev.config.json',
|
|
105
|
-
'./infra/.ai.dev.config.json'
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
'./infra/.ai.dev.config.yml'
|
|
112
|
-
], options.jsonVariables ?? {})
|
|
221
|
+
'./infra/.ai.dev.config.json',
|
|
222
|
+
'./.ai.dev.config.yaml',
|
|
223
|
+
'./.ai.dev.config.yml',
|
|
224
|
+
'./infra/.ai.dev.config.yaml',
|
|
225
|
+
'./infra/.ai.dev.config.yml'
|
|
226
|
+
], options.jsonVariables ?? {})
|
|
113
227
|
: undefined
|
|
114
228
|
])();
|
|
115
229
|
configCache.set(cacheKey, nextConfig);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Config } from '@vibe-forge/types';
|
|
2
|
+
export declare const mergeRecord: <T>(left?: Record<string, T>, right?: Record<string, T>) => {
|
|
3
|
+
[x: string]: T;
|
|
4
|
+
} | undefined;
|
|
5
|
+
export declare const mergeList: <T>(left?: T[], right?: T[]) => T[] | undefined;
|
|
6
|
+
export declare const mergeUniqueList: <T>(left?: T[], right?: T[]) => T[] | undefined;
|
|
7
|
+
export declare const mergeConfigs: <T extends Partial<Config> | undefined>(left: T, right: T) => T;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { mergeAdapterConfigs } from '@vibe-forge/utils';
|
|
2
|
+
const hasOwnKeys = (value) => Object.keys(value).length > 0;
|
|
3
|
+
const isRecord = (value) => (value != null &&
|
|
4
|
+
typeof value === 'object' &&
|
|
5
|
+
!Array.isArray(value));
|
|
6
|
+
export const mergeRecord = (left, right) => {
|
|
7
|
+
if (left == null && right == null)
|
|
8
|
+
return undefined;
|
|
9
|
+
return {
|
|
10
|
+
...(left ?? {}),
|
|
11
|
+
...(right ?? {})
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export const mergeList = (left, right) => {
|
|
15
|
+
if (left == null && right == null)
|
|
16
|
+
return undefined;
|
|
17
|
+
return [
|
|
18
|
+
...(left ?? []),
|
|
19
|
+
...(right ?? [])
|
|
20
|
+
];
|
|
21
|
+
};
|
|
22
|
+
export const mergeUniqueList = (left, right) => {
|
|
23
|
+
const merged = mergeList(left, right);
|
|
24
|
+
return merged == null ? undefined : Array.from(new Set(merged));
|
|
25
|
+
};
|
|
26
|
+
const mergeNotificationEventConfigs = (left, right) => {
|
|
27
|
+
const keys = new Set([
|
|
28
|
+
...Object.keys(left ?? {}),
|
|
29
|
+
...Object.keys(right ?? {})
|
|
30
|
+
]);
|
|
31
|
+
if (keys.size === 0)
|
|
32
|
+
return undefined;
|
|
33
|
+
const merged = Object.fromEntries(Array.from(keys).map((key) => [
|
|
34
|
+
key,
|
|
35
|
+
{
|
|
36
|
+
...(left?.[key] ?? {}),
|
|
37
|
+
...(right?.[key] ?? {})
|
|
38
|
+
}
|
|
39
|
+
]));
|
|
40
|
+
return hasOwnKeys(merged) ? merged : undefined;
|
|
41
|
+
};
|
|
42
|
+
const mergeNotifications = (left, right) => {
|
|
43
|
+
if (left == null && right == null)
|
|
44
|
+
return undefined;
|
|
45
|
+
const merged = {
|
|
46
|
+
...(left ?? {}),
|
|
47
|
+
...(right ?? {}),
|
|
48
|
+
events: mergeNotificationEventConfigs(left?.events, right?.events)
|
|
49
|
+
};
|
|
50
|
+
return hasOwnKeys(merged) ? merged : undefined;
|
|
51
|
+
};
|
|
52
|
+
const mergePermissions = (left, right) => {
|
|
53
|
+
if (left == null && right == null)
|
|
54
|
+
return undefined;
|
|
55
|
+
const merged = {
|
|
56
|
+
...(left ?? {}),
|
|
57
|
+
...(right ?? {}),
|
|
58
|
+
allow: mergeList(left?.allow, right?.allow),
|
|
59
|
+
deny: mergeList(left?.deny, right?.deny),
|
|
60
|
+
ask: mergeList(left?.ask, right?.ask)
|
|
61
|
+
};
|
|
62
|
+
return hasOwnKeys(merged) ? merged : undefined;
|
|
63
|
+
};
|
|
64
|
+
const mergePluginConfigs = (left, right) => {
|
|
65
|
+
if (!isRecord(left) || !isRecord(right)) {
|
|
66
|
+
return right ?? left;
|
|
67
|
+
}
|
|
68
|
+
return mergeRecord(left, right);
|
|
69
|
+
};
|
|
70
|
+
export const mergeConfigs = (left, right) => {
|
|
71
|
+
const merged = {
|
|
72
|
+
...(left ?? {}),
|
|
73
|
+
...(right ?? {}),
|
|
74
|
+
adapters: mergeAdapterConfigs(left?.adapters, right?.adapters),
|
|
75
|
+
models: mergeRecord(left?.models, right?.models),
|
|
76
|
+
modelServices: mergeRecord(left?.modelServices, right?.modelServices),
|
|
77
|
+
channels: mergeRecord(left?.channels, right?.channels),
|
|
78
|
+
mcpServers: mergeRecord(left?.mcpServers, right?.mcpServers),
|
|
79
|
+
defaultIncludeMcpServers: mergeUniqueList(left?.defaultIncludeMcpServers, right?.defaultIncludeMcpServers),
|
|
80
|
+
defaultExcludeMcpServers: mergeUniqueList(left?.defaultExcludeMcpServers, right?.defaultExcludeMcpServers),
|
|
81
|
+
permissions: mergePermissions(left?.permissions, right?.permissions),
|
|
82
|
+
env: mergeRecord(left?.env, right?.env),
|
|
83
|
+
announcements: mergeList(left?.announcements, right?.announcements),
|
|
84
|
+
shortcuts: mergeRecord(left?.shortcuts, right?.shortcuts),
|
|
85
|
+
conversation: mergeRecord(left?.conversation, right?.conversation),
|
|
86
|
+
notifications: mergeNotifications(left?.notifications, right?.notifications),
|
|
87
|
+
plugins: mergePluginConfigs(left?.plugins, right?.plugins),
|
|
88
|
+
enabledPlugins: mergeRecord(left?.enabledPlugins, right?.enabledPlugins),
|
|
89
|
+
extraKnownMarketplaces: mergeRecord(left?.extraKnownMarketplaces, right?.extraKnownMarketplaces)
|
|
90
|
+
};
|
|
91
|
+
return merged;
|
|
92
|
+
};
|