@inkeep/agents-cli 0.51.0 → 0.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents-cli/package.js +6 -0
- package/dist/commands/config.js +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/pull-v3/component-parser.js +4 -10
- package/dist/commands/pull-v4/agent-generator.js +274 -0
- package/dist/commands/pull-v4/artifact-component-generator.js +69 -0
- package/dist/commands/pull-v4/context-config-generator.js +264 -0
- package/dist/commands/pull-v4/credential-generator.js +30 -0
- package/dist/commands/pull-v4/data-component-generator.js +50 -0
- package/dist/commands/pull-v4/environment-generator.js +123 -0
- package/dist/commands/pull-v4/external-agent-generator.js +56 -0
- package/dist/commands/pull-v4/function-tool-generator.js +48 -0
- package/dist/commands/pull-v4/introspect/index.js +365 -0
- package/dist/commands/pull-v4/introspect/test-helpers.js +143 -0
- package/dist/commands/pull-v4/introspect-generator.js +691 -0
- package/dist/commands/pull-v4/mcp-tool-generator.js +91 -0
- package/dist/commands/pull-v4/module-merge.js +379 -0
- package/dist/commands/pull-v4/project-generator.js +101 -0
- package/dist/commands/pull-v4/status-component-generator.js +35 -0
- package/dist/commands/pull-v4/sub-agent-generator.js +168 -0
- package/dist/commands/pull-v4/trigger-generator.js +58 -0
- package/dist/commands/pull-v4/utils.js +219 -0
- package/dist/commands/push.js +1 -1
- package/dist/commands/update.js +2 -2
- package/dist/index.js +18 -44
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +18 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +180 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +8 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +12 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +60 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +37 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +31 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +118 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js +11 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +141 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +63 -0
- package/dist/utils/ci-environment.js +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/environment-loader.js +1 -1
- package/dist/utils/file-finder.js +1 -1
- package/dist/utils/mcp-runner.js +1 -1
- package/dist/utils/profile-config.js +1 -1
- package/dist/utils/profiles/profile-manager.js +1 -1
- package/dist/utils/project-directory.js +1 -1
- package/dist/utils/project-loader.js +1 -1
- package/dist/utils/version-check.js +6 -15
- package/package.json +5 -4
- package/dist/commands/pull-v3/component-updater.js +0 -768
- package/dist/commands/pull-v3/components/agent-generator.js +0 -255
- package/dist/commands/pull-v3/components/artifact-component-generator.js +0 -143
- package/dist/commands/pull-v3/components/context-config-generator.js +0 -190
- package/dist/commands/pull-v3/components/credential-generator.js +0 -89
- package/dist/commands/pull-v3/components/data-component-generator.js +0 -102
- package/dist/commands/pull-v3/components/environment-generator.js +0 -173
- package/dist/commands/pull-v3/components/external-agent-generator.js +0 -75
- package/dist/commands/pull-v3/components/function-tool-generator.js +0 -92
- package/dist/commands/pull-v3/components/mcp-tool-generator.js +0 -86
- package/dist/commands/pull-v3/components/project-generator.js +0 -157
- package/dist/commands/pull-v3/components/status-component-generator.js +0 -92
- package/dist/commands/pull-v3/components/sub-agent-generator.js +0 -295
- package/dist/commands/pull-v3/components/trigger-generator.js +0 -185
- package/dist/commands/pull-v3/index.js +0 -510
- package/dist/commands/pull-v3/introspect-generator.js +0 -286
- package/dist/commands/pull-v3/llm-content-merger.js +0 -192
- package/dist/commands/pull-v3/new-component-generator.js +0 -279
- package/dist/commands/pull-v3/project-index-generator.js +0 -32
- package/dist/commands/pull-v3/project-validator.js +0 -358
- package/dist/utils/url.js +0 -26
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { addValueToObject, createFactoryDefinition, formatInlineLiteral, formatStringLiteral, toCamelCase } from "./utils.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/commands/pull-v4/mcp-tool-generator.ts
|
|
5
|
+
const McpToolSchema = z.looseObject({
|
|
6
|
+
mcpToolId: z.string().nonempty(),
|
|
7
|
+
name: z.string().nonempty(),
|
|
8
|
+
description: z.string().nullable().optional(),
|
|
9
|
+
config: z.looseObject({ mcp: z.looseObject({
|
|
10
|
+
server: z.looseObject({ url: z.string().optional() }).optional(),
|
|
11
|
+
transport: z.unknown().optional(),
|
|
12
|
+
activeTools: z.array(z.unknown()).optional()
|
|
13
|
+
}).optional() }).optional(),
|
|
14
|
+
serverUrl: z.string().optional(),
|
|
15
|
+
transport: z.object({ type: z.string() }).optional(),
|
|
16
|
+
activeTools: z.array(z.unknown()).optional(),
|
|
17
|
+
imageUrl: z.string().optional(),
|
|
18
|
+
headers: z.unknown().optional(),
|
|
19
|
+
credential: z.unknown().optional(),
|
|
20
|
+
credentialReferenceId: z.string().optional()
|
|
21
|
+
}).superRefine((value, context) => {
|
|
22
|
+
if (!resolveServerUrl(value)) context.addIssue({
|
|
23
|
+
code: "custom",
|
|
24
|
+
message: "serverUrl is required (from config.mcp.server.url or serverUrl)",
|
|
25
|
+
path: ["serverUrl"]
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
function generateMcpToolDefinition(data) {
|
|
29
|
+
const result = McpToolSchema.safeParse(data);
|
|
30
|
+
if (!result.success) throw new Error(`Validation failed for MCP tool:\n${z.prettifyError(result.error)}`);
|
|
31
|
+
const parsed = result.data;
|
|
32
|
+
const { sourceFile, configObject } = createFactoryDefinition({
|
|
33
|
+
importName: "mcpTool",
|
|
34
|
+
variableName: toCamelCase(parsed.mcpToolId)
|
|
35
|
+
});
|
|
36
|
+
if (parsed.credentialReferenceId && parsed.credential === void 0) sourceFile.addImportDeclaration({
|
|
37
|
+
namedImports: ["envSettings"],
|
|
38
|
+
moduleSpecifier: "../environments"
|
|
39
|
+
});
|
|
40
|
+
writeMcpToolConfig(configObject, parsed);
|
|
41
|
+
return sourceFile;
|
|
42
|
+
}
|
|
43
|
+
function writeMcpToolConfig(configObject, { mcpToolId, description, serverUrl, config, transport, activeTools, credential, credentialReferenceId, ...rest }) {
|
|
44
|
+
for (const [k, v] of Object.entries({
|
|
45
|
+
id: mcpToolId,
|
|
46
|
+
...rest,
|
|
47
|
+
description: description ?? void 0,
|
|
48
|
+
serverUrl: resolveServerUrl({
|
|
49
|
+
config,
|
|
50
|
+
serverUrl
|
|
51
|
+
}),
|
|
52
|
+
transport: resolveTransport({
|
|
53
|
+
config,
|
|
54
|
+
transport
|
|
55
|
+
}),
|
|
56
|
+
activeTools: resolveActiveTools({
|
|
57
|
+
config,
|
|
58
|
+
activeTools
|
|
59
|
+
})
|
|
60
|
+
})) addValueToObject(configObject, k, v);
|
|
61
|
+
if (credential !== void 0 && credential !== null) {
|
|
62
|
+
if (typeof credential === "string") {
|
|
63
|
+
configObject.addPropertyAssignment({
|
|
64
|
+
name: "credential",
|
|
65
|
+
initializer: credential
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
configObject.addPropertyAssignment({
|
|
70
|
+
name: "credential",
|
|
71
|
+
initializer: formatInlineLiteral(credential)
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (credentialReferenceId) configObject.addPropertyAssignment({
|
|
76
|
+
name: "credential",
|
|
77
|
+
initializer: `envSettings.getEnvironmentCredential(${formatStringLiteral(credentialReferenceId)})`
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function resolveServerUrl(data) {
|
|
81
|
+
return data.config?.mcp?.server?.url ?? data.serverUrl;
|
|
82
|
+
}
|
|
83
|
+
function resolveTransport(data) {
|
|
84
|
+
return data.config?.mcp?.transport ?? data.transport;
|
|
85
|
+
}
|
|
86
|
+
function resolveActiveTools(data) {
|
|
87
|
+
return data.config?.mcp?.activeTools ?? data.activeTools;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { generateMcpToolDefinition };
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { createInMemoryProject } from "./utils.js";
|
|
2
|
+
import { Node, SyntaxKind } from "ts-morph";
|
|
3
|
+
|
|
4
|
+
//#region src/commands/pull-v4/module-merge.ts
|
|
5
|
+
function mergeGeneratedModule(existingContent, generatedContent) {
|
|
6
|
+
const project = createInMemoryProject();
|
|
7
|
+
const existingSourceFile = project.createSourceFile("existing.ts", existingContent, { overwrite: true });
|
|
8
|
+
const generatedSourceFile = project.createSourceFile("generated.ts", generatedContent, { overwrite: true });
|
|
9
|
+
mergeImports(existingSourceFile, generatedSourceFile);
|
|
10
|
+
for (const statement of generatedSourceFile.getStatements()) {
|
|
11
|
+
if (Node.isImportDeclaration(statement)) continue;
|
|
12
|
+
upsertStatement(existingSourceFile, statement);
|
|
13
|
+
}
|
|
14
|
+
return dedupeConsecutiveIdenticalSingleLineComments(existingSourceFile.getFullText().trimEnd());
|
|
15
|
+
}
|
|
16
|
+
function mergeImports(existingFile, generatedFile) {
|
|
17
|
+
for (const generatedImport of generatedFile.getImportDeclarations()) {
|
|
18
|
+
const moduleSpecifier = generatedImport.getModuleSpecifierValue();
|
|
19
|
+
const matchingImports = existingFile.getImportDeclarations().filter((existingImport) => existingImport.getModuleSpecifierValue() === moduleSpecifier);
|
|
20
|
+
if (!matchingImports.length) {
|
|
21
|
+
if (areGeneratedImportBindingsAlreadyPresent(existingFile, generatedImport)) continue;
|
|
22
|
+
existingFile.addImportDeclaration(generatedImport.getStructure());
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const targetImport = findBestImportTarget(matchingImports, generatedImport);
|
|
26
|
+
if (!targetImport) {
|
|
27
|
+
if (!hasImportWithText(matchingImports, generatedImport.getText())) existingFile.addImportDeclaration(generatedImport.getStructure());
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!generatedImport.isTypeOnly() && targetImport.isTypeOnly()) targetImport.setIsTypeOnly(false);
|
|
31
|
+
const generatedDefaultImport = generatedImport.getDefaultImport();
|
|
32
|
+
if (generatedDefaultImport && !targetImport.getDefaultImport()) targetImport.setDefaultImport(generatedDefaultImport.getText());
|
|
33
|
+
const generatedNamespaceImport = generatedImport.getNamespaceImport();
|
|
34
|
+
if (generatedNamespaceImport && !targetImport.getNamespaceImport()) targetImport.setNamespaceImport(generatedNamespaceImport.getText());
|
|
35
|
+
for (const generatedNamedImport of generatedImport.getNamedImports()) {
|
|
36
|
+
const generatedName = generatedNamedImport.getName();
|
|
37
|
+
const generatedAlias = generatedNamedImport.getAliasNode()?.getText();
|
|
38
|
+
const generatedIsTypeOnly = generatedNamedImport.isTypeOnly();
|
|
39
|
+
if (!targetImport.getNamedImports().some((existingNamedImport) => {
|
|
40
|
+
return existingNamedImport.getName() === generatedName && existingNamedImport.getAliasNode()?.getText() === generatedAlias && existingNamedImport.isTypeOnly() === generatedIsTypeOnly;
|
|
41
|
+
})) targetImport.addNamedImport({
|
|
42
|
+
name: generatedName,
|
|
43
|
+
alias: generatedAlias,
|
|
44
|
+
isTypeOnly: generatedIsTypeOnly
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function findBestImportTarget(matchingImports, generatedImport) {
|
|
50
|
+
if (generatedImport.getNamespaceImport()) {
|
|
51
|
+
const namespaceText = generatedImport.getNamespaceImport()?.getText();
|
|
52
|
+
return matchingImports.find((importDeclaration) => importDeclaration.getNamespaceImport()?.getText() === namespaceText);
|
|
53
|
+
}
|
|
54
|
+
const nonNamespaceImport = matchingImports.find((importDeclaration) => !importDeclaration.getNamespaceImport());
|
|
55
|
+
if (nonNamespaceImport) return nonNamespaceImport;
|
|
56
|
+
}
|
|
57
|
+
function hasImportWithText(imports, text) {
|
|
58
|
+
return imports.some((importDeclaration) => importDeclaration.getText() === text);
|
|
59
|
+
}
|
|
60
|
+
function areGeneratedImportBindingsAlreadyPresent(existingFile, generatedImport) {
|
|
61
|
+
const generatedBindings = getImportBindingNames(generatedImport);
|
|
62
|
+
if (!generatedBindings.length) return false;
|
|
63
|
+
const existingImports = existingFile.getImportDeclarations();
|
|
64
|
+
return generatedBindings.every((binding) => existingImports.some((existingImport) => importHasBinding(existingImport, binding)));
|
|
65
|
+
}
|
|
66
|
+
function getImportBindingNames(importDeclaration) {
|
|
67
|
+
const bindings = [];
|
|
68
|
+
const defaultImport = importDeclaration.getDefaultImport();
|
|
69
|
+
if (defaultImport) bindings.push(defaultImport.getText());
|
|
70
|
+
const namespaceImport = importDeclaration.getNamespaceImport();
|
|
71
|
+
if (namespaceImport) bindings.push(namespaceImport.getText());
|
|
72
|
+
for (const namedImport of importDeclaration.getNamedImports()) bindings.push(namedImport.getAliasNode()?.getText() ?? namedImport.getName());
|
|
73
|
+
return bindings;
|
|
74
|
+
}
|
|
75
|
+
function importHasBinding(importDeclaration, bindingName) {
|
|
76
|
+
if (importDeclaration.getDefaultImport()?.getText() === bindingName) return true;
|
|
77
|
+
if (importDeclaration.getNamespaceImport()?.getText() === bindingName) return true;
|
|
78
|
+
return importDeclaration.getNamedImports().some((namedImport) => {
|
|
79
|
+
return (namedImport.getAliasNode()?.getText() ?? namedImport.getName()) === bindingName;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function upsertStatement(existingFile, generatedStatement) {
|
|
83
|
+
if (Node.isVariableStatement(generatedStatement)) {
|
|
84
|
+
upsertVariableStatement(existingFile, generatedStatement);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (Node.isFunctionDeclaration(generatedStatement)) {
|
|
88
|
+
upsertNamedStatement(existingFile, generatedStatement, (sourceFile, name) => sourceFile.getFunction(name));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (Node.isClassDeclaration(generatedStatement)) {
|
|
92
|
+
upsertNamedStatement(existingFile, generatedStatement, (sourceFile, name) => sourceFile.getClass(name));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (Node.isInterfaceDeclaration(generatedStatement)) {
|
|
96
|
+
upsertNamedStatement(existingFile, generatedStatement, (sourceFile, name) => sourceFile.getInterface(name));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (Node.isTypeAliasDeclaration(generatedStatement)) {
|
|
100
|
+
upsertNamedStatement(existingFile, generatedStatement, (sourceFile, name) => sourceFile.getTypeAlias(name));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (Node.isEnumDeclaration(generatedStatement)) {
|
|
104
|
+
upsertNamedStatement(existingFile, generatedStatement, (sourceFile, name) => sourceFile.getEnum(name));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
appendUniqueStatement(existingFile, generatedStatement);
|
|
108
|
+
}
|
|
109
|
+
function upsertVariableStatement(existingFile, generatedStatement) {
|
|
110
|
+
if (!Node.isVariableStatement(generatedStatement)) return;
|
|
111
|
+
const generatedDeclarations = generatedStatement.getDeclarations();
|
|
112
|
+
if (!generatedDeclarations.length) {
|
|
113
|
+
appendUniqueStatement(existingFile, generatedStatement);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const existingStatements = /* @__PURE__ */ new Set();
|
|
117
|
+
for (const generatedDeclaration of generatedDeclarations) {
|
|
118
|
+
let existingDeclaration = existingFile.getVariableDeclaration(generatedDeclaration.getName());
|
|
119
|
+
if (!existingDeclaration) {
|
|
120
|
+
existingDeclaration = findExistingDeclarationByEntitySignature(existingFile, generatedDeclaration);
|
|
121
|
+
if (existingDeclaration) generatedDeclaration.rename(existingDeclaration.getName());
|
|
122
|
+
}
|
|
123
|
+
if (!existingDeclaration) continue;
|
|
124
|
+
const existingStatement = existingDeclaration.getFirstAncestorByKind(SyntaxKind.VariableStatement);
|
|
125
|
+
if (existingStatement) existingStatements.add(existingStatement);
|
|
126
|
+
}
|
|
127
|
+
if (!existingStatements.size) {
|
|
128
|
+
appendUniqueStatement(existingFile, generatedStatement);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const [firstExistingStatement, ...remainingStatements] = [...existingStatements];
|
|
132
|
+
if (firstExistingStatement) firstExistingStatement.replaceWithText(buildReplacementStatementText(firstExistingStatement, generatedStatement));
|
|
133
|
+
for (const statement of remainingStatements) statement.remove();
|
|
134
|
+
}
|
|
135
|
+
function findExistingDeclarationByEntitySignature(existingFile, generatedDeclaration) {
|
|
136
|
+
const generatedSignature = getVariableDeclarationEntitySignature(generatedDeclaration);
|
|
137
|
+
if (!generatedSignature) return;
|
|
138
|
+
const matchingDeclarations = existingFile.getVariableDeclarations().filter((declaration) => getVariableDeclarationEntitySignature(declaration) === generatedSignature);
|
|
139
|
+
if (!matchingDeclarations.length) return;
|
|
140
|
+
return matchingDeclarations.find((declaration) => declaration.getFirstAncestorByKind(SyntaxKind.VariableStatement)?.hasExportKeyword()) ?? matchingDeclarations[0];
|
|
141
|
+
}
|
|
142
|
+
function getVariableDeclarationEntitySignature(declaration) {
|
|
143
|
+
const initializer = declaration.getInitializer();
|
|
144
|
+
if (!initializer || !Node.isCallExpression(initializer)) return;
|
|
145
|
+
const expression = initializer.getExpression();
|
|
146
|
+
if (!Node.isIdentifier(expression)) return;
|
|
147
|
+
const args = initializer.getArguments();
|
|
148
|
+
if (!args.length || !Node.isObjectLiteralExpression(args[0])) return;
|
|
149
|
+
const factoryName = expression.getText();
|
|
150
|
+
const entityId = readEntityId(args[0], factoryName);
|
|
151
|
+
if (!entityId) return;
|
|
152
|
+
return `${factoryName}:${entityId}`;
|
|
153
|
+
}
|
|
154
|
+
function readEntityId(configObject, factoryName) {
|
|
155
|
+
const idProperty = configObject.getProperty("id");
|
|
156
|
+
if (idProperty && Node.isPropertyAssignment(idProperty)) {
|
|
157
|
+
const idInitializer = idProperty.getInitializer();
|
|
158
|
+
if (idInitializer && Node.isStringLiteral(idInitializer)) return idInitializer.getLiteralValue();
|
|
159
|
+
}
|
|
160
|
+
if (factoryName === "statusComponent") {
|
|
161
|
+
const typeProperty = configObject.getProperty("type");
|
|
162
|
+
if (typeProperty && Node.isPropertyAssignment(typeProperty)) {
|
|
163
|
+
const typeInitializer = typeProperty.getInitializer();
|
|
164
|
+
if (typeInitializer && Node.isStringLiteral(typeInitializer)) return typeInitializer.getLiteralValue();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (factoryName === "functionTool") {
|
|
168
|
+
const nameProperty = configObject.getProperty("name");
|
|
169
|
+
if (nameProperty && Node.isPropertyAssignment(nameProperty)) {
|
|
170
|
+
const nameInitializer = nameProperty.getInitializer();
|
|
171
|
+
if (nameInitializer && Node.isStringLiteral(nameInitializer)) return nameInitializer.getLiteralValue();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function upsertNamedStatement(existingFile, generatedStatement, finder) {
|
|
176
|
+
const statementName = Node.isFunctionDeclaration(generatedStatement) || Node.isClassDeclaration(generatedStatement) || Node.isInterfaceDeclaration(generatedStatement) || Node.isTypeAliasDeclaration(generatedStatement) || Node.isEnumDeclaration(generatedStatement) ? generatedStatement.getName() : void 0;
|
|
177
|
+
if (!statementName) {
|
|
178
|
+
appendUniqueStatement(existingFile, generatedStatement);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const existingStatement = finder(existingFile, statementName);
|
|
182
|
+
if (!existingStatement) {
|
|
183
|
+
appendUniqueStatement(existingFile, generatedStatement);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
existingStatement.replaceWithText(buildReplacementStatementText(existingStatement, generatedStatement));
|
|
187
|
+
}
|
|
188
|
+
function appendUniqueStatement(existingFile, generatedStatement) {
|
|
189
|
+
const statementText = generatedStatement.getText();
|
|
190
|
+
if (existingFile.getStatements().some((statement) => statement.getText() === statementText)) return;
|
|
191
|
+
existingFile.addStatements([statementText]);
|
|
192
|
+
}
|
|
193
|
+
function buildReplacementStatementText(existingStatement, generatedStatement) {
|
|
194
|
+
return withPreservedLeadingComments(existingStatement, alignStatementOrdering(existingStatement, generatedStatement));
|
|
195
|
+
}
|
|
196
|
+
function alignStatementOrdering(existingStatement, generatedStatement) {
|
|
197
|
+
if (Node.isVariableStatement(existingStatement) && Node.isVariableStatement(generatedStatement)) return alignVariableStatementOrdering(existingStatement, generatedStatement);
|
|
198
|
+
return generatedStatement.getText();
|
|
199
|
+
}
|
|
200
|
+
function alignVariableStatementOrdering(existingStatement, generatedStatement) {
|
|
201
|
+
generatedStatement.setIsExported(existingStatement.isExported());
|
|
202
|
+
const generatedText = generatedStatement.getText();
|
|
203
|
+
const generatedStatementStart = generatedStatement.getStart();
|
|
204
|
+
const existingDeclarationsByName = new Map(existingStatement.getDeclarations().map((declaration) => [declaration.getName(), declaration]));
|
|
205
|
+
const replacements = [];
|
|
206
|
+
for (const generatedDeclaration of generatedStatement.getDeclarations()) {
|
|
207
|
+
const existingDeclaration = existingDeclarationsByName.get(generatedDeclaration.getName());
|
|
208
|
+
if (!existingDeclaration) continue;
|
|
209
|
+
const generatedInitializer = generatedDeclaration.getInitializer();
|
|
210
|
+
const existingInitializer = existingDeclaration.getInitializer();
|
|
211
|
+
if (!generatedInitializer || !existingInitializer) continue;
|
|
212
|
+
const alignedInitializerText = alignExpressionText(existingInitializer, generatedInitializer);
|
|
213
|
+
if (alignedInitializerText === generatedInitializer.getText()) continue;
|
|
214
|
+
replacements.push({
|
|
215
|
+
start: generatedInitializer.getStart() - generatedStatementStart,
|
|
216
|
+
end: generatedInitializer.getEnd() - generatedStatementStart,
|
|
217
|
+
text: alignedInitializerText
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return applyTextReplacements(generatedText, replacements);
|
|
221
|
+
}
|
|
222
|
+
function alignExpressionText(existingExpression, generatedExpression) {
|
|
223
|
+
if (!existingExpression) return generatedExpression.getText();
|
|
224
|
+
if (Node.isObjectLiteralExpression(existingExpression) && Node.isObjectLiteralExpression(generatedExpression)) return alignObjectLiteralText(existingExpression, generatedExpression);
|
|
225
|
+
if (Node.isArrayLiteralExpression(existingExpression) && Node.isArrayLiteralExpression(generatedExpression)) return alignArrayLiteralText(existingExpression, generatedExpression);
|
|
226
|
+
if (Node.isArrowFunction(existingExpression) && Node.isArrowFunction(generatedExpression)) return alignArrowFunctionText(existingExpression, generatedExpression);
|
|
227
|
+
if (Node.isCallExpression(existingExpression) && Node.isCallExpression(generatedExpression)) return alignCallExpressionText(existingExpression, generatedExpression);
|
|
228
|
+
if (Node.isParenthesizedExpression(existingExpression) && Node.isParenthesizedExpression(generatedExpression)) return `(${alignExpressionText(existingExpression.getExpression(), generatedExpression.getExpression())})`;
|
|
229
|
+
return generatedExpression.getText();
|
|
230
|
+
}
|
|
231
|
+
function alignCallExpressionText(existingCall, generatedCall) {
|
|
232
|
+
if (!Node.isCallExpression(existingCall) || !Node.isCallExpression(generatedCall)) return generatedCall.getText();
|
|
233
|
+
const generatedText = generatedCall.getText();
|
|
234
|
+
const generatedCallStart = generatedCall.getStart();
|
|
235
|
+
const existingArguments = existingCall.getArguments();
|
|
236
|
+
const generatedArguments = generatedCall.getArguments();
|
|
237
|
+
const replacements = [];
|
|
238
|
+
for (const [index, generatedArgument] of generatedArguments.entries()) {
|
|
239
|
+
const existingArgument = existingArguments[index];
|
|
240
|
+
if (!existingArgument) continue;
|
|
241
|
+
const alignedArgumentText = alignExpressionText(existingArgument, generatedArgument);
|
|
242
|
+
if (alignedArgumentText === generatedArgument.getText()) continue;
|
|
243
|
+
replacements.push({
|
|
244
|
+
start: generatedArgument.getStart() - generatedCallStart,
|
|
245
|
+
end: generatedArgument.getEnd() - generatedCallStart,
|
|
246
|
+
text: alignedArgumentText
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return applyTextReplacements(generatedText, replacements);
|
|
250
|
+
}
|
|
251
|
+
function alignArrowFunctionText(existingArrow, generatedArrow) {
|
|
252
|
+
if (!Node.isArrowFunction(existingArrow) || !Node.isArrowFunction(generatedArrow)) return generatedArrow.getText();
|
|
253
|
+
const existingBody = existingArrow.getBody();
|
|
254
|
+
const generatedBody = generatedArrow.getBody();
|
|
255
|
+
if (!Node.isExpression(existingBody) || !Node.isExpression(generatedBody)) return generatedArrow.getText();
|
|
256
|
+
const alignedBodyText = alignExpressionText(existingBody, generatedBody);
|
|
257
|
+
if (alignedBodyText === generatedBody.getText()) return generatedArrow.getText();
|
|
258
|
+
return applyTextReplacements(generatedArrow.getText(), [{
|
|
259
|
+
start: generatedBody.getStart() - generatedArrow.getStart(),
|
|
260
|
+
end: generatedBody.getEnd() - generatedArrow.getStart(),
|
|
261
|
+
text: alignedBodyText
|
|
262
|
+
}]);
|
|
263
|
+
}
|
|
264
|
+
function alignObjectLiteralText(existingObject, generatedObject) {
|
|
265
|
+
const propertyTexts = orderObjectProperties(existingObject.getProperties(), generatedObject.getProperties()).map(({ existingProperty, generatedProperty }) => {
|
|
266
|
+
if (!existingProperty) return generatedProperty.getText();
|
|
267
|
+
return withPreservedLeadingComments(existingProperty, alignObjectPropertyText(existingProperty, generatedProperty));
|
|
268
|
+
});
|
|
269
|
+
return formatCollectionLiteralText(generatedObject.getText(), propertyTexts, "{", "}");
|
|
270
|
+
}
|
|
271
|
+
function alignObjectPropertyText(existingProperty, generatedProperty) {
|
|
272
|
+
const text = generatedProperty.getText();
|
|
273
|
+
if (!Node.isPropertyAssignment(generatedProperty)) return text;
|
|
274
|
+
const generatedInitializer = generatedProperty.getInitializer();
|
|
275
|
+
if (!generatedInitializer) return text;
|
|
276
|
+
const alignedInitializerText = alignExpressionText(Node.isPropertyAssignment(existingProperty) ? existingProperty.getInitializer() : void 0, generatedInitializer);
|
|
277
|
+
return `${generatedProperty.getNameNode().getText()}: ${alignedInitializerText}`;
|
|
278
|
+
}
|
|
279
|
+
function alignArrayLiteralText(existingArray, generatedArray) {
|
|
280
|
+
if (!Node.isArrayLiteralExpression(existingArray) || !Node.isArrayLiteralExpression(generatedArray)) return generatedArray.getText();
|
|
281
|
+
const elementTexts = orderArrayElements(existingArray.getElements(), generatedArray.getElements()).map(({ existingElement, generatedElement }) => alignExpressionText(existingElement, generatedElement));
|
|
282
|
+
return formatCollectionLiteralText(generatedArray.getText(), elementTexts, "[", "]");
|
|
283
|
+
}
|
|
284
|
+
function orderObjectProperties(existingProperties, generatedProperties) {
|
|
285
|
+
return orderNodesBySignature(existingProperties, generatedProperties, getObjectPropertyKey, getObjectPropertyKey).map(({ existingNode, generatedNode }) => ({
|
|
286
|
+
existingProperty: existingNode,
|
|
287
|
+
generatedProperty: generatedNode
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
function orderArrayElements(existingElements, generatedElements) {
|
|
291
|
+
return orderNodesBySignature(existingElements, generatedElements, getArrayElementSignature, getArrayElementSignature).map(({ existingNode, generatedNode }) => ({
|
|
292
|
+
existingElement: existingNode,
|
|
293
|
+
generatedElement: generatedNode
|
|
294
|
+
}));
|
|
295
|
+
}
|
|
296
|
+
function orderNodesBySignature(existingNodes, generatedNodes, getExistingSignature, getGeneratedSignature) {
|
|
297
|
+
const generatedEntries = generatedNodes.map((generatedNode) => ({
|
|
298
|
+
generatedNode,
|
|
299
|
+
signature: getGeneratedSignature(generatedNode)
|
|
300
|
+
}));
|
|
301
|
+
const usedGeneratedIndexes = /* @__PURE__ */ new Set();
|
|
302
|
+
const ordered = [];
|
|
303
|
+
for (const existingNode of existingNodes) {
|
|
304
|
+
const existingSignature = getExistingSignature(existingNode);
|
|
305
|
+
if (!existingSignature) continue;
|
|
306
|
+
const generatedIndex = generatedEntries.findIndex((entry, index) => !usedGeneratedIndexes.has(index) && entry.signature === existingSignature);
|
|
307
|
+
if (generatedIndex === -1) continue;
|
|
308
|
+
const generatedEntry = generatedEntries[generatedIndex];
|
|
309
|
+
if (!generatedEntry) continue;
|
|
310
|
+
usedGeneratedIndexes.add(generatedIndex);
|
|
311
|
+
ordered.push({
|
|
312
|
+
existingNode,
|
|
313
|
+
generatedNode: generatedEntry.generatedNode
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
for (const [index, generatedEntry] of generatedEntries.entries()) {
|
|
317
|
+
if (usedGeneratedIndexes.has(index)) continue;
|
|
318
|
+
ordered.push({ generatedNode: generatedEntry.generatedNode });
|
|
319
|
+
}
|
|
320
|
+
return ordered;
|
|
321
|
+
}
|
|
322
|
+
function getObjectPropertyKey(property) {
|
|
323
|
+
if (Node.isPropertyAssignment(property) || Node.isShorthandPropertyAssignment(property) || Node.isMethodDeclaration(property) || Node.isGetAccessorDeclaration(property) || Node.isSetAccessorDeclaration(property)) return property.getName();
|
|
324
|
+
if (Node.isSpreadAssignment(property)) return `...${property.getExpression().getText()}`;
|
|
325
|
+
}
|
|
326
|
+
function getArrayElementSignature(node) {
|
|
327
|
+
if (Node.isIdentifier(node)) return `id:${node.getText()}`;
|
|
328
|
+
if (Node.isStringLiteral(node)) return `str:${node.getLiteralValue()}`;
|
|
329
|
+
if (Node.isObjectLiteralExpression(node)) {
|
|
330
|
+
const objectId = readStringLiteralObjectProperty(node, "id") || readStringLiteralObjectProperty(node, "type") || readStringLiteralObjectProperty(node, "name");
|
|
331
|
+
if (objectId) return `obj:${objectId}`;
|
|
332
|
+
}
|
|
333
|
+
if (Node.isCallExpression(node)) {
|
|
334
|
+
const expression = node.getExpression();
|
|
335
|
+
if (Node.isPropertyAccessExpression(expression) && expression.getName() === "with") return `with:${expression.getExpression().getText()}`;
|
|
336
|
+
}
|
|
337
|
+
return node.getText();
|
|
338
|
+
}
|
|
339
|
+
function readStringLiteralObjectProperty(objectLiteral, propertyName) {
|
|
340
|
+
const property = objectLiteral.getProperty(propertyName);
|
|
341
|
+
if (!property || !Node.isPropertyAssignment(property)) return;
|
|
342
|
+
const initializer = property.getInitializer();
|
|
343
|
+
if (!initializer || !Node.isStringLiteral(initializer)) return;
|
|
344
|
+
return initializer.getLiteralValue();
|
|
345
|
+
}
|
|
346
|
+
function formatCollectionLiteralText(originalText, itemTexts, openToken, closeToken) {
|
|
347
|
+
if (originalText.includes("\n")) return `${openToken}\n${itemTexts.map((line) => {
|
|
348
|
+
return line.replaceAll(/^\s+\*/gm, " *");
|
|
349
|
+
}).join(",\n")}${closeToken}`;
|
|
350
|
+
const openingWithSpacing = originalText.startsWith(`${openToken} `) ? `${openToken} ` : openToken;
|
|
351
|
+
const closingWithSpacing = originalText.endsWith(` ${closeToken}`) ? ` ${closeToken}` : closeToken;
|
|
352
|
+
return `${openingWithSpacing}${itemTexts.join(", ")}${closingWithSpacing}`;
|
|
353
|
+
}
|
|
354
|
+
function applyTextReplacements(sourceText, replacements) {
|
|
355
|
+
if (!replacements.length) return sourceText;
|
|
356
|
+
let nextText = sourceText;
|
|
357
|
+
const replacementsInDescendingOrder = [...replacements].sort((a, b) => b.start - a.start);
|
|
358
|
+
for (const replacement of replacementsInDescendingOrder) nextText = nextText.slice(0, replacement.start) + replacement.text + nextText.slice(replacement.end);
|
|
359
|
+
return nextText;
|
|
360
|
+
}
|
|
361
|
+
function withPreservedLeadingComments(existingStatement, replacementText) {
|
|
362
|
+
const leadingComments = existingStatement.getLeadingCommentRanges().map((comment) => comment.getText()).join("\n");
|
|
363
|
+
if (!leadingComments) return replacementText;
|
|
364
|
+
return `${leadingComments}\n${replacementText}`;
|
|
365
|
+
}
|
|
366
|
+
function dedupeConsecutiveIdenticalSingleLineComments(content) {
|
|
367
|
+
const lines = content.split("\n");
|
|
368
|
+
const deduped = [];
|
|
369
|
+
for (const line of lines) {
|
|
370
|
+
const trimmedLine = line.trim();
|
|
371
|
+
const previousTrimmedLine = deduped.at(-1)?.trim();
|
|
372
|
+
if (trimmedLine.startsWith("//") && previousTrimmedLine?.startsWith("//") && trimmedLine === previousTrimmedLine) continue;
|
|
373
|
+
deduped.push(line);
|
|
374
|
+
}
|
|
375
|
+
return deduped.join("\n");
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
//#endregion
|
|
379
|
+
export { mergeGeneratedModule };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { addReferenceGetterProperty, addValueToObject, convertNullToUndefined, createFactoryDefinition, formatStringLiteral, hasReferences, resolveReferenceName, toCamelCase } from "./utils.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/commands/pull-v4/project-generator.ts
|
|
5
|
+
const ReferenceNameByIdSchema = z.record(z.string(), z.string().nonempty());
|
|
6
|
+
const ReferenceOverridesSchema = z.object({
|
|
7
|
+
agents: ReferenceNameByIdSchema.optional(),
|
|
8
|
+
tools: ReferenceNameByIdSchema.optional(),
|
|
9
|
+
externalAgents: ReferenceNameByIdSchema.optional(),
|
|
10
|
+
dataComponents: ReferenceNameByIdSchema.optional(),
|
|
11
|
+
artifactComponents: ReferenceNameByIdSchema.optional(),
|
|
12
|
+
credentialReferences: ReferenceNameByIdSchema.optional()
|
|
13
|
+
});
|
|
14
|
+
const ProjectSchema = z.looseObject({
|
|
15
|
+
projectId: z.string().nonempty(),
|
|
16
|
+
name: z.string().nonempty(),
|
|
17
|
+
description: z.string().optional(),
|
|
18
|
+
models: z.looseObject({
|
|
19
|
+
base: z.looseObject({ model: z.string().nonempty() }),
|
|
20
|
+
structuredOutput: z.looseObject({}).optional(),
|
|
21
|
+
summarizer: z.looseObject({}).optional()
|
|
22
|
+
}),
|
|
23
|
+
stopWhen: z.preprocess(convertNullToUndefined, z.strictObject({
|
|
24
|
+
transferCountIs: z.int().optional(),
|
|
25
|
+
stepCountIs: z.int().optional()
|
|
26
|
+
}).optional()),
|
|
27
|
+
skills: z.array(z.string()).optional(),
|
|
28
|
+
agents: z.array(z.string()).optional(),
|
|
29
|
+
tools: z.array(z.string()).optional(),
|
|
30
|
+
externalAgents: z.array(z.string()).optional(),
|
|
31
|
+
dataComponents: z.array(z.string()).optional(),
|
|
32
|
+
artifactComponents: z.array(z.string()).optional(),
|
|
33
|
+
credentialReferences: z.array(z.string()).optional(),
|
|
34
|
+
referenceOverrides: ReferenceOverridesSchema.optional()
|
|
35
|
+
});
|
|
36
|
+
function generateProjectDefinition(data) {
|
|
37
|
+
const result = ProjectSchema.safeParse(data);
|
|
38
|
+
if (!result.success) throw new Error(`Validation failed for project:
|
|
39
|
+
${z.prettifyError(result.error)}`);
|
|
40
|
+
const parsed = result.data;
|
|
41
|
+
const { sourceFile, configObject } = createFactoryDefinition({
|
|
42
|
+
importName: "project",
|
|
43
|
+
variableName: toCamelCase(parsed.projectId)
|
|
44
|
+
});
|
|
45
|
+
if (hasReferences(parsed.skills)) {
|
|
46
|
+
sourceFile.getImportDeclarationOrThrow("@inkeep/agents-sdk").addNamedImport("loadSkills");
|
|
47
|
+
sourceFile.addImportDeclaration({
|
|
48
|
+
defaultImport: "path",
|
|
49
|
+
moduleSpecifier: "node:path"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const { projectId, skills, agents, tools, externalAgents, dataComponents, artifactComponents, credentialReferences, referenceOverrides, ...rest } = parsed;
|
|
53
|
+
for (const [key, value] of Object.entries({
|
|
54
|
+
id: projectId,
|
|
55
|
+
...rest
|
|
56
|
+
})) addValueToObject(configObject, key, value);
|
|
57
|
+
if (hasReferences(skills)) configObject.addPropertyAssignment({
|
|
58
|
+
name: "skills",
|
|
59
|
+
initializer: `() => loadSkills(path.join(${formatStringLiteral(projectId)}, 'skills'))`
|
|
60
|
+
});
|
|
61
|
+
if (hasReferences(agents)) {
|
|
62
|
+
addReferenceImports(sourceFile, agents, "./agents", referenceOverrides?.agents);
|
|
63
|
+
addReferenceGetterProperty(configObject, "agents", toReferenceNames(agents, referenceOverrides?.agents));
|
|
64
|
+
}
|
|
65
|
+
if (hasReferences(tools)) {
|
|
66
|
+
addReferenceImports(sourceFile, tools, "./tools", referenceOverrides?.tools);
|
|
67
|
+
addReferenceGetterProperty(configObject, "tools", toReferenceNames(tools, referenceOverrides?.tools));
|
|
68
|
+
}
|
|
69
|
+
if (hasReferences(externalAgents)) {
|
|
70
|
+
addReferenceImports(sourceFile, externalAgents, "./external-agents", referenceOverrides?.externalAgents);
|
|
71
|
+
addReferenceGetterProperty(configObject, "externalAgents", toReferenceNames(externalAgents, referenceOverrides?.externalAgents));
|
|
72
|
+
}
|
|
73
|
+
if (hasReferences(dataComponents)) {
|
|
74
|
+
addReferenceImports(sourceFile, dataComponents, "./data-components", referenceOverrides?.dataComponents);
|
|
75
|
+
addReferenceGetterProperty(configObject, "dataComponents", toReferenceNames(dataComponents, referenceOverrides?.dataComponents));
|
|
76
|
+
}
|
|
77
|
+
if (hasReferences(artifactComponents)) {
|
|
78
|
+
addReferenceImports(sourceFile, artifactComponents, "./artifact-components", referenceOverrides?.artifactComponents);
|
|
79
|
+
addReferenceGetterProperty(configObject, "artifactComponents", toReferenceNames(artifactComponents, referenceOverrides?.artifactComponents));
|
|
80
|
+
}
|
|
81
|
+
if (hasReferences(credentialReferences)) {
|
|
82
|
+
addReferenceImports(sourceFile, credentialReferences, "./credentials", referenceOverrides?.credentialReferences);
|
|
83
|
+
addReferenceGetterProperty(configObject, "credentialReferences", toReferenceNames(credentialReferences, referenceOverrides?.credentialReferences));
|
|
84
|
+
}
|
|
85
|
+
return sourceFile;
|
|
86
|
+
}
|
|
87
|
+
function addReferenceImports(sourceFile, references, basePath, referenceOverrides) {
|
|
88
|
+
for (const reference of references) {
|
|
89
|
+
const referenceName = resolveReferenceName(reference, [referenceOverrides]);
|
|
90
|
+
sourceFile.addImportDeclaration({
|
|
91
|
+
namedImports: [referenceName],
|
|
92
|
+
moduleSpecifier: `${basePath}/${reference}`
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function toReferenceNames(references, referenceOverrides) {
|
|
97
|
+
return references.map((reference) => resolveReferenceName(reference, [referenceOverrides]));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
export { generateProjectDefinition };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { addValueToObject, convertJsonSchemaToZodSafe, createFactoryDefinition, toCamelCase } from "./utils.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/commands/pull-v4/status-component-generator.ts
|
|
5
|
+
const StatusComponentSchema = z.looseObject({
|
|
6
|
+
statusComponentId: z.string().nonempty(),
|
|
7
|
+
type: z.string().nonempty(),
|
|
8
|
+
description: z.string().optional(),
|
|
9
|
+
detailsSchema: z.unknown().optional(),
|
|
10
|
+
schema: z.unknown().optional()
|
|
11
|
+
});
|
|
12
|
+
function generateStatusComponentDefinition(data) {
|
|
13
|
+
const result = StatusComponentSchema.safeParse(data);
|
|
14
|
+
if (!result.success) throw new Error(`Validation failed for status component:\n${z.prettifyError(result.error)}`);
|
|
15
|
+
const parsed = result.data;
|
|
16
|
+
const detailsSchema = parsed.detailsSchema !== void 0 ? parsed.detailsSchema : parsed.schema;
|
|
17
|
+
const { sourceFile, configObject } = createFactoryDefinition({
|
|
18
|
+
importName: "statusComponent",
|
|
19
|
+
variableName: toCamelCase(parsed.statusComponentId)
|
|
20
|
+
});
|
|
21
|
+
if (detailsSchema !== void 0) sourceFile.addImportDeclaration({
|
|
22
|
+
namedImports: ["z"],
|
|
23
|
+
moduleSpecifier: "zod"
|
|
24
|
+
});
|
|
25
|
+
const { statusComponentId, id, detailsSchema: _, schema: _2, ...rest } = parsed;
|
|
26
|
+
for (const [k, v] of Object.entries(rest)) addValueToObject(configObject, k, v);
|
|
27
|
+
if (detailsSchema) configObject.addPropertyAssignment({
|
|
28
|
+
name: "detailsSchema",
|
|
29
|
+
initializer: convertJsonSchemaToZodSafe(detailsSchema)
|
|
30
|
+
});
|
|
31
|
+
return sourceFile;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { generateStatusComponentDefinition };
|