@inkeep/agents-cli 0.52.0 → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents-cli/package.js +1 -1
- package/dist/commands/{pull-v3 → pull-v4}/component-parser.js +3 -3
- package/dist/commands/{pull-v3/utils → pull-v4}/component-registry.js +1 -1
- package/dist/commands/pull-v4/{agent-generator.js → generators/agent-generator.js} +2 -18
- package/dist/commands/pull-v4/{artifact-component-generator.js → generators/artifact-component-generator.js} +2 -2
- package/dist/commands/pull-v4/{context-config-generator.js → generators/context-config-generator.js} +2 -2
- package/dist/commands/pull-v4/{credential-generator.js → generators/credential-generator.js} +2 -2
- package/dist/commands/pull-v4/{data-component-generator.js → generators/data-component-generator.js} +2 -2
- package/dist/commands/pull-v4/{environment-generator.js → generators/environment-generator.js} +2 -2
- package/dist/commands/pull-v4/{external-agent-generator.js → generators/external-agent-generator.js} +2 -2
- package/dist/commands/pull-v4/{function-tool-generator.js → generators/function-tool-generator.js} +2 -2
- package/dist/commands/pull-v4/{mcp-tool-generator.js → generators/mcp-tool-generator.js} +5 -5
- package/dist/commands/pull-v4/{project-generator.js → generators/project-generator.js} +48 -24
- package/dist/commands/{pull-v3/components → pull-v4/generators}/skill-generator.js +1 -1
- package/dist/commands/pull-v4/{status-component-generator.js → generators/status-component-generator.js} +2 -2
- package/dist/commands/pull-v4/{sub-agent-generator.js → generators/sub-agent-generator.js} +103 -2
- package/dist/commands/pull-v4/{trigger-generator.js → generators/trigger-generator.js} +2 -2
- package/dist/commands/pull-v4/introspect/index.js +3 -3
- package/dist/commands/pull-v4/introspect/test-helpers.js +1 -1
- package/dist/commands/pull-v4/introspect-generator.js +26 -11
- package/dist/commands/pull-v4/module-merge.js +33 -7
- package/dist/commands/pull-v4/utils.js +17 -1
- package/package.json +3 -6
- package/dist/commands/pull-v3/project-comparator.js +0 -914
- package/dist/commands/pull-v3/targeted-typescript-placeholders.js +0 -173
- package/dist/commands/pull-v3/utils/component-tracker.js +0 -165
- package/dist/commands/pull-v3/utils/generator-utils.js +0 -146
- package/dist/commands/pull-v3/utils/model-provider-detector.js +0 -50
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { Node, Project } from "ts-morph";
|
|
2
|
-
import { randomBytes } from "node:crypto";
|
|
3
|
-
|
|
4
|
-
//#region src/commands/pull-v3/targeted-typescript-placeholders.ts
|
|
5
|
-
/**
|
|
6
|
-
* Targeted TypeScript Placeholder System
|
|
7
|
-
*
|
|
8
|
-
* Uses AST parsing to intelligently identify large content blocks for replacement:
|
|
9
|
-
* - prompt: (template literals or strings)
|
|
10
|
-
* - description: (string literals)
|
|
11
|
-
* - inputSchema: (object literals)
|
|
12
|
-
* - detailsSchema: (object literals)
|
|
13
|
-
* - props: (object literals in artifact/data components)
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Generate a unique placeholder ID
|
|
17
|
-
*/
|
|
18
|
-
function generatePlaceholderId() {
|
|
19
|
-
return randomBytes(4).toString("hex").toUpperCase();
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Minimum length threshold for replacement (only replace if longer than this)
|
|
23
|
-
*/
|
|
24
|
-
const MIN_REPLACEMENT_LENGTH = 10;
|
|
25
|
-
/**
|
|
26
|
-
* Create targeted placeholders using AST parsing for better accuracy
|
|
27
|
-
*/
|
|
28
|
-
function createTargetedTypeScriptPlaceholders(content) {
|
|
29
|
-
const replacements = {};
|
|
30
|
-
let replacedFields = 0;
|
|
31
|
-
const originalSize = content.length;
|
|
32
|
-
try {
|
|
33
|
-
const sourceFile = new Project({ useInMemoryFileSystem: true }).createSourceFile("temp.ts", content);
|
|
34
|
-
const replacementOperations = [];
|
|
35
|
-
sourceFile.forEachDescendant((node) => {
|
|
36
|
-
if (Node.isPropertyAssignment(node)) {
|
|
37
|
-
const propertyName = node.getName();
|
|
38
|
-
const valueNode = node.getInitializer();
|
|
39
|
-
if (!valueNode) return;
|
|
40
|
-
let valueText = valueNode.getText();
|
|
41
|
-
if (valueText.trim().length < MIN_REPLACEMENT_LENGTH) return;
|
|
42
|
-
let placeholderPrefix = "";
|
|
43
|
-
switch (propertyName) {
|
|
44
|
-
case "prompt":
|
|
45
|
-
placeholderPrefix = "PROMPT";
|
|
46
|
-
break;
|
|
47
|
-
case "description":
|
|
48
|
-
placeholderPrefix = "DESC";
|
|
49
|
-
break;
|
|
50
|
-
case "inputSchema":
|
|
51
|
-
placeholderPrefix = "INPUT_SCHEMA";
|
|
52
|
-
break;
|
|
53
|
-
case "detailsSchema":
|
|
54
|
-
placeholderPrefix = "DETAILS_SCHEMA";
|
|
55
|
-
break;
|
|
56
|
-
case "props":
|
|
57
|
-
placeholderPrefix = "PROPS";
|
|
58
|
-
break;
|
|
59
|
-
case "render":
|
|
60
|
-
placeholderPrefix = "RENDER";
|
|
61
|
-
break;
|
|
62
|
-
default: return;
|
|
63
|
-
}
|
|
64
|
-
const start = valueNode.getStart();
|
|
65
|
-
let end = valueNode.getEnd();
|
|
66
|
-
const propertyEnd = node.getEnd();
|
|
67
|
-
if (propertyName === "inputSchema" || propertyName === "render") {
|
|
68
|
-
const searchStart = start;
|
|
69
|
-
let braceCount = 0;
|
|
70
|
-
let correctEnd = -1;
|
|
71
|
-
let inString = false;
|
|
72
|
-
let stringChar = "";
|
|
73
|
-
for (let i = searchStart; i < content.length; i++) {
|
|
74
|
-
const char = content[i];
|
|
75
|
-
const prevChar = i > 0 ? content[i - 1] : "";
|
|
76
|
-
if ((char === "\"" || char === "'") && prevChar !== "\\") {
|
|
77
|
-
if (!inString) {
|
|
78
|
-
inString = true;
|
|
79
|
-
stringChar = char;
|
|
80
|
-
} else if (char === stringChar) {
|
|
81
|
-
inString = false;
|
|
82
|
-
stringChar = "";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (!inString) {
|
|
86
|
-
if (char === "{") braceCount++;
|
|
87
|
-
else if (char === "}") {
|
|
88
|
-
braceCount--;
|
|
89
|
-
if (braceCount === 0) {
|
|
90
|
-
let j = i + 1;
|
|
91
|
-
while (j < content.length && /\s/.test(content[j])) j++;
|
|
92
|
-
if (j < content.length && content[j] === ",") {
|
|
93
|
-
correctEnd = j + 1;
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (correctEnd > start && correctEnd < end + 100) {
|
|
101
|
-
end = correctEnd;
|
|
102
|
-
valueText = content.slice(start, end);
|
|
103
|
-
}
|
|
104
|
-
} else if (!content.slice(end, end + 20).match(/^\s*[,}]/)) {
|
|
105
|
-
let correctEnd = end;
|
|
106
|
-
while (correctEnd > start && !content.slice(correctEnd, correctEnd + 10).match(/^\s*[,}]/)) correctEnd--;
|
|
107
|
-
if (correctEnd > start) {
|
|
108
|
-
end = correctEnd;
|
|
109
|
-
valueText = content.slice(start, end);
|
|
110
|
-
} else return;
|
|
111
|
-
}
|
|
112
|
-
if (end > propertyEnd) return;
|
|
113
|
-
const actualText = content.slice(start, end);
|
|
114
|
-
if (valueText !== actualText) return;
|
|
115
|
-
if (!content.slice(end, end + 20).match(/^\s*[,}]/)) return;
|
|
116
|
-
const placeholder = `<${placeholderPrefix}_${generatePlaceholderId()}>`;
|
|
117
|
-
replacements[placeholder] = valueText;
|
|
118
|
-
replacedFields++;
|
|
119
|
-
replacementOperations.push({
|
|
120
|
-
start,
|
|
121
|
-
end,
|
|
122
|
-
placeholder,
|
|
123
|
-
originalText: valueText
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
replacementOperations.sort((a, b) => b.start - a.start);
|
|
128
|
-
let processedContent = content;
|
|
129
|
-
for (const op of replacementOperations) processedContent = processedContent.slice(0, op.start) + op.placeholder + processedContent.slice(op.end);
|
|
130
|
-
const processedSize = processedContent.length;
|
|
131
|
-
const savings = originalSize - processedSize;
|
|
132
|
-
const savingsPercentage = originalSize > 0 ? savings / originalSize * 100 : 0;
|
|
133
|
-
return {
|
|
134
|
-
processedContent,
|
|
135
|
-
replacements,
|
|
136
|
-
stats: {
|
|
137
|
-
originalSize,
|
|
138
|
-
processedSize,
|
|
139
|
-
savings,
|
|
140
|
-
savingsPercentage,
|
|
141
|
-
replacedFields
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
} catch {
|
|
145
|
-
return {
|
|
146
|
-
processedContent: content,
|
|
147
|
-
replacements: {},
|
|
148
|
-
stats: {
|
|
149
|
-
originalSize,
|
|
150
|
-
processedSize: originalSize,
|
|
151
|
-
savings: 0,
|
|
152
|
-
savingsPercentage: 0,
|
|
153
|
-
replacedFields: 0
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Restore placeholders in TypeScript content
|
|
160
|
-
*/
|
|
161
|
-
function restoreTargetedTypeScriptPlaceholders(content, replacements) {
|
|
162
|
-
let restoredContent = content;
|
|
163
|
-
const sortedPlaceholders = Object.keys(replacements).sort((a, b) => b.length - a.length);
|
|
164
|
-
for (const placeholder of sortedPlaceholders) {
|
|
165
|
-
const originalValue = replacements[placeholder];
|
|
166
|
-
if (!restoredContent.includes(placeholder)) continue;
|
|
167
|
-
restoredContent = restoredContent.replace(placeholder, originalValue);
|
|
168
|
-
}
|
|
169
|
-
return restoredContent;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
//#endregion
|
|
173
|
-
export { createTargetedTypeScriptPlaceholders, restoreTargetedTypeScriptPlaceholders };
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
//#region src/commands/pull-v3/utils/component-tracker.ts
|
|
2
|
-
var ComponentTracker = class {
|
|
3
|
-
components = /* @__PURE__ */ new Map();
|
|
4
|
-
usedNames = /* @__PURE__ */ new Set();
|
|
5
|
-
/**
|
|
6
|
-
* Register a component in the tracker
|
|
7
|
-
*/
|
|
8
|
-
register(info) {
|
|
9
|
-
const uniqueName = this.ensureUniqueName(info.name, info.type);
|
|
10
|
-
const uniqueExportName = this.ensureUniqueName(info.exportName, info.type);
|
|
11
|
-
const updatedInfo = {
|
|
12
|
-
...info,
|
|
13
|
-
name: uniqueName,
|
|
14
|
-
exportName: uniqueExportName
|
|
15
|
-
};
|
|
16
|
-
this.components.set(info.id, updatedInfo);
|
|
17
|
-
this.usedNames.add(uniqueName);
|
|
18
|
-
this.usedNames.add(uniqueExportName);
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Ensure a variable name is unique across the project
|
|
22
|
-
*/
|
|
23
|
-
ensureUniqueName(baseName, type) {
|
|
24
|
-
let uniqueName = baseName;
|
|
25
|
-
let counter = 1;
|
|
26
|
-
while (this.usedNames.has(uniqueName)) {
|
|
27
|
-
if (counter === 1) uniqueName = `${this.getTypePrefix(type)}${baseName.charAt(0).toUpperCase() + baseName.slice(1)}`;
|
|
28
|
-
else uniqueName = `${baseName}${counter}`;
|
|
29
|
-
counter++;
|
|
30
|
-
if (counter > 100) {
|
|
31
|
-
uniqueName = `${baseName}_${Date.now()}`;
|
|
32
|
-
break;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return uniqueName;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get type prefix for uniqueness resolution
|
|
39
|
-
*/
|
|
40
|
-
getTypePrefix(type) {
|
|
41
|
-
switch (type) {
|
|
42
|
-
case "agent": return "agent";
|
|
43
|
-
case "subAgent": return "sub";
|
|
44
|
-
case "externalAgent": return "ext";
|
|
45
|
-
case "tool": return "tool";
|
|
46
|
-
case "functionTool": return "func";
|
|
47
|
-
case "dataComponent": return "data";
|
|
48
|
-
case "artifactComponent": return "artifact";
|
|
49
|
-
case "credential": return "cred";
|
|
50
|
-
case "statusComponent": return "status";
|
|
51
|
-
case "contextConfig": return "context";
|
|
52
|
-
default: return "comp";
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Get component info by ID
|
|
57
|
-
*/
|
|
58
|
-
get(id) {
|
|
59
|
-
return this.components.get(id);
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Check if component exists
|
|
63
|
-
*/
|
|
64
|
-
has(id) {
|
|
65
|
-
return this.components.has(id);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Get all components of a specific type
|
|
69
|
-
*/
|
|
70
|
-
getByType(type) {
|
|
71
|
-
return Array.from(this.components.values()).filter((c) => c.type === type);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Extract IDs from mixed array (objects with id property or strings)
|
|
75
|
-
*/
|
|
76
|
-
extractIds(references) {
|
|
77
|
-
if (!Array.isArray(references)) return [];
|
|
78
|
-
return references.map((ref) => {
|
|
79
|
-
if (typeof ref === "string") return ref;
|
|
80
|
-
if (typeof ref === "object" && ref) {
|
|
81
|
-
if (ref.id) return ref.id;
|
|
82
|
-
if (ref.type) return ref.type;
|
|
83
|
-
if (ref.name) return ref.name;
|
|
84
|
-
console.warn("ComponentTracker: Skipping reference without clear ID:", ref);
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
return null;
|
|
88
|
-
}).filter(Boolean);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Resolve references to import statements and variable names
|
|
92
|
-
*/
|
|
93
|
-
resolveReferences(references, currentFilePath) {
|
|
94
|
-
const ids = this.extractIds(references);
|
|
95
|
-
const imports = [];
|
|
96
|
-
const variableNames = [];
|
|
97
|
-
for (const id of ids) {
|
|
98
|
-
const component = this.get(id);
|
|
99
|
-
if (component) {
|
|
100
|
-
const importPath = this.getRelativeImportPath(currentFilePath, component.filePath);
|
|
101
|
-
imports.push(`import { ${component.exportName} } from '${importPath}';`);
|
|
102
|
-
variableNames.push(component.name);
|
|
103
|
-
} else variableNames.push(id);
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
imports,
|
|
107
|
-
variableNames
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Generate formatted array of variable names for code generation
|
|
112
|
-
*/
|
|
113
|
-
formatReferencesForCode(references, style, indentLevel) {
|
|
114
|
-
const ids = this.extractIds(references);
|
|
115
|
-
const variableNames = [];
|
|
116
|
-
for (const id of ids) {
|
|
117
|
-
const component = this.get(id);
|
|
118
|
-
if (component) variableNames.push(component.name);
|
|
119
|
-
else variableNames.push(id);
|
|
120
|
-
}
|
|
121
|
-
if (variableNames.length === 0) return "[]";
|
|
122
|
-
const { indentation } = style;
|
|
123
|
-
const indent = indentation.repeat(indentLevel);
|
|
124
|
-
if (variableNames.length === 1) return `[${variableNames[0]}]`;
|
|
125
|
-
const lines = ["["];
|
|
126
|
-
for (const name of variableNames) lines.push(`${indent}${name},`);
|
|
127
|
-
if (lines.length > 1 && lines[lines.length - 1].endsWith(",")) lines[lines.length - 1] = lines[lines.length - 1].slice(0, -1);
|
|
128
|
-
lines.push(`${indentation.repeat(indentLevel - 1)}]`);
|
|
129
|
-
return lines.join("\n");
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Calculate relative import path between files
|
|
133
|
-
*/
|
|
134
|
-
getRelativeImportPath(fromPath, toPath) {
|
|
135
|
-
const fromParts = fromPath.replace(".ts", "").split("/");
|
|
136
|
-
const toParts = toPath.replace(".ts", "").split("/");
|
|
137
|
-
fromParts.pop();
|
|
138
|
-
let relativePath = "";
|
|
139
|
-
for (let i = 0; i < fromParts.length; i++) relativePath += "../";
|
|
140
|
-
relativePath += toParts.join("/");
|
|
141
|
-
if (relativePath.startsWith("../")) return relativePath;
|
|
142
|
-
return `./${relativePath}`;
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Get all components as a list
|
|
146
|
-
*/
|
|
147
|
-
getAllComponents() {
|
|
148
|
-
return Array.from(this.components.values());
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Clear all registered components
|
|
152
|
-
*/
|
|
153
|
-
clear() {
|
|
154
|
-
this.components.clear();
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
/**
|
|
158
|
-
* Convert kebab-case or snake_case to camelCase
|
|
159
|
-
*/
|
|
160
|
-
function toCamelCase(str) {
|
|
161
|
-
return str.toLowerCase().replace(/[-_](.)/g, (_, char) => char.toUpperCase()).replace(/[^a-zA-Z0-9]/g, "").replace(/^[0-9]/, "_$&");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
//#endregion
|
|
165
|
-
export { ComponentTracker, toCamelCase };
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
//#region src/commands/pull-v3/utils/generator-utils.ts
|
|
2
|
-
const DEFAULT_STYLE = {
|
|
3
|
-
quotes: "single",
|
|
4
|
-
semicolons: true,
|
|
5
|
-
indentation: " "
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Convert kebab-case or snake_case to camelCase for variable names
|
|
9
|
-
*/
|
|
10
|
-
function toCamelCase(str) {
|
|
11
|
-
const result = str.replace(/[-_](.)/g, (_, char) => char.toUpperCase()).replace(/[^a-zA-Z0-9]/g, "").replace(/^[0-9]/, "_$&");
|
|
12
|
-
return result.charAt(0).toLowerCase() + result.slice(1);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Format a string value with proper quoting and multiline handling
|
|
16
|
-
*/
|
|
17
|
-
function formatString(str, quote = "'", multiline = false) {
|
|
18
|
-
if (!str && str !== "") return `${quote}${quote}`;
|
|
19
|
-
if (multiline && (str.includes("\n") || str.length > 80)) return `\`${str.replace(/`/g, "\\`")}\``;
|
|
20
|
-
return `${quote}${str.replace(new RegExp(quote, "g"), `\\${quote}`)}${quote}`;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Check if a string contains template variables like {{user.name}}
|
|
24
|
-
*/
|
|
25
|
-
function hasTemplateVariables(str) {
|
|
26
|
-
return /\{\{[^}]+\}\}/.test(str);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Determine if a variable path exists in headers schema
|
|
30
|
-
*/
|
|
31
|
-
function isHeadersVariable(variablePath, contextConfigData) {
|
|
32
|
-
if (!contextConfigData?.headersSchema?.schema) return false;
|
|
33
|
-
const schemaStr = JSON.stringify(contextConfigData.headersSchema.schema);
|
|
34
|
-
return schemaStr.includes(`"${variablePath}"`) || schemaStr.includes(variablePath.split(".")[0]);
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Determine if a variable path exists in context variables
|
|
38
|
-
*/
|
|
39
|
-
function isContextVariable(variablePath, contextConfigData) {
|
|
40
|
-
if (!contextConfigData?.contextVariables) return false;
|
|
41
|
-
const topLevelVar = variablePath.split(".")[0];
|
|
42
|
-
return Object.keys(contextConfigData.contextVariables).includes(topLevelVar);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Format prompt strings with appropriate context.toTemplate() or headers.toTemplate() based on actual schema structure
|
|
46
|
-
*/
|
|
47
|
-
function formatPromptWithContext(str, contextVarName, headersVarName, contextConfigData, quote = "'", multiline = false) {
|
|
48
|
-
if (!str && str !== "") return `${quote}${quote}`;
|
|
49
|
-
if (hasTemplateVariables(str)) return `\`${str.replace(/\{\{([^}]+)\}\}/g, (_match, variablePath) => {
|
|
50
|
-
if (isContextVariable(variablePath, contextConfigData)) return `\${${contextVarName}.toTemplate("${variablePath}")}`;
|
|
51
|
-
if (isHeadersVariable(variablePath, contextConfigData)) return `\${${headersVarName}.toTemplate("${variablePath}")}`;
|
|
52
|
-
return `\${${contextVarName}.toTemplate("${variablePath}")}`;
|
|
53
|
-
}).replace(/`/g, "\\`")}\``;
|
|
54
|
-
return formatString(str, quote, multiline);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Format prompt strings with headers.toTemplate() only (for backwards compatibility)
|
|
58
|
-
*/
|
|
59
|
-
function formatPromptWithHeaders(str, headersVarName, quote = "'", multiline = false) {
|
|
60
|
-
if (!str && str !== "") return `${quote}${quote}`;
|
|
61
|
-
if (hasTemplateVariables(str)) return `\`${str.replace(/\{\{([^}]+)\}\}/g, `\${${headersVarName}.toTemplate("$1")}`).replace(/`/g, "\\`")}\``;
|
|
62
|
-
return formatString(str, quote, multiline);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Format array of references (tools, agents, components) with proper indentation
|
|
66
|
-
*/
|
|
67
|
-
function formatReferencesArray(references, style, indentLevel) {
|
|
68
|
-
let refArray;
|
|
69
|
-
if (Array.isArray(references)) refArray = references.map((item) => {
|
|
70
|
-
if (typeof item === "string") return toCamelCase(item);
|
|
71
|
-
if (typeof item === "object" && item && item.id) return toCamelCase(item.id);
|
|
72
|
-
return toCamelCase(String(item));
|
|
73
|
-
});
|
|
74
|
-
else if (references && typeof references === "object") refArray = Object.keys(references).map((key) => toCamelCase(key));
|
|
75
|
-
else return "[]";
|
|
76
|
-
if (!refArray || refArray.length === 0) return "[]";
|
|
77
|
-
const { indentation } = style;
|
|
78
|
-
const indent = indentation.repeat(indentLevel);
|
|
79
|
-
if (refArray.length === 1) return `[${refArray[0]}]`;
|
|
80
|
-
const lines = ["["];
|
|
81
|
-
for (const ref of refArray) lines.push(`${indent}${ref},`);
|
|
82
|
-
if (lines.length > 1 && lines[lines.length - 1].endsWith(",")) lines[lines.length - 1] = lines[lines.length - 1].slice(0, -1);
|
|
83
|
-
lines.push(`${indentation.repeat(indentLevel - 1)}]`);
|
|
84
|
-
return lines.join("\n");
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Format object properties as JavaScript object literal
|
|
88
|
-
*/
|
|
89
|
-
function formatObject(obj, style, indentLevel) {
|
|
90
|
-
if (!obj || typeof obj !== "object") return "{}";
|
|
91
|
-
const { quotes, indentation } = style;
|
|
92
|
-
const q = quotes === "single" ? "'" : "\"";
|
|
93
|
-
const indent = indentation.repeat(indentLevel);
|
|
94
|
-
const lines = ["{"];
|
|
95
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
96
|
-
if (value === null || value === void 0) continue;
|
|
97
|
-
const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : formatString(key, q);
|
|
98
|
-
if (typeof value === "string") lines.push(`${indent}${formattedKey}: ${formatString(value, q)},`);
|
|
99
|
-
else if (typeof value === "object") lines.push(`${indent}${formattedKey}: ${formatObject(value, style, indentLevel + 1)},`);
|
|
100
|
-
else lines.push(`${indent}${formattedKey}: ${JSON.stringify(value)},`);
|
|
101
|
-
}
|
|
102
|
-
if (lines.length > 1 && lines[lines.length - 1].endsWith(",")) lines[lines.length - 1] = lines[lines.length - 1].slice(0, -1);
|
|
103
|
-
lines.push(`${indentation.repeat(indentLevel - 1)}}`);
|
|
104
|
-
return lines.join("\n");
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Remove trailing comma from the last line in an array of lines
|
|
108
|
-
*/
|
|
109
|
-
function removeTrailingComma(lines) {
|
|
110
|
-
if (lines.length > 0 && lines[lines.length - 1].endsWith(",")) lines[lines.length - 1] = lines[lines.length - 1].slice(0, -1);
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Generate standard import statement with proper quoting and semicolons
|
|
114
|
-
*/
|
|
115
|
-
function generateImport(imports, from, style) {
|
|
116
|
-
const { quotes, semicolons } = style;
|
|
117
|
-
const q = quotes === "single" ? "'" : "\"";
|
|
118
|
-
const semi = semicolons ? ";" : "";
|
|
119
|
-
if (imports.length === 1) return `import { ${imports[0]} } from ${q}${from}${q}${semi}`;
|
|
120
|
-
return `import { ${imports.join(", ")} } from ${q}${from}${q}${semi}`;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Check if a value is truthy and should be included in output
|
|
124
|
-
*/
|
|
125
|
-
function shouldInclude(value) {
|
|
126
|
-
if (value === null || value === void 0) return false;
|
|
127
|
-
if (Array.isArray(value) && value.length === 0) return false;
|
|
128
|
-
if (typeof value === "object" && Object.keys(value).length === 0) return false;
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Generate complete file content with imports and definitions
|
|
133
|
-
*/
|
|
134
|
-
function generateFileContent(imports, definitions) {
|
|
135
|
-
const content = [];
|
|
136
|
-
if (imports.length > 0) content.push(imports.join("\n"));
|
|
137
|
-
if (definitions.length > 0) {
|
|
138
|
-
if (content.length > 0) content.push("");
|
|
139
|
-
content.push(definitions.join("\n\n"));
|
|
140
|
-
}
|
|
141
|
-
content.push("");
|
|
142
|
-
return content.join("\n");
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
//#endregion
|
|
146
|
-
export { DEFAULT_STYLE, formatObject, formatPromptWithContext, formatPromptWithHeaders, formatReferencesArray, formatString, generateFileContent, generateImport, hasTemplateVariables, removeTrailingComma, shouldInclude, toCamelCase };
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { anthropic } from "@ai-sdk/anthropic";
|
|
2
|
-
import { google } from "@ai-sdk/google";
|
|
3
|
-
import { openai } from "@ai-sdk/openai";
|
|
4
|
-
|
|
5
|
-
//#region src/commands/pull-v3/utils/model-provider-detector.ts
|
|
6
|
-
/**
|
|
7
|
-
* Model Provider Detector - Detect available API keys and select appropriate models
|
|
8
|
-
*/
|
|
9
|
-
const PROVIDER_CONFIGS = [
|
|
10
|
-
{
|
|
11
|
-
name: "anthropic",
|
|
12
|
-
envVars: ["ANTHROPIC_API_KEY"],
|
|
13
|
-
model: "claude-sonnet-4-5"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: "openai",
|
|
17
|
-
envVars: ["OPENAI_API_KEY"],
|
|
18
|
-
model: "gpt-5.1"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: "google",
|
|
22
|
-
envVars: ["GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
23
|
-
model: "gemini-2.5-flash"
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: "azure",
|
|
27
|
-
envVars: ["AZURE_API_KEY"],
|
|
28
|
-
model: ""
|
|
29
|
-
}
|
|
30
|
-
];
|
|
31
|
-
/**
|
|
32
|
-
* Get a model instance for LLM content merging
|
|
33
|
-
* Returns first available provider or throws if none available
|
|
34
|
-
*/
|
|
35
|
-
function getAvailableModel() {
|
|
36
|
-
for (const config of PROVIDER_CONFIGS) if (config.envVars.some((envVar) => {
|
|
37
|
-
const value = process.env[envVar];
|
|
38
|
-
return value && value.trim() !== "";
|
|
39
|
-
})) switch (config.name) {
|
|
40
|
-
case "anthropic": return anthropic(config.model);
|
|
41
|
-
case "openai": return openai(config.model);
|
|
42
|
-
case "google": return google(config.model);
|
|
43
|
-
case "azure": continue;
|
|
44
|
-
default: throw new Error(`Unknown provider: ${config.name}`);
|
|
45
|
-
}
|
|
46
|
-
throw new Error("No API keys detected. Please set ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, or AZURE_API_KEY");
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
//#endregion
|
|
50
|
-
export { getAvailableModel };
|