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