@inkeep/agents-cli 0.39.4 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/rolldown_runtime.js +7 -0
- package/dist/api.js +185 -0
- package/dist/commands/add.js +139 -0
- package/dist/commands/config.js +86 -0
- package/dist/commands/dev.js +259 -0
- package/dist/commands/init.js +360 -0
- package/dist/commands/list-agents.js +56 -0
- package/dist/commands/login.js +179 -0
- package/dist/commands/logout.js +56 -0
- package/dist/commands/profile.js +276 -0
- package/dist/{component-parser2.js → commands/pull-v3/component-parser.js} +16 -3
- package/dist/commands/pull-v3/component-updater.js +710 -0
- package/dist/commands/pull-v3/components/agent-generator.js +241 -0
- package/dist/commands/pull-v3/components/artifact-component-generator.js +127 -0
- package/dist/commands/pull-v3/components/context-config-generator.js +190 -0
- package/dist/commands/pull-v3/components/credential-generator.js +89 -0
- package/dist/commands/pull-v3/components/data-component-generator.js +102 -0
- package/dist/commands/pull-v3/components/environment-generator.js +170 -0
- package/dist/commands/pull-v3/components/external-agent-generator.js +75 -0
- package/dist/commands/pull-v3/components/function-tool-generator.js +94 -0
- package/dist/commands/pull-v3/components/mcp-tool-generator.js +86 -0
- package/dist/commands/pull-v3/components/project-generator.js +145 -0
- package/dist/commands/pull-v3/components/status-component-generator.js +92 -0
- package/dist/commands/pull-v3/components/sub-agent-generator.js +285 -0
- package/dist/commands/pull-v3/index.js +510 -0
- package/dist/commands/pull-v3/introspect-generator.js +278 -0
- package/dist/commands/pull-v3/llm-content-merger.js +192 -0
- package/dist/{new-component-generator.js → commands/pull-v3/new-component-generator.js} +14 -3
- package/dist/commands/pull-v3/project-comparator.js +914 -0
- package/dist/{project-index-generator.js → commands/pull-v3/project-index-generator.js} +1 -2
- package/dist/{project-validator.js → commands/pull-v3/project-validator.js} +4 -4
- package/dist/commands/pull-v3/targeted-typescript-placeholders.js +173 -0
- package/dist/commands/pull-v3/utils/component-registry.js +369 -0
- package/dist/commands/pull-v3/utils/component-tracker.js +165 -0
- package/dist/commands/pull-v3/utils/generator-utils.js +146 -0
- package/dist/commands/pull-v3/utils/model-provider-detector.js +44 -0
- package/dist/commands/push.js +326 -0
- package/dist/commands/status.js +89 -0
- package/dist/commands/update.js +97 -0
- package/dist/commands/whoami.js +38 -0
- package/dist/config.js +0 -1
- package/dist/env.js +30 -0
- package/dist/exports.js +3 -0
- package/dist/index.js +28 -196514
- package/dist/instrumentation.js +47 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/tsx.d.d.ts +1 -0
- package/dist/utils/background-version-check.js +19 -0
- package/dist/utils/ci-environment.js +87 -0
- package/dist/utils/cli-pipeline.js +158 -0
- package/dist/utils/config.js +290 -0
- package/dist/utils/credentials.js +132 -0
- package/dist/utils/environment-loader.js +28 -0
- package/dist/utils/file-finder.js +62 -0
- package/dist/utils/json-comparator.js +185 -0
- package/dist/utils/json-comparison.js +232 -0
- package/dist/utils/mcp-runner.js +120 -0
- package/dist/utils/model-config.js +182 -0
- package/dist/utils/package-manager.js +58 -0
- package/dist/utils/profile-config.js +85 -0
- package/dist/utils/profiles/index.js +4 -0
- package/dist/utils/profiles/profile-manager.js +219 -0
- package/dist/utils/profiles/types.js +62 -0
- package/dist/utils/project-directory.js +33 -0
- package/dist/utils/project-loader.js +29 -0
- package/dist/utils/schema-introspection.js +44 -0
- package/dist/utils/templates.js +198 -0
- package/dist/utils/tsx-loader.js +27 -0
- package/dist/utils/url.js +26 -0
- package/dist/utils/version-check.js +79 -0
- package/package.json +4 -19
- package/dist/component-parser.js +0 -4
- package/dist/component-updater.js +0 -4
- package/dist/config2.js +0 -4
- package/dist/credential-stores.js +0 -4
- package/dist/environment-generator.js +0 -4
- package/dist/nodefs.js +0 -27
- package/dist/opfs-ahp.js +0 -368
- package/dist/project-loader.js +0 -4
- package/dist/tsx-loader.js +0 -4
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
import { generateAgentFile } from "./components/agent-generator.js";
|
|
2
|
+
import { generateArtifactComponentFile } from "./components/artifact-component-generator.js";
|
|
3
|
+
import { generateContextConfigFile } from "./components/context-config-generator.js";
|
|
4
|
+
import { generateCredentialFile } from "./components/credential-generator.js";
|
|
5
|
+
import { generateDataComponentFile } from "./components/data-component-generator.js";
|
|
6
|
+
import { generateEnvironmentFile } from "./components/environment-generator.js";
|
|
7
|
+
import { generateExternalAgentFile } from "./components/external-agent-generator.js";
|
|
8
|
+
import { generateFunctionToolFile } from "./components/function-tool-generator.js";
|
|
9
|
+
import { generateMcpToolFile } from "./components/mcp-tool-generator.js";
|
|
10
|
+
import { generateProjectFile } from "./components/project-generator.js";
|
|
11
|
+
import { generateStatusComponentFile } from "./components/status-component-generator.js";
|
|
12
|
+
import { generateSubAgentFile } from "./components/sub-agent-generator.js";
|
|
13
|
+
import { getAvailableModel } from "./utils/model-provider-detector.js";
|
|
14
|
+
import { mergeComponentsWithLLM } from "./llm-content-merger.js";
|
|
15
|
+
import { findSubAgentWithParent } from "./utils/component-registry.js";
|
|
16
|
+
import "./project-validator.js";
|
|
17
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
19
|
+
import chalk from "chalk";
|
|
20
|
+
import { spawn } from "node:child_process";
|
|
21
|
+
import { generateText } from "ai";
|
|
22
|
+
|
|
23
|
+
//#region src/commands/pull-v3/component-updater.ts
|
|
24
|
+
/**
|
|
25
|
+
* Component Updater - Update existing components with new data
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Copy entire project to temp directory, including symlinks to parent files
|
|
29
|
+
* that might be imported (e.g., ../../env.ts)
|
|
30
|
+
*/
|
|
31
|
+
function copyProjectToTemp(projectRoot, tempDirName) {
|
|
32
|
+
const tempDir = join(projectRoot, tempDirName);
|
|
33
|
+
function copyRecursively(sourceDir, targetDir) {
|
|
34
|
+
if (!existsSync(sourceDir)) return;
|
|
35
|
+
mkdirSync(targetDir, { recursive: true });
|
|
36
|
+
const entries = readdirSync(sourceDir);
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
if (entry.startsWith(".temp-") || entry === "node_modules") continue;
|
|
39
|
+
const sourcePath = join(sourceDir, entry);
|
|
40
|
+
const targetPath = join(targetDir, entry);
|
|
41
|
+
const stat = statSync(sourcePath);
|
|
42
|
+
if (stat.isDirectory()) copyRecursively(sourcePath, targetPath);
|
|
43
|
+
else if (stat.isFile()) copyFileSync(sourcePath, targetPath);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
copyRecursively(projectRoot, tempDir);
|
|
47
|
+
createParentSymlinks(projectRoot, tempDir);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create symlinks in the temp directory for parent files that might be imported
|
|
51
|
+
* Scans project files for parent imports (../) and creates appropriate symlinks
|
|
52
|
+
*/
|
|
53
|
+
function createParentSymlinks(projectRoot, tempDir) {
|
|
54
|
+
const parentImports = findParentImports(tempDir);
|
|
55
|
+
for (const parentPath of parentImports) {
|
|
56
|
+
const sourcePath = resolve(projectRoot, parentPath);
|
|
57
|
+
if (!existsSync(sourcePath)) continue;
|
|
58
|
+
const targetPath = join(tempDir, parentPath);
|
|
59
|
+
if (existsSync(targetPath)) continue;
|
|
60
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
61
|
+
try {
|
|
62
|
+
symlinkSync(sourcePath, targetPath);
|
|
63
|
+
} catch {
|
|
64
|
+
try {
|
|
65
|
+
if (statSync(sourcePath).isFile()) copyFileSync(sourcePath, targetPath);
|
|
66
|
+
} catch {}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Find all parent imports (../) in TypeScript files within a directory
|
|
72
|
+
*/
|
|
73
|
+
function findParentImports(dir) {
|
|
74
|
+
const parentImports = /* @__PURE__ */ new Set();
|
|
75
|
+
const importRegex = /(?:from\s+['"]|import\s+['"]|require\s*\(\s*['"])(\.\.[^'"]+)['"]/g;
|
|
76
|
+
function scanDir(currentDir) {
|
|
77
|
+
if (!existsSync(currentDir)) return;
|
|
78
|
+
try {
|
|
79
|
+
const entries = readdirSync(currentDir);
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
if (entry === "node_modules" || entry.startsWith(".temp-")) continue;
|
|
82
|
+
const fullPath = join(currentDir, entry);
|
|
83
|
+
const stat = statSync(fullPath);
|
|
84
|
+
if (stat.isDirectory()) scanDir(fullPath);
|
|
85
|
+
else if (stat.isFile() && /\.[tj]sx?$/.test(entry)) {
|
|
86
|
+
const content = readFileSync(fullPath, "utf8");
|
|
87
|
+
let match;
|
|
88
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
89
|
+
const importPath = match[1];
|
|
90
|
+
const resolvedImport = join(relative(dir, dirname(fullPath)), importPath);
|
|
91
|
+
if (resolvedImport.startsWith("..")) {
|
|
92
|
+
parentImports.add(resolvedImport);
|
|
93
|
+
if (!resolvedImport.endsWith(".ts") && !resolvedImport.endsWith(".js")) parentImports.add(resolvedImport + ".ts");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch {}
|
|
99
|
+
}
|
|
100
|
+
scanDir(dir);
|
|
101
|
+
return Array.from(parentImports);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check for stale components and prompt user for cleanup permission
|
|
105
|
+
*/
|
|
106
|
+
async function checkAndPromptForStaleComponentCleanup(projectRoot, remoteProject, localRegistry) {
|
|
107
|
+
const remoteComponentIds = /* @__PURE__ */ new Set();
|
|
108
|
+
if (remoteProject.agents) Object.keys(remoteProject.agents).forEach((id) => remoteComponentIds.add(id));
|
|
109
|
+
if (remoteProject.tools) Object.keys(remoteProject.tools).forEach((id) => remoteComponentIds.add(id));
|
|
110
|
+
if (remoteProject.functionTools) Object.keys(remoteProject.functionTools).forEach((id) => remoteComponentIds.add(id));
|
|
111
|
+
if (remoteProject.functions) Object.keys(remoteProject.functions).forEach((id) => remoteComponentIds.add(id));
|
|
112
|
+
if (remoteProject.dataComponents) Object.keys(remoteProject.dataComponents).forEach((id) => remoteComponentIds.add(id));
|
|
113
|
+
if (remoteProject.artifactComponents) Object.keys(remoteProject.artifactComponents).forEach((id) => remoteComponentIds.add(id));
|
|
114
|
+
if (remoteProject.credentialReferences) Object.keys(remoteProject.credentialReferences).forEach((id) => remoteComponentIds.add(id));
|
|
115
|
+
if (remoteProject.externalAgents) Object.keys(remoteProject.externalAgents).forEach((id) => remoteComponentIds.add(id));
|
|
116
|
+
if (remoteProject.environments) Object.keys(remoteProject.environments).forEach((id) => remoteComponentIds.add(id));
|
|
117
|
+
if (remoteProject.headers) Object.keys(remoteProject.headers).forEach((id) => remoteComponentIds.add(id));
|
|
118
|
+
if (remoteProject.models) remoteComponentIds.add("project");
|
|
119
|
+
if (remoteProject.name || remoteProject.description) remoteComponentIds.add(remoteProject.name || "project");
|
|
120
|
+
if (remoteProject.agents) Object.values(remoteProject.agents).forEach((agent) => {
|
|
121
|
+
if (agent.subAgents) {
|
|
122
|
+
Object.keys(agent.subAgents).forEach((id) => remoteComponentIds.add(id));
|
|
123
|
+
Object.values(agent.subAgents).forEach((subAgent) => {
|
|
124
|
+
if (subAgent.functionTools) Object.keys(subAgent.functionTools).forEach((id) => remoteComponentIds.add(id));
|
|
125
|
+
if (subAgent.tools) Object.keys(subAgent.tools).forEach((id) => remoteComponentIds.add(id));
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (agent.contextConfig && agent.contextConfig.id) {
|
|
129
|
+
remoteComponentIds.add(agent.contextConfig.id);
|
|
130
|
+
if (agent.contextConfig.contextVariables) Object.values(agent.contextConfig.contextVariables).forEach((variable) => {
|
|
131
|
+
if (variable && typeof variable === "object" && variable.id) remoteComponentIds.add(variable.id);
|
|
132
|
+
});
|
|
133
|
+
if (agent.contextConfig.headers) Object.keys(agent.contextConfig.headers).forEach((id) => remoteComponentIds.add(id));
|
|
134
|
+
}
|
|
135
|
+
if (agent.statusUpdates?.statusComponents) agent.statusUpdates.statusComponents.forEach((statusComp) => {
|
|
136
|
+
const statusCompId = statusComp.type || statusComp.id;
|
|
137
|
+
if (statusCompId) remoteComponentIds.add(statusCompId);
|
|
138
|
+
});
|
|
139
|
+
if (agent.models) remoteComponentIds.add(`${agent.id || "unknown"}-models`);
|
|
140
|
+
});
|
|
141
|
+
const staleComponents = [];
|
|
142
|
+
for (const component of localRegistry.getAllComponents()) {
|
|
143
|
+
if (component.type === "project") continue;
|
|
144
|
+
if (!remoteComponentIds.has(component.id)) staleComponents.push(component);
|
|
145
|
+
}
|
|
146
|
+
if (staleComponents.length === 0) return false;
|
|
147
|
+
console.log(chalk.yellow(`\n🧹 Found ${staleComponents.length} stale component(s) that don't exist in remote project:`));
|
|
148
|
+
staleComponents.forEach((comp) => {
|
|
149
|
+
const typeLabel = comp.type.replace(/s$/, "").replace(/^./, (c) => c.toUpperCase());
|
|
150
|
+
console.log(chalk.gray(` • ${typeLabel}: ${chalk.cyan(comp.id)}`));
|
|
151
|
+
console.log(chalk.gray(` └─ File: ${comp.filePath}`));
|
|
152
|
+
});
|
|
153
|
+
console.log(chalk.cyan(`\n❓ Would you like to remove these stale components from your project?`));
|
|
154
|
+
console.log(chalk.green(` [Y] Yes - Clean up stale components`));
|
|
155
|
+
console.log(chalk.red(` [N] No - Keep existing components`));
|
|
156
|
+
return new Promise((resolve$1) => {
|
|
157
|
+
process.stdin.removeAllListeners("data");
|
|
158
|
+
process.stdin.removeAllListeners("keypress");
|
|
159
|
+
process.stdin.removeAllListeners("end");
|
|
160
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
161
|
+
process.stdin.resume();
|
|
162
|
+
process.stdin.setEncoding("utf8");
|
|
163
|
+
const onKeypress = (key) => {
|
|
164
|
+
process.stdin.removeAllListeners("data");
|
|
165
|
+
process.stdin.removeAllListeners("keypress");
|
|
166
|
+
process.stdin.removeAllListeners("end");
|
|
167
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
168
|
+
process.stdin.pause();
|
|
169
|
+
const normalizedKey = key.toLowerCase();
|
|
170
|
+
if (normalizedKey === "y") {
|
|
171
|
+
console.log(chalk.green(`\n✅ Selected: Yes - Will clean up stale components`));
|
|
172
|
+
resolve$1(true);
|
|
173
|
+
} else if (normalizedKey === "n") {
|
|
174
|
+
console.log(chalk.yellow(`\n❌ Selected: No - Keeping existing components`));
|
|
175
|
+
resolve$1(false);
|
|
176
|
+
} else {
|
|
177
|
+
console.log(chalk.red(`\n❌ Invalid key: "${key}". Skipping cleanup.`));
|
|
178
|
+
resolve$1(false);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
process.stdin.once("data", onKeypress);
|
|
182
|
+
process.stdout.write(chalk.cyan("\nPress [Y] for Yes or [N] for No: "));
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Clean up stale components that don't exist in remote project
|
|
187
|
+
* @param projectRoot - Root project directory
|
|
188
|
+
* @param tempDirName - Temp directory name (empty string = operate on original project)
|
|
189
|
+
* @param remoteProject - Remote project definition
|
|
190
|
+
* @param localRegistry - Local component registry
|
|
191
|
+
*/
|
|
192
|
+
async function cleanupStaleComponents(projectRoot, tempDirName, remoteProject, localRegistry) {
|
|
193
|
+
const tempDir = join(projectRoot, tempDirName);
|
|
194
|
+
const remoteComponentIds = /* @__PURE__ */ new Set();
|
|
195
|
+
if (remoteProject.agents) Object.keys(remoteProject.agents).forEach((id) => remoteComponentIds.add(id));
|
|
196
|
+
if (remoteProject.tools) Object.keys(remoteProject.tools).forEach((id) => remoteComponentIds.add(id));
|
|
197
|
+
if (remoteProject.functionTools) Object.keys(remoteProject.functionTools).forEach((id) => remoteComponentIds.add(id));
|
|
198
|
+
if (remoteProject.functions) Object.keys(remoteProject.functions).forEach((id) => remoteComponentIds.add(id));
|
|
199
|
+
if (remoteProject.dataComponents) Object.keys(remoteProject.dataComponents).forEach((id) => remoteComponentIds.add(id));
|
|
200
|
+
if (remoteProject.artifactComponents) Object.keys(remoteProject.artifactComponents).forEach((id) => remoteComponentIds.add(id));
|
|
201
|
+
if (remoteProject.credentialReferences) Object.keys(remoteProject.credentialReferences).forEach((id) => remoteComponentIds.add(id));
|
|
202
|
+
if (remoteProject.externalAgents) Object.keys(remoteProject.externalAgents).forEach((id) => remoteComponentIds.add(id));
|
|
203
|
+
if (remoteProject.environments) Object.keys(remoteProject.environments).forEach((id) => remoteComponentIds.add(id));
|
|
204
|
+
if (remoteProject.headers) Object.keys(remoteProject.headers).forEach((id) => remoteComponentIds.add(id));
|
|
205
|
+
if (remoteProject.models) remoteComponentIds.add("project");
|
|
206
|
+
if (remoteProject.name || remoteProject.description) remoteComponentIds.add(remoteProject.name || "project");
|
|
207
|
+
if (remoteProject.agents) Object.values(remoteProject.agents).forEach((agent) => {
|
|
208
|
+
if (agent.subAgents) {
|
|
209
|
+
Object.keys(agent.subAgents).forEach((id) => remoteComponentIds.add(id));
|
|
210
|
+
Object.values(agent.subAgents).forEach((subAgent) => {
|
|
211
|
+
if (subAgent.functionTools) Object.keys(subAgent.functionTools).forEach((id) => remoteComponentIds.add(id));
|
|
212
|
+
if (subAgent.tools) Object.keys(subAgent.tools).forEach((id) => remoteComponentIds.add(id));
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (agent.contextConfig && agent.contextConfig.id) {
|
|
216
|
+
remoteComponentIds.add(agent.contextConfig.id);
|
|
217
|
+
if (agent.contextConfig.contextVariables) Object.values(agent.contextConfig.contextVariables).forEach((variable) => {
|
|
218
|
+
if (variable && typeof variable === "object" && variable.id) remoteComponentIds.add(variable.id);
|
|
219
|
+
});
|
|
220
|
+
if (agent.contextConfig.headers) Object.keys(agent.contextConfig.headers).forEach((id) => remoteComponentIds.add(id));
|
|
221
|
+
}
|
|
222
|
+
if (agent.statusUpdates?.statusComponents) agent.statusUpdates.statusComponents.forEach((statusComp) => {
|
|
223
|
+
const statusCompId = statusComp.type || statusComp.id;
|
|
224
|
+
if (statusCompId) remoteComponentIds.add(statusCompId);
|
|
225
|
+
});
|
|
226
|
+
if (agent.models) remoteComponentIds.add(`${agent.id || "unknown"}-models`);
|
|
227
|
+
});
|
|
228
|
+
localRegistry.getAllComponents();
|
|
229
|
+
const staleComponents = [];
|
|
230
|
+
for (const component of localRegistry.getAllComponents()) {
|
|
231
|
+
if (component.type === "project") continue;
|
|
232
|
+
if (!remoteComponentIds.has(component.id)) staleComponents.push(component);
|
|
233
|
+
}
|
|
234
|
+
if (staleComponents.length === 0) return;
|
|
235
|
+
const staleComponentsByFile = /* @__PURE__ */ new Map();
|
|
236
|
+
for (const component of staleComponents) {
|
|
237
|
+
const filePath = component.filePath;
|
|
238
|
+
if (!staleComponentsByFile.has(filePath)) staleComponentsByFile.set(filePath, []);
|
|
239
|
+
staleComponentsByFile.get(filePath).push(component);
|
|
240
|
+
}
|
|
241
|
+
for (const [originalFilePath, staleComponentsInFile] of staleComponentsByFile) {
|
|
242
|
+
const tempFilePath = join(tempDir, originalFilePath.replace(projectRoot + "/", ""));
|
|
243
|
+
if (!existsSync(tempFilePath)) continue;
|
|
244
|
+
if (localRegistry.getComponentsInFile(originalFilePath).filter((component) => !staleComponentsInFile.some((stale) => stale.id === component.id)).length === 0) unlinkSync(tempFilePath);
|
|
245
|
+
else {
|
|
246
|
+
const currentContent = readFileSync(tempFilePath, "utf8");
|
|
247
|
+
const cleanedContent = await removeComponentsFromFile(currentContent, staleComponentsInFile.map((c) => ({
|
|
248
|
+
id: c.id,
|
|
249
|
+
type: c.type
|
|
250
|
+
})), tempFilePath);
|
|
251
|
+
if (cleanedContent !== currentContent) writeFileSync(tempFilePath, cleanedContent, "utf8");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (const staleComponent of staleComponents) localRegistry.removeComponent(staleComponent.type, staleComponent.id);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Use LLM specifically for component removal with custom prompt
|
|
258
|
+
*/
|
|
259
|
+
async function removeComponentsWithLLM(fileContent, prompt) {
|
|
260
|
+
try {
|
|
261
|
+
let cleanedResponse = (await generateText({
|
|
262
|
+
model: await getAvailableModel(),
|
|
263
|
+
prompt: prompt + "\n\nFile content:\n```typescript\n" + fileContent + "\n```"
|
|
264
|
+
})).text.replace(/^```(?:typescript|ts|javascript|js)?\s*\n?/i, "");
|
|
265
|
+
cleanedResponse = cleanedResponse.replace(/\n?```\s*$/i, "");
|
|
266
|
+
return cleanedResponse.trim();
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error("LLM removal failed:", error);
|
|
269
|
+
return fileContent;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Use LLM to remove specific components from file content
|
|
274
|
+
*/
|
|
275
|
+
async function removeComponentsFromFile(fileContent, componentsToRemove, filePath) {
|
|
276
|
+
const prompt = `Remove the following components from this TypeScript file: ${componentsToRemove.map((c) => `${c.type}:${c.id}`).join(", ")}
|
|
277
|
+
|
|
278
|
+
Please remove these components completely, including:
|
|
279
|
+
- Their export statements
|
|
280
|
+
- Their variable declarations/definitions
|
|
281
|
+
- Any imports that are no longer needed after removal
|
|
282
|
+
- Any related helper code specific to these components
|
|
283
|
+
|
|
284
|
+
Keep all other components, imports, and code that are still needed. Ensure the file remains syntactically valid TypeScript.
|
|
285
|
+
|
|
286
|
+
Original file content:
|
|
287
|
+
${fileContent}
|
|
288
|
+
|
|
289
|
+
Return only the cleaned TypeScript code with the specified components removed.`;
|
|
290
|
+
try {
|
|
291
|
+
return await removeComponentsWithLLM(fileContent, prompt);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
return fileContent;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Write content to temp directory (overwrite if exists)
|
|
298
|
+
*/
|
|
299
|
+
function writeToTempDirectory(projectRoot, filePath, content, tempDirName) {
|
|
300
|
+
const tempFilePath = join(join(projectRoot, tempDirName), filePath.replace(projectRoot + "/", ""));
|
|
301
|
+
mkdirSync(dirname(tempFilePath), { recursive: true });
|
|
302
|
+
writeFileSync(tempFilePath, content, "utf8");
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Run Biome formatter and linter on a file
|
|
306
|
+
*/
|
|
307
|
+
async function runBiomeOnFile(filePath) {
|
|
308
|
+
try {
|
|
309
|
+
const ext = extname(filePath);
|
|
310
|
+
if (![
|
|
311
|
+
".ts",
|
|
312
|
+
".js",
|
|
313
|
+
".tsx",
|
|
314
|
+
".jsx"
|
|
315
|
+
].includes(ext)) return true;
|
|
316
|
+
await new Promise((resolve$1, reject) => {
|
|
317
|
+
const formatProcess = spawn("npx", [
|
|
318
|
+
"biome",
|
|
319
|
+
"format",
|
|
320
|
+
"--write",
|
|
321
|
+
filePath
|
|
322
|
+
], { stdio: "pipe" });
|
|
323
|
+
formatProcess.on("close", (code) => {
|
|
324
|
+
if (code === 0) resolve$1();
|
|
325
|
+
else reject(/* @__PURE__ */ new Error(`Biome format exited with code ${code}`));
|
|
326
|
+
});
|
|
327
|
+
formatProcess.on("error", (err) => {
|
|
328
|
+
reject(/* @__PURE__ */ new Error(`Failed to run biome format: ${err.message}`));
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
await new Promise((resolve$1, reject) => {
|
|
332
|
+
const lintProcess = spawn("npx", [
|
|
333
|
+
"biome",
|
|
334
|
+
"lint",
|
|
335
|
+
"--write",
|
|
336
|
+
filePath
|
|
337
|
+
], { stdio: "pipe" });
|
|
338
|
+
lintProcess.on("close", (code) => {
|
|
339
|
+
if (code === 0) resolve$1();
|
|
340
|
+
else reject(/* @__PURE__ */ new Error(`Biome lint exited with code ${code}`));
|
|
341
|
+
});
|
|
342
|
+
lintProcess.on("error", (err) => {
|
|
343
|
+
reject(/* @__PURE__ */ new Error(`Failed to run biome lint: ${err.message}`));
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
return true;
|
|
347
|
+
} catch (error) {
|
|
348
|
+
error instanceof Error && error.message;
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Run Biome formatter and linter on an entire directory
|
|
354
|
+
*/
|
|
355
|
+
async function runBiomeOnDirectory(dirPath) {
|
|
356
|
+
try {
|
|
357
|
+
await new Promise((resolve$1, reject) => {
|
|
358
|
+
const formatProcess = spawn("npx", [
|
|
359
|
+
"biome",
|
|
360
|
+
"format",
|
|
361
|
+
"--write",
|
|
362
|
+
"."
|
|
363
|
+
], {
|
|
364
|
+
cwd: dirPath,
|
|
365
|
+
stdio: "pipe"
|
|
366
|
+
});
|
|
367
|
+
formatProcess.on("close", (code) => {
|
|
368
|
+
if (code === 0) resolve$1();
|
|
369
|
+
else reject(/* @__PURE__ */ new Error(`Biome format exited with code ${code}`));
|
|
370
|
+
});
|
|
371
|
+
formatProcess.on("error", (err) => {
|
|
372
|
+
reject(/* @__PURE__ */ new Error(`Failed to run biome format: ${err.message}`));
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
await new Promise((resolve$1, reject) => {
|
|
376
|
+
const lintProcess = spawn("npx", [
|
|
377
|
+
"biome",
|
|
378
|
+
"lint",
|
|
379
|
+
"--write",
|
|
380
|
+
"."
|
|
381
|
+
], {
|
|
382
|
+
cwd: dirPath,
|
|
383
|
+
stdio: "pipe"
|
|
384
|
+
});
|
|
385
|
+
lintProcess.on("close", (code) => {
|
|
386
|
+
if (code === 0) resolve$1();
|
|
387
|
+
else reject(/* @__PURE__ */ new Error(`Biome lint exited with code ${code}`));
|
|
388
|
+
});
|
|
389
|
+
lintProcess.on("error", (err) => {
|
|
390
|
+
reject(/* @__PURE__ */ new Error(`Failed to run biome lint: ${err.message}`));
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
return true;
|
|
394
|
+
} catch (error) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Generate updated component content using appropriate generator
|
|
400
|
+
*/
|
|
401
|
+
function generateUpdatedComponentContent(componentType, componentId, componentData, remoteProject, localRegistry, environment, actualFilePath) {
|
|
402
|
+
const defaultStyle = {
|
|
403
|
+
quotes: "single",
|
|
404
|
+
indentation: " ",
|
|
405
|
+
semicolons: true
|
|
406
|
+
};
|
|
407
|
+
switch (componentType) {
|
|
408
|
+
case "agents": {
|
|
409
|
+
const contextConfigData = componentData.contextConfig;
|
|
410
|
+
const projectModels = remoteProject.models;
|
|
411
|
+
return generateAgentFile(componentId, componentData, defaultStyle, localRegistry, contextConfigData, projectModels, actualFilePath);
|
|
412
|
+
}
|
|
413
|
+
case "subAgents": {
|
|
414
|
+
const parentInfo = findSubAgentWithParent(remoteProject, componentId);
|
|
415
|
+
const parentAgentId = parentInfo?.parentAgentId;
|
|
416
|
+
const contextConfigData = parentInfo?.contextConfigData;
|
|
417
|
+
return generateSubAgentFile(componentId, componentData, defaultStyle, localRegistry, parentAgentId, contextConfigData, parentInfo ? remoteProject.agents?.[parentInfo.parentAgentId]?.models : void 0, actualFilePath);
|
|
418
|
+
}
|
|
419
|
+
case "tools": return generateMcpToolFile(componentId, componentData, defaultStyle, localRegistry);
|
|
420
|
+
case "functionTools":
|
|
421
|
+
case "functions": return generateFunctionToolFile(componentId, componentData, defaultStyle);
|
|
422
|
+
case "dataComponents": return generateDataComponentFile(componentId, componentData, defaultStyle);
|
|
423
|
+
case "artifactComponents": return generateArtifactComponentFile(componentId, componentData, defaultStyle);
|
|
424
|
+
case "statusComponents": return generateStatusComponentFile(componentId, componentData, defaultStyle);
|
|
425
|
+
case "environments": return generateEnvironmentFile(componentId, componentData, defaultStyle, localRegistry);
|
|
426
|
+
case "externalAgents": return generateExternalAgentFile(componentId, componentData, defaultStyle, localRegistry);
|
|
427
|
+
case "credentials": return generateCredentialFile(componentId, componentData, defaultStyle);
|
|
428
|
+
case "contextConfigs": {
|
|
429
|
+
const agentId = componentData._agentId;
|
|
430
|
+
const cleanComponentData = { ...componentData };
|
|
431
|
+
delete cleanComponentData._agentId;
|
|
432
|
+
return generateContextConfigFile(componentId, cleanComponentData, defaultStyle, localRegistry, agentId);
|
|
433
|
+
}
|
|
434
|
+
case "fetchDefinitions": return "";
|
|
435
|
+
case "projects": return generateProjectFile(componentId, componentData, defaultStyle, localRegistry);
|
|
436
|
+
default: throw new Error(`No generator for component type: ${componentType}`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Update existing components that have been modified
|
|
441
|
+
*/
|
|
442
|
+
async function updateModifiedComponents(comparison, remoteProject, localRegistry, projectRoot, environment, debug = false, providedTempDirName, newComponents) {
|
|
443
|
+
const results = [];
|
|
444
|
+
const tempDirName = providedTempDirName || `.temp-${Date.now()}`;
|
|
445
|
+
if (!providedTempDirName) {
|
|
446
|
+
console.log(chalk.cyan(`📁 Copying project to ${tempDirName}...`));
|
|
447
|
+
copyProjectToTemp(projectRoot, tempDirName);
|
|
448
|
+
console.log(chalk.green(`✅ Project copied to temp directory`));
|
|
449
|
+
}
|
|
450
|
+
const allModifiedComponents = [];
|
|
451
|
+
for (const [componentType, changes] of Object.entries(comparison.componentChanges)) for (const componentId of changes.modified) allModifiedComponents.push({
|
|
452
|
+
type: componentType,
|
|
453
|
+
id: componentId
|
|
454
|
+
});
|
|
455
|
+
if (allModifiedComponents.length === 0) return results;
|
|
456
|
+
const componentsByFile = /* @__PURE__ */ new Map();
|
|
457
|
+
for (const { type: componentType, id: componentId } of allModifiedComponents) {
|
|
458
|
+
let actualComponentType = componentType;
|
|
459
|
+
if (componentType === "functions") actualComponentType = "functionTools";
|
|
460
|
+
const localComponent = localRegistry.get(componentId, actualComponentType);
|
|
461
|
+
const singularType = actualComponentType.slice(0, -1);
|
|
462
|
+
const localComponentSingular = localRegistry.get(componentId, singularType);
|
|
463
|
+
const actualComponent = localComponent || localComponentSingular;
|
|
464
|
+
if (actualComponent) {
|
|
465
|
+
const filePath = actualComponent.filePath.startsWith("/") ? actualComponent.filePath : `${projectRoot}/${actualComponent.filePath}`;
|
|
466
|
+
if (!componentsByFile.has(filePath)) componentsByFile.set(filePath, []);
|
|
467
|
+
componentsByFile.get(filePath).push({
|
|
468
|
+
type: componentType,
|
|
469
|
+
id: componentId,
|
|
470
|
+
registryInfo: actualComponent
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
console.log(chalk.cyan(`\n🔄 Updating ${componentsByFile.size} files with modified components...`));
|
|
475
|
+
let fileIndex = 0;
|
|
476
|
+
const totalFiles = componentsByFile.size;
|
|
477
|
+
for (const [filePath, fileComponents] of componentsByFile) {
|
|
478
|
+
fileIndex++;
|
|
479
|
+
try {
|
|
480
|
+
const relativeFilePath = filePath.replace(projectRoot + "/", "");
|
|
481
|
+
const componentNames = fileComponents.map((c) => `${c.type}:${c.id}`).join(", ");
|
|
482
|
+
console.log(chalk.gray(` [${fileIndex}/${totalFiles}] Processing: ${relativeFilePath}`));
|
|
483
|
+
console.log(chalk.gray(` Components: ${componentNames}`));
|
|
484
|
+
const oldContent = readFileSync(filePath, "utf8");
|
|
485
|
+
const componentContentParts = [];
|
|
486
|
+
const componentResults = [];
|
|
487
|
+
for (const { type: componentType, id: componentId } of fileComponents) {
|
|
488
|
+
let componentData = null;
|
|
489
|
+
if (componentType === "contextConfigs") {
|
|
490
|
+
for (const [agentId, agentData] of Object.entries(remoteProject.agents || {})) if (agentData.contextConfig && agentData.contextConfig.id === componentId) {
|
|
491
|
+
componentData = agentData.contextConfig;
|
|
492
|
+
componentData._agentId = agentId;
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
} else if (componentType === "fetchDefinitions") for (const [agentId, agentData] of Object.entries(remoteProject.agents || {})) {
|
|
496
|
+
const contextConfig = agentData.contextConfig;
|
|
497
|
+
if (contextConfig && contextConfig.contextVariables) {
|
|
498
|
+
for (const [varName, variable] of Object.entries(contextConfig.contextVariables)) if (variable?.id === componentId) {
|
|
499
|
+
componentData = variable;
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
if (componentData) break;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
else if (componentType === "subAgents") {
|
|
506
|
+
for (const [agentId, agentData] of Object.entries(remoteProject.agents || {})) if (agentData.subAgents && agentData.subAgents[componentId]) {
|
|
507
|
+
componentData = agentData.subAgents[componentId];
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
} else if (componentType === "statusComponents") {
|
|
511
|
+
for (const [agentId, agentData] of Object.entries(remoteProject.agents || {})) if (agentData.statusUpdates?.statusComponents && agentData.statusUpdates.statusComponents) {
|
|
512
|
+
for (const statusComp of agentData.statusUpdates.statusComponents) if (statusComp["type"] === componentId) {
|
|
513
|
+
componentData = statusComp;
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
} else if (componentType === "credentials") componentData = remoteProject.credentialReferences?.[componentId];
|
|
518
|
+
else if (componentType === "environments") componentData = {
|
|
519
|
+
name: `${componentId} Environment`,
|
|
520
|
+
description: `Environment configuration for ${componentId}`,
|
|
521
|
+
credentials: remoteProject.credentialReferences || {}
|
|
522
|
+
};
|
|
523
|
+
else {
|
|
524
|
+
componentData = (remoteProject[componentType] || {})[componentId];
|
|
525
|
+
if (componentType === "agents" && componentData && !componentData.credentials && remoteProject.credentialReferences) {
|
|
526
|
+
const agentCredentials = [];
|
|
527
|
+
const credentialSet = /* @__PURE__ */ new Set();
|
|
528
|
+
if (componentData.contextConfig?.contextVariables) {
|
|
529
|
+
for (const [varName, varData] of Object.entries(componentData.contextConfig.contextVariables)) if (varData && typeof varData === "object" && varData.credentialReferenceId) {
|
|
530
|
+
const credId = varData.credentialReferenceId;
|
|
531
|
+
if (remoteProject.credentialReferences[credId] && !credentialSet.has(credId)) {
|
|
532
|
+
credentialSet.add(credId);
|
|
533
|
+
agentCredentials.push({ id: credId });
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
for (const [credId, credData] of Object.entries(remoteProject.credentialReferences)) if (credData.usedBy) {
|
|
538
|
+
for (const usage of credData.usedBy) if (usage.type === "agent" && usage.id === componentId && !credentialSet.has(credId)) {
|
|
539
|
+
credentialSet.add(credId);
|
|
540
|
+
agentCredentials.push({ id: credId });
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (agentCredentials.length > 0) componentData.credentials = agentCredentials;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (!componentData) {
|
|
548
|
+
componentResults.push({
|
|
549
|
+
componentId,
|
|
550
|
+
componentType,
|
|
551
|
+
success: false,
|
|
552
|
+
error: `Component data not found in remote project.${componentType}`
|
|
553
|
+
});
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
try {
|
|
557
|
+
const componentContent = generateUpdatedComponentContent(componentType, componentId, componentData, remoteProject, localRegistry, environment, relativeFilePath);
|
|
558
|
+
componentContentParts.push(`// ${componentType}:${componentId}\n${componentContent}`);
|
|
559
|
+
componentResults.push({
|
|
560
|
+
componentId,
|
|
561
|
+
componentType,
|
|
562
|
+
success: true
|
|
563
|
+
});
|
|
564
|
+
} catch (error) {
|
|
565
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
566
|
+
componentResults.push({
|
|
567
|
+
componentId,
|
|
568
|
+
componentType,
|
|
569
|
+
success: false,
|
|
570
|
+
error: errorMsg
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const failedComponents = componentResults.filter((r) => !r.success);
|
|
575
|
+
if (failedComponents.length > 0) {
|
|
576
|
+
failedComponents.forEach((comp) => {
|
|
577
|
+
results.push({
|
|
578
|
+
componentId: comp.componentId,
|
|
579
|
+
componentType: comp.componentType,
|
|
580
|
+
filePath,
|
|
581
|
+
success: false,
|
|
582
|
+
error: comp.error
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
if (failedComponents.length === componentResults.length) continue;
|
|
586
|
+
}
|
|
587
|
+
const newComponentContent = componentContentParts.join("\n\n");
|
|
588
|
+
let componentsToExport = [];
|
|
589
|
+
try {
|
|
590
|
+
componentsToExport = analyzeComponentsToExport(newComponents || [], relativeFilePath, localRegistry);
|
|
591
|
+
} catch (error) {}
|
|
592
|
+
const mergeResult = await mergeComponentsWithLLM({
|
|
593
|
+
oldContent,
|
|
594
|
+
newContent: newComponentContent,
|
|
595
|
+
modifiedComponents: fileComponents.map((c) => ({
|
|
596
|
+
componentId: c.id,
|
|
597
|
+
componentType: c.type
|
|
598
|
+
})),
|
|
599
|
+
filePath,
|
|
600
|
+
newComponents,
|
|
601
|
+
componentsToExport
|
|
602
|
+
});
|
|
603
|
+
let finalContent;
|
|
604
|
+
if (!mergeResult.success) finalContent = newComponentContent;
|
|
605
|
+
else finalContent = mergeResult.mergedContent;
|
|
606
|
+
writeToTempDirectory(projectRoot, filePath, finalContent, tempDirName);
|
|
607
|
+
const relativePath = filePath.replace(projectRoot + "/", "");
|
|
608
|
+
const tempFilePath = join(projectRoot, tempDirName, relativePath);
|
|
609
|
+
if (await runBiomeOnFile(tempFilePath)) {
|
|
610
|
+
const formattedContent = readFileSync(tempFilePath, "utf8");
|
|
611
|
+
console.log(chalk.green(` ✅ File formatted and written: ${tempDirName}/${relativePath} (${formattedContent.length} chars)`));
|
|
612
|
+
} else console.log(chalk.cyan(` 💾 Final content written to ${tempDirName}/${relativePath} (${finalContent.length} chars)`));
|
|
613
|
+
if (oldContent.trim() === finalContent.trim()) {
|
|
614
|
+
fileComponents.forEach((comp) => {
|
|
615
|
+
results.push({
|
|
616
|
+
componentId: comp.id,
|
|
617
|
+
componentType: comp.type,
|
|
618
|
+
filePath,
|
|
619
|
+
success: true,
|
|
620
|
+
oldContent,
|
|
621
|
+
newContent: finalContent
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
fileComponents.forEach((comp) => {
|
|
627
|
+
results.push({
|
|
628
|
+
componentId: comp.id,
|
|
629
|
+
componentType: comp.type,
|
|
630
|
+
filePath,
|
|
631
|
+
success: true,
|
|
632
|
+
oldContent,
|
|
633
|
+
newContent: newComponentContent
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
} catch (error) {
|
|
637
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
638
|
+
fileComponents.forEach((comp) => {
|
|
639
|
+
results.push({
|
|
640
|
+
componentId: comp.id,
|
|
641
|
+
componentType: comp.type,
|
|
642
|
+
filePath,
|
|
643
|
+
success: false,
|
|
644
|
+
error: errorMsg
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const successful = results.filter((r) => r.success);
|
|
650
|
+
const failed = results.filter((r) => !r.success);
|
|
651
|
+
const actualChanges = successful.filter((r) => r.oldContent?.trim() !== r.newContent?.trim());
|
|
652
|
+
console.log(chalk.yellow(`\n📋 Analyzed ${actualChanges.length} components with changes`));
|
|
653
|
+
if (actualChanges.length > 0) actualChanges.forEach((change) => {
|
|
654
|
+
console.log(chalk.blue(` 🔄 ${change.componentType}:${change.componentId} in ${change.filePath}`));
|
|
655
|
+
if (debug) {
|
|
656
|
+
console.log(chalk.gray(` 🔍 Available comparison changes: ${comparison.changes.length}`));
|
|
657
|
+
comparison.changes.forEach((c, i) => {
|
|
658
|
+
console.log(chalk.gray(` ${i}: ${c.componentType}:${c.componentId} (${c.changeType})`));
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
const normalizedCompType = change.componentType.endsWith("s") && change.componentType !== "headers" ? change.componentType.slice(0, -1) : change.componentType;
|
|
662
|
+
const componentChanges = comparison.changes.filter((c) => c.componentId === change.componentId && c.componentType === normalizedCompType);
|
|
663
|
+
if (debug) console.log(chalk.gray(` 🔍 Matching changes found: ${componentChanges.length}`));
|
|
664
|
+
componentChanges.forEach((compChange) => {
|
|
665
|
+
if (compChange.changedFields && compChange.changedFields.length > 0) compChange.changedFields.forEach((fieldChange) => {
|
|
666
|
+
const changeSymbol = fieldChange.changeType === "added" ? "➕" : fieldChange.changeType === "deleted" ? "➖" : "🔄";
|
|
667
|
+
console.log(chalk.gray(` ${changeSymbol} ${fieldChange.field}: ${fieldChange.description || fieldChange.changeType}`));
|
|
668
|
+
});
|
|
669
|
+
else if (debug) console.log(chalk.gray(` 🔍 No changedFields data available for this change`));
|
|
670
|
+
if (compChange.summary) console.log(chalk.gray(` 📝 ${compChange.summary}`));
|
|
671
|
+
});
|
|
672
|
+
});
|
|
673
|
+
if (successful.length > actualChanges.length) console.log(chalk.gray(` ⚪ ${successful.length - actualChanges.length} components had no changes`));
|
|
674
|
+
if (failed.length > 0) console.log(chalk.red(` ❌ ${failed.length} components failed to analyze`));
|
|
675
|
+
await runBiomeOnDirectory(join(projectRoot, tempDirName));
|
|
676
|
+
return results;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Analyze which existing components need to be exported because they're referenced by new components
|
|
680
|
+
*/
|
|
681
|
+
function analyzeComponentsToExport(newComponents, currentFilePath, localRegistry) {
|
|
682
|
+
const componentsToExport = [];
|
|
683
|
+
for (const newComp of newComponents) {
|
|
684
|
+
if (newComp.filePath === currentFilePath) continue;
|
|
685
|
+
const allLocalComponents = localRegistry.getAllComponents();
|
|
686
|
+
for (const localComp of allLocalComponents) if ((localComp.filePath.startsWith("/") ? localComp.filePath.split("/").slice(-2).join("/") : localComp.filePath) === currentFilePath) {
|
|
687
|
+
if (shouldComponentBeExported(localComp, newComponents)) {
|
|
688
|
+
if (!componentsToExport.find((c) => c.componentId === localComp.id)) componentsToExport.push({
|
|
689
|
+
componentId: localComp.id,
|
|
690
|
+
variableName: localComp.name,
|
|
691
|
+
reason: `referenced by new component ${newComp.componentType}:${newComp.componentId}`
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return componentsToExport;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Determine if a component should be exported based on heuristics
|
|
700
|
+
*/
|
|
701
|
+
function shouldComponentBeExported(localComponent, newComponents) {
|
|
702
|
+
if (localComponent.type === "agents" || localComponent.type === "subAgents") return true;
|
|
703
|
+
if (localComponent.type === "tools" || localComponent.type === "functionTools") return true;
|
|
704
|
+
if (localComponent.type === "contextConfigs") return true;
|
|
705
|
+
if (localComponent.type === "artifactComponents") return true;
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
//#endregion
|
|
710
|
+
export { checkAndPromptForStaleComponentCleanup, cleanupStaleComponents, copyProjectToTemp, updateModifiedComponents };
|