@inkeep/agents-cli 0.51.0 โ 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.
- package/dist/agents-cli/package.js +6 -0
- package/dist/commands/config.js +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/pull-v3/component-parser.js +4 -10
- package/dist/commands/pull-v4/agent-generator.js +274 -0
- package/dist/commands/pull-v4/artifact-component-generator.js +69 -0
- package/dist/commands/pull-v4/context-config-generator.js +264 -0
- package/dist/commands/pull-v4/credential-generator.js +30 -0
- package/dist/commands/pull-v4/data-component-generator.js +50 -0
- package/dist/commands/pull-v4/environment-generator.js +123 -0
- package/dist/commands/pull-v4/external-agent-generator.js +56 -0
- package/dist/commands/pull-v4/function-tool-generator.js +48 -0
- package/dist/commands/pull-v4/introspect/index.js +365 -0
- package/dist/commands/pull-v4/introspect/test-helpers.js +143 -0
- package/dist/commands/pull-v4/introspect-generator.js +691 -0
- package/dist/commands/pull-v4/mcp-tool-generator.js +91 -0
- package/dist/commands/pull-v4/module-merge.js +379 -0
- package/dist/commands/pull-v4/project-generator.js +101 -0
- package/dist/commands/pull-v4/status-component-generator.js +35 -0
- package/dist/commands/pull-v4/sub-agent-generator.js +168 -0
- package/dist/commands/pull-v4/trigger-generator.js +58 -0
- package/dist/commands/pull-v4/utils.js +219 -0
- package/dist/commands/push.js +1 -1
- package/dist/commands/update.js +2 -2
- package/dist/index.js +18 -44
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +18 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +180 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +8 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +12 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +60 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +37 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +31 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +118 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js +11 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +141 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +63 -0
- package/dist/utils/ci-environment.js +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/environment-loader.js +1 -1
- package/dist/utils/file-finder.js +1 -1
- package/dist/utils/mcp-runner.js +1 -1
- package/dist/utils/profile-config.js +1 -1
- package/dist/utils/profiles/profile-manager.js +1 -1
- package/dist/utils/project-directory.js +1 -1
- package/dist/utils/project-loader.js +1 -1
- package/dist/utils/version-check.js +6 -15
- package/package.json +5 -4
- package/dist/commands/pull-v3/component-updater.js +0 -768
- package/dist/commands/pull-v3/components/agent-generator.js +0 -255
- package/dist/commands/pull-v3/components/artifact-component-generator.js +0 -143
- package/dist/commands/pull-v3/components/context-config-generator.js +0 -190
- package/dist/commands/pull-v3/components/credential-generator.js +0 -89
- package/dist/commands/pull-v3/components/data-component-generator.js +0 -102
- package/dist/commands/pull-v3/components/environment-generator.js +0 -173
- package/dist/commands/pull-v3/components/external-agent-generator.js +0 -75
- package/dist/commands/pull-v3/components/function-tool-generator.js +0 -92
- package/dist/commands/pull-v3/components/mcp-tool-generator.js +0 -86
- package/dist/commands/pull-v3/components/project-generator.js +0 -157
- package/dist/commands/pull-v3/components/status-component-generator.js +0 -92
- package/dist/commands/pull-v3/components/sub-agent-generator.js +0 -295
- package/dist/commands/pull-v3/components/trigger-generator.js +0 -185
- package/dist/commands/pull-v3/index.js +0 -510
- package/dist/commands/pull-v3/introspect-generator.js +0 -286
- package/dist/commands/pull-v3/llm-content-merger.js +0 -192
- package/dist/commands/pull-v3/new-component-generator.js +0 -279
- package/dist/commands/pull-v3/project-index-generator.js +0 -32
- package/dist/commands/pull-v3/project-validator.js +0 -358
- 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 };
|