@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.
Files changed (76) hide show
  1. package/dist/agents-cli/package.js +6 -0
  2. package/dist/commands/config.js +1 -1
  3. package/dist/commands/dev.js +1 -1
  4. package/dist/commands/init.js +1 -1
  5. package/dist/commands/{pull-v3 → pull-v4}/component-parser.js +6 -12
  6. package/dist/commands/{pull-v3/utils → pull-v4}/component-registry.js +1 -1
  7. package/dist/commands/pull-v4/generators/agent-generator.js +258 -0
  8. package/dist/commands/pull-v4/generators/artifact-component-generator.js +69 -0
  9. package/dist/commands/pull-v4/generators/context-config-generator.js +264 -0
  10. package/dist/commands/pull-v4/generators/credential-generator.js +30 -0
  11. package/dist/commands/pull-v4/generators/data-component-generator.js +50 -0
  12. package/dist/commands/pull-v4/generators/environment-generator.js +123 -0
  13. package/dist/commands/pull-v4/generators/external-agent-generator.js +56 -0
  14. package/dist/commands/pull-v4/generators/function-tool-generator.js +48 -0
  15. package/dist/commands/pull-v4/generators/mcp-tool-generator.js +91 -0
  16. package/dist/commands/pull-v4/generators/project-generator.js +125 -0
  17. package/dist/commands/{pull-v3/components → pull-v4/generators}/skill-generator.js +1 -1
  18. package/dist/commands/pull-v4/generators/status-component-generator.js +35 -0
  19. package/dist/commands/pull-v4/generators/sub-agent-generator.js +269 -0
  20. package/dist/commands/pull-v4/generators/trigger-generator.js +58 -0
  21. package/dist/commands/pull-v4/introspect/index.js +365 -0
  22. package/dist/commands/pull-v4/introspect/test-helpers.js +143 -0
  23. package/dist/commands/pull-v4/introspect-generator.js +706 -0
  24. package/dist/commands/pull-v4/module-merge.js +405 -0
  25. package/dist/commands/pull-v4/utils.js +235 -0
  26. package/dist/commands/push.js +1 -1
  27. package/dist/commands/update.js +2 -2
  28. package/dist/index.js +18 -44
  29. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +18 -0
  30. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +180 -0
  31. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +8 -0
  32. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +12 -0
  33. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +60 -0
  34. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +37 -0
  35. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +31 -0
  36. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +118 -0
  37. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js +11 -0
  38. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +141 -0
  39. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +63 -0
  40. package/dist/utils/ci-environment.js +1 -1
  41. package/dist/utils/config.js +1 -1
  42. package/dist/utils/environment-loader.js +1 -1
  43. package/dist/utils/file-finder.js +1 -1
  44. package/dist/utils/mcp-runner.js +1 -1
  45. package/dist/utils/profile-config.js +1 -1
  46. package/dist/utils/profiles/profile-manager.js +1 -1
  47. package/dist/utils/project-directory.js +1 -1
  48. package/dist/utils/project-loader.js +1 -1
  49. package/dist/utils/version-check.js +6 -15
  50. package/package.json +5 -7
  51. package/dist/commands/pull-v3/component-updater.js +0 -768
  52. package/dist/commands/pull-v3/components/agent-generator.js +0 -255
  53. package/dist/commands/pull-v3/components/artifact-component-generator.js +0 -143
  54. package/dist/commands/pull-v3/components/context-config-generator.js +0 -190
  55. package/dist/commands/pull-v3/components/credential-generator.js +0 -89
  56. package/dist/commands/pull-v3/components/data-component-generator.js +0 -102
  57. package/dist/commands/pull-v3/components/environment-generator.js +0 -173
  58. package/dist/commands/pull-v3/components/external-agent-generator.js +0 -75
  59. package/dist/commands/pull-v3/components/function-tool-generator.js +0 -92
  60. package/dist/commands/pull-v3/components/mcp-tool-generator.js +0 -86
  61. package/dist/commands/pull-v3/components/project-generator.js +0 -157
  62. package/dist/commands/pull-v3/components/status-component-generator.js +0 -92
  63. package/dist/commands/pull-v3/components/sub-agent-generator.js +0 -295
  64. package/dist/commands/pull-v3/components/trigger-generator.js +0 -185
  65. package/dist/commands/pull-v3/index.js +0 -510
  66. package/dist/commands/pull-v3/introspect-generator.js +0 -286
  67. package/dist/commands/pull-v3/llm-content-merger.js +0 -192
  68. package/dist/commands/pull-v3/new-component-generator.js +0 -279
  69. package/dist/commands/pull-v3/project-comparator.js +0 -914
  70. package/dist/commands/pull-v3/project-index-generator.js +0 -32
  71. package/dist/commands/pull-v3/project-validator.js +0 -358
  72. package/dist/commands/pull-v3/targeted-typescript-placeholders.js +0 -173
  73. package/dist/commands/pull-v3/utils/component-tracker.js +0 -165
  74. package/dist/commands/pull-v3/utils/generator-utils.js +0 -146
  75. package/dist/commands/pull-v3/utils/model-provider-detector.js +0 -50
  76. package/dist/utils/url.js +0 -26
