@inkeep/agents-cli 0.50.6 โ†’ 0.52.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 (69) hide show
  1. package/dist/agents-cli/package.js +6 -0
  2. package/dist/commands/config.js +1 -1
  3. package/dist/commands/dev.js +1 -1
  4. package/dist/commands/init.js +1 -1
  5. package/dist/commands/pull-v3/component-parser.js +4 -10
  6. package/dist/commands/pull-v4/agent-generator.js +274 -0
  7. package/dist/commands/pull-v4/artifact-component-generator.js +69 -0
  8. package/dist/commands/pull-v4/context-config-generator.js +264 -0
  9. package/dist/commands/pull-v4/credential-generator.js +30 -0
  10. package/dist/commands/pull-v4/data-component-generator.js +50 -0
  11. package/dist/commands/pull-v4/environment-generator.js +123 -0
  12. package/dist/commands/pull-v4/external-agent-generator.js +56 -0
  13. package/dist/commands/pull-v4/function-tool-generator.js +48 -0
  14. package/dist/commands/pull-v4/introspect/index.js +365 -0
  15. package/dist/commands/pull-v4/introspect/test-helpers.js +143 -0
  16. package/dist/commands/pull-v4/introspect-generator.js +691 -0
  17. package/dist/commands/pull-v4/mcp-tool-generator.js +91 -0
  18. package/dist/commands/pull-v4/module-merge.js +379 -0
  19. package/dist/commands/pull-v4/project-generator.js +101 -0
  20. package/dist/commands/pull-v4/status-component-generator.js +35 -0
  21. package/dist/commands/pull-v4/sub-agent-generator.js +168 -0
  22. package/dist/commands/pull-v4/trigger-generator.js +58 -0
  23. package/dist/commands/pull-v4/utils.js +219 -0
  24. package/dist/commands/push.js +1 -1
  25. package/dist/commands/update.js +2 -2
  26. package/dist/index.js +18 -44
  27. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +18 -0
  28. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +180 -0
  29. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +8 -0
  30. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +12 -0
  31. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +60 -0
  32. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +37 -0
  33. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +31 -0
  34. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +118 -0
  35. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js +11 -0
  36. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +141 -0
  37. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +63 -0
  38. package/dist/utils/ci-environment.js +1 -1
  39. package/dist/utils/config.js +1 -1
  40. package/dist/utils/environment-loader.js +1 -1
  41. package/dist/utils/file-finder.js +1 -1
  42. package/dist/utils/mcp-runner.js +1 -1
  43. package/dist/utils/profile-config.js +1 -1
  44. package/dist/utils/profiles/profile-manager.js +1 -1
  45. package/dist/utils/project-directory.js +1 -1
  46. package/dist/utils/project-loader.js +1 -1
  47. package/dist/utils/version-check.js +6 -15
  48. package/package.json +5 -4
  49. package/dist/commands/pull-v3/component-updater.js +0 -768
  50. package/dist/commands/pull-v3/components/agent-generator.js +0 -255
  51. package/dist/commands/pull-v3/components/artifact-component-generator.js +0 -143
  52. package/dist/commands/pull-v3/components/context-config-generator.js +0 -190
  53. package/dist/commands/pull-v3/components/credential-generator.js +0 -89
  54. package/dist/commands/pull-v3/components/data-component-generator.js +0 -102
  55. package/dist/commands/pull-v3/components/environment-generator.js +0 -173
  56. package/dist/commands/pull-v3/components/external-agent-generator.js +0 -75
  57. package/dist/commands/pull-v3/components/function-tool-generator.js +0 -92
  58. package/dist/commands/pull-v3/components/mcp-tool-generator.js +0 -86
  59. package/dist/commands/pull-v3/components/project-generator.js +0 -157
  60. package/dist/commands/pull-v3/components/status-component-generator.js +0 -92
  61. package/dist/commands/pull-v3/components/sub-agent-generator.js +0 -295
  62. package/dist/commands/pull-v3/components/trigger-generator.js +0 -185
  63. package/dist/commands/pull-v3/index.js +0 -510
  64. package/dist/commands/pull-v3/introspect-generator.js +0 -286
  65. package/dist/commands/pull-v3/llm-content-merger.js +0 -192
  66. package/dist/commands/pull-v3/new-component-generator.js +0 -279
  67. package/dist/commands/pull-v3/project-index-generator.js +0 -32
  68. package/dist/commands/pull-v3/project-validator.js +0 -358
  69. package/dist/utils/url.js +0 -26
