@inkeep/agents-cli 0.51.0 → 0.53.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 → pull-v4}/component-parser.js +6 -12
- package/dist/commands/{pull-v3/utils → pull-v4}/component-registry.js +1 -1
- package/dist/commands/pull-v4/generators/agent-generator.js +258 -0
- package/dist/commands/pull-v4/generators/artifact-component-generator.js +69 -0
- package/dist/commands/pull-v4/generators/context-config-generator.js +264 -0
- package/dist/commands/pull-v4/generators/credential-generator.js +30 -0
- package/dist/commands/pull-v4/generators/data-component-generator.js +50 -0
- package/dist/commands/pull-v4/generators/environment-generator.js +123 -0
- package/dist/commands/pull-v4/generators/external-agent-generator.js +56 -0
- package/dist/commands/pull-v4/generators/function-tool-generator.js +48 -0
- package/dist/commands/pull-v4/generators/mcp-tool-generator.js +91 -0
- package/dist/commands/pull-v4/generators/project-generator.js +125 -0
- package/dist/commands/{pull-v3/components → pull-v4/generators}/skill-generator.js +1 -1
- package/dist/commands/pull-v4/generators/status-component-generator.js +35 -0
- package/dist/commands/pull-v4/generators/sub-agent-generator.js +269 -0
- package/dist/commands/pull-v4/generators/trigger-generator.js +58 -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 +706 -0
- package/dist/commands/pull-v4/module-merge.js +405 -0
- package/dist/commands/pull-v4/utils.js +235 -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 -7
- 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-comparator.js +0 -914
- package/dist/commands/pull-v3/project-index-generator.js +0 -32
- package/dist/commands/pull-v3/project-validator.js +0 -358
- 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
- package/dist/utils/url.js +0 -26
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { ManagementApiClient } from "../../../api.js";
|
|
2
|
+
import { initializeCommand } from "../../../utils/cli-pipeline.js";
|
|
3
|
+
import { performBackgroundVersionCheck } from "../../../utils/background-version-check.js";
|
|
4
|
+
import { loadProject } from "../../../utils/project-loader.js";
|
|
5
|
+
import { extractSubAgents } from "../component-registry.js";
|
|
6
|
+
import { introspectGenerate } from "../introspect-generator.js";
|
|
7
|
+
import { join, resolve } from "node:path";
|
|
8
|
+
import * as p from "@clack/prompts";
|
|
9
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { EventEmitter } from "node:events";
|
|
11
|
+
import { styleText } from "node:util";
|
|
12
|
+
|
|
13
|
+
//#region src/commands/pull-v4/introspect/index.ts
|
|
14
|
+
/**
|
|
15
|
+
* Pull v3 - Clean, efficient project generation
|
|
16
|
+
*
|
|
17
|
+
* Step 1: Validate and compile existing code
|
|
18
|
+
* Step 2: Compare project with DB to detect ALL changes
|
|
19
|
+
* Step 3: Classify changes as new vs modified components
|
|
20
|
+
* Step 4: Generate new components deterministically
|
|
21
|
+
* Step 5: Use LLM to correct modified components
|
|
22
|
+
*/
|
|
23
|
+
EventEmitter.defaultMaxListeners = 20;
|
|
24
|
+
/**
|
|
25
|
+
* Create project directory structure
|
|
26
|
+
*/
|
|
27
|
+
function createProjectStructure(projectRoot) {
|
|
28
|
+
mkdirSync(projectRoot, { recursive: true });
|
|
29
|
+
return {
|
|
30
|
+
projectRoot,
|
|
31
|
+
agentsDir: join(projectRoot, "agents"),
|
|
32
|
+
toolsDir: join(projectRoot, "tools"),
|
|
33
|
+
dataComponentsDir: join(projectRoot, "data-components"),
|
|
34
|
+
artifactComponentsDir: join(projectRoot, "artifact-components"),
|
|
35
|
+
statusComponentsDir: join(projectRoot, "status-components"),
|
|
36
|
+
environmentsDir: join(projectRoot, "environments"),
|
|
37
|
+
credentialsDir: join(projectRoot, "credentials"),
|
|
38
|
+
contextConfigsDir: join(projectRoot, "context-configs"),
|
|
39
|
+
externalAgentsDir: join(projectRoot, "external-agents"),
|
|
40
|
+
skillsDir: join(projectRoot, "skills")
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Enrich canDelegateTo references with component type information
|
|
45
|
+
*/
|
|
46
|
+
function enrichCanDelegateToWithTypes(project) {
|
|
47
|
+
const agentsIdSet = new Set(project.agents ? Object.keys(project.agents) : []);
|
|
48
|
+
const subAgentsIdSet = new Set(Object.keys(extractSubAgents(project)));
|
|
49
|
+
const externalAgentsIdSet = new Set(project.externalAgents ? Object.keys(project.externalAgents) : []);
|
|
50
|
+
function enrichCanDelegateToArray(canDelegateTo) {
|
|
51
|
+
return canDelegateTo.map((item) => {
|
|
52
|
+
if (typeof item !== "string") return item;
|
|
53
|
+
if (agentsIdSet.has(item)) return { agentId: item };
|
|
54
|
+
if (subAgentsIdSet.has(item)) return { subAgentId: item };
|
|
55
|
+
if (externalAgentsIdSet.has(item)) return { externalAgentId: item };
|
|
56
|
+
return item;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (project.agents) {
|
|
60
|
+
for (const agentData of Object.values(project.agents)) if (agentData.subAgents) {
|
|
61
|
+
for (const subAgentData of Object.values(agentData.subAgents)) if (subAgentData.canDelegateTo) subAgentData.canDelegateTo = enrichCanDelegateToArray(subAgentData.canDelegateTo);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Main pull v4 command
|
|
67
|
+
* @returns PullResult when in batch mode, otherwise void (exits process)
|
|
68
|
+
*/
|
|
69
|
+
async function pullV4Command(options) {
|
|
70
|
+
if (options.all) {
|
|
71
|
+
await pullAllProjects(options);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const batchMode = options._batchMode ?? false;
|
|
75
|
+
const originalLogLevel = process.env.LOG_LEVEL;
|
|
76
|
+
process.env.LOG_LEVEL = "silent";
|
|
77
|
+
const restoreLogLevel = () => {
|
|
78
|
+
if (originalLogLevel !== void 0) process.env.LOG_LEVEL = originalLogLevel;
|
|
79
|
+
else delete process.env.LOG_LEVEL;
|
|
80
|
+
};
|
|
81
|
+
if (!batchMode) performBackgroundVersionCheck();
|
|
82
|
+
console.log(styleText("blue", "\nInkeep Pull:"));
|
|
83
|
+
if (options.introspect) console.log(styleText("gray", " Introspect mode • Complete regeneration • No comparison needed"));
|
|
84
|
+
else console.log(styleText("gray", " Smart comparison • Detect all changes • Targeted updates"));
|
|
85
|
+
const s = p.spinner();
|
|
86
|
+
try {
|
|
87
|
+
const { config, isCI } = await initializeCommand({
|
|
88
|
+
configPath: options.config,
|
|
89
|
+
profileName: options.profile,
|
|
90
|
+
tag: options.tag,
|
|
91
|
+
showSpinner: true,
|
|
92
|
+
spinnerText: "Loading configuration...",
|
|
93
|
+
logConfig: true,
|
|
94
|
+
quiet: options.quiet
|
|
95
|
+
});
|
|
96
|
+
s.start("Detecting project...");
|
|
97
|
+
let projectDir;
|
|
98
|
+
let projectId;
|
|
99
|
+
let localProjectForId = null;
|
|
100
|
+
const currentDir = process.cwd();
|
|
101
|
+
if (existsSync(join(currentDir, "index.ts"))) {
|
|
102
|
+
projectDir = currentDir;
|
|
103
|
+
s.start("Loading local project...");
|
|
104
|
+
try {
|
|
105
|
+
localProjectForId = await loadProject(projectDir);
|
|
106
|
+
const localProjectId = localProjectForId.getId();
|
|
107
|
+
if (options.project) {
|
|
108
|
+
if (localProjectId !== options.project) {
|
|
109
|
+
s.stop("Project ID mismatch");
|
|
110
|
+
console.error(styleText("red", `Local project ID "${localProjectId}" doesn't match --project "${options.project}"`));
|
|
111
|
+
console.error(styleText("yellow", "Either remove --project flag or ensure it matches the local project ID"));
|
|
112
|
+
if (batchMode) return {
|
|
113
|
+
success: false,
|
|
114
|
+
error: "Project ID mismatch"
|
|
115
|
+
};
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
projectId = localProjectId;
|
|
120
|
+
s.stop(`Using local project: ${projectId}`);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
s.stop("Failed to load local project");
|
|
123
|
+
throw new Error(`Could not load local project: ${error instanceof Error ? error.message : String(error)}`);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
if (!options.project) {
|
|
127
|
+
s.stop("No index.ts found in current directory");
|
|
128
|
+
console.error(styleText("yellow", "Please run this command from a directory containing index.ts or use --project <project-id>"));
|
|
129
|
+
if (batchMode) return {
|
|
130
|
+
success: false,
|
|
131
|
+
error: "No index.ts found and no --project specified"
|
|
132
|
+
};
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
const projectPath = resolve(currentDir, options.project);
|
|
136
|
+
if (existsSync(join(projectPath, "index.ts"))) {
|
|
137
|
+
projectDir = projectPath;
|
|
138
|
+
s.start("Loading project from specified path...");
|
|
139
|
+
try {
|
|
140
|
+
localProjectForId = await loadProject(projectDir);
|
|
141
|
+
projectId = localProjectForId.getId();
|
|
142
|
+
s.stop(`Using project from path: ${projectId}`);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
s.stop("Failed to load project from path");
|
|
145
|
+
throw new Error(`Could not load project from ${projectPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
projectId = options.project;
|
|
149
|
+
projectDir = join(currentDir, projectId);
|
|
150
|
+
s.stop(`Creating new project directory: ${projectDir}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
s.start(`Fetching project: ${projectId}`);
|
|
154
|
+
const remoteProject = await (await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, projectId, isCI, config.agentsApiKey)).getFullProject(projectId);
|
|
155
|
+
if (options.debug && remoteProject.functions) {
|
|
156
|
+
console.log(styleText("gray", " 📋 Project-level functions from API:"), Object.keys(remoteProject.functions));
|
|
157
|
+
Object.entries(remoteProject.functions).forEach(([id, data]) => {
|
|
158
|
+
console.log(styleText("gray", ` ${id}: has name=${!!data.name}, has description=${!!data.description}`));
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (remoteProject.agents) for (const [agentId, agentData] of Object.entries(remoteProject.agents)) {
|
|
162
|
+
if (agentData.functionTools) {
|
|
163
|
+
remoteProject.functionTools = remoteProject.functionTools || {};
|
|
164
|
+
Object.assign(remoteProject.functionTools, agentData.functionTools);
|
|
165
|
+
if (options.debug) console.log(styleText("gray", ` Hoisted functionTools from agent ${agentId}: ${Object.keys(agentData.functionTools).join(", ")}`));
|
|
166
|
+
}
|
|
167
|
+
if (agentData.functions) {
|
|
168
|
+
remoteProject.functions = remoteProject.functions || {};
|
|
169
|
+
Object.entries(agentData.functions).forEach(([funcId, funcData]) => {
|
|
170
|
+
if (!remoteProject.functions[funcId]) remoteProject.functions[funcId] = {
|
|
171
|
+
id: funcData.id,
|
|
172
|
+
inputSchema: funcData.inputSchema,
|
|
173
|
+
executeCode: funcData.executeCode,
|
|
174
|
+
dependencies: funcData.dependencies
|
|
175
|
+
};
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (remoteProject.agents && remoteProject.tools) {
|
|
180
|
+
const projectToolIds = Object.keys(remoteProject.tools);
|
|
181
|
+
for (const agentData of Object.values(remoteProject.agents)) if (agentData.tools) {
|
|
182
|
+
const agentSpecificTools = Object.fromEntries(Object.entries(agentData.tools).filter(([toolId]) => !projectToolIds.includes(toolId)));
|
|
183
|
+
if (Object.keys(agentSpecificTools).length > 0) agentData.tools = agentSpecificTools;
|
|
184
|
+
else delete agentData.tools;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
enrichCanDelegateToWithTypes(remoteProject);
|
|
188
|
+
s.message("Project data fetched");
|
|
189
|
+
if (options.json) {
|
|
190
|
+
console.log(JSON.stringify(remoteProject, null, 2));
|
|
191
|
+
restoreLogLevel();
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const paths = createProjectStructure(projectDir);
|
|
195
|
+
if (remoteProject.skills && Object.keys(remoteProject.skills).length) {
|
|
196
|
+
const { generateSkills } = await import("../generators/skill-generator.js");
|
|
197
|
+
await generateSkills(remoteProject.skills, paths.skillsDir);
|
|
198
|
+
}
|
|
199
|
+
s.start("Starting generating files...");
|
|
200
|
+
await introspectGenerate({
|
|
201
|
+
project: remoteProject,
|
|
202
|
+
paths,
|
|
203
|
+
debug: options.debug
|
|
204
|
+
});
|
|
205
|
+
s.stop("All files generated");
|
|
206
|
+
console.log(styleText("green", "\nProject synced successfully!"));
|
|
207
|
+
console.log(styleText("gray", ` Location: ${paths.projectRoot}`));
|
|
208
|
+
console.log(styleText("gray", ` Environment: ${options.env || "development"}`));
|
|
209
|
+
console.log(styleText("yellow", "⚠️ If you encounter broken code after running `inkeep pull`, please report it at https://github.com/inkeep/agents/issues."));
|
|
210
|
+
restoreLogLevel();
|
|
211
|
+
if (batchMode) return { success: true };
|
|
212
|
+
process.exit(0);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
const message = error instanceof Error ? error.stack : String(error);
|
|
215
|
+
s.stop();
|
|
216
|
+
console.error(styleText("red", `\nError: ${message}`));
|
|
217
|
+
if (options.debug && error instanceof Error) console.error(styleText("red", error.stack || ""));
|
|
218
|
+
restoreLogLevel();
|
|
219
|
+
if (batchMode) return {
|
|
220
|
+
success: false,
|
|
221
|
+
error: message
|
|
222
|
+
};
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Pull all projects for the current tenant
|
|
228
|
+
* Uses smart comparison with LLM merging for existing projects, introspect for new projects
|
|
229
|
+
*/
|
|
230
|
+
async function pullAllProjects(options) {
|
|
231
|
+
console.log(styleText("blue", "\n🔄 Batch Pull: Sequential processing with smart comparison\n"));
|
|
232
|
+
console.log(styleText("gray", " • Existing projects: Smart comparison + LLM merging + confirmation prompts"));
|
|
233
|
+
console.log(styleText("gray", " • New projects: Fresh generation with introspect mode\n"));
|
|
234
|
+
performBackgroundVersionCheck();
|
|
235
|
+
const { config, isCI } = await initializeCommand({
|
|
236
|
+
configPath: options.config,
|
|
237
|
+
profileName: options.profile,
|
|
238
|
+
tag: options.tag,
|
|
239
|
+
showSpinner: true,
|
|
240
|
+
spinnerText: "Loading configuration...",
|
|
241
|
+
logConfig: true,
|
|
242
|
+
quiet: options.quiet
|
|
243
|
+
});
|
|
244
|
+
const s = p.spinner();
|
|
245
|
+
try {
|
|
246
|
+
s.start("Fetching project list from API...");
|
|
247
|
+
const projects = await (await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, void 0, isCI, config.agentsApiKey)).listAllProjects();
|
|
248
|
+
s.stop(`Found ${projects.length} project(s)`);
|
|
249
|
+
if (!projects.length) {
|
|
250
|
+
console.log(styleText("yellow", "No projects found for this tenant."));
|
|
251
|
+
process.exit(0);
|
|
252
|
+
}
|
|
253
|
+
const existingProjects = [];
|
|
254
|
+
const newProjects = [];
|
|
255
|
+
for (const project of projects) if (existsSync(join(join(process.cwd(), project.id), "index.ts"))) existingProjects.push(project);
|
|
256
|
+
else newProjects.push(project);
|
|
257
|
+
console.log(styleText("gray", "\nProjects to pull:\n"));
|
|
258
|
+
if (existingProjects.length > 0) {
|
|
259
|
+
console.log(styleText("cyan", " Existing (smart comparison):"));
|
|
260
|
+
for (const project of existingProjects) console.log(styleText("gray", ` • ${project.name || project.id} (${project.id})`));
|
|
261
|
+
}
|
|
262
|
+
if (newProjects.length > 0) {
|
|
263
|
+
console.log(styleText("cyan", " New (introspect):"));
|
|
264
|
+
for (const project of newProjects) console.log(styleText("gray", ` • ${project.name || project.id} (${project.id})`));
|
|
265
|
+
}
|
|
266
|
+
console.log();
|
|
267
|
+
const results = [];
|
|
268
|
+
const total = projects.length;
|
|
269
|
+
for (let i = 0; i < projects.length; i++) {
|
|
270
|
+
const project = projects[i];
|
|
271
|
+
const progress = `[${i + 1}/${total}]`;
|
|
272
|
+
console.log(styleText("cyan", `\n${"─".repeat(60)}`));
|
|
273
|
+
console.log(styleText("cyan", `${progress} Pulling ${project.name || project.id}...`));
|
|
274
|
+
const result = await pullSingleProject(project.id, project.name, options, config, isCI);
|
|
275
|
+
results.push(result);
|
|
276
|
+
if (result.success) console.log(styleText("green", `\n ✓ ${result.projectName || result.projectId} → ${result.targetDir}`));
|
|
277
|
+
else console.log(styleText("red", `\n ✗ ${result.projectName || result.projectId}: ${result.error}`));
|
|
278
|
+
}
|
|
279
|
+
const succeeded = results.filter((r) => r.success).length;
|
|
280
|
+
const failed = results.filter((r) => !r.success).length;
|
|
281
|
+
console.log(styleText("cyan", `\n${"═".repeat(60)}`));
|
|
282
|
+
console.log(styleText("cyan", "📊 Batch Pull Summary:"));
|
|
283
|
+
console.log(styleText("green", ` ✓ Succeeded: ${succeeded}`));
|
|
284
|
+
if (failed > 0) {
|
|
285
|
+
console.log(styleText("red", ` ✗ Failed: ${failed}`));
|
|
286
|
+
console.log(styleText("red", "\nFailed projects:"));
|
|
287
|
+
for (const result of results) if (!result.success) console.log(styleText("red", ` • ${result.projectId}: ${result.error}`));
|
|
288
|
+
}
|
|
289
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
s.stop();
|
|
292
|
+
console.error(styleText("red", `\nError: ${error instanceof Error ? error.message : String(error)}`));
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Pull a single project (used by batch operations)
|
|
298
|
+
* Uses smart comparison flow for existing projects, introspect for new projects
|
|
299
|
+
*/
|
|
300
|
+
async function pullSingleProject(projectId, projectName, options, config, isCI) {
|
|
301
|
+
const targetDir = join(process.cwd(), projectId);
|
|
302
|
+
const hasExistingProject = existsSync(join(targetDir, "index.ts"));
|
|
303
|
+
try {
|
|
304
|
+
if (hasExistingProject) {
|
|
305
|
+
console.log(styleText("gray", ` 📂 Existing project found - using smart comparison mode`));
|
|
306
|
+
const originalDir = process.cwd();
|
|
307
|
+
process.chdir(targetDir);
|
|
308
|
+
try {
|
|
309
|
+
const result = await pullV4Command({
|
|
310
|
+
...options,
|
|
311
|
+
project: projectId,
|
|
312
|
+
all: false,
|
|
313
|
+
_batchMode: true
|
|
314
|
+
});
|
|
315
|
+
process.chdir(originalDir);
|
|
316
|
+
if (result && typeof result === "object") return {
|
|
317
|
+
projectId,
|
|
318
|
+
projectName,
|
|
319
|
+
targetDir,
|
|
320
|
+
success: result.success,
|
|
321
|
+
error: result.error
|
|
322
|
+
};
|
|
323
|
+
return {
|
|
324
|
+
projectId,
|
|
325
|
+
projectName,
|
|
326
|
+
targetDir,
|
|
327
|
+
success: true
|
|
328
|
+
};
|
|
329
|
+
} catch (error) {
|
|
330
|
+
process.chdir(originalDir);
|
|
331
|
+
throw error;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
console.log(styleText("gray", ` 🆕 New project - using introspect mode`));
|
|
335
|
+
const originalLogLevel = process.env.LOG_LEVEL;
|
|
336
|
+
process.env.LOG_LEVEL = "silent";
|
|
337
|
+
const restoreLogLevel = () => {
|
|
338
|
+
if (originalLogLevel !== void 0) process.env.LOG_LEVEL = originalLogLevel;
|
|
339
|
+
else delete process.env.LOG_LEVEL;
|
|
340
|
+
};
|
|
341
|
+
const remoteProject = await (await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, projectId, isCI, config.agentsApiKey)).getFullProject(projectId);
|
|
342
|
+
await introspectGenerate({
|
|
343
|
+
project: remoteProject,
|
|
344
|
+
paths: createProjectStructure(targetDir)
|
|
345
|
+
});
|
|
346
|
+
restoreLogLevel();
|
|
347
|
+
return {
|
|
348
|
+
projectId,
|
|
349
|
+
projectName: projectName || remoteProject.name,
|
|
350
|
+
targetDir,
|
|
351
|
+
success: true
|
|
352
|
+
};
|
|
353
|
+
} catch (error) {
|
|
354
|
+
return {
|
|
355
|
+
projectId,
|
|
356
|
+
projectName,
|
|
357
|
+
targetDir,
|
|
358
|
+
success: false,
|
|
359
|
+
error: error instanceof Error ? error.message : String(error)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
//#endregion
|
|
365
|
+
export { createProjectStructure, enrichCanDelegateToWithTypes, pullV4Command };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createTwoFilesPatch } from "../../../node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js";
|
|
2
|
+
import "../../../node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
//#region src/commands/pull-v4/introspect/test-helpers.ts
|
|
8
|
+
const beforeCredentialContent = `import { credential } from '@inkeep/agents-sdk';
|
|
9
|
+
|
|
10
|
+
const keepMe = () => 'keep-me';
|
|
11
|
+
|
|
12
|
+
export const apiCredentials = credential({
|
|
13
|
+
id: 'api-credentials',
|
|
14
|
+
name: 'Old API Credentials',
|
|
15
|
+
type: 'bearer',
|
|
16
|
+
credentialStoreId: 'main-store'
|
|
17
|
+
});
|
|
18
|
+
`.trimStart();
|
|
19
|
+
function createTestEnvironment() {
|
|
20
|
+
const testDir = join(tmpdir(), `introspect-v4-test-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`);
|
|
21
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
22
|
+
return {
|
|
23
|
+
testDir,
|
|
24
|
+
projectPaths: {
|
|
25
|
+
projectRoot: testDir,
|
|
26
|
+
agentsDir: join(testDir, "agents"),
|
|
27
|
+
toolsDir: join(testDir, "tools"),
|
|
28
|
+
dataComponentsDir: join(testDir, "data-components"),
|
|
29
|
+
artifactComponentsDir: join(testDir, "artifact-components"),
|
|
30
|
+
statusComponentsDir: join(testDir, "status-components"),
|
|
31
|
+
environmentsDir: join(testDir, "environments"),
|
|
32
|
+
credentialsDir: join(testDir, "credentials"),
|
|
33
|
+
contextConfigsDir: join(testDir, "context-configs"),
|
|
34
|
+
externalAgentsDir: join(testDir, "external-agents")
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function cleanupTestEnvironment(testDir) {
|
|
39
|
+
fs.rmSync(testDir, {
|
|
40
|
+
recursive: true,
|
|
41
|
+
force: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function getTestPath() {
|
|
45
|
+
return `../__tests__/__snapshots__/introspect/${expect.getState().currentTestName?.split(" > ").at(-1)}`;
|
|
46
|
+
}
|
|
47
|
+
function createProjectFixture() {
|
|
48
|
+
return {
|
|
49
|
+
id: "support-project",
|
|
50
|
+
name: "Support Project",
|
|
51
|
+
description: "Support project for introspect v4 tests",
|
|
52
|
+
models: { base: { model: "gpt-4o-mini" } },
|
|
53
|
+
credentialReferences: { "api-credentials": {
|
|
54
|
+
id: "api-credentials",
|
|
55
|
+
name: "API Credentials",
|
|
56
|
+
type: "bearer",
|
|
57
|
+
credentialStoreId: "main-store",
|
|
58
|
+
retrievalParams: { key: "token" }
|
|
59
|
+
} },
|
|
60
|
+
dataComponents: { "customer-profile": {
|
|
61
|
+
id: "customer-profile",
|
|
62
|
+
name: "Customer Profile",
|
|
63
|
+
description: "Customer profile data component",
|
|
64
|
+
props: {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
fullName: { type: "string" },
|
|
68
|
+
avatarUrl: { type: "string" }
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
render: {
|
|
72
|
+
component: "<img src=\"{{avatarUrl}}\" alt=\"{{fullName}}\" />",
|
|
73
|
+
mockData: {
|
|
74
|
+
fullName: "Ada Lovelace",
|
|
75
|
+
avatarUrl: "https://example.com/avatar.png"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} },
|
|
79
|
+
artifactComponents: { "ticket-summary": {
|
|
80
|
+
id: "ticket-summary",
|
|
81
|
+
name: "Ticket Summary",
|
|
82
|
+
props: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: { title: { type: "string" } }
|
|
85
|
+
}
|
|
86
|
+
} },
|
|
87
|
+
agents: { "support-agent": {
|
|
88
|
+
id: "support-agent",
|
|
89
|
+
name: "Support Agent",
|
|
90
|
+
defaultSubAgentId: "tier-one",
|
|
91
|
+
subAgents: { "tier-one": {
|
|
92
|
+
id: "tier-one",
|
|
93
|
+
name: "Tier One"
|
|
94
|
+
} },
|
|
95
|
+
contextConfig: {
|
|
96
|
+
id: "support-context",
|
|
97
|
+
headersSchema: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: { user_id: { type: "string" } }
|
|
100
|
+
},
|
|
101
|
+
contextVariables: { userInfo: {
|
|
102
|
+
id: "user-info",
|
|
103
|
+
name: "User Information",
|
|
104
|
+
trigger: "initialization",
|
|
105
|
+
fetchConfig: {
|
|
106
|
+
url: "https://api.example.com/users/${headersSchema.toTemplate(\"user_id\")}",
|
|
107
|
+
method: "GET"
|
|
108
|
+
},
|
|
109
|
+
responseSchema: {
|
|
110
|
+
type: "object",
|
|
111
|
+
properties: { name: { type: "string" } }
|
|
112
|
+
},
|
|
113
|
+
defaultValue: "Unable to fetch user information"
|
|
114
|
+
} }
|
|
115
|
+
},
|
|
116
|
+
triggers: { "github-webhook": {
|
|
117
|
+
id: "github-webhook",
|
|
118
|
+
name: "GitHub Webhook",
|
|
119
|
+
messageTemplate: "New webhook event"
|
|
120
|
+
} },
|
|
121
|
+
statusUpdates: {
|
|
122
|
+
numEvents: 1,
|
|
123
|
+
statusComponents: [{
|
|
124
|
+
id: "tool-summary",
|
|
125
|
+
type: "tool_summary",
|
|
126
|
+
description: "Tool summary status component",
|
|
127
|
+
detailsSchema: {
|
|
128
|
+
type: "object",
|
|
129
|
+
properties: { tool_name: { type: "string" } }
|
|
130
|
+
}
|
|
131
|
+
}]
|
|
132
|
+
}
|
|
133
|
+
} },
|
|
134
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
135
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function createUnifiedDiff(filePath, before, after) {
|
|
139
|
+
return createTwoFilesPatch(filePath, filePath, before, after, "before", "after", { context: 3 });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
export { beforeCredentialContent, cleanupTestEnvironment, createProjectFixture, createTestEnvironment, createUnifiedDiff, getTestPath };
|