@@ -1,510 +0,0 @@
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 "./utils/component-registry.js";
6
- import { checkAndPromptForStaleComponentCleanup, cleanupStaleComponents, copyProjectToTemp } from "./component-updater.js";
7
- import { introspectGenerate } from "./introspect-generator.js";
8
- import { compareProjects } from "./project-comparator.js";
9
- import { existsSync, mkdirSync } from "node:fs";
10
- import { join, resolve } from "node:path";
11
- import * as p from "@clack/prompts";
12
- import chalk from "chalk";
13
- import { EventEmitter } from "node:events";
14
-
15
- //#region src/commands/pull-v3/index.ts
16
- /**
17
- * Pull v3 - Clean, efficient project generation
18
- *
19
- * Step 1: Validate and compile existing code
20
- * Step 2: Compare project with DB to detect ALL changes
21
- * Step 3: Classify changes as new vs modified components
22
- * Step 4: Generate new components deterministically
23
- * Step 5: Use LLM to correct modified components
24
- */
25
- EventEmitter.defaultMaxListeners = 20;
26
- /**
27
- * Clean up stdin state between interactive prompts to prevent listener leaks
28
- */
29
- function resetStdinState() {
30
- process.stdin.removeAllListeners("data");
31
- process.stdin.removeAllListeners("keypress");
32
- process.stdin.removeAllListeners("end");
33
- if (process.stdin.isTTY && process.stdin.isRaw) process.stdin.setRawMode(false);
34
- if (!process.stdin.isPaused()) process.stdin.pause();
35
- }
36
- /**
37
- * Create project directory structure
38
- */
39
- function createProjectStructure(projectDir) {
40
- const projectRoot = projectDir;
41
- const paths = {
42
- projectRoot,
43
- agentsDir: join(projectRoot, "agents"),
44
- toolsDir: join(projectRoot, "tools"),
45
- dataComponentsDir: join(projectRoot, "data-components"),
46
- artifactComponentsDir: join(projectRoot, "artifact-components"),
47
- statusComponentsDir: join(projectRoot, "status-components"),
48
- environmentsDir: join(projectRoot, "environments"),
49
- credentialsDir: join(projectRoot, "credentials"),
50
- contextConfigsDir: join(projectRoot, "context-configs"),
51
- externalAgentsDir: join(projectRoot, "external-agents"),
52
- skillsDir: join(projectRoot, "skills")
53
- };
54
- Object.values(paths).forEach((dir) => {
55
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
56
- });
57
- return paths;
58
- }
59
- /**
60
- * Enrich canDelegateTo references with component type information
61
- */
62
- function enrichCanDelegateToWithTypes(project) {
63
- const agentIds = new Set(project.agents ? Object.keys(project.agents) : []);
64
- const subAgentIds = new Set(Object.keys(extractSubAgents(project)));
65
- const externalAgentIds = new Set(project.externalAgents ? Object.keys(project.externalAgents) : []);
66
- const enrichCanDelegateToArray = (canDelegateTo) => {
67
- if (!Array.isArray(canDelegateTo)) return;
68
- for (let i = 0; i < canDelegateTo.length; i++) {
69
- const item = canDelegateTo[i];
70
- if (typeof item !== "string") continue;
71
- const id = item;
72
- let enrichedItem = null;
73
- if (agentIds.has(id)) enrichedItem = { agentId: id };
74
- else if (subAgentIds.has(id)) enrichedItem = { subAgentId: id };
75
- else if (externalAgentIds.has(id)) enrichedItem = { externalAgentId: id };
76
- else continue;
77
- canDelegateTo[i] = enrichedItem;
78
- }
79
- };
80
- if (project.agents) {
81
- for (const agentData of Object.values(project.agents)) if (agentData.subAgents) {
82
- for (const subAgentData of Object.values(agentData.subAgents)) if (subAgentData.canDelegateTo) enrichCanDelegateToArray(subAgentData.canDelegateTo);
83
- }
84
- }
85
- }
86
- /**
87
- * Read existing project from filesystem if it exists
88
- */
89
- async function readExistingProject(projectRoot) {
90
- if (!existsSync(join(projectRoot, "index.ts"))) return null;
91
- try {
92
- const { loadProject: loadProject$1 } = await import("../../utils/project-loader.js");
93
- const project = await loadProject$1(projectRoot);
94
- return await Promise.race([project.getFullDefinition(), new Promise((_, reject) => {
95
- setTimeout(() => {
96
- reject(/* @__PURE__ */ new Error("getFullDefinition() timed out after 30 seconds - likely circular reference or infinite loop in local project"));
97
- }, 3e4);
98
- })]);
99
- } catch {
100
- return null;
101
- }
102
- }
103
- /**
104
- * Main pull-v3 command
105
- * @returns PullResult when in batch mode, otherwise void (exits process)
106
- */
107
- async function pullV3Command(options) {
108
- if (options.all) {
109
- await pullAllProjects(options);
110
- return;
111
- }
112
- const batchMode = options._batchMode ?? false;
113
- const originalLogLevel = process.env.LOG_LEVEL;
114
- process.env.LOG_LEVEL = "silent";
115
- const restoreLogLevel = () => {
116
- if (originalLogLevel !== void 0) process.env.LOG_LEVEL = originalLogLevel;
117
- else delete process.env.LOG_LEVEL;
118
- };
119
- if (!batchMode) performBackgroundVersionCheck();
120
- console.log(chalk.blue("\nInkeep Pull:"));
121
- if (options.introspect) console.log(chalk.gray(" Introspect mode • Complete regeneration • No comparison needed"));
122
- else console.log(chalk.gray(" Smart comparison • Detect all changes • Targeted updates"));
123
- const s = p.spinner();
124
- try {
125
- const { config, isCI } = await initializeCommand({
126
- configPath: options.config,
127
- profileName: options.profile,
128
- tag: options.tag,
129
- showSpinner: true,
130
- spinnerText: "Loading configuration...",
131
- logConfig: true,
132
- quiet: options.quiet
133
- });
134
- s.start("Detecting project...");
135
- let projectDir;
136
- let projectId;
137
- let localProjectForId = null;
138
- const currentDir = process.cwd();
139
- if (existsSync(join(currentDir, "index.ts"))) {
140
- projectDir = currentDir;
141
- s.start("Loading local project...");
142
- try {
143
- localProjectForId = await loadProject(projectDir);
144
- const localProjectId = localProjectForId.getId();
145
- if (options.project) {
146
- if (localProjectId !== options.project) {
147
- s.stop("Project ID mismatch");
148
- console.error(chalk.red(`Local project ID "${localProjectId}" doesn't match --project "${options.project}"`));
149
- console.error(chalk.yellow("Either remove --project flag or ensure it matches the local project ID"));
150
- if (batchMode) return {
151
- success: false,
152
- error: "Project ID mismatch"
153
- };
154
- process.exit(1);
155
- }
156
- }
157
- projectId = localProjectId;
158
- s.stop(`Using local project: ${projectId}`);
159
- } catch (error) {
160
- s.stop("Failed to load local project");
161
- throw new Error(`Could not load local project: ${error instanceof Error ? error.message : String(error)}`);
162
- }
163
- } else {
164
- if (!options.project) {
165
- s.stop("No index.ts found in current directory");
166
- console.error(chalk.yellow("Please run this command from a directory containing index.ts or use --project <project-id>"));
167
- if (batchMode) return {
168
- success: false,
169
- error: "No index.ts found and no --project specified"
170
- };
171
- process.exit(1);
172
- }
173
- const projectPath = resolve(currentDir, options.project);
174
- if (existsSync(join(projectPath, "index.ts"))) {
175
- projectDir = projectPath;
176
- s.start("Loading project from specified path...");
177
- try {
178
- localProjectForId = await loadProject(projectDir);
179
- projectId = localProjectForId.getId();
180
- s.stop(`Using project from path: ${projectId}`);
181
- } catch (error) {
182
- s.stop("Failed to load project from path");
183
- throw new Error(`Could not load project from ${projectPath}: ${error instanceof Error ? error.message : String(error)}`);
184
- }
185
- } else {
186
- projectId = options.project;
187
- projectDir = join(currentDir, projectId);
188
- s.stop(`Creating new project directory: ${projectDir}`);
189
- }
190
- }
191
- s.start(`Fetching project: ${projectId}`);
192
- const remoteProject = await (await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, projectId, isCI, config.agentsApiKey)).getFullProject(projectId);
193
- if (options.debug && remoteProject.functions) {
194
- console.log(chalk.gray(" 📋 Project-level functions from API:"), Object.keys(remoteProject.functions));
195
- Object.entries(remoteProject.functions).forEach(([id, data]) => {
196
- console.log(chalk.gray(` ${id}: has name=${!!data.name}, has description=${!!data.description}`));
197
- });
198
- }
199
- if (remoteProject.agents) for (const [agentId, agentData] of Object.entries(remoteProject.agents)) {
200
- if (agentData.functionTools) {
201
- remoteProject.functionTools = remoteProject.functionTools || {};
202
- Object.assign(remoteProject.functionTools, agentData.functionTools);
203
- if (options.debug) console.log(chalk.gray(` Hoisted functionTools from agent ${agentId}: ${Object.keys(agentData.functionTools).join(", ")}`));
204
- }
205
- if (agentData.functions) {
206
- remoteProject.functions = remoteProject.functions || {};
207
- Object.entries(agentData.functions).forEach(([funcId, funcData]) => {
208
- if (!remoteProject.functions[funcId]) remoteProject.functions[funcId] = {
209
- id: funcData.id,
210
- inputSchema: funcData.inputSchema,
211
- executeCode: funcData.executeCode,
212
- dependencies: funcData.dependencies
213
- };
214
- });
215
- }
216
- }
217
- if (remoteProject.agents && remoteProject.tools) {
218
- const projectToolIds = Object.keys(remoteProject.tools);
219
- for (const agentData of Object.values(remoteProject.agents)) if (agentData.tools) {
220
- const agentSpecificTools = Object.fromEntries(Object.entries(agentData.tools).filter(([toolId]) => !projectToolIds.includes(toolId)));
221
- if (Object.keys(agentSpecificTools).length > 0) agentData.tools = agentSpecificTools;
222
- else delete agentData.tools;
223
- }
224
- }
225
- enrichCanDelegateToWithTypes(remoteProject);
226
- s.message("Project data fetched");
227
- if (options.json) {
228
- console.log(JSON.stringify(remoteProject, null, 2));
229
- restoreLogLevel();
230
- return;
231
- }
232
- const paths = createProjectStructure(projectDir);
233
- if (remoteProject.skills && Object.keys(remoteProject.skills).length) {
234
- const { generateSkills } = await import("./components/skill-generator.js");
235
- await generateSkills(remoteProject.skills, paths.skillsDir);
236
- }
237
- if (options.introspect) {
238
- console.log(chalk.yellow("\n🔍 Introspect mode: Regenerating all files from scratch"));
239
- s.start("Generating all files deterministically...");
240
- await introspectGenerate(remoteProject, paths, options.env || "development", options.debug || false);
241
- s.stop("All files generated");
242
- console.log(chalk.green("\n✅ Project regenerated successfully with introspect mode!"));
243
- console.log(chalk.gray(` 📁 Location: ${paths.projectRoot}`));
244
- console.log(chalk.gray(` 🌍 Environment: ${options.env || "development"}`));
245
- console.log(chalk.gray(` 🚀 Mode: Complete regeneration (no comparison)`));
246
- restoreLogLevel();
247
- if (batchMode) return { success: true };
248
- process.exit(0);
249
- }
250
- const localProject = await readExistingProject(paths.projectRoot);
251
- if (!localProject) s.message("No existing project found - treating as new project");
252
- else s.message("Existing project loaded");
253
- s.start("Building component registry from local files...");
254
- const { buildComponentRegistryFromParsing } = await import("./component-parser.js");
255
- const localRegistry = buildComponentRegistryFromParsing(paths.projectRoot, options.debug);
256
- s.message("Component registry built");
257
- if (options.debug) {
258
- console.log(chalk.cyan("\n🔍 Component Registry Debug:"));
259
- const allComponents = localRegistry.getAllComponents();
260
- console.log(chalk.gray(" Total components registered:"), allComponents.length);
261
- const nameGroups = /* @__PURE__ */ new Map();
262
- for (const comp of allComponents) {
263
- if (!nameGroups.has(comp.name)) nameGroups.set(comp.name, []);
264
- nameGroups.get(comp.name)?.push(comp);
265
- }
266
- for (const [varName, components] of nameGroups.entries()) if (components.length > 1) {
267
- console.log(chalk.red(` ❌ Variable name conflict: "${varName}"`));
268
- for (const comp of components) console.log(chalk.gray(` - ${comp.type}:${comp.id} -> ${comp.filePath}`));
269
- } else console.log(chalk.gray(` ✅ ${varName} (${components[0].type}:${components[0].id})`));
270
- }
271
- s.start("Comparing projects for changes...");
272
- const comparison = await compareProjects(localProject, remoteProject, options.debug);
273
- if (!comparison.hasChanges && !options.force) {
274
- s.stop();
275
- console.log(chalk.green("✅ Project is already up to date"));
276
- console.log(chalk.gray(" No differences detected between local and remote projects"));
277
- restoreLogLevel();
278
- if (batchMode) return {
279
- success: true,
280
- upToDate: true
281
- };
282
- process.exit(0);
283
- }
284
- s.message(`Detected ${comparison.changeCount} differences`);
285
- const tempDirName = `.temp-validation-${Date.now()}`;
286
- s.start("Preparing temp directory...");
287
- let performedCleanup = false;
288
- if (localProject) {
289
- copyProjectToTemp(paths.projectRoot, tempDirName);
290
- console.log(chalk.green(`✅ Existing project copied to temp directory`));
291
- s.start("Checking for stale components...");
292
- const shouldCleanupStale = await checkAndPromptForStaleComponentCleanup(remoteProject, localRegistry);
293
- resetStdinState();
294
- if (shouldCleanupStale) {
295
- s.start("Cleaning up stale components from temp directory...");
296
- await cleanupStaleComponents(paths.projectRoot, tempDirName, remoteProject, localRegistry);
297
- console.log(chalk.green(`✅ Stale components cleaned up from temp directory`));
298
- performedCleanup = true;
299
- }
300
- } else {
301
- mkdirSync(join(paths.projectRoot, tempDirName), { recursive: true });
302
- console.log(chalk.green(`✅ Empty temp directory created for new project`));
303
- }
304
- s.message("Temp directory prepared");
305
- const newComponentCount = Object.values(comparison.componentChanges).reduce((sum, changes) => sum + changes.added.length, 0);
306
- let newComponentResults = [];
307
- if (newComponentCount > 0) {
308
- s.start("Creating new component files in temp directory...");
309
- const { createNewComponents } = await import("./new-component-generator.js");
310
- newComponentResults = await createNewComponents(comparison, remoteProject, localRegistry, paths, options.env || "development", tempDirName);
311
- if (options.debug) {
312
- console.log(chalk.cyan("\n🔍 Component Registry After Generation:"));
313
- const allComponents = localRegistry.getAllComponents();
314
- console.log(chalk.gray(" Total components registered:"), allComponents.length);
315
- const nameGroups = /* @__PURE__ */ new Map();
316
- for (const comp of allComponents) {
317
- if (!nameGroups.has(comp.name)) nameGroups.set(comp.name, []);
318
- nameGroups.get(comp.name)?.push(comp);
319
- }
320
- for (const [varName, components] of nameGroups.entries()) if (components.length > 1) {
321
- console.log(chalk.red(` ❌ Variable name conflict: "${varName}"`));
322
- for (const comp of components) console.log(chalk.gray(` - ${comp.type}:${comp.id} -> ${comp.filePath}`));
323
- } else console.log(chalk.gray(` ✅ ${varName} (${components[0].type}:${components[0].id})`));
324
- }
325
- const successful = newComponentResults.filter((r) => r.success);
326
- console.log(chalk.green(`✅ Added ${successful.length} new components to temp directory`));
327
- s.message("New component files created");
328
- }
329
- const modifiedCount = Object.values(comparison.componentChanges).reduce((sum, changes) => sum + changes.modified.length, 0);
330
- if (modifiedCount > 0) {
331
- s.stop();
332
- const { updateModifiedComponents } = await import("./component-updater.js");
333
- const newComponentsForContext = newComponentResults && newComponentResults.length > 0 ? newComponentResults.filter((result) => result.success).map((result) => ({
334
- componentId: result.componentId,
335
- componentType: result.componentType,
336
- filePath: result.filePath.replace(`${paths.projectRoot}/`, "")
337
- })) : void 0;
338
- await updateModifiedComponents(comparison, remoteProject, localRegistry, paths.projectRoot, options.debug, tempDirName, newComponentsForContext);
339
- }
340
- s.start("Generating project index file in temp directory...");
341
- const { generateProjectIndex } = await import("./project-index-generator.js");
342
- await generateProjectIndex(join(paths.projectRoot, tempDirName), remoteProject, localRegistry, projectId);
343
- s.message("Project index file created");
344
- if (newComponentCount > 0 || modifiedCount > 0 || performedCleanup) {
345
- s.stop("Running validation on complete project...");
346
- const { validateTempDirectory } = await import("./project-validator.js");
347
- const validationResult = await validateTempDirectory(paths.projectRoot, tempDirName, remoteProject, { skipExit: batchMode });
348
- if (batchMode) {
349
- restoreLogLevel();
350
- return {
351
- success: validationResult.success,
352
- upToDate: validationResult.upToDate
353
- };
354
- }
355
- } else {
356
- s.stop();
357
- console.log(chalk.green("\n✅ No changes detected - project is up to date"));
358
- }
359
- restoreLogLevel();
360
- if (batchMode) return { success: true };
361
- process.exit(0);
362
- } catch (error) {
363
- s.stop();
364
- console.error(chalk.red(`\nError: ${error instanceof Error ? error.message : String(error)}`));
365
- if (options.debug && error instanceof Error) console.error(chalk.red(error.stack || ""));
366
- restoreLogLevel();
367
- if (batchMode) return {
368
- success: false,
369
- error: error instanceof Error ? error.message : String(error)
370
- };
371
- process.exit(1);
372
- }
373
- }
374
- /**
375
- * Pull all projects for the current tenant
376
- * Uses smart comparison with LLM merging for existing projects, introspect for new projects
377
- */
378
- async function pullAllProjects(options) {
379
- console.log(chalk.blue("\n🔄 Batch Pull: Sequential processing with smart comparison\n"));
380
- console.log(chalk.gray(" • Existing projects: Smart comparison + LLM merging + confirmation prompts"));
381
- console.log(chalk.gray(" • New projects: Fresh generation with introspect mode\n"));
382
- performBackgroundVersionCheck();
383
- const { config, isCI } = await initializeCommand({
384
- configPath: options.config,
385
- profileName: options.profile,
386
- tag: options.tag,
387
- showSpinner: true,
388
- spinnerText: "Loading configuration...",
389
- logConfig: true,
390
- quiet: options.quiet
391
- });
392
- const s = p.spinner();
393
- try {
394
- s.start("Fetching project list from API...");
395
- const projects = await (await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, void 0, isCI, config.agentsApiKey)).listAllProjects();
396
- s.stop(`Found ${projects.length} project(s)`);
397
- if (projects.length === 0) {
398
- console.log(chalk.yellow("No projects found for this tenant."));
399
- process.exit(0);
400
- }
401
- const existingProjects = [];
402
- const newProjects = [];
403
- for (const project of projects) if (existsSync(join(join(process.cwd(), project.id), "index.ts"))) existingProjects.push(project);
404
- else newProjects.push(project);
405
- console.log(chalk.gray("\nProjects to pull:\n"));
406
- if (existingProjects.length > 0) {
407
- console.log(chalk.cyan(" Existing (smart comparison):"));
408
- for (const project of existingProjects) console.log(chalk.gray(` • ${project.name || project.id} (${project.id})`));
409
- }
410
- if (newProjects.length > 0) {
411
- console.log(chalk.cyan(" New (introspect):"));
412
- for (const project of newProjects) console.log(chalk.gray(` • ${project.name || project.id} (${project.id})`));
413
- }
414
- console.log();
415
- const results = [];
416
- const total = projects.length;
417
- for (let i = 0; i < projects.length; i++) {
418
- const project = projects[i];
419
- const progress = `[${i + 1}/${total}]`;
420
- console.log(chalk.cyan(`\n${"─".repeat(60)}`));
421
- console.log(chalk.cyan(`${progress} Pulling ${project.name || project.id}...`));
422
- const result = await pullSingleProject(project.id, project.name, options, config, isCI);
423
- results.push(result);
424
- if (result.success) console.log(chalk.green(`\n ✓ ${result.projectName || result.projectId} → ${result.targetDir}`));
425
- else console.log(chalk.red(`\n ✗ ${result.projectName || result.projectId}: ${result.error}`));
426
- }
427
- const succeeded = results.filter((r) => r.success).length;
428
- const failed = results.filter((r) => !r.success).length;
429
- console.log(chalk.cyan(`\n${"═".repeat(60)}`));
430
- console.log(chalk.cyan("📊 Batch Pull Summary:"));
431
- console.log(chalk.green(` ✓ Succeeded: ${succeeded}`));
432
- if (failed > 0) {
433
- console.log(chalk.red(` ✗ Failed: ${failed}`));
434
- console.log(chalk.red("\nFailed projects:"));
435
- for (const result of results) if (!result.success) console.log(chalk.red(` • ${result.projectId}: ${result.error}`));
436
- }
437
- process.exit(failed > 0 ? 1 : 0);
438
- } catch (error) {
439
- s.stop();
440
- console.error(chalk.red(`\nError: ${error instanceof Error ? error.message : String(error)}`));
441
- process.exit(1);
442
- }
443
- }
444
- /**
445
- * Pull a single project (used by batch operations)
446
- * Uses smart comparison flow for existing projects, introspect for new projects
447
- */
448
- async function pullSingleProject(projectId, projectName, options, config, isCI) {
449
- const targetDir = join(process.cwd(), projectId);
450
- const hasExistingProject = existsSync(join(targetDir, "index.ts"));
451
- try {
452
- if (hasExistingProject) {
453
- console.log(chalk.gray(` 📂 Existing project found - using smart comparison mode`));
454
- const originalDir = process.cwd();
455
- process.chdir(targetDir);
456
- try {
457
- const result = await pullV3Command({
458
- ...options,
459
- project: projectId,
460
- all: false,
461
- _batchMode: true
462
- });
463
- process.chdir(originalDir);
464
- if (result && typeof result === "object") return {
465
- projectId,
466
- projectName,
467
- targetDir,
468
- success: result.success,
469
- error: result.error
470
- };
471
- return {
472
- projectId,
473
- projectName,
474
- targetDir,
475
- success: true
476
- };
477
- } catch (error) {
478
- process.chdir(originalDir);
479
- throw error;
480
- }
481
- }
482
- console.log(chalk.gray(` 🆕 New project - using introspect mode`));
483
- const originalLogLevel = process.env.LOG_LEVEL;
484
- process.env.LOG_LEVEL = "silent";
485
- const restoreLogLevel = () => {
486
- if (originalLogLevel !== void 0) process.env.LOG_LEVEL = originalLogLevel;
487
- else delete process.env.LOG_LEVEL;
488
- };
489
- const remoteProject = await (await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, projectId, isCI, config.agentsApiKey)).getFullProject(projectId);
490
- await introspectGenerate(remoteProject, createProjectStructure(targetDir), options.env || "development", false);
491
- restoreLogLevel();
492
- return {
493
- projectId,
494
- projectName: projectName || remoteProject.name,
495
- targetDir,
496
- success: true
497
- };
498
- } catch (error) {
499
- return {
500
- projectId,
501
- projectName,
502
- targetDir,
503
- success: false,
504
- error: error instanceof Error ? error.message : String(error)
505
- };
506
- }
507
- }
508
-
509
- //#endregion
510
- export { enrichCanDelegateToWithTypes, pullV3Command };