@@ -1,279 +0,0 @@
1
- import { toCamelCase } from "./utils/generator-utils.js";
2
- import { generateAgentFile } from "./components/agent-generator.js";
3
- import { generateArtifactComponentFile } from "./components/artifact-component-generator.js";
4
- import { generateContextConfigFile } from "./components/context-config-generator.js";
5
- import { generateCredentialFile } from "./components/credential-generator.js";
6
- import { generateDataComponentFile } from "./components/data-component-generator.js";
7
- import { generateEnvironmentFile } from "./components/environment-generator.js";
8
- import { generateExternalAgentFile } from "./components/external-agent-generator.js";
9
- import { generateFunctionToolFile } from "./components/function-tool-generator.js";
10
- import { generateMcpToolFile } from "./components/mcp-tool-generator.js";
11
- import { generateStatusComponentFile } from "./components/status-component-generator.js";
12
- import { generateSubAgentFile } from "./components/sub-agent-generator.js";
13
- import { findSubAgentWithParent } from "./utils/component-registry.js";
14
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
15
- import { dirname, join } from "node:path";
16
- import chalk from "chalk";
17
-
18
- //#region src/commands/pull-v3/new-component-generator.ts
19
- /**
20
- * New Component Generator - Create brand new files for components that don't exist
21
- */
22
- /**
23
- * Convert component ID to kebab-case filename
24
- */
25
- function toKebabCase(id) {
26
- return id.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_]/g, "-");
27
- }
28
- /**
29
- * Determine file path for new component based on type and existing structure
30
- */
31
- function determineNewFilePath(componentType, componentId, paths) {
32
- const fileName = `${toKebabCase(componentId)}.ts`;
33
- switch (componentType) {
34
- case "agents": return join(paths.agentsDir, fileName);
35
- case "tools": return join(paths.toolsDir, fileName);
36
- case "dataComponents": return join(paths.dataComponentsDir, fileName);
37
- case "artifactComponents": return join(paths.artifactComponentsDir, fileName);
38
- case "statusComponents": return join(paths.statusComponentsDir, fileName);
39
- case "environments": return join(paths.environmentsDir, `${toKebabCase(componentId)}.env.ts`);
40
- case "subAgents": return join(paths.agentsDir, "sub-agents", fileName);
41
- case "externalAgents": return join(paths.externalAgentsDir, fileName);
42
- case "functions":
43
- case "functionTools": return join(join(paths.toolsDir, "functions"), fileName);
44
- case "credentials": return join(paths.credentialsDir, fileName);
45
- case "contextConfigs": return join(paths.contextConfigsDir, fileName);
46
- default: throw new Error(`Unknown component type for new file: ${componentType}`);
47
- }
48
- }
49
- /**
50
- * Generate component content using appropriate generator
51
- */
52
- function generateComponentContent(componentType, componentId, componentData, componentRegistry) {
53
- const defaultStyle = {
54
- quotes: "single",
55
- indentation: " ",
56
- semicolons: true
57
- };
58
- switch (componentType) {
59
- case "agents": return generateAgentFile(componentId, componentData, defaultStyle, componentRegistry);
60
- case "subAgents": {
61
- const parentAgentId = componentData._parentAgentId;
62
- const contextConfigData = componentData._contextConfigData;
63
- const cleanComponentData = { ...componentData };
64
- delete cleanComponentData._parentAgentId;
65
- delete cleanComponentData._contextConfigData;
66
- return generateSubAgentFile(componentId, cleanComponentData, defaultStyle, componentRegistry, parentAgentId, contextConfigData);
67
- }
68
- case "tools": return generateMcpToolFile(componentId, componentData, defaultStyle, componentRegistry);
69
- case "dataComponents": return generateDataComponentFile(componentId, componentData, defaultStyle);
70
- case "artifactComponents": return generateArtifactComponentFile(componentId, componentData, defaultStyle);
71
- case "statusComponents": return generateStatusComponentFile(componentId, componentData, defaultStyle);
72
- case "environments": return generateEnvironmentFile(componentId, componentData, defaultStyle, componentRegistry);
73
- case "externalAgents": return generateExternalAgentFile(componentId, componentData, defaultStyle, componentRegistry);
74
- case "functions":
75
- case "functionTools": return generateFunctionToolFile(componentId, componentData, defaultStyle);
76
- case "credentials": return generateCredentialFile(componentId, componentData, defaultStyle);
77
- case "contextConfigs": {
78
- const cleanComponentData = { ...componentData };
79
- delete cleanComponentData._agentId;
80
- return generateContextConfigFile(componentId, cleanComponentData, defaultStyle, componentRegistry);
81
- }
82
- default: throw new Error(`No generator for component type: ${componentType}`);
83
- }
84
- }
85
- /**
86
- * Create new component files for components that don't exist locally
87
- */
88
- async function createNewComponents(comparison, remoteProject, localRegistry, paths, environment, tempDirName) {
89
- const results = [];
90
- if (!comparison.hasChanges) return results;
91
- const targetPaths = tempDirName ? {
92
- projectRoot: join(paths.projectRoot, tempDirName),
93
- agentsDir: join(paths.projectRoot, tempDirName, "agents"),
94
- toolsDir: join(paths.projectRoot, tempDirName, "tools"),
95
- dataComponentsDir: join(paths.projectRoot, tempDirName, "data-components"),
96
- artifactComponentsDir: join(paths.projectRoot, tempDirName, "artifact-components"),
97
- statusComponentsDir: join(paths.projectRoot, tempDirName, "status-components"),
98
- environmentsDir: join(paths.projectRoot, tempDirName, "environments"),
99
- credentialsDir: join(paths.projectRoot, tempDirName, "credentials"),
100
- contextConfigsDir: join(paths.projectRoot, tempDirName, "context-configs"),
101
- externalAgentsDir: join(paths.projectRoot, tempDirName, "external-agents"),
102
- skillsDir: join(paths.projectRoot, tempDirName, "skills")
103
- } : paths;
104
- const actionText = tempDirName ? "Creating component files in temp directory..." : "Creating new component files...";
105
- console.log(chalk.cyan(`\n๐Ÿ†• ${actionText}`));
106
- if (!comparison.componentChanges.environments?.added.includes(environment)) {
107
- if (!comparison.componentChanges.environments) comparison.componentChanges.environments = {
108
- added: [],
109
- modified: [],
110
- deleted: []
111
- };
112
- comparison.componentChanges.environments.added.push(environment);
113
- }
114
- const creationOrder = [
115
- "credentials",
116
- "environments",
117
- "contextConfigs",
118
- "functionTools",
119
- "functions",
120
- "tools",
121
- "dataComponents",
122
- "artifactComponents",
123
- "statusComponents",
124
- "externalAgents",
125
- "subAgents",
126
- "agents"
127
- ];
128
- console.log(chalk.cyan("๐Ÿ“ Registering all new components in registry..."));
129
- for (const componentType of creationOrder) {
130
- const changes = comparison.componentChanges[componentType];
131
- if (!changes) continue;
132
- const addedComponents = changes.added || [];
133
- for (const componentId of addedComponents) {
134
- if (localRegistry.get(componentId, componentType)) continue;
135
- const relativePath = determineNewFilePath(componentType, componentId, targetPaths).replace(`${tempDirName ? targetPaths.projectRoot : paths.projectRoot}/`, "");
136
- let explicitVariableName;
137
- if (componentType === "contextConfigs") {
138
- const contextResult = findContextConfigData(remoteProject, componentId);
139
- if (contextResult) explicitVariableName = `${toCamelCase(contextResult.agentId)}Context`;
140
- }
141
- localRegistry.register(componentId, componentType, relativePath, explicitVariableName, false);
142
- }
143
- }
144
- console.log(chalk.cyan("๐Ÿ”จ Generating component files..."));
145
- for (const componentType of creationOrder) {
146
- const changes = comparison.componentChanges[componentType];
147
- if (!changes) continue;
148
- const addedComponents = changes.added || [];
149
- if (addedComponents.length === 0) continue;
150
- const remoteComponents = remoteProject[componentType] || {};
151
- for (const componentId of addedComponents) try {
152
- const filePath = determineNewFilePath(componentType, componentId, targetPaths);
153
- if (existsSync(filePath)) continue;
154
- let componentData = null;
155
- if (componentType === "statusComponents") componentData = findStatusComponentData(remoteProject, componentId);
156
- else if (componentType === "credentials") componentData = remoteProject.credentialReferences?.[componentId];
157
- else if (componentType === "contextConfigs") {
158
- const contextResult = findContextConfigData(remoteProject, componentId);
159
- if (contextResult) {
160
- componentData = contextResult.contextConfig;
161
- componentData._agentId = contextResult.agentId;
162
- }
163
- } else if (componentType === "functions") componentData = remoteProject.functions?.[componentId];
164
- else if (componentType === "functionTools") {
165
- const functionToolData = remoteProject.functionTools?.[componentId] || remoteProject.functions?.[componentId];
166
- if (functionToolData && "functionId" in functionToolData && functionToolData.functionId && remoteProject.functions?.[functionToolData.functionId]) componentData = {
167
- ...remoteProject.functions[functionToolData.functionId],
168
- ...functionToolData
169
- };
170
- else componentData = functionToolData;
171
- } else if (componentType === "subAgents") {
172
- const subAgentInfo = findSubAgentWithParent(remoteProject, componentId);
173
- if (subAgentInfo) {
174
- componentData = subAgentInfo.subAgentData;
175
- componentData._parentAgentId = subAgentInfo.parentAgentId;
176
- componentData._contextConfigData = subAgentInfo.contextConfigData;
177
- } else componentData = null;
178
- } else if (componentType === "environments") componentData = {
179
- name: `${componentId} Environment`,
180
- description: `Environment configuration for ${componentId}`,
181
- credentials: remoteProject.credentialReferences ? Object.keys(remoteProject.credentialReferences) : []
182
- };
183
- else componentData = remoteComponents[componentId];
184
- if (!componentData) {
185
- results.push({
186
- componentId,
187
- componentType,
188
- filePath: "",
189
- variableName: "",
190
- success: false,
191
- error: "No data found in remote project"
192
- });
193
- continue;
194
- }
195
- mkdirSync(dirname(filePath), { recursive: true });
196
- writeFileSync(filePath, generateComponentContent(componentType, componentId, componentData, localRegistry), "utf8");
197
- const registryEntry = localRegistry.get(componentId, componentType);
198
- if (!registryEntry) throw new Error(`Component ${componentId} (${componentType}) was not registered in the registry`);
199
- const variableName = registryEntry.name;
200
- results.push({
201
- componentId,
202
- componentType,
203
- filePath,
204
- variableName,
205
- success: true
206
- });
207
- } catch (error) {
208
- const errorMsg = error instanceof Error ? error.message : String(error);
209
- results.push({
210
- componentId,
211
- componentType,
212
- filePath: "",
213
- variableName: "",
214
- success: false,
215
- error: errorMsg
216
- });
217
- }
218
- }
219
- const createdEnvironments = results.filter((r) => r.success && r.componentType === "environments");
220
- if (createdEnvironments.length > 0) try {
221
- console.log(chalk.cyan("๐Ÿ“ Generating environments index file..."));
222
- const { generateEnvironmentIndexFile } = await import("./components/environment-generator.js");
223
- const indexContent = generateEnvironmentIndexFile(createdEnvironments.map((r) => r.componentId), {
224
- quotes: "single",
225
- indentation: " ",
226
- semicolons: true
227
- });
228
- const indexPath = join(targetPaths.environmentsDir, "index.ts");
229
- mkdirSync(dirname(indexPath), { recursive: true });
230
- writeFileSync(indexPath, indexContent, "utf8");
231
- console.log(chalk.green("โœ… Environment index file created"));
232
- } catch (error) {
233
- console.log(chalk.yellow("โš ๏ธ Failed to create environment index file:", error instanceof Error ? error.message : String(error)));
234
- }
235
- const successful = results.filter((r) => r.success);
236
- const failed = results.filter((r) => !r.success);
237
- console.log(chalk.green(`\nโœ… Created ${successful.length} new component files`));
238
- if (failed.length > 0) console.log(chalk.red(`โŒ ${failed.length} components failed`));
239
- if (failed.length > 0) {
240
- console.log(chalk.red("\nโŒ Failed to create:"));
241
- failed.forEach((result) => {
242
- console.log(chalk.red(` ${result.componentType}:${result.componentId} - ${result.error}`));
243
- });
244
- }
245
- return results;
246
- }
247
- /**
248
- * Find status component data by ID from project agents
249
- */
250
- function findStatusComponentData(project, statusId) {
251
- if (project.agents) {
252
- for (const agentData of Object.values(project.agents)) if (agentData.statusUpdates?.statusComponents) for (const statusComp of agentData.statusUpdates.statusComponents) {
253
- let compId;
254
- if (typeof statusComp === "string") compId = statusComp;
255
- else if (typeof statusComp === "object" && statusComp) compId = statusComp.type;
256
- if (compId === statusId) return typeof statusComp === "string" ? {
257
- id: statusId,
258
- type: statusId,
259
- description: `Status component for ${statusId}`
260
- } : statusComp;
261
- }
262
- }
263
- }
264
- /**
265
- * Find context config data by ID from project agents
266
- */
267
- function findContextConfigData(project, contextId) {
268
- if (project.agents) {
269
- for (const [agentId, agentData] of Object.entries(project.agents)) if (agentData.contextConfig) {
270
- if (agentData.contextConfig.id === contextId) return {
271
- contextConfig: agentData.contextConfig,
272
- agentId
273
- };
274
- }
275
- }
276
- }
277
-
278
- //#endregion
279
- export { createNewComponents };
@@ -1,32 +0,0 @@
1
- import { generateProjectFile } from "./components/project-generator.js";
2
- import { writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
-
5
- //#region src/commands/pull-v3/project-index-generator.ts
6
- /**
7
- * Project Index Generator - Generate index.ts file for new projects
8
- */
9
- /**
10
- * Generate project index.ts file
11
- */
12
- async function generateProjectIndex(projectRoot, remoteProject, localRegistry, projectId) {
13
- const indexPath = join(projectRoot, "index.ts");
14
- const defaultStyle = {
15
- quotes: "single",
16
- indentation: " ",
17
- semicolons: true
18
- };
19
- const registryComponents = localRegistry.getAllComponents();
20
- writeFileSync(indexPath, generateProjectFile(projectId, {
21
- ...remoteProject,
22
- agents: registryComponents.filter((c) => c.type === "agents").map((c) => c.id),
23
- tools: registryComponents.filter((c) => c.type === "tools").map((c) => c.id),
24
- externalAgents: registryComponents.filter((c) => c.type === "externalAgents").map((c) => c.id),
25
- dataComponents: registryComponents.filter((c) => c.type === "dataComponents").map((c) => c.id),
26
- artifactComponents: registryComponents.filter((c) => c.type === "artifactComponents").map((c) => c.id),
27
- credentialReferences: registryComponents.filter((c) => c.type === "credentials").map((c) => c.id)
28
- }, defaultStyle, localRegistry), "utf8");
29
- }
30
-
31
- //#endregion
32
- export { generateProjectIndex };
@@ -1,358 +0,0 @@
1
- import { compareProjects } from "./project-comparator.js";
2
- import { enrichCanDelegateToWithTypes } from "./index.js";
3
- import { buildComponentRegistryFromParsing } from "./component-parser.js";
4
- import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
5
- import { dirname, join } from "node:path";
6
- import chalk from "chalk";
7
-
8
- //#region src/commands/pull-v3/project-validator.ts
9
- /**
10
- * Project Validator - Validate generated projects with TypeScript compilation and equivalence checking
11
- */
12
- /**
13
- * Get a complete preview of an object for logging (pretty-printed JSON)
14
- */
15
- function getObjectPreview(obj) {
16
- if (obj === null) return "null";
17
- if (obj === void 0) return "undefined";
18
- try {
19
- if (typeof obj === "object") return JSON.stringify(obj, null, 2);
20
- return String(obj);
21
- } catch {
22
- return `[Error stringifying: ${typeof obj}]`;
23
- }
24
- }
25
- /**
26
- * Find key differences between two objects without full JSON dump
27
- */
28
- /**
29
- * Extract credential IDs from an agent object, handling different storage structures
30
- */
31
- function extractCredentialIds(agentObj) {
32
- const credentialIds = [];
33
- if (agentObj.credentials && Array.isArray(agentObj.credentials)) agentObj.credentials.forEach((cred) => {
34
- if (cred.id) credentialIds.push(cred.id);
35
- });
36
- if (agentObj.contextConfig?.contextVariables) Object.values(agentObj.contextConfig.contextVariables).forEach((variable) => {
37
- if (variable && typeof variable === "object" && variable.credentialReferenceId) credentialIds.push(variable.credentialReferenceId);
38
- });
39
- return [...new Set(credentialIds)];
40
- }
41
- const IGNORED_COMPARISON_FIELDS = new Set([
42
- "type",
43
- "tenantId",
44
- "projectId",
45
- "agentId",
46
- "lastError",
47
- "lastErrorAt",
48
- "status",
49
- "usedBy",
50
- "tools",
51
- "createdAt",
52
- "updatedAt"
53
- ]);
54
- function findKeyDifferences(obj1, obj2) {
55
- const differences = [];
56
- const allKeys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]);
57
- for (const key of allKeys) {
58
- const val1 = obj1?.[key];
59
- const val2 = obj2?.[key];
60
- if (key.startsWith("_") || IGNORED_COMPARISON_FIELDS.has(key)) continue;
61
- if (key === "credentials") {
62
- const creds1 = extractCredentialIds(obj1);
63
- const creds2 = extractCredentialIds(obj2);
64
- creds1.sort();
65
- creds2.sort();
66
- if (JSON.stringify(creds1) !== JSON.stringify(creds2)) differences.push(`~ credentials: usage differs (${creds1.join(", ")} vs ${creds2.join(", ")})`);
67
- continue;
68
- }
69
- const val1IsEmpty = val1 === null || val1 === void 0 || Array.isArray(val1) && val1.length === 0 || typeof val1 === "object" && val1 !== null && Object.keys(val1).length === 0;
70
- const val2IsEmpty = val2 === null || val2 === void 0 || Array.isArray(val2) && val2.length === 0 || typeof val2 === "object" && val2 !== null && Object.keys(val2).length === 0;
71
- if (val1IsEmpty && val2IsEmpty) continue;
72
- if (val1IsEmpty && !val2IsEmpty) differences.push(`+ ${key}: ${typeof val2} (only in remote)`);
73
- else if (!val1IsEmpty && val2IsEmpty) differences.push(`- ${key}: ${typeof val1} (only in generated)`);
74
- else if (val1 !== val2) if (Array.isArray(val1) && Array.isArray(val2)) {
75
- if (val1.length !== val2.length) differences.push(`~ ${key}: array length differs (${val1.length} vs ${val2.length})`);
76
- } else if (typeof val1 === "object" && typeof val2 === "object" && val1 !== null && val2 !== null) {
77
- const filterKeys = (obj) => Object.keys(obj).filter((k) => {
78
- if (k.startsWith("_") || IGNORED_COMPARISON_FIELDS.has(k)) return false;
79
- const v = obj[k];
80
- return !(v === null || v === void 0 || Array.isArray(v) && v.length === 0 || typeof v === "object" && v !== null && Object.keys(v).length === 0);
81
- });
82
- const keys1 = filterKeys(val1);
83
- const keys2 = filterKeys(val2);
84
- const subKeys1 = keys1.length;
85
- const subKeys2 = keys2.length;
86
- if (subKeys1 !== subKeys2) differences.push(`~ ${key}: object size differs (${subKeys1} vs ${subKeys2} keys)`);
87
- } else if (typeof val1 !== typeof val2) differences.push(`~ ${key}: type differs (${typeof val1} vs ${typeof val2})`);
88
- else if (key === "render" || key === "component") {
89
- const val1Preview = getObjectPreview(val1);
90
- const val2Preview = getObjectPreview(val2);
91
- differences.push(`~ ${key}:`);
92
- differences.push(` Generated: ${val1Preview}`);
93
- differences.push(` Remote: ${val2Preview}`);
94
- } else {
95
- const val1Str = String(val1);
96
- const val2Str = String(val2);
97
- if (val1Str.length < 100 && val2Str.length < 100) differences.push(`~ ${key}: "${val1Str}" vs "${val2Str}"`);
98
- else differences.push(`~ ${key}: values differ (both ${typeof val1})`);
99
- }
100
- }
101
- return differences.slice(0, 10);
102
- }
103
- /**
104
- * Get a specific component from a project by type and ID
105
- */
106
- function getComponentFromProject(project, componentType, componentId) {
107
- switch (componentType) {
108
- case "credentials": return project.credentialReferences?.[componentId];
109
- case "tools": return project.tools?.[componentId];
110
- case "agents": return project.agents?.[componentId];
111
- case "subAgents":
112
- if (project.agents) {
113
- for (const [_agentId, agentData] of Object.entries(project.agents)) if (agentData.subAgents?.[componentId]) return agentData.subAgents[componentId];
114
- }
115
- return null;
116
- case "contextConfigs":
117
- if (project.agents) {
118
- for (const [_agentId, agentData] of Object.entries(project.agents)) if (agentData.contextConfig && agentData.contextConfig.id === componentId) return agentData.contextConfig;
119
- }
120
- return null;
121
- case "fetchDefinitions":
122
- if (project.agents) {
123
- for (const [_agentId, agentData] of Object.entries(project.agents)) if (agentData.contextConfig?.contextVariables) {
124
- for (const [_varId, variable] of Object.entries(agentData.contextConfig.contextVariables)) if (variable && typeof variable === "object" && variable.id === componentId) return variable;
125
- }
126
- }
127
- return null;
128
- case "dataComponents": return project.dataComponents?.[componentId];
129
- case "artifactComponents": return project.artifactComponents?.[componentId];
130
- case "externalAgents": return project.externalAgents?.[componentId];
131
- case "functions": return project.functions?.[componentId];
132
- case "functionTools": return project.functionTools?.[componentId];
133
- default: return null;
134
- }
135
- }
136
- /**
137
- * Load project from temp directory and compare with remote project
138
- */
139
- async function validateProjectEquivalence(tempDir, remoteProject) {
140
- try {
141
- const { loadProject } = await import("../../utils/project-loader.js");
142
- const tempProject = await loadProject(tempDir);
143
- const tempProjectDefinition = await Promise.race([tempProject.getFullDefinition(), new Promise((_, reject) => {
144
- setTimeout(() => {
145
- reject(/* @__PURE__ */ new Error("getFullDefinition() timed out after 30 seconds"));
146
- }, 3e4);
147
- })]);
148
- enrichCanDelegateToWithTypes(tempProjectDefinition);
149
- buildComponentRegistryFromParsing(tempDir, false);
150
- const comparison = await compareProjects(tempProjectDefinition, remoteProject, true);
151
- if (!comparison.hasChanges) return true;
152
- let hasMeaningfulDifferences = false;
153
- let hasAddedOrDeleted = false;
154
- const meaningfulDiffs = [];
155
- const addedComponents = [];
156
- const deletedComponents = [];
157
- for (const [componentType, changes] of Object.entries(comparison.componentChanges)) {
158
- if (changes.added.length > 0) {
159
- addedComponents.push({
160
- type: componentType,
161
- ids: changes.added
162
- });
163
- hasAddedOrDeleted = true;
164
- }
165
- if (changes.deleted.length > 0) {
166
- deletedComponents.push({
167
- type: componentType,
168
- ids: changes.deleted
169
- });
170
- hasAddedOrDeleted = true;
171
- }
172
- if (changes.modified.length > 0) for (const modifiedId of changes.modified) {
173
- const generatedComponent = getComponentFromProject(tempProjectDefinition, componentType, modifiedId);
174
- const remoteComponent = getComponentFromProject(remoteProject, componentType, modifiedId);
175
- if (generatedComponent && remoteComponent) {
176
- const differences = findKeyDifferences(generatedComponent, remoteComponent);
177
- if (differences.length > 0) {
178
- meaningfulDiffs.push({
179
- componentType,
180
- componentId: modifiedId,
181
- differences
182
- });
183
- hasMeaningfulDifferences = true;
184
- }
185
- } else if (!generatedComponent) {
186
- meaningfulDiffs.push({
187
- componentType,
188
- componentId: modifiedId,
189
- differences: [],
190
- isMissing: "generated"
191
- });
192
- hasMeaningfulDifferences = true;
193
- } else if (!remoteComponent) {
194
- meaningfulDiffs.push({
195
- componentType,
196
- componentId: modifiedId,
197
- differences: [],
198
- isMissing: "remote"
199
- });
200
- hasMeaningfulDifferences = true;
201
- }
202
- }
203
- }
204
- if (!hasMeaningfulDifferences && !hasAddedOrDeleted) return true;
205
- console.log(chalk.yellow(` ๐Ÿ”„ Found differences:`));
206
- for (const { type, ids } of addedComponents) {
207
- console.log(chalk.cyan(` ${type}:`));
208
- console.log(chalk.green(` โž• Added: ${ids.join(", ")}`));
209
- }
210
- for (const { type, ids } of deletedComponents) {
211
- console.log(chalk.cyan(` ${type}:`));
212
- console.log(chalk.red(` โž– Deleted: ${ids.join(", ")}`));
213
- }
214
- const modifiedByType = /* @__PURE__ */ new Map();
215
- for (const diff of meaningfulDiffs) {
216
- const existing = modifiedByType.get(diff.componentType) ?? [];
217
- existing.push(diff);
218
- modifiedByType.set(diff.componentType, existing);
219
- }
220
- for (const [componentType, diffs] of modifiedByType) {
221
- console.log(chalk.cyan(` ${componentType}:`));
222
- console.log(chalk.yellow(` ๐Ÿ“ Modified: ${diffs.map((d) => d.componentId).join(", ")}`));
223
- for (const diff of diffs) {
224
- console.log(chalk.gray(` ${diff.componentId} detailed differences:`));
225
- if (diff.isMissing === "generated") console.log(chalk.red(` Component missing in generated project`));
226
- else if (diff.isMissing === "remote") console.log(chalk.red(` Component missing in remote project`));
227
- else for (const d of diff.differences) console.log(chalk.gray(` ${d}`));
228
- }
229
- }
230
- return false;
231
- } catch (error) {
232
- const errorMsg = error instanceof Error ? error.message : String(error);
233
- console.log(chalk.red(` โŒ Project validation failed: ${errorMsg}`));
234
- return false;
235
- }
236
- }
237
- let isWaitingForInput = false;
238
- let currentKeypressHandler = null;
239
- async function validateTempDirectory(originalProjectRoot, tempDirName, remoteProject, options) {
240
- const tempDir = join(originalProjectRoot, tempDirName);
241
- const skipExit = options?.skipExit ?? false;
242
- if (await validateProjectEquivalence(tempDir, remoteProject)) {
243
- console.log(chalk.green(`\nโœ… Project is already up to date - no meaningful changes detected`));
244
- console.log(chalk.gray(` Cleaning up temp directory...`));
245
- try {
246
- rmSync(tempDir, {
247
- recursive: true,
248
- force: true
249
- });
250
- console.log(chalk.gray(` Temp directory cleaned up.`));
251
- } catch {
252
- console.log(chalk.yellow(` Note: Could not clean up temp directory: ${tempDirName}`));
253
- }
254
- console.log(chalk.green(`\n๐ŸŽ‰ Pull completed - project is up to date!`));
255
- if (!skipExit) process.exit(0);
256
- return {
257
- success: true,
258
- upToDate: true
259
- };
260
- }
261
- console.log(chalk.yellow(`\nโ“ Would you like to overwrite your project files with the generated files?`));
262
- console.log(chalk.gray(` This will replace your current files with the validated generated ones.`));
263
- console.log(chalk.green(` [Y] Yes - Replace files and clean up temp directory`));
264
- console.log(chalk.red(` [N] No - Keep temp directory for manual review`));
265
- return new Promise((resolve$1) => {
266
- if (isWaitingForInput && currentKeypressHandler) process.stdin.removeListener("data", currentKeypressHandler);
267
- process.stdin.removeAllListeners("data");
268
- process.stdin.removeAllListeners("keypress");
269
- process.stdin.removeAllListeners("end");
270
- if (process.stdin.isTTY && !process.stdin.isRaw) process.stdin.setRawMode(true);
271
- if (process.stdin.isPaused()) process.stdin.resume();
272
- process.stdin.setEncoding("utf8");
273
- const onKeypress = (key) => {
274
- if (!isWaitingForInput) return;
275
- isWaitingForInput = false;
276
- currentKeypressHandler = null;
277
- process.stdin.removeAllListeners("data");
278
- process.stdin.removeAllListeners("keypress");
279
- process.stdin.removeAllListeners("end");
280
- if (process.stdin.isTTY) process.stdin.setRawMode(false);
281
- process.stdin.pause();
282
- const normalizedKey = key.toLowerCase();
283
- if (normalizedKey === "y") {
284
- console.log(chalk.green(`\nโœ… Selected: Yes - Replacing files...`));
285
- overwriteProjectFiles(originalProjectRoot, tempDirName, tempDir);
286
- console.log(chalk.green(`\n๐ŸŽ‰ Pull completed successfully!`));
287
- if (!skipExit) process.exit(0);
288
- resolve$1({ success: true });
289
- } else if (normalizedKey === "n") {
290
- console.log(chalk.yellow(`\nโŒ Selected: No - Files not replaced`));
291
- console.log(chalk.gray(`๐Ÿ“‚ Generated files remain in: ${tempDirName}`));
292
- console.log(chalk.gray(` You can manually review and copy files as needed.`));
293
- console.log(chalk.cyan(`\nโœ… Pull completed - temp directory preserved for review.`));
294
- if (!skipExit) process.exit(0);
295
- resolve$1({
296
- success: true,
297
- userDeclined: true
298
- });
299
- } else {
300
- console.log(chalk.red(`\nโŒ Invalid key: "${key}". Please press Y or N.`));
301
- console.log(chalk.gray(`๐Ÿ“‚ Files not replaced. Generated files remain in: ${tempDirName}`));
302
- console.log(chalk.yellow(`\nโš ๏ธ Pull completed with invalid input - temp directory preserved.`));
303
- if (!skipExit) process.exit(0);
304
- resolve$1({
305
- success: true,
306
- userDeclined: true
307
- });
308
- }
309
- };
310
- currentKeypressHandler = onKeypress;
311
- isWaitingForInput = true;
312
- process.stdin.once("data", onKeypress);
313
- process.stdout.write(chalk.cyan("\nPress [Y] for Yes or [N] for No: "));
314
- });
315
- }
316
- /**
317
- * Overwrite project files with validated temp directory files and clean up
318
- */
319
- function overwriteProjectFiles(originalProjectRoot, tempDirName, tempDir) {
320
- try {
321
- console.log(chalk.cyan(`\n๐Ÿ”„ Replacing project files with generated files...`));
322
- let filesReplaced = 0;
323
- function copyRecursively(sourceDir, targetDir) {
324
- if (!existsSync(sourceDir)) return;
325
- const entries = readdirSync(sourceDir);
326
- for (const entry of entries) {
327
- if (entry.startsWith(".temp-") || entry.startsWith(".DS_Store") || entry === "node_modules" || entry === ".git" || entry === "tsconfig.json" || entry === "package.json") continue;
328
- const sourcePath = join(sourceDir, entry);
329
- const targetPath = join(targetDir, entry);
330
- const stat = statSync(sourcePath);
331
- if (stat.isDirectory()) copyRecursively(sourcePath, targetPath);
332
- else if (stat.isFile()) {
333
- mkdirSync(dirname(targetPath), { recursive: true });
334
- copyFileSync(sourcePath, targetPath);
335
- filesReplaced++;
336
- const relativePath = targetPath.replace(`${originalProjectRoot}/`, "");
337
- console.log(chalk.green(` โœ… Replaced: ${relativePath}`));
338
- }
339
- }
340
- }
341
- copyRecursively(tempDir, originalProjectRoot);
342
- console.log(chalk.cyan(`\n๐Ÿงน Cleaning up temp directory...`));
343
- rmSync(tempDir, {
344
- recursive: true,
345
- force: true
346
- });
347
- console.log(chalk.green(`\n๐ŸŽ‰ Successfully replaced ${filesReplaced} files!`));
348
- console.log(chalk.gray(` Your project files have been updated with the generated content.`));
349
- console.log(chalk.gray(` Temp directory cleaned up.`));
350
- } catch (error) {
351
- const errorMsg = error instanceof Error ? error.message : String(error);
352
- console.log(chalk.red(`\nโŒ Failed to overwrite project files: ${errorMsg}`));
353
- console.log(chalk.yellow(` Generated files remain in: ${tempDirName} for manual review`));
354
- }
355
- }
356
-
357
- //#endregion
358
- export { validateTempDirectory };