@inkeep/agents-cli 0.39.4 → 0.40.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/_virtual/rolldown_runtime.js +7 -0
- package/dist/api.js +185 -0
- package/dist/commands/add.js +139 -0
- package/dist/commands/config.js +86 -0
- package/dist/commands/dev.js +259 -0
- package/dist/commands/init.js +360 -0
- package/dist/commands/list-agents.js +56 -0
- package/dist/commands/login.js +179 -0
- package/dist/commands/logout.js +56 -0
- package/dist/commands/profile.js +276 -0
- package/dist/{component-parser2.js → commands/pull-v3/component-parser.js} +16 -3
- package/dist/commands/pull-v3/component-updater.js +710 -0
- package/dist/commands/pull-v3/components/agent-generator.js +241 -0
- package/dist/commands/pull-v3/components/artifact-component-generator.js +127 -0
- package/dist/commands/pull-v3/components/context-config-generator.js +190 -0
- package/dist/commands/pull-v3/components/credential-generator.js +89 -0
- package/dist/commands/pull-v3/components/data-component-generator.js +102 -0
- package/dist/commands/pull-v3/components/environment-generator.js +170 -0
- package/dist/commands/pull-v3/components/external-agent-generator.js +75 -0
- package/dist/commands/pull-v3/components/function-tool-generator.js +94 -0
- package/dist/commands/pull-v3/components/mcp-tool-generator.js +86 -0
- package/dist/commands/pull-v3/components/project-generator.js +145 -0
- package/dist/commands/pull-v3/components/status-component-generator.js +92 -0
- package/dist/commands/pull-v3/components/sub-agent-generator.js +285 -0
- package/dist/commands/pull-v3/index.js +510 -0
- package/dist/commands/pull-v3/introspect-generator.js +278 -0
- package/dist/commands/pull-v3/llm-content-merger.js +192 -0
- package/dist/{new-component-generator.js → commands/pull-v3/new-component-generator.js} +14 -3
- package/dist/commands/pull-v3/project-comparator.js +914 -0
- package/dist/{project-index-generator.js → commands/pull-v3/project-index-generator.js} +1 -2
- package/dist/{project-validator.js → commands/pull-v3/project-validator.js} +4 -4
- package/dist/commands/pull-v3/targeted-typescript-placeholders.js +173 -0
- package/dist/commands/pull-v3/utils/component-registry.js +369 -0
- package/dist/commands/pull-v3/utils/component-tracker.js +165 -0
- package/dist/commands/pull-v3/utils/generator-utils.js +146 -0
- package/dist/commands/pull-v3/utils/model-provider-detector.js +44 -0
- package/dist/commands/push.js +326 -0
- package/dist/commands/status.js +89 -0
- package/dist/commands/update.js +97 -0
- package/dist/commands/whoami.js +38 -0
- package/dist/config.js +0 -1
- package/dist/env.js +30 -0
- package/dist/exports.js +3 -0
- package/dist/index.js +28 -196514
- package/dist/instrumentation.js +47 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/tsx.d.d.ts +1 -0
- package/dist/utils/background-version-check.js +19 -0
- package/dist/utils/ci-environment.js +87 -0
- package/dist/utils/cli-pipeline.js +158 -0
- package/dist/utils/config.js +290 -0
- package/dist/utils/credentials.js +132 -0
- package/dist/utils/environment-loader.js +28 -0
- package/dist/utils/file-finder.js +62 -0
- package/dist/utils/json-comparator.js +185 -0
- package/dist/utils/json-comparison.js +232 -0
- package/dist/utils/mcp-runner.js +120 -0
- package/dist/utils/model-config.js +182 -0
- package/dist/utils/package-manager.js +58 -0
- package/dist/utils/profile-config.js +85 -0
- package/dist/utils/profiles/index.js +4 -0
- package/dist/utils/profiles/profile-manager.js +219 -0
- package/dist/utils/profiles/types.js +62 -0
- package/dist/utils/project-directory.js +33 -0
- package/dist/utils/project-loader.js +29 -0
- package/dist/utils/schema-introspection.js +44 -0
- package/dist/utils/templates.js +198 -0
- package/dist/utils/tsx-loader.js +27 -0
- package/dist/utils/url.js +26 -0
- package/dist/utils/version-check.js +79 -0
- package/package.json +4 -19
- package/dist/component-parser.js +0 -4
- package/dist/component-updater.js +0 -4
- package/dist/config2.js +0 -4
- package/dist/credential-stores.js +0 -4
- package/dist/environment-generator.js +0 -4
- package/dist/nodefs.js +0 -27
- package/dist/opfs-ahp.js +0 -368
- package/dist/project-loader.js +0 -4
- package/dist/tsx-loader.js +0 -4
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
import { compareJsonObjects } from "../../utils/json-comparator.js";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
|
|
4
|
+
//#region src/commands/pull-v3/project-comparator.ts
|
|
5
|
+
/**
|
|
6
|
+
* Compare two projects and classify all changes using direct component comparison
|
|
7
|
+
*/
|
|
8
|
+
async function compareProjects(localProject, remoteProject, localRegistry, debug = false) {
|
|
9
|
+
if (debug) console.log(chalk.gray("\n🔍 Comparing local and remote projects..."));
|
|
10
|
+
if (!localProject) return createNewProjectComparison(remoteProject, debug);
|
|
11
|
+
const changes = compareComponentsDirectly(localProject, remoteProject, localRegistry, debug);
|
|
12
|
+
const componentChanges = groupChangesByType(changes);
|
|
13
|
+
return {
|
|
14
|
+
hasChanges: changes.length > 0,
|
|
15
|
+
changeCount: changes.length,
|
|
16
|
+
changes,
|
|
17
|
+
rawDifferences: [],
|
|
18
|
+
componentChanges
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Handle new project case (everything is added)
|
|
23
|
+
*/
|
|
24
|
+
function createNewProjectComparison(project, debug) {
|
|
25
|
+
const changes = [];
|
|
26
|
+
if (project.agents) Object.keys(project.agents).forEach((agentId) => {
|
|
27
|
+
changes.push({
|
|
28
|
+
componentType: "agents",
|
|
29
|
+
componentId: agentId,
|
|
30
|
+
changeType: "added"
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
if (project.tools) Object.keys(project.tools).forEach((toolId) => {
|
|
34
|
+
changes.push({
|
|
35
|
+
componentType: "tools",
|
|
36
|
+
componentId: toolId,
|
|
37
|
+
changeType: "added"
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
if (project.functionTools) Object.keys(project.functionTools).forEach((toolId) => {
|
|
41
|
+
changes.push({
|
|
42
|
+
componentType: "functionTools",
|
|
43
|
+
componentId: toolId,
|
|
44
|
+
changeType: "added"
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
if (project.functions) Object.keys(project.functions).forEach((funcId) => {
|
|
48
|
+
changes.push({
|
|
49
|
+
componentType: "functions",
|
|
50
|
+
componentId: funcId,
|
|
51
|
+
changeType: "added"
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
if (project.dataComponents) Object.keys(project.dataComponents).forEach((componentId) => {
|
|
55
|
+
changes.push({
|
|
56
|
+
componentType: "dataComponents",
|
|
57
|
+
componentId,
|
|
58
|
+
changeType: "added"
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
if (project.artifactComponents) Object.keys(project.artifactComponents).forEach((componentId) => {
|
|
62
|
+
changes.push({
|
|
63
|
+
componentType: "artifactComponents",
|
|
64
|
+
componentId,
|
|
65
|
+
changeType: "added"
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
if (project.agents) Object.entries(project.agents).forEach(([agentId, agentData]) => {
|
|
69
|
+
if (agentData.subAgents) Object.keys(agentData.subAgents).forEach((subAgentId) => {
|
|
70
|
+
changes.push({
|
|
71
|
+
componentType: "subAgents",
|
|
72
|
+
componentId: subAgentId,
|
|
73
|
+
changeType: "added"
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
extractStatusComponentIds(project).forEach((componentId) => {
|
|
78
|
+
changes.push({
|
|
79
|
+
componentType: "statusComponents",
|
|
80
|
+
componentId,
|
|
81
|
+
changeType: "added"
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
if (project.agents) Object.entries(project.agents).forEach(([agentId, agentData]) => {
|
|
85
|
+
if (agentData.contextConfig) {
|
|
86
|
+
const contextConfigId = agentData.contextConfig.id;
|
|
87
|
+
if (!contextConfigId) return;
|
|
88
|
+
changes.push({
|
|
89
|
+
componentType: "contextConfigs",
|
|
90
|
+
componentId: contextConfigId,
|
|
91
|
+
changeType: "added"
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
if (project.externalAgents) Object.keys(project.externalAgents).forEach((extAgentId) => {
|
|
96
|
+
changes.push({
|
|
97
|
+
componentType: "externalAgents",
|
|
98
|
+
componentId: extAgentId,
|
|
99
|
+
changeType: "added"
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
if (project.credentialReferences) Object.keys(project.credentialReferences).forEach((credId) => {
|
|
103
|
+
changes.push({
|
|
104
|
+
componentType: "credentials",
|
|
105
|
+
componentId: credId,
|
|
106
|
+
changeType: "added"
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
const componentChanges = groupChangesByType(changes);
|
|
110
|
+
return {
|
|
111
|
+
hasChanges: true,
|
|
112
|
+
changeCount: changes.length,
|
|
113
|
+
changes,
|
|
114
|
+
rawDifferences: [],
|
|
115
|
+
componentChanges
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Direct component-by-component comparison
|
|
120
|
+
*/
|
|
121
|
+
function compareComponentsDirectly(localProject, remoteProject, localRegistry, debug) {
|
|
122
|
+
const changes = [];
|
|
123
|
+
changes.push(...compareAgents(localProject.agents || {}, remoteProject.agents || {}, debug));
|
|
124
|
+
changes.push(...compareSubAgents(localProject.agents || {}, remoteProject.agents || {}, debug));
|
|
125
|
+
changes.push(...compareTools(localProject.tools || {}, remoteProject.tools || {}, debug));
|
|
126
|
+
changes.push(...compareFunctionTools(localProject.functionTools || {}, remoteProject.functionTools || {}, debug));
|
|
127
|
+
changes.push(...compareFunctions(localProject.functions || {}, remoteProject.functions || {}, debug));
|
|
128
|
+
changes.push(...compareDataComponents(localProject.dataComponents || {}, remoteProject.dataComponents || {}, debug));
|
|
129
|
+
changes.push(...compareArtifactComponents(localProject.artifactComponents || {}, remoteProject.artifactComponents || {}, debug));
|
|
130
|
+
changes.push(...compareCredentials(localProject.credentialReferences || {}, remoteProject.credentialReferences || {}, debug));
|
|
131
|
+
changes.push(...compareExternalAgents(localProject.externalAgents || {}, remoteProject.externalAgents || {}, debug));
|
|
132
|
+
const localStatusComponents = extractStatusComponentsFromProject(localProject);
|
|
133
|
+
const remoteStatusComponents = extractStatusComponentsFromProject(remoteProject);
|
|
134
|
+
changes.push(...compareStatusComponents(localStatusComponents, remoteStatusComponents, debug));
|
|
135
|
+
changes.push(...compareContextConfigs(localProject, remoteProject, localRegistry, debug));
|
|
136
|
+
changes.push(...compareFetchDefinitions(localProject, remoteProject, debug));
|
|
137
|
+
changes.push(...compareProjectModels(localProject.models, remoteProject.models, debug));
|
|
138
|
+
changes.push(...compareProjectFields(localProject, remoteProject, debug));
|
|
139
|
+
return changes;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Compare agents between local and remote
|
|
143
|
+
*/
|
|
144
|
+
function compareAgents(localAgents, remoteAgents, debug) {
|
|
145
|
+
const changes = [];
|
|
146
|
+
const localIds = Object.keys(localAgents);
|
|
147
|
+
const remoteIds = Object.keys(remoteAgents);
|
|
148
|
+
remoteIds.filter((id) => !localIds.includes(id)).forEach((id) => {
|
|
149
|
+
const agent = remoteAgents[id];
|
|
150
|
+
changes.push({
|
|
151
|
+
componentType: "agents",
|
|
152
|
+
componentId: id,
|
|
153
|
+
changeType: "added",
|
|
154
|
+
summary: `New agent: ${agent.name || id}`
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
localIds.filter((id) => !remoteIds.includes(id)).forEach((id) => {
|
|
158
|
+
const agent = localAgents[id];
|
|
159
|
+
changes.push({
|
|
160
|
+
componentType: "agents",
|
|
161
|
+
componentId: id,
|
|
162
|
+
changeType: "deleted",
|
|
163
|
+
summary: `Removed agent: ${agent.name || id}`
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
localIds.filter((id) => remoteIds.includes(id)).forEach((id) => {
|
|
167
|
+
const fieldChanges = getDetailedFieldChanges("", localAgents[id], remoteAgents[id]);
|
|
168
|
+
if (fieldChanges.length > 0) {
|
|
169
|
+
const summary = generateAgentChangeSummary(fieldChanges);
|
|
170
|
+
changes.push({
|
|
171
|
+
componentType: "agents",
|
|
172
|
+
componentId: id,
|
|
173
|
+
changeType: "modified",
|
|
174
|
+
changedFields: fieldChanges,
|
|
175
|
+
summary
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
return changes;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Compare subAgents between local and remote
|
|
183
|
+
* Extracts subAgents from all agents and compares them as separate components
|
|
184
|
+
*/
|
|
185
|
+
function compareSubAgents(localAgents, remoteAgents, debug) {
|
|
186
|
+
const changes = [];
|
|
187
|
+
const localSubAgents = {};
|
|
188
|
+
for (const [agentId, agentData] of Object.entries(localAgents)) if (agentData.subAgents) for (const [subAgentId, subAgentData] of Object.entries(agentData.subAgents)) localSubAgents[subAgentId] = subAgentData;
|
|
189
|
+
const remoteSubAgents = {};
|
|
190
|
+
for (const [agentId, agentData] of Object.entries(remoteAgents)) if (agentData.subAgents) for (const [subAgentId, subAgentData] of Object.entries(agentData.subAgents)) remoteSubAgents[subAgentId] = subAgentData;
|
|
191
|
+
const localIds = Object.keys(localSubAgents);
|
|
192
|
+
const remoteIds = Object.keys(remoteSubAgents);
|
|
193
|
+
remoteIds.filter((id) => !localIds.includes(id)).forEach((id) => {
|
|
194
|
+
const subAgent = remoteSubAgents[id];
|
|
195
|
+
changes.push({
|
|
196
|
+
componentType: "subAgents",
|
|
197
|
+
componentId: id,
|
|
198
|
+
changeType: "added",
|
|
199
|
+
summary: `New subAgent: ${subAgent.name || id}`
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
localIds.filter((id) => !remoteIds.includes(id)).forEach((id) => {
|
|
203
|
+
const subAgent = localSubAgents[id];
|
|
204
|
+
changes.push({
|
|
205
|
+
componentType: "subAgents",
|
|
206
|
+
componentId: id,
|
|
207
|
+
changeType: "deleted",
|
|
208
|
+
summary: `Removed subAgent: ${subAgent.name || id}`
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
localIds.filter((id) => remoteIds.includes(id)).forEach((id) => {
|
|
212
|
+
const fieldChanges = getDetailedFieldChanges("", localSubAgents[id], remoteSubAgents[id]);
|
|
213
|
+
if (fieldChanges.length > 0) {
|
|
214
|
+
const summary = generateSubAgentChangeSummary(fieldChanges);
|
|
215
|
+
changes.push({
|
|
216
|
+
componentType: "subAgents",
|
|
217
|
+
componentId: id,
|
|
218
|
+
changeType: "modified",
|
|
219
|
+
changedFields: fieldChanges,
|
|
220
|
+
summary
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return changes;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Generate a summary for subAgent changes
|
|
228
|
+
*/
|
|
229
|
+
function generateSubAgentChangeSummary(fieldChanges) {
|
|
230
|
+
const changeTypes = new Set(fieldChanges.map((c) => c.changeType));
|
|
231
|
+
const fieldNames = fieldChanges.map((c) => c.field.split(".")[0]).filter((value, index, self) => self.indexOf(value) === index);
|
|
232
|
+
if (changeTypes.has("modified") && fieldNames.length === 1) return `Modified ${fieldNames[0]}`;
|
|
233
|
+
if (changeTypes.has("added") && changeTypes.has("deleted")) return `Updated configuration (${fieldChanges.length} changes)`;
|
|
234
|
+
if (changeTypes.has("added")) return `Added ${fieldNames.join(", ")}`;
|
|
235
|
+
if (changeTypes.has("deleted")) return `Removed ${fieldNames.join(", ")}`;
|
|
236
|
+
return `Modified ${fieldNames.join(", ")}`;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Compare tools between local and remote
|
|
240
|
+
*/
|
|
241
|
+
function compareTools(localTools, remoteTools, debug) {
|
|
242
|
+
return compareComponentMaps("tools", localTools, remoteTools, debug);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Compare function tools between local and remote
|
|
246
|
+
*/
|
|
247
|
+
function compareFunctionTools(localFunctionTools, remoteFunctionTools, debug) {
|
|
248
|
+
return compareComponentMaps("functionTools", localFunctionTools, remoteFunctionTools, debug);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Compare functions between local and remote
|
|
252
|
+
*/
|
|
253
|
+
function compareFunctions(localFunctions, remoteFunctions, debug) {
|
|
254
|
+
const cleanLocalFunctions = {};
|
|
255
|
+
const cleanRemoteFunctions = {};
|
|
256
|
+
for (const [id, func] of Object.entries(localFunctions)) cleanLocalFunctions[id] = {
|
|
257
|
+
id: func.id,
|
|
258
|
+
inputSchema: func.inputSchema,
|
|
259
|
+
executeCode: func.executeCode,
|
|
260
|
+
dependencies: func.dependencies
|
|
261
|
+
};
|
|
262
|
+
for (const [id, func] of Object.entries(remoteFunctions)) cleanRemoteFunctions[id] = {
|
|
263
|
+
id: func.id,
|
|
264
|
+
inputSchema: func.inputSchema,
|
|
265
|
+
executeCode: func.executeCode,
|
|
266
|
+
dependencies: func.dependencies
|
|
267
|
+
};
|
|
268
|
+
return compareComponentMaps("functions", cleanLocalFunctions, cleanRemoteFunctions, debug);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Compare data components between local and remote
|
|
272
|
+
*/
|
|
273
|
+
function compareDataComponents(localDataComponents, remoteDataComponents, debug) {
|
|
274
|
+
return compareComponentMaps("dataComponents", localDataComponents, remoteDataComponents, debug);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Compare artifact components between local and remote
|
|
278
|
+
*/
|
|
279
|
+
function compareArtifactComponents(localArtifactComponents, remoteArtifactComponents, debug) {
|
|
280
|
+
return compareComponentMaps("artifactComponents", localArtifactComponents, remoteArtifactComponents, debug);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Compare credentials between local and remote
|
|
284
|
+
*/
|
|
285
|
+
function compareCredentials(localCredentials, remoteCredentials, debug) {
|
|
286
|
+
return compareComponentMaps("credentials", localCredentials, remoteCredentials, debug);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Compare external agents between local and remote
|
|
290
|
+
*/
|
|
291
|
+
function compareExternalAgents(localExternalAgents, remoteExternalAgents, debug) {
|
|
292
|
+
return compareComponentMaps("externalAgents", localExternalAgents, remoteExternalAgents, debug);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Compare status components between local and remote
|
|
296
|
+
*/
|
|
297
|
+
function compareStatusComponents(localStatusComponents, remoteStatusComponents, debug) {
|
|
298
|
+
return compareComponentMaps("statusComponents", localStatusComponents, remoteStatusComponents, debug);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Compare project-level models
|
|
302
|
+
*/
|
|
303
|
+
function compareProjectModels(localModels, remoteModels, debug) {
|
|
304
|
+
const changes = [];
|
|
305
|
+
const fieldChanges = getDetailedFieldChanges("", localModels, remoteModels);
|
|
306
|
+
if (fieldChanges.length > 0) {
|
|
307
|
+
const summary = generateModelsChangeSummary(fieldChanges);
|
|
308
|
+
changes.push({
|
|
309
|
+
componentType: "models",
|
|
310
|
+
componentId: "project",
|
|
311
|
+
changeType: "modified",
|
|
312
|
+
changedFields: fieldChanges,
|
|
313
|
+
summary
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return changes;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Generate summary for model changes
|
|
320
|
+
*/
|
|
321
|
+
function generateModelsChangeSummary(fieldChanges) {
|
|
322
|
+
const modelTypes = [];
|
|
323
|
+
fieldChanges.forEach((change) => {
|
|
324
|
+
const field = change.field;
|
|
325
|
+
if (field.includes("base")) modelTypes.push("base model");
|
|
326
|
+
else if (field.includes("structuredOutput")) modelTypes.push("structured output model");
|
|
327
|
+
else if (field.includes("model")) modelTypes.push("model configuration");
|
|
328
|
+
});
|
|
329
|
+
const uniqueTypes = [...new Set(modelTypes)];
|
|
330
|
+
if (uniqueTypes.length > 0) return `Updated ${uniqueTypes.join(", ")}`;
|
|
331
|
+
return `${fieldChanges.length} model configuration changes`;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Compare project-level fields like name, description, etc.
|
|
335
|
+
*/
|
|
336
|
+
function compareProjectFields(localProject, remoteProject, debug) {
|
|
337
|
+
const changes = [];
|
|
338
|
+
for (const field of [
|
|
339
|
+
"name",
|
|
340
|
+
"description",
|
|
341
|
+
"stopWhen"
|
|
342
|
+
]) {
|
|
343
|
+
const oldValue = localProject[field];
|
|
344
|
+
const newValue = remoteProject[field];
|
|
345
|
+
if (!deepEqual(oldValue, newValue)) {
|
|
346
|
+
const fieldChanges = getDetailedFieldChanges("", oldValue, newValue);
|
|
347
|
+
if (fieldChanges.length > 0) {
|
|
348
|
+
const summary = `Project ${field} updated`;
|
|
349
|
+
changes.push({
|
|
350
|
+
componentType: "contextConfigs",
|
|
351
|
+
componentId: `project-${field}`,
|
|
352
|
+
changeType: "modified",
|
|
353
|
+
changedFields: fieldChanges,
|
|
354
|
+
summary
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return changes;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Generic component map comparison with detailed field tracking
|
|
363
|
+
*/
|
|
364
|
+
function compareComponentMaps(componentType, localMap, remoteMap, debug) {
|
|
365
|
+
const changes = [];
|
|
366
|
+
const localIds = Object.keys(localMap);
|
|
367
|
+
const remoteIds = Object.keys(remoteMap);
|
|
368
|
+
remoteIds.filter((id) => !localIds.includes(id)).forEach((id) => {
|
|
369
|
+
const component = remoteMap[id];
|
|
370
|
+
const summary = generateComponentSummary(componentType, "added", component);
|
|
371
|
+
changes.push({
|
|
372
|
+
componentType,
|
|
373
|
+
componentId: id,
|
|
374
|
+
changeType: "added",
|
|
375
|
+
summary
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
localIds.filter((id) => !remoteIds.includes(id)).forEach((id) => {
|
|
379
|
+
const component = localMap[id];
|
|
380
|
+
const summary = generateComponentSummary(componentType, "deleted", component);
|
|
381
|
+
changes.push({
|
|
382
|
+
componentType,
|
|
383
|
+
componentId: id,
|
|
384
|
+
changeType: "deleted",
|
|
385
|
+
summary
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
localIds.filter((id) => remoteIds.includes(id)).forEach((id) => {
|
|
389
|
+
if (componentType === "artifactComponents") {
|
|
390
|
+
if (!compareJsonObjects(localMap[id], remoteMap[id], {
|
|
391
|
+
ignoreArrayOrder: true,
|
|
392
|
+
showDetails: false
|
|
393
|
+
}).isEqual) changes.push({
|
|
394
|
+
componentType,
|
|
395
|
+
componentId: id,
|
|
396
|
+
changeType: "modified",
|
|
397
|
+
summary: `Modified ${componentType}: ${id}`
|
|
398
|
+
});
|
|
399
|
+
} else {
|
|
400
|
+
const fieldChanges = getDetailedFieldChanges("", localMap[id], remoteMap[id]);
|
|
401
|
+
if (fieldChanges.length > 0) {
|
|
402
|
+
const summary = generateComponentChangeSummary(componentType, fieldChanges);
|
|
403
|
+
changes.push({
|
|
404
|
+
componentType,
|
|
405
|
+
componentId: id,
|
|
406
|
+
changeType: "modified",
|
|
407
|
+
changedFields: fieldChanges,
|
|
408
|
+
summary
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
return changes;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Check if a value is considered "empty" (null, undefined, empty array, empty object)
|
|
417
|
+
*/
|
|
418
|
+
function isEmpty(value) {
|
|
419
|
+
if (value === null || value === void 0) return true;
|
|
420
|
+
if (Array.isArray(value) && value.length === 0) return true;
|
|
421
|
+
if (typeof value === "object" && value !== null && Object.keys(value).length === 0) return true;
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Compare arrays as sets (order-independent) using a key function to identify items
|
|
426
|
+
*/
|
|
427
|
+
function compareArraysAsSet(basePath, oldArray, newArray, depth) {
|
|
428
|
+
const changes = [];
|
|
429
|
+
const getItemKey = (item) => {
|
|
430
|
+
if (typeof item === "string") return item;
|
|
431
|
+
if (typeof item === "object" && item !== null) {
|
|
432
|
+
if (item.toolId) return `tool:${item.toolId}`;
|
|
433
|
+
if (item.agentId) return `agent:${item.agentId}`;
|
|
434
|
+
if (item.externalAgentId) return `external:${item.externalAgentId}`;
|
|
435
|
+
if (item.subAgentId) return `subagent:${item.subAgentId}`;
|
|
436
|
+
if (item.id) return item.id;
|
|
437
|
+
if (item.type) return `type:${item.type}`;
|
|
438
|
+
return JSON.stringify(item);
|
|
439
|
+
}
|
|
440
|
+
return String(item);
|
|
441
|
+
};
|
|
442
|
+
const oldMap = /* @__PURE__ */ new Map();
|
|
443
|
+
const newMap = /* @__PURE__ */ new Map();
|
|
444
|
+
oldArray.forEach((item, index) => {
|
|
445
|
+
const key = getItemKey(item);
|
|
446
|
+
oldMap.set(key, {
|
|
447
|
+
item,
|
|
448
|
+
index
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
newArray.forEach((item, index) => {
|
|
452
|
+
const key = getItemKey(item);
|
|
453
|
+
newMap.set(key, {
|
|
454
|
+
item,
|
|
455
|
+
index
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
for (const [key, { item }] of newMap) if (!oldMap.has(key)) changes.push({
|
|
459
|
+
field: `${basePath}[+${key}]`,
|
|
460
|
+
changeType: "added",
|
|
461
|
+
newValue: item,
|
|
462
|
+
description: `Added array item: ${formatValue(item)}`
|
|
463
|
+
});
|
|
464
|
+
for (const [key, { item }] of oldMap) if (!newMap.has(key)) changes.push({
|
|
465
|
+
field: `${basePath}[-${key}]`,
|
|
466
|
+
changeType: "deleted",
|
|
467
|
+
oldValue: item,
|
|
468
|
+
description: `Removed array item: ${formatValue(item)}`
|
|
469
|
+
});
|
|
470
|
+
for (const [key, { item: newItem }] of newMap) if (oldMap.has(key)) {
|
|
471
|
+
const { item: oldItem } = oldMap.get(key);
|
|
472
|
+
const itemChanges = getDetailedFieldChanges(`${basePath}[${key}]`, oldItem, newItem, depth + 1);
|
|
473
|
+
changes.push(...itemChanges);
|
|
474
|
+
}
|
|
475
|
+
return changes;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Extract credential IDs from an agent object, handling different storage structures
|
|
479
|
+
*/
|
|
480
|
+
function extractCredentialIds(agentObj) {
|
|
481
|
+
const credentialIds = [];
|
|
482
|
+
if (agentObj.credentials && Array.isArray(agentObj.credentials)) agentObj.credentials.forEach((cred) => {
|
|
483
|
+
if (cred.id) credentialIds.push(cred.id);
|
|
484
|
+
});
|
|
485
|
+
if (agentObj.contextConfig?.contextVariables) Object.values(agentObj.contextConfig.contextVariables).forEach((variable) => {
|
|
486
|
+
if (variable && typeof variable === "object" && variable.credentialReferenceId) credentialIds.push(variable.credentialReferenceId);
|
|
487
|
+
});
|
|
488
|
+
return [...new Set(credentialIds)];
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Get detailed field-level changes between two objects
|
|
492
|
+
*/
|
|
493
|
+
function getDetailedFieldChanges(basePath, oldObj, newObj, depth = 0) {
|
|
494
|
+
const changes = [];
|
|
495
|
+
if (depth > 10) return changes;
|
|
496
|
+
const ignoredFields = [
|
|
497
|
+
"_agentId",
|
|
498
|
+
"_parentAgentId",
|
|
499
|
+
"_contextConfigData",
|
|
500
|
+
"type",
|
|
501
|
+
"tenantId",
|
|
502
|
+
"projectId",
|
|
503
|
+
"agentId",
|
|
504
|
+
"lastError",
|
|
505
|
+
"contextConfig.id",
|
|
506
|
+
"lastErrorAt",
|
|
507
|
+
"status",
|
|
508
|
+
"usedBy",
|
|
509
|
+
"tools",
|
|
510
|
+
"createdAt",
|
|
511
|
+
"updatedAt"
|
|
512
|
+
];
|
|
513
|
+
const oldIsEmpty = isEmpty(oldObj);
|
|
514
|
+
const newIsEmpty = isEmpty(newObj);
|
|
515
|
+
if (oldIsEmpty && newIsEmpty) return changes;
|
|
516
|
+
if (oldIsEmpty && !newIsEmpty) {
|
|
517
|
+
const fieldPath = basePath || "root";
|
|
518
|
+
changes.push({
|
|
519
|
+
field: fieldPath,
|
|
520
|
+
changeType: "added",
|
|
521
|
+
oldValue: oldObj,
|
|
522
|
+
newValue: newObj,
|
|
523
|
+
description: `Added: ${formatValue(newObj)}`
|
|
524
|
+
});
|
|
525
|
+
return changes;
|
|
526
|
+
}
|
|
527
|
+
if (!oldIsEmpty && newIsEmpty) {
|
|
528
|
+
const fieldPath = basePath || "root";
|
|
529
|
+
changes.push({
|
|
530
|
+
field: fieldPath,
|
|
531
|
+
changeType: "deleted",
|
|
532
|
+
oldValue: oldObj,
|
|
533
|
+
newValue: newObj,
|
|
534
|
+
description: `Removed: ${formatValue(oldObj)}`
|
|
535
|
+
});
|
|
536
|
+
return changes;
|
|
537
|
+
}
|
|
538
|
+
if (Array.isArray(oldObj) && Array.isArray(newObj)) {
|
|
539
|
+
if (basePath.endsWith("canDelegateTo")) return compareArraysAsSet(basePath, normalizeCanDelegateTo(oldObj), normalizeCanDelegateTo(newObj), depth);
|
|
540
|
+
return compareArraysAsSet(basePath, oldObj, newObj, depth);
|
|
541
|
+
}
|
|
542
|
+
if (typeof oldObj === "object" && typeof newObj === "object") {
|
|
543
|
+
const oldKeys = Object.keys(oldObj);
|
|
544
|
+
const newKeys = Object.keys(newObj);
|
|
545
|
+
const allKeys = [...new Set([...oldKeys, ...newKeys])];
|
|
546
|
+
for (const key of allKeys) {
|
|
547
|
+
const fieldPath = basePath ? `${basePath}.${key}` : key;
|
|
548
|
+
if (ignoredFields.some((ignored) => {
|
|
549
|
+
if (fieldPath === ignored) return true;
|
|
550
|
+
if (key === ignored) return true;
|
|
551
|
+
if (ignored.includes(".") && fieldPath === ignored) return true;
|
|
552
|
+
return false;
|
|
553
|
+
})) continue;
|
|
554
|
+
if (key === "credentials" && basePath === "") {
|
|
555
|
+
const oldCredIds = extractCredentialIds(oldObj);
|
|
556
|
+
const newCredIds = extractCredentialIds(newObj);
|
|
557
|
+
oldCredIds.sort();
|
|
558
|
+
newCredIds.sort();
|
|
559
|
+
if (JSON.stringify(oldCredIds) !== JSON.stringify(newCredIds)) changes.push({
|
|
560
|
+
field: fieldPath,
|
|
561
|
+
changeType: "modified",
|
|
562
|
+
oldValue: oldCredIds,
|
|
563
|
+
newValue: newCredIds,
|
|
564
|
+
description: `Credential usage differs: [${oldCredIds.join(", ")}] vs [${newCredIds.join(", ")}]`
|
|
565
|
+
});
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
const oldValue = oldObj[key];
|
|
569
|
+
const newValue = newObj[key];
|
|
570
|
+
if (!(key in oldObj)) {
|
|
571
|
+
if (!isEmpty(newValue)) changes.push({
|
|
572
|
+
field: fieldPath,
|
|
573
|
+
changeType: "added",
|
|
574
|
+
newValue,
|
|
575
|
+
description: `Added field: ${formatValue(newValue)}`
|
|
576
|
+
});
|
|
577
|
+
} else if (!(key in newObj)) {
|
|
578
|
+
if (!isEmpty(oldValue)) changes.push({
|
|
579
|
+
field: fieldPath,
|
|
580
|
+
changeType: "deleted",
|
|
581
|
+
oldValue,
|
|
582
|
+
description: `Removed field: ${formatValue(oldValue)}`
|
|
583
|
+
});
|
|
584
|
+
} else {
|
|
585
|
+
const oldIsEmpty$1 = isEmpty(oldValue);
|
|
586
|
+
const newIsEmpty$1 = isEmpty(newValue);
|
|
587
|
+
if (oldIsEmpty$1 && newIsEmpty$1) continue;
|
|
588
|
+
if (key === "models") {
|
|
589
|
+
if ((oldValue === null || oldValue === void 0) !== (newValue === null || newValue === void 0)) continue;
|
|
590
|
+
}
|
|
591
|
+
const recursiveChanges = getDetailedFieldChanges(fieldPath, oldValue, newValue, depth + 1);
|
|
592
|
+
changes.push(...recursiveChanges);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return changes;
|
|
596
|
+
}
|
|
597
|
+
if (oldObj !== newObj) {
|
|
598
|
+
const fieldPath = basePath || "value";
|
|
599
|
+
changes.push({
|
|
600
|
+
field: fieldPath,
|
|
601
|
+
changeType: "modified",
|
|
602
|
+
oldValue: oldObj,
|
|
603
|
+
newValue: newObj,
|
|
604
|
+
description: `Changed from ${formatValue(oldObj)} to ${formatValue(newObj)}`
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
return changes;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Format a value for display in change descriptions
|
|
611
|
+
*/
|
|
612
|
+
function formatValue(value) {
|
|
613
|
+
if (value === null) return "null";
|
|
614
|
+
if (value === void 0) return "undefined";
|
|
615
|
+
if (typeof value === "string") {
|
|
616
|
+
if (value.length > 50) return `"${value.substring(0, 47)}..."`;
|
|
617
|
+
return `"${value}"`;
|
|
618
|
+
}
|
|
619
|
+
if (typeof value === "object") {
|
|
620
|
+
if (Array.isArray(value)) {
|
|
621
|
+
if (value.length === 0) return "[]";
|
|
622
|
+
if (value.length === 1) {
|
|
623
|
+
const firstItem$1 = value[0];
|
|
624
|
+
if (typeof firstItem$1 === "object" && firstItem$1 !== null) {
|
|
625
|
+
const keys$1 = Object.keys(firstItem$1);
|
|
626
|
+
if (keys$1.length > 0) return `[{${keys$1.slice(0, 2).join(", ")}${keys$1.length > 2 ? ", ..." : ""}}]`;
|
|
627
|
+
}
|
|
628
|
+
return `["${String(firstItem$1).substring(0, 20)}..."]`;
|
|
629
|
+
}
|
|
630
|
+
const firstItem = value[0];
|
|
631
|
+
if (typeof firstItem === "object" && firstItem !== null) return `[{${Object.keys(firstItem).slice(0, 2).join(", ")}}, ...] (${value.length} items)`;
|
|
632
|
+
return `[${value.length} items]`;
|
|
633
|
+
}
|
|
634
|
+
if (Object.keys(value).length === 0) return "{}";
|
|
635
|
+
const keys = Object.keys(value);
|
|
636
|
+
if (keys.length <= 3) return `{${keys.map((key) => {
|
|
637
|
+
const val = value[key];
|
|
638
|
+
if (typeof val === "string") return `${key}: "${val.length > 15 ? val.substring(0, 12) + "..." : val}"`;
|
|
639
|
+
if (typeof val === "object" && val !== null) return `${key}: {...}`;
|
|
640
|
+
return `${key}: ${val}`;
|
|
641
|
+
}).join(", ")}}`;
|
|
642
|
+
if (keys.length <= 5) return `{${keys.join(", ")}}`;
|
|
643
|
+
return `{${keys.slice(0, 3).join(", ")}, ...} (${keys.length} fields)`;
|
|
644
|
+
}
|
|
645
|
+
return String(value);
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Generate human-readable summary for agent changes
|
|
649
|
+
*/
|
|
650
|
+
function generateAgentChangeSummary(fieldChanges) {
|
|
651
|
+
const summaryParts = [];
|
|
652
|
+
const nameChange = fieldChanges.find((c) => c.field === "name");
|
|
653
|
+
const promptChange = fieldChanges.find((c) => c.field === "prompt");
|
|
654
|
+
const modelChanges = fieldChanges.filter((c) => c.field.startsWith("models"));
|
|
655
|
+
const toolChanges = fieldChanges.filter((c) => c.field.includes("canUse") || c.field.includes("tools"));
|
|
656
|
+
const subAgentChanges = fieldChanges.filter((c) => c.field.includes("subAgents") || c.field.includes("canDelegateTo"));
|
|
657
|
+
if (nameChange) summaryParts.push("name updated");
|
|
658
|
+
if (promptChange) summaryParts.push("prompt changed");
|
|
659
|
+
if (modelChanges.length > 0) summaryParts.push(`${modelChanges.length} model changes`);
|
|
660
|
+
if (toolChanges.length > 0) summaryParts.push(`${toolChanges.length} tool changes`);
|
|
661
|
+
if (subAgentChanges.length > 0) summaryParts.push(`${subAgentChanges.length} sub-agent changes`);
|
|
662
|
+
if (summaryParts.length === 0) return `${fieldChanges.length} field changes`;
|
|
663
|
+
return summaryParts.join(", ");
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Generate summary for component addition/deletion
|
|
667
|
+
*/
|
|
668
|
+
function generateComponentSummary(componentType, changeType, component) {
|
|
669
|
+
const name = component?.name || component?.id || "unnamed";
|
|
670
|
+
const action = changeType === "added" ? "Added" : "Removed";
|
|
671
|
+
if (componentType === "tools") return `${action} ${component?.config?.type || "unknown type"} tool: ${name}`;
|
|
672
|
+
return `${action} ${componentType}: ${name}`;
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Generate summary for component modifications
|
|
676
|
+
*/
|
|
677
|
+
function generateComponentChangeSummary(componentType, fieldChanges) {
|
|
678
|
+
if (componentType === "tools") {
|
|
679
|
+
const configChanges = fieldChanges.filter((c) => c.field.startsWith("config"));
|
|
680
|
+
if (configChanges.length > 0) return `Configuration updated (${configChanges.length} changes)`;
|
|
681
|
+
}
|
|
682
|
+
return `${fieldChanges.length} field changes`;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Deep equality check for component comparison with empty value equivalence
|
|
686
|
+
*/
|
|
687
|
+
function deepEqual(a, b) {
|
|
688
|
+
const aIsEmpty = isEmpty(a);
|
|
689
|
+
const bIsEmpty = isEmpty(b);
|
|
690
|
+
if (aIsEmpty && bIsEmpty) return true;
|
|
691
|
+
if (aIsEmpty !== bIsEmpty) return false;
|
|
692
|
+
return getDetailedFieldChanges("", a, b).length === 0;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Extract status component IDs from agents
|
|
696
|
+
*/
|
|
697
|
+
function extractStatusComponentIds(project) {
|
|
698
|
+
const statusComponentIds = [];
|
|
699
|
+
if (!project.agents) return statusComponentIds;
|
|
700
|
+
for (const agentData of Object.values(project.agents)) if (agentData.statusUpdates?.statusComponents) for (const statusComp of agentData.statusUpdates.statusComponents) {
|
|
701
|
+
const statusCompId = statusComp.type || statusComp.id;
|
|
702
|
+
if (statusCompId && !statusComponentIds.includes(statusCompId)) statusComponentIds.push(statusCompId);
|
|
703
|
+
}
|
|
704
|
+
return statusComponentIds;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Extract actual status component data from agents for comparison
|
|
708
|
+
*/
|
|
709
|
+
function extractStatusComponentsFromProject(project) {
|
|
710
|
+
const statusComponents = {};
|
|
711
|
+
if (!project.agents) return statusComponents;
|
|
712
|
+
for (const [_, agentData] of Object.entries(project.agents)) if (agentData.statusUpdates?.statusComponents) for (const statusComp of agentData.statusUpdates.statusComponents) {
|
|
713
|
+
const statusCompId = statusComp.type || statusComp.id;
|
|
714
|
+
if (statusCompId) statusComponents[statusCompId] = statusComp;
|
|
715
|
+
}
|
|
716
|
+
return statusComponents;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Group changes by component type for easier processing
|
|
720
|
+
*/
|
|
721
|
+
function groupChangesByType(changes) {
|
|
722
|
+
const result = createEmptyComponentChanges();
|
|
723
|
+
changes.forEach((change) => {
|
|
724
|
+
const group = result[change.componentType];
|
|
725
|
+
if (group && !group[change.changeType].includes(change.componentId)) group[change.changeType].push(change.componentId);
|
|
726
|
+
});
|
|
727
|
+
return result;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Create empty component changes structure
|
|
731
|
+
*/
|
|
732
|
+
function createEmptyComponentChanges() {
|
|
733
|
+
return {
|
|
734
|
+
agents: {
|
|
735
|
+
added: [],
|
|
736
|
+
modified: [],
|
|
737
|
+
deleted: []
|
|
738
|
+
},
|
|
739
|
+
subAgents: {
|
|
740
|
+
added: [],
|
|
741
|
+
modified: [],
|
|
742
|
+
deleted: []
|
|
743
|
+
},
|
|
744
|
+
tools: {
|
|
745
|
+
added: [],
|
|
746
|
+
modified: [],
|
|
747
|
+
deleted: []
|
|
748
|
+
},
|
|
749
|
+
functionTools: {
|
|
750
|
+
added: [],
|
|
751
|
+
modified: [],
|
|
752
|
+
deleted: []
|
|
753
|
+
},
|
|
754
|
+
functions: {
|
|
755
|
+
added: [],
|
|
756
|
+
modified: [],
|
|
757
|
+
deleted: []
|
|
758
|
+
},
|
|
759
|
+
dataComponents: {
|
|
760
|
+
added: [],
|
|
761
|
+
modified: [],
|
|
762
|
+
deleted: []
|
|
763
|
+
},
|
|
764
|
+
artifactComponents: {
|
|
765
|
+
added: [],
|
|
766
|
+
modified: [],
|
|
767
|
+
deleted: []
|
|
768
|
+
},
|
|
769
|
+
statusComponents: {
|
|
770
|
+
added: [],
|
|
771
|
+
modified: [],
|
|
772
|
+
deleted: []
|
|
773
|
+
},
|
|
774
|
+
environments: {
|
|
775
|
+
added: [],
|
|
776
|
+
modified: [],
|
|
777
|
+
deleted: []
|
|
778
|
+
},
|
|
779
|
+
contextConfigs: {
|
|
780
|
+
added: [],
|
|
781
|
+
modified: [],
|
|
782
|
+
deleted: []
|
|
783
|
+
},
|
|
784
|
+
fetchDefinitions: {
|
|
785
|
+
added: [],
|
|
786
|
+
modified: [],
|
|
787
|
+
deleted: []
|
|
788
|
+
},
|
|
789
|
+
headers: {
|
|
790
|
+
added: [],
|
|
791
|
+
modified: [],
|
|
792
|
+
deleted: []
|
|
793
|
+
},
|
|
794
|
+
credentials: {
|
|
795
|
+
added: [],
|
|
796
|
+
modified: [],
|
|
797
|
+
deleted: []
|
|
798
|
+
},
|
|
799
|
+
externalAgents: {
|
|
800
|
+
added: [],
|
|
801
|
+
modified: [],
|
|
802
|
+
deleted: []
|
|
803
|
+
},
|
|
804
|
+
models: {
|
|
805
|
+
added: [],
|
|
806
|
+
modified: [],
|
|
807
|
+
deleted: []
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Compare contextConfig components across agents
|
|
813
|
+
*/
|
|
814
|
+
function compareContextConfigs(localProject, remoteProject, localRegistry, debug) {
|
|
815
|
+
const changes = [];
|
|
816
|
+
new Set([...Object.keys(localProject.agents || {}), ...Object.keys(remoteProject.agents || {})]).forEach((agentId) => {
|
|
817
|
+
const localAgent = localProject.agents?.[agentId];
|
|
818
|
+
const remoteAgent = remoteProject.agents?.[agentId];
|
|
819
|
+
const localContextConfig = localAgent?.contextConfig;
|
|
820
|
+
const remoteContextConfig = remoteAgent?.contextConfig;
|
|
821
|
+
const contextId = localContextConfig?.id || remoteContextConfig?.id;
|
|
822
|
+
if (!contextId) return;
|
|
823
|
+
if (!localContextConfig && remoteContextConfig) changes.push({
|
|
824
|
+
componentType: "contextConfigs",
|
|
825
|
+
componentId: contextId,
|
|
826
|
+
changeType: "added",
|
|
827
|
+
summary: `Added contextConfig for agent: ${agentId}`
|
|
828
|
+
});
|
|
829
|
+
else if (localContextConfig && !remoteContextConfig) changes.push({
|
|
830
|
+
componentType: "contextConfigs",
|
|
831
|
+
componentId: contextId,
|
|
832
|
+
changeType: "deleted",
|
|
833
|
+
summary: `Removed contextConfig for agent: ${agentId}`
|
|
834
|
+
});
|
|
835
|
+
else if (localContextConfig && remoteContextConfig) {
|
|
836
|
+
const filteredChanges = getDetailedFieldChanges("", localContextConfig, remoteContextConfig).filter((change) => change.field !== "id");
|
|
837
|
+
if (filteredChanges.length > 0) changes.push({
|
|
838
|
+
componentType: "contextConfigs",
|
|
839
|
+
componentId: contextId,
|
|
840
|
+
changeType: "modified",
|
|
841
|
+
changedFields: filteredChanges,
|
|
842
|
+
summary: `Modified contextConfig for agent: ${agentId} (${filteredChanges.length} changes)`
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
return changes;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Compare fetchDefinition components across contextConfigs
|
|
850
|
+
*/
|
|
851
|
+
function compareFetchDefinitions(localProject, remoteProject, debug) {
|
|
852
|
+
const changes = [];
|
|
853
|
+
const fetchDefinitions = /* @__PURE__ */ new Map();
|
|
854
|
+
const extractFetchDefinitions = (contextConfig) => {
|
|
855
|
+
const fetchDefs = [];
|
|
856
|
+
if (contextConfig && typeof contextConfig === "object" && contextConfig.contextVariables) Object.values(contextConfig.contextVariables).forEach((variable) => {
|
|
857
|
+
if (variable && typeof variable === "object" && variable.id && variable.fetchConfig) fetchDefs.push(variable);
|
|
858
|
+
});
|
|
859
|
+
return fetchDefs;
|
|
860
|
+
};
|
|
861
|
+
Object.entries(localProject.agents || {}).forEach(([agentId, agentData]) => {
|
|
862
|
+
if (agentData.contextConfig) extractFetchDefinitions(agentData.contextConfig).forEach((fetchDef) => {
|
|
863
|
+
if (!fetchDefinitions.has(fetchDef.id)) fetchDefinitions.set(fetchDef.id, {});
|
|
864
|
+
fetchDefinitions.get(fetchDef.id).local = fetchDef;
|
|
865
|
+
});
|
|
866
|
+
});
|
|
867
|
+
Object.entries(remoteProject.agents || {}).forEach(([agentId, agentData]) => {
|
|
868
|
+
if (agentData.contextConfig) extractFetchDefinitions(agentData.contextConfig).forEach((fetchDef) => {
|
|
869
|
+
if (!fetchDefinitions.has(fetchDef.id)) fetchDefinitions.set(fetchDef.id, {});
|
|
870
|
+
fetchDefinitions.get(fetchDef.id).remote = fetchDef;
|
|
871
|
+
});
|
|
872
|
+
});
|
|
873
|
+
fetchDefinitions.forEach((configs, fetchId) => {
|
|
874
|
+
const { local, remote } = configs;
|
|
875
|
+
if (!local && remote) changes.push({
|
|
876
|
+
componentType: "fetchDefinitions",
|
|
877
|
+
componentId: fetchId,
|
|
878
|
+
changeType: "added",
|
|
879
|
+
summary: `Added fetchDefinition: ${fetchId}`
|
|
880
|
+
});
|
|
881
|
+
else if (local && !remote) changes.push({
|
|
882
|
+
componentType: "fetchDefinitions",
|
|
883
|
+
componentId: fetchId,
|
|
884
|
+
changeType: "deleted",
|
|
885
|
+
summary: `Removed fetchDefinition: ${fetchId}`
|
|
886
|
+
});
|
|
887
|
+
else if (local && remote) {
|
|
888
|
+
if (!compareJsonObjects(local, remote, {
|
|
889
|
+
ignoreArrayOrder: true,
|
|
890
|
+
showDetails: true
|
|
891
|
+
}).isEqual) changes.push({
|
|
892
|
+
componentType: "fetchDefinitions",
|
|
893
|
+
componentId: fetchId,
|
|
894
|
+
changeType: "modified",
|
|
895
|
+
summary: `Modified fetchDefinition: ${fetchId}`
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
return changes;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Normalize canDelegateTo array to handle enriched vs non-enriched forms
|
|
903
|
+
* Converts both [{subAgentId: "id"}] and ["id"] to the same normalized form
|
|
904
|
+
*/
|
|
905
|
+
function normalizeCanDelegateTo(canDelegateTo) {
|
|
906
|
+
return canDelegateTo.map((item) => {
|
|
907
|
+
if (typeof item === "string") return item;
|
|
908
|
+
if (typeof item === "object" && item !== null) return item.subAgentId || item.agentId || item.externalAgentId || String(item);
|
|
909
|
+
return String(item);
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
//#endregion
|
|
914
|
+
export { compareProjects };
|