@inkeep/agents-cli 0.39.5 → 0.41.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 (80) hide show
  1. package/dist/_virtual/rolldown_runtime.js +7 -0
  2. package/dist/api.js +185 -0
  3. package/dist/commands/add.js +139 -0
  4. package/dist/commands/config.js +86 -0
  5. package/dist/commands/dev.js +259 -0
  6. package/dist/commands/init.js +360 -0
  7. package/dist/commands/list-agents.js +56 -0
  8. package/dist/commands/login.js +179 -0
  9. package/dist/commands/logout.js +56 -0
  10. package/dist/commands/profile.js +276 -0
  11. package/dist/{component-parser2.js → commands/pull-v3/component-parser.js} +16 -3
  12. package/dist/commands/pull-v3/component-updater.js +710 -0
  13. package/dist/commands/pull-v3/components/agent-generator.js +241 -0
  14. package/dist/commands/pull-v3/components/artifact-component-generator.js +143 -0
  15. package/dist/commands/pull-v3/components/context-config-generator.js +190 -0
  16. package/dist/commands/pull-v3/components/credential-generator.js +89 -0
  17. package/dist/commands/pull-v3/components/data-component-generator.js +102 -0
  18. package/dist/commands/pull-v3/components/environment-generator.js +170 -0
  19. package/dist/commands/pull-v3/components/external-agent-generator.js +75 -0
  20. package/dist/commands/pull-v3/components/function-tool-generator.js +94 -0
  21. package/dist/commands/pull-v3/components/mcp-tool-generator.js +86 -0
  22. package/dist/commands/pull-v3/components/project-generator.js +145 -0
  23. package/dist/commands/pull-v3/components/status-component-generator.js +92 -0
  24. package/dist/commands/pull-v3/components/sub-agent-generator.js +285 -0
  25. package/dist/commands/pull-v3/index.js +510 -0
  26. package/dist/commands/pull-v3/introspect-generator.js +278 -0
  27. package/dist/commands/pull-v3/llm-content-merger.js +192 -0
  28. package/dist/{new-component-generator.js → commands/pull-v3/new-component-generator.js} +14 -3
  29. package/dist/commands/pull-v3/project-comparator.js +914 -0
  30. package/dist/{project-index-generator.js → commands/pull-v3/project-index-generator.js} +1 -2
  31. package/dist/{project-validator.js → commands/pull-v3/project-validator.js} +4 -4
  32. package/dist/commands/pull-v3/targeted-typescript-placeholders.js +173 -0
  33. package/dist/commands/pull-v3/utils/component-registry.js +369 -0
  34. package/dist/commands/pull-v3/utils/component-tracker.js +165 -0
  35. package/dist/commands/pull-v3/utils/generator-utils.js +146 -0
  36. package/dist/commands/pull-v3/utils/model-provider-detector.js +44 -0
  37. package/dist/commands/push.js +326 -0
  38. package/dist/commands/status.js +89 -0
  39. package/dist/commands/update.js +97 -0
  40. package/dist/commands/whoami.js +38 -0
  41. package/dist/config.js +0 -1
  42. package/dist/env.js +30 -0
  43. package/dist/exports.js +3 -0
  44. package/dist/index.js +28 -196514
  45. package/dist/instrumentation.js +47 -0
  46. package/dist/types/agent.js +1 -0
  47. package/dist/types/tsx.d.d.ts +1 -0
  48. package/dist/utils/background-version-check.js +19 -0
  49. package/dist/utils/ci-environment.js +87 -0
  50. package/dist/utils/cli-pipeline.js +158 -0
  51. package/dist/utils/config.js +290 -0
  52. package/dist/utils/credentials.js +132 -0
  53. package/dist/utils/environment-loader.js +28 -0
  54. package/dist/utils/file-finder.js +62 -0
  55. package/dist/utils/json-comparator.js +185 -0
  56. package/dist/utils/json-comparison.js +232 -0
  57. package/dist/utils/mcp-runner.js +120 -0
  58. package/dist/utils/model-config.js +182 -0
  59. package/dist/utils/package-manager.js +58 -0
  60. package/dist/utils/profile-config.js +85 -0
  61. package/dist/utils/profiles/index.js +4 -0
  62. package/dist/utils/profiles/profile-manager.js +219 -0
  63. package/dist/utils/profiles/types.js +62 -0
  64. package/dist/utils/project-directory.js +33 -0
  65. package/dist/utils/project-loader.js +29 -0
  66. package/dist/utils/schema-introspection.js +44 -0
  67. package/dist/utils/templates.js +198 -0
  68. package/dist/utils/tsx-loader.js +27 -0
  69. package/dist/utils/url.js +26 -0
  70. package/dist/utils/version-check.js +79 -0
  71. package/package.json +9 -24
  72. package/dist/component-parser.js +0 -4
  73. package/dist/component-updater.js +0 -4
  74. package/dist/config2.js +0 -4
  75. package/dist/credential-stores.js +0 -4
  76. package/dist/environment-generator.js +0 -4
  77. package/dist/nodefs.js +0 -27
  78. package/dist/opfs-ahp.js +0 -368
  79. package/dist/project-loader.js +0 -4
  80. 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 };