@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.
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,286 +0,0 @@
1
- import { DEFAULT_STYLE } 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, generateEnvironmentIndexFile } 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 { generateProjectFile } from "./components/project-generator.js";
12
- import { generateStatusComponentFile } from "./components/status-component-generator.js";
13
- import { generateSubAgentFile } from "./components/sub-agent-generator.js";
14
- import { ComponentRegistry, registerAllComponents } from "./utils/component-registry.js";
15
- import { generateTriggerFile } from "./components/trigger-generator.js";
16
- import { mkdirSync, writeFileSync } from "node:fs";
17
- import { dirname, join } from "node:path";
18
- import chalk from "chalk";
19
-
20
- //#region src/commands/pull-v3/introspect-generator.ts
21
- /**
22
- * Introspect Generator - Complete project regeneration
23
- *
24
- * This module handles the --introspect mode which regenerates all files
25
- * from scratch without any comparison or diffing logic.
26
- */
27
- /**
28
- * Helper function to ensure directory exists
29
- */
30
- function ensureDir(filePath) {
31
- mkdirSync(dirname(filePath), { recursive: true });
32
- }
33
- /**
34
- * Check if an agent is complete enough for code generation
35
- * An agent needs a name, defaultSubAgentId, and at least one sub-agent
36
- */
37
- function isAgentComplete(agentData) {
38
- if (!agentData.name) return {
39
- complete: false,
40
- reason: "missing name"
41
- };
42
- if (!agentData.defaultSubAgentId) return {
43
- complete: false,
44
- reason: "missing defaultSubAgentId (no sub-agents configured)"
45
- };
46
- if (!agentData.subAgents || Object.keys(agentData.subAgents).length === 0) return {
47
- complete: false,
48
- reason: "no sub-agents defined"
49
- };
50
- return { complete: true };
51
- }
52
- /**
53
- * Generate all files from scratch using deterministic generation
54
- */
55
- async function introspectGenerate(project, paths, environment, debug, options = {}) {
56
- if (debug) console.log(chalk.gray("šŸ” Regenerating all project files..."));
57
- const generatedFiles = [];
58
- const style = {
59
- ...DEFAULT_STYLE,
60
- ...options.codeStyle
61
- };
62
- const skippedAgents = [];
63
- const registry = new ComponentRegistry();
64
- try {
65
- registerAllComponents(project, registry);
66
- if (project.credentialReferences) for (const [credId, credData] of Object.entries(project.credentialReferences)) {
67
- const credentialFile = join(paths.credentialsDir, `${credId}.ts`);
68
- const credentialContent = generateCredentialFile(credId, credData, style);
69
- ensureDir(credentialFile);
70
- writeFileSync(credentialFile, credentialContent, "utf-8");
71
- generatedFiles.push(credentialFile);
72
- }
73
- const envFile = join(paths.environmentsDir, `${environment}.env.ts`);
74
- const envContent = generateEnvironmentFile(environment, {
75
- name: `${environment} Environment`,
76
- description: `Environment configuration for ${environment}`,
77
- credentials: project.credentialReferences ? Object.keys(project.credentialReferences) : []
78
- }, style, registry);
79
- ensureDir(envFile);
80
- writeFileSync(envFile, envContent, "utf-8");
81
- generatedFiles.push(envFile);
82
- const envIndexFile = join(paths.environmentsDir, "index.ts");
83
- const envIndexContent = generateEnvironmentIndexFile([environment], style);
84
- ensureDir(envIndexFile);
85
- writeFileSync(envIndexFile, envIndexContent, "utf-8");
86
- generatedFiles.push(envIndexFile);
87
- const functionToolsGenerated = /* @__PURE__ */ new Set();
88
- if (project.functionTools) for (const [toolId, toolData] of Object.entries(project.functionTools)) {
89
- const functionId = toolData.functionId;
90
- const funcData = functionId ? project.functions?.[functionId] : void 0;
91
- const mergedData = {
92
- name: toolData.name,
93
- description: toolData.description,
94
- inputSchema: funcData?.inputSchema,
95
- executeCode: funcData?.executeCode,
96
- execute: funcData?.executeCode,
97
- dependencies: funcData?.dependencies
98
- };
99
- const functionFile = join(paths.toolsDir, "functions", `${toolId}.ts`);
100
- const functionContent = generateFunctionToolFile(toolId, mergedData, style);
101
- ensureDir(functionFile);
102
- writeFileSync(functionFile, functionContent, "utf-8");
103
- generatedFiles.push(functionFile);
104
- functionToolsGenerated.add(toolId);
105
- }
106
- if (project.agents) for (const agentData of Object.values(project.agents)) {
107
- const agentFunctionTools = agentData.functionTools;
108
- const agentFunctions = agentData.functions;
109
- if (agentFunctionTools) for (const [toolId, toolData] of Object.entries(agentFunctionTools)) {
110
- if (functionToolsGenerated.has(toolId)) continue;
111
- const functionId = toolData.functionId;
112
- const funcData = functionId ? agentFunctions?.[functionId] || project.functions?.[functionId] : void 0;
113
- const mergedData = {
114
- name: toolData.name,
115
- description: toolData.description,
116
- inputSchema: funcData?.inputSchema,
117
- executeCode: funcData?.executeCode,
118
- execute: funcData?.executeCode,
119
- dependencies: funcData?.dependencies
120
- };
121
- const functionFile = join(paths.toolsDir, "functions", `${toolId}.ts`);
122
- const functionContent = generateFunctionToolFile(toolId, mergedData, style);
123
- ensureDir(functionFile);
124
- writeFileSync(functionFile, functionContent, "utf-8");
125
- generatedFiles.push(functionFile);
126
- functionToolsGenerated.add(toolId);
127
- }
128
- }
129
- if (project.functions) {
130
- for (const funcId of Object.keys(project.functions)) if (!functionToolsGenerated.has(funcId)) {
131
- if (!(Object.values(project.functionTools || {}).some((ft) => ft.functionId === funcId) || Object.values(project.agents || {}).some((agent) => Object.values(agent.functionTools || {}).some((ft) => ft.functionId === funcId))) && debug) console.log(chalk.yellow(`āš ļø Skipping orphaned function '${funcId}' - no functionTool references it`));
132
- }
133
- }
134
- if (project.tools) for (const [toolId, toolData] of Object.entries(project.tools)) {
135
- const toolFile = join(paths.toolsDir, `${toolId}.ts`);
136
- const toolContent = generateMcpToolFile(toolId, toolData, style, registry);
137
- ensureDir(toolFile);
138
- writeFileSync(toolFile, toolContent, "utf-8");
139
- generatedFiles.push(toolFile);
140
- }
141
- if (project.dataComponents) for (const [dataId, dataData] of Object.entries(project.dataComponents)) {
142
- const dataFile = join(paths.dataComponentsDir, `${dataId}.ts`);
143
- const dataContent = generateDataComponentFile(dataId, dataData, style);
144
- ensureDir(dataFile);
145
- writeFileSync(dataFile, dataContent, "utf-8");
146
- generatedFiles.push(dataFile);
147
- }
148
- if (project.artifactComponents) for (const [artifactId, artifactData] of Object.entries(project.artifactComponents)) {
149
- const artifactFile = join(paths.artifactComponentsDir, `${artifactId}.ts`);
150
- const artifactContent = generateArtifactComponentFile(artifactId, artifactData, style);
151
- ensureDir(artifactFile);
152
- writeFileSync(artifactFile, artifactContent, "utf-8");
153
- generatedFiles.push(artifactFile);
154
- }
155
- const registeredStatusComponents = registry.getAllComponents().filter((c) => c.type === "statusComponents");
156
- if (registeredStatusComponents.length > 0) for (const statusComp of registeredStatusComponents) {
157
- const statusData = findStatusComponentData(project, statusComp.id);
158
- if (statusData) {
159
- const statusFile = join(paths.statusComponentsDir, `${statusComp.id}.ts`);
160
- const statusContent = generateStatusComponentFile(statusComp.id, statusData, style);
161
- ensureDir(statusFile);
162
- writeFileSync(statusFile, statusContent, "utf-8");
163
- generatedFiles.push(statusFile);
164
- }
165
- }
166
- if (project.externalAgents) for (const [extAgentId, extAgentData] of Object.entries(project.externalAgents)) {
167
- const extAgentFile = join(paths.externalAgentsDir, `${extAgentId}.ts`);
168
- const extAgentContent = generateExternalAgentFile(extAgentId, extAgentData, style, registry);
169
- ensureDir(extAgentFile);
170
- writeFileSync(extAgentFile, extAgentContent, "utf-8");
171
- generatedFiles.push(extAgentFile);
172
- }
173
- const registeredContextConfigs = registry.getAllComponents().filter((c) => c.type === "contextConfigs");
174
- if (registeredContextConfigs.length > 0) for (const contextComp of registeredContextConfigs) {
175
- const contextData = findContextConfigData(project, contextComp.id);
176
- if (contextData) {
177
- const contextFile = join(paths.contextConfigsDir, `${contextComp.id}.ts`);
178
- const contextContent = generateContextConfigFile(contextComp.id, contextData, style, registry);
179
- ensureDir(contextFile);
180
- writeFileSync(contextFile, contextContent, "utf-8");
181
- generatedFiles.push(contextFile);
182
- }
183
- }
184
- const completeAgentIds = /* @__PURE__ */ new Set();
185
- if (project.agents) for (const [agentId, agentData] of Object.entries(project.agents)) {
186
- const completeness = isAgentComplete(agentData);
187
- if (completeness.complete) completeAgentIds.add(agentId);
188
- else {
189
- skippedAgents.push({
190
- id: agentId,
191
- reason: completeness.reason || "incomplete"
192
- });
193
- if (debug) console.log(chalk.yellow(`āš ļø Skipping incomplete agent '${agentId}': ${completeness.reason}`));
194
- }
195
- }
196
- if (project.agents && Object.keys(project.agents).length > 0) {
197
- let totalSubAgents = 0;
198
- for (const [agentId, agentData] of Object.entries(project.agents)) {
199
- if (!completeAgentIds.has(agentId)) continue;
200
- if (agentData.subAgents) for (const _subAgentId of Object.keys(agentData.subAgents)) totalSubAgents++;
201
- }
202
- if (totalSubAgents > 0) for (const [agentId, agentData] of Object.entries(project.agents)) {
203
- if (!completeAgentIds.has(agentId)) continue;
204
- if (agentData.subAgents) {
205
- const contextConfigData = agentData.contextConfig?.id ? findContextConfigData(project, agentData.contextConfig.id) : void 0;
206
- for (const [subAgentId, subAgentData] of Object.entries(agentData.subAgents)) {
207
- const subAgentFile = join(paths.agentsDir, "sub-agents", `${subAgentId}.ts`);
208
- const subAgentContent = generateSubAgentFile(subAgentId, subAgentData, style, registry, agentId, contextConfigData, agentData.models || project.models);
209
- ensureDir(subAgentFile);
210
- writeFileSync(subAgentFile, subAgentContent, "utf-8");
211
- generatedFiles.push(subAgentFile);
212
- }
213
- }
214
- }
215
- }
216
- if (project.agents) for (const [agentId, agentData] of Object.entries(project.agents)) {
217
- if (!completeAgentIds.has(agentId)) continue;
218
- const agentFile = join(paths.agentsDir, `${agentId}.ts`);
219
- const agentContent = generateAgentFile(agentId, agentData, style, registry, agentData.contextConfig?.id ? findContextConfigData(project, agentData.contextConfig.id) : void 0, project.models);
220
- ensureDir(agentFile);
221
- writeFileSync(agentFile, agentContent, "utf-8");
222
- generatedFiles.push(agentFile);
223
- if (agentData.triggers && Object.keys(agentData.triggers).length > 0) for (const [triggerId, triggerData] of Object.entries(agentData.triggers)) {
224
- const triggerFile = join(paths.agentsDir, "triggers", `${triggerId}.ts`);
225
- const triggerContent = generateTriggerFile(triggerId, triggerData, style, registry);
226
- ensureDir(triggerFile);
227
- writeFileSync(triggerFile, triggerContent, "utf-8");
228
- generatedFiles.push(triggerFile);
229
- }
230
- }
231
- const projectDataForGenerator = {
232
- ...project,
233
- agents: project.agents ? Object.keys(project.agents).filter((id) => completeAgentIds.has(id)) : [],
234
- tools: project.tools ? Object.keys(project.tools) : [],
235
- externalAgents: project.externalAgents ? Object.keys(project.externalAgents) : [],
236
- dataComponents: project.dataComponents ? Object.keys(project.dataComponents) : [],
237
- artifactComponents: project.artifactComponents ? Object.keys(project.artifactComponents) : [],
238
- credentialReferences: project.credentialReferences ? Object.keys(project.credentialReferences) : []
239
- };
240
- const projectFile = join(paths.projectRoot, "index.ts");
241
- const projectContent = generateProjectFile(project.id, projectDataForGenerator, style, registry);
242
- ensureDir(projectFile);
243
- writeFileSync(projectFile, projectContent, "utf-8");
244
- generatedFiles.push(projectFile);
245
- if (debug) console.log(chalk.green(`āœ… Generated ${generatedFiles.length} files`));
246
- if (skippedAgents.length > 0) {
247
- console.log(chalk.yellow(`\nāš ļø Skipped ${skippedAgents.length} incomplete agent(s):`));
248
- for (const { id, reason } of skippedAgents) console.log(chalk.yellow(` • ${id}: ${reason}`));
249
- console.log(chalk.gray(" To fix: Add at least one sub-agent to each agent in the UI and set it as default."));
250
- }
251
- } catch (error) {
252
- console.error(chalk.red("\nāŒ Introspect regeneration failed:"));
253
- console.error(chalk.red(` Error: ${error instanceof Error ? error.message : "Unknown error"}`));
254
- throw error;
255
- }
256
- }
257
- /**
258
- * Find context config data by agent-based ID from project agents
259
- */
260
- function findContextConfigData(project, contextId) {
261
- if (project.agents) {
262
- for (const agentData of Object.values(project.agents)) if (agentData.contextConfig) {
263
- if (agentData.contextConfig.id === contextId) return agentData.contextConfig;
264
- }
265
- }
266
- }
267
- /**
268
- * Find status component data by ID from project agents
269
- */
270
- function findStatusComponentData(project, statusId) {
271
- if (project.agents) {
272
- for (const agentData of Object.values(project.agents)) if (agentData.statusUpdates?.statusComponents) for (const statusComp of agentData.statusUpdates.statusComponents) {
273
- let compId;
274
- if (typeof statusComp === "string") compId = statusComp;
275
- else if (typeof statusComp === "object" && statusComp) compId = statusComp.type;
276
- if (compId === statusId) return typeof statusComp === "string" ? {
277
- id: statusId,
278
- type: statusId,
279
- description: `Status component for ${statusId}`
280
- } : statusComp;
281
- }
282
- }
283
- }
284
-
285
- //#endregion
286
- export { introspectGenerate };
@@ -1,192 +0,0 @@
1
- import { createTargetedTypeScriptPlaceholders, restoreTargetedTypeScriptPlaceholders } from "./targeted-typescript-placeholders.js";
2
- import { getAvailableModel } from "./utils/model-provider-detector.js";
3
- import chalk from "chalk";
4
- import { generateText } from "ai";
5
-
6
- //#region src/commands/pull-v3/llm-content-merger.ts
7
- /**
8
- * LLM Content Merger - Intelligently merge old and new component content
9
- *
10
- * Uses an LLM to selectively update modified components while preserving:
11
- * - Original file structure and formatting
12
- * - Code style consistency
13
- * - Better zod schemas
14
- * - Imports and other non-component code
15
- */
16
- /**
17
- * Strip code fences from LLM response if present
18
- */
19
- function stripCodeFences(content) {
20
- content = content.replace(/^```(?:typescript|ts|javascript|js)?\s*\n?/i, "");
21
- content = content.replace(/\n?```\s*$/i, "");
22
- return content;
23
- }
24
- /**
25
- * Estimate tokens in text (rough approximation: 1 token ā‰ˆ 4 characters)
26
- */
27
- function estimateTokens(text) {
28
- return Math.ceil(text.length / 4);
29
- }
30
- function calculateCostEstimate(promptTokens, completionTokens) {
31
- return promptTokens / 1e6 * 3 + completionTokens / 1e6 * 15;
32
- }
33
- /**
34
- * Use LLM to intelligently merge old content with new component definitions
35
- */
36
- async function mergeComponentsWithLLM(request) {
37
- const { oldContent, newContent, modifiedComponents, filePath, newComponents, componentsToExport } = request;
38
- const componentList = modifiedComponents.map((c) => `- ${c.componentType}:${c.componentId}`).join("\n");
39
- const newComponentsList = newComponents && newComponents.length > 0 ? newComponents.map((c) => {
40
- const currentDir = filePath.replace(/^.*\/([^/]+\/[^/]+)$/, "$1").replace(/\/[^/]+$/, "");
41
- let componentPath = c.filePath;
42
- if (componentPath.includes(".temp-")) componentPath = componentPath.replace(/^.*\.temp-[^/]+\//, "");
43
- componentPath = componentPath.replace(/\.ts$/, "");
44
- const importPath = calculateRelativeImportPath(currentDir, componentPath);
45
- const variableName = c.componentId.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
46
- return `- ${c.componentType}:${c.componentId} (import as: import { ${variableName} } from '${importPath}')`;
47
- }).join("\n") : "";
48
- function calculateRelativeImportPath(fromDir, toPath) {
49
- const fromParts = fromDir.split("/");
50
- const toParts = toPath.split("/");
51
- let commonLength = 0;
52
- while (commonLength < fromParts.length && commonLength < toParts.length - 1 && fromParts[commonLength] === toParts[commonLength]) commonLength++;
53
- const upLevels = fromParts.length - commonLength;
54
- let relativePath = "";
55
- for (let i = 0; i < upLevels; i++) relativePath += "../";
56
- relativePath += toParts.slice(commonLength).join("/");
57
- return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
58
- }
59
- const componentsToExportList = componentsToExport && componentsToExport.length > 0 ? componentsToExport.map((c) => `- ${c.variableName} (${c.reason})`).join("\n") : "";
60
- const prompt = `You are a TypeScript code expert tasked with intelligently merging component updates.
61
-
62
- ## Task
63
- Merge the OLD file content with NEW component definitions, preserving the original file structure while updating only the modified components.
64
-
65
- ## Modified Components to Update
66
- ${componentList}
67
- ${newComponentsList ? `
68
- ## New Components Available (can be imported)
69
- ${newComponentsList}
70
- ` : ""}${componentsToExportList ? `
71
- ## Components That Need To Be Exported
72
- The following existing components are referenced by new components and must be exported:
73
- ${componentsToExportList}
74
-
75
- Ensure these components have export statements (convert \`const\` to \`export const\`, or add \`export\` to existing declarations).
76
- ` : ""}
77
- ## Instructions
78
- 0. **Please ensure you focus changes to minimize git diff size.** We want a clean git history.
79
- 1. **Preserve original structure**: Keep imports, exports, comments, and overall file organization
80
- 2. **Update only modified components**: Replace the specified components with their new versions
81
- 3. **Maintain code style**: Match the original formatting, indentation, and style
82
- 4. **Improve schemas**: Use better zod schemas from the new content where applicable. E.g. if the new content uses something like z.union([z.null(), z.string()]), use z.string().nullable() instead.
83
- 5. **Keep variable names**: Preserve original variable names and declarations
84
- 6. **Preserve non-component code**: Keep any non-component logic, comments, or utilities
85
- 7. **Smart import handling**:
86
- - Please leave all imports at the top of the file. Don't use .js imports, use .ts imports instead. (import example from './example')
87
- - Preserve all imports from the original content that are not modified, if a component is modified or no longer exists, remove the import.
88
- - For NEW components listed above, add proper import statements
89
- - For components that exist in the same file (modified components), DO NOT add import statements
90
- - Remove any incorrect imports from the NEW component definitions that reference same-file components
91
- - Use relative paths for imports (e.g., './example' not './example.js')
92
- 8. **Format JavaScript functions for maximum readability**:
93
- - When you see compressed/minified function code like \`async({params})=>{...code...}\`, expand and prettify it
94
- - Add proper line breaks, spacing, and indentation to make the function readable
95
- - Ensure all braces \`{}\`, parentheses \`()\`, and syntax are properly balanced and valid
96
- - Format the function code following TypeScript/JavaScript best practices
97
- - Make sure the final code is compilable and syntactically correct
98
- - Example: \`async({a,b})=>{return a+b}\` should become:
99
- \`\`\`
100
- async ({ a, b }) => {
101
- return a + b;
102
- }
103
- \`\`\`
104
-
105
- ## OLD File to be updated with new component definitions:
106
- \`\`\`typescript
107
- ${oldContent}
108
- \`\`\`
109
-
110
- ## NEW Component Definitions to replace/add to the old file:
111
- \`\`\`typescript
112
- ${newContent}
113
- \`\`\`
114
-
115
- ## Output
116
- Provide the merged TypeScript file that:
117
- - Keeps the original file structure
118
- - Updates ONLY the modified components listed above
119
- - Maintains consistent code style
120
- - Uses improved schemas where beneficial
121
- - Preserves all imports, exports, and other code that are necessary to keep the file working.
122
- - **Formats all function code beautifully with proper spacing, line breaks, and indentation**
123
- - **Ensures all syntax is valid and compilable TypeScript/JavaScript**
124
- - Start the code immidiately with the first line of the file, skip any backticks or other formatting announcing that it is a code block or typescript file.
125
- - Please follow biomes.dev code style.
126
- - Please remember the NEW component definitions are to replace/add to the old file.
127
-
128
- Return only the merged TypeScript code without any explanation or markdown formatting.`;
129
- try {
130
- const oldPlaceholders = createTargetedTypeScriptPlaceholders(oldContent);
131
- const newPlaceholders = createTargetedTypeScriptPlaceholders(newContent);
132
- const processedPrompt = prompt.replace(oldContent, oldPlaceholders.processedContent).replace(newContent, newPlaceholders.processedContent);
133
- const estimatedPromptTokens = estimateTokens(processedPrompt);
134
- let mergedContent = (await generateText({
135
- model: getAvailableModel(),
136
- prompt: processedPrompt
137
- })).text.trim();
138
- mergedContent = stripCodeFences(mergedContent);
139
- const estimatedCompletionTokens = estimateTokens(mergedContent);
140
- const totalTokens = estimatedPromptTokens + estimatedCompletionTokens;
141
- const estimatedCost = calculateCostEstimate(estimatedPromptTokens, estimatedCompletionTokens);
142
- console.log(chalk.gray(` šŸ’° LLM usage: ~${totalTokens.toLocaleString()} tokens ($${estimatedCost.toFixed(4)})`));
143
- const allReplacements = {
144
- ...oldPlaceholders.replacements,
145
- ...newPlaceholders.replacements
146
- };
147
- if (Object.keys(allReplacements).length > 0) mergedContent = restoreTargetedTypeScriptPlaceholders(mergedContent, allReplacements);
148
- const changes = modifiedComponents.map((c) => `Updated ${c.componentType}:${c.componentId}`);
149
- return {
150
- mergedContent,
151
- changes,
152
- success: true,
153
- usage: {
154
- promptTokens: estimatedPromptTokens,
155
- completionTokens: estimatedCompletionTokens,
156
- totalTokens,
157
- estimatedCost
158
- }
159
- };
160
- } catch (error) {
161
- return {
162
- mergedContent: oldContent,
163
- changes: [],
164
- success: false,
165
- error: error instanceof Error ? error.message : String(error)
166
- };
167
- }
168
- }
169
- /**
170
- * Preview the merge result by showing a diff-like summary
171
- */
172
- function previewMergeResult(oldContent, mergedContent, changes) {
173
- console.log(chalk.cyan("\nšŸ” Merge Preview:"));
174
- console.log(chalk.gray(` Old content: ${oldContent.length} characters`));
175
- console.log(chalk.gray(` New content: ${mergedContent.length} characters`));
176
- console.log(chalk.yellow(` Changes applied:`));
177
- changes.forEach((change) => {
178
- console.log(chalk.gray(` • ${change}`));
179
- });
180
- const lines = mergedContent.split("\n");
181
- const preview = lines.slice(0, 10).join("\n");
182
- console.log(chalk.cyan("\nšŸ“„ Merged content preview (first 10 lines):"));
183
- console.log(chalk.gray(" ā”Œā”€ā”€ā”€ā”€ā”€"));
184
- preview.split("\n").forEach((line, i) => {
185
- console.log(chalk.gray(` │ ${String(i + 1).padStart(2, " ")}: ${line}`));
186
- });
187
- if (lines.length > 10) console.log(chalk.gray(` │ ... (${lines.length - 10} more lines)`));
188
- console.log(chalk.gray(" └─────"));
189
- }
190
-
191
- //#endregion
192
- export { mergeComponentsWithLLM, previewMergeResult };