@inkeep/agents-cli 0.50.6 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/agents-cli/package.js +6 -0
  2. package/dist/commands/config.js +1 -1
  3. package/dist/commands/dev.js +1 -1
  4. package/dist/commands/init.js +1 -1
  5. package/dist/commands/pull-v3/component-parser.js +4 -10
  6. package/dist/commands/pull-v4/agent-generator.js +274 -0
  7. package/dist/commands/pull-v4/artifact-component-generator.js +69 -0
  8. package/dist/commands/pull-v4/context-config-generator.js +264 -0
  9. package/dist/commands/pull-v4/credential-generator.js +30 -0
  10. package/dist/commands/pull-v4/data-component-generator.js +50 -0
  11. package/dist/commands/pull-v4/environment-generator.js +123 -0
  12. package/dist/commands/pull-v4/external-agent-generator.js +56 -0
  13. package/dist/commands/pull-v4/function-tool-generator.js +48 -0
  14. package/dist/commands/pull-v4/introspect/index.js +365 -0
  15. package/dist/commands/pull-v4/introspect/test-helpers.js +143 -0
  16. package/dist/commands/pull-v4/introspect-generator.js +691 -0
  17. package/dist/commands/pull-v4/mcp-tool-generator.js +91 -0
  18. package/dist/commands/pull-v4/module-merge.js +379 -0
  19. package/dist/commands/pull-v4/project-generator.js +101 -0
  20. package/dist/commands/pull-v4/status-component-generator.js +35 -0
  21. package/dist/commands/pull-v4/sub-agent-generator.js +168 -0
  22. package/dist/commands/pull-v4/trigger-generator.js +58 -0
  23. package/dist/commands/pull-v4/utils.js +219 -0
  24. package/dist/commands/push.js +1 -1
  25. package/dist/commands/update.js +2 -2
  26. package/dist/index.js +18 -44
  27. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +18 -0
  28. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +180 -0
  29. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +8 -0
  30. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +12 -0
  31. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +60 -0
  32. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +37 -0
  33. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +31 -0
  34. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +118 -0
  35. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js +11 -0
  36. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +141 -0
  37. package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +63 -0
  38. package/dist/utils/ci-environment.js +1 -1
  39. package/dist/utils/config.js +1 -1
  40. package/dist/utils/environment-loader.js +1 -1
  41. package/dist/utils/file-finder.js +1 -1
  42. package/dist/utils/mcp-runner.js +1 -1
  43. package/dist/utils/profile-config.js +1 -1
  44. package/dist/utils/profiles/profile-manager.js +1 -1
  45. package/dist/utils/project-directory.js +1 -1
  46. package/dist/utils/project-loader.js +1 -1
  47. package/dist/utils/version-check.js +6 -15
  48. package/package.json +5 -4
  49. package/dist/commands/pull-v3/component-updater.js +0 -768
  50. package/dist/commands/pull-v3/components/agent-generator.js +0 -255
  51. package/dist/commands/pull-v3/components/artifact-component-generator.js +0 -143
  52. package/dist/commands/pull-v3/components/context-config-generator.js +0 -190
  53. package/dist/commands/pull-v3/components/credential-generator.js +0 -89
  54. package/dist/commands/pull-v3/components/data-component-generator.js +0 -102
  55. package/dist/commands/pull-v3/components/environment-generator.js +0 -173
  56. package/dist/commands/pull-v3/components/external-agent-generator.js +0 -75
  57. package/dist/commands/pull-v3/components/function-tool-generator.js +0 -92
  58. package/dist/commands/pull-v3/components/mcp-tool-generator.js +0 -86
  59. package/dist/commands/pull-v3/components/project-generator.js +0 -157
  60. package/dist/commands/pull-v3/components/status-component-generator.js +0 -92
  61. package/dist/commands/pull-v3/components/sub-agent-generator.js +0 -295
  62. package/dist/commands/pull-v3/components/trigger-generator.js +0 -185
  63. package/dist/commands/pull-v3/index.js +0 -510
  64. package/dist/commands/pull-v3/introspect-generator.js +0 -286
  65. package/dist/commands/pull-v3/llm-content-merger.js +0 -192
  66. package/dist/commands/pull-v3/new-component-generator.js +0 -279
  67. package/dist/commands/pull-v3/project-index-generator.js +0 -32
  68. package/dist/commands/pull-v3/project-validator.js +0 -358
  69. package/dist/utils/url.js +0 -26
@@ -0,0 +1,30 @@
1
+ import { addValueToObject, createFactoryDefinition, toCamelCase } from "./utils.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/commands/pull-v4/credential-generator.ts
5
+ const CredentialSchema = z.object({
6
+ credentialId: z.string().nonempty(),
7
+ name: z.string().nonempty(),
8
+ type: z.string().nonempty(),
9
+ credentialStoreId: z.string().nonempty(),
10
+ description: z.string().optional(),
11
+ retrievalParams: z.unknown().optional()
12
+ });
13
+ function generateCredentialDefinition(data) {
14
+ const result = CredentialSchema.safeParse(data);
15
+ if (!result.success) throw new Error(`Validation failed for credential:\n${z.prettifyError(result.error)}`);
16
+ const parsed = result.data;
17
+ const { sourceFile, configObject } = createFactoryDefinition({
18
+ importName: "credential",
19
+ variableName: toCamelCase(parsed.credentialId)
20
+ });
21
+ const { credentialId, ...rest } = parsed;
22
+ for (const [k, v] of Object.entries({
23
+ id: credentialId,
24
+ ...rest
25
+ })) addValueToObject(configObject, k, v);
26
+ return sourceFile;
27
+ }
28
+
29
+ //#endregion
30
+ export { generateCredentialDefinition };
@@ -0,0 +1,50 @@
1
+ import { addStringProperty, addValueToObject, convertJsonSchemaToZodSafe, createFactoryDefinition, toCamelCase } from "./utils.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/commands/pull-v4/data-component-generator.ts
5
+ const DataComponentSchema = z.object({
6
+ dataComponentId: z.string().nonempty(),
7
+ name: z.string().nonempty(),
8
+ description: z.string().nullable().optional(),
9
+ props: z.unknown().optional(),
10
+ schema: z.unknown().optional(),
11
+ render: z.looseObject({
12
+ component: z.string().optional(),
13
+ mockData: z.looseObject({}).optional()
14
+ }).nullable().optional()
15
+ });
16
+ function generateDataComponentDefinition(data) {
17
+ const result = DataComponentSchema.safeParse(data);
18
+ if (!result.success) throw new Error(`Validation failed for data component:\n${z.prettifyError(result.error)}`);
19
+ const parsed = result.data;
20
+ const props = parsed.props !== void 0 ? parsed.props : parsed.schema;
21
+ const { sourceFile, configObject } = createFactoryDefinition({
22
+ importName: "dataComponent",
23
+ variableName: toCamelCase(parsed.dataComponentId)
24
+ });
25
+ if (props !== void 0) sourceFile.addImportDeclaration({
26
+ namedImports: ["z"],
27
+ moduleSpecifier: "zod"
28
+ });
29
+ writeDataComponentConfig(configObject, parsed, props);
30
+ return sourceFile;
31
+ }
32
+ function writeDataComponentConfig(configObject, data, props) {
33
+ addStringProperty(configObject, "id", data.dataComponentId);
34
+ addStringProperty(configObject, "name", data.name);
35
+ if (typeof data.description === "string") addStringProperty(configObject, "description", data.description);
36
+ if (props !== void 0) configObject.addPropertyAssignment({
37
+ name: "props",
38
+ initializer: convertJsonSchemaToZodSafe(props)
39
+ });
40
+ if (data.render) addRenderProperty(configObject, data.render);
41
+ }
42
+ function addRenderProperty(configObject, render) {
43
+ if (render.component) addValueToObject(configObject, "render", {
44
+ component: render.component,
45
+ mockData: render.mockData
46
+ });
47
+ }
48
+
49
+ //#endregion
50
+ export { generateDataComponentDefinition };
@@ -0,0 +1,123 @@
1
+ import { addStringProperty, createFactoryDefinition, formatInlineLiteral, formatPropertyName, isPlainObject } from "./utils.js";
2
+ import { z } from "zod";
3
+ import { SyntaxKind } from "ts-morph";
4
+
5
+ //#region src/commands/pull-v4/environment-generator.ts
6
+ const EnvironmentSettingsSchema = z.looseObject({ credentials: z.record(z.string(), z.unknown()).nullable().optional() });
7
+ const EnvironmentIndexSchema = z.array(z.string());
8
+ function generateEnvironmentSettingsImports(environmentData) {
9
+ const imports = [`import { registerEnvironmentSettings } from '@inkeep/agents-sdk';`];
10
+ if (needsCredentialStoreType(environmentData)) imports.push(`import { CredentialStoreType } from '@inkeep/agents-core';`);
11
+ return imports;
12
+ }
13
+ function generateEnvironmentIndexImports(environments) {
14
+ const result = EnvironmentIndexSchema.safeParse(environments);
15
+ if (!result.success) throw new Error(`Validation failed for environments index:\n${z.prettifyError(result.error)}`);
16
+ const imports = [`import { createEnvironmentSettings } from '@inkeep/agents-sdk';`];
17
+ for (const environmentName of result.data) imports.push(`import { ${environmentName} } from './${environmentName}.env';`);
18
+ return imports;
19
+ }
20
+ function generateEnvironmentSettingsDefinition(environmentName, environmentData) {
21
+ const environmentNameResult = z.string().nonempty().safeParse(environmentName);
22
+ if (!environmentNameResult.success) throw new Error(`Validation failed for environment name:\n${z.prettifyError(environmentNameResult.error)}`);
23
+ const result = EnvironmentSettingsSchema.safeParse(environmentData);
24
+ if (!result.success) throw new Error(`Validation failed for environment settings:\n${z.prettifyError(result.error)}`);
25
+ const parsed = result.data;
26
+ const { sourceFile, configObject } = createFactoryDefinition({
27
+ importName: "registerEnvironmentSettings",
28
+ variableName: environmentNameResult.data
29
+ });
30
+ const hasCredentialStoreType = needsCredentialStoreType(parsed);
31
+ if (hasCredentialStoreType) sourceFile.addImportDeclaration({
32
+ namedImports: ["CredentialStoreType"],
33
+ moduleSpecifier: "@inkeep/agents-core"
34
+ });
35
+ addCredentialsProperty(configObject, parsed.credentials, hasCredentialStoreType);
36
+ return sourceFile;
37
+ }
38
+ function generateEnvironmentIndexDefinition(environments) {
39
+ const result = EnvironmentIndexSchema.safeParse(environments);
40
+ if (!result.success) throw new Error(`Validation failed for environments index:\n${z.prettifyError(result.error)}`);
41
+ const { sourceFile, configObject } = createFactoryDefinition({
42
+ importName: "createEnvironmentSettings",
43
+ variableName: "envSettings"
44
+ });
45
+ for (const environmentName of result.data) sourceFile.addImportDeclaration({
46
+ namedImports: [environmentName],
47
+ moduleSpecifier: `./${environmentName}.env`
48
+ });
49
+ for (const environmentName of result.data) configObject.addShorthandPropertyAssignment({ name: environmentName });
50
+ return sourceFile;
51
+ }
52
+ function generateEnvironmentSettingsFile(environmentName, environmentData) {
53
+ return generateEnvironmentSettingsDefinition(environmentName, environmentData);
54
+ }
55
+ function generateEnvironmentIndexFile(environments) {
56
+ return generateEnvironmentIndexDefinition(environments);
57
+ }
58
+ function needsCredentialStoreType(environmentData) {
59
+ if (!isPlainObject(environmentData.credentials)) return false;
60
+ return Object.values(environmentData.credentials).some((credential) => isPlainObject(credential) && typeof credential.type === "string" && [
61
+ "memory",
62
+ "env",
63
+ "keychain"
64
+ ].includes(credential.type));
65
+ }
66
+ function addCredentialsProperty(configObject, credentials, hasCredentialStoreType) {
67
+ if (!isPlainObject(credentials) || !Object.keys(credentials).length) {
68
+ configObject.addPropertyAssignment({
69
+ name: "credentials",
70
+ initializer: "{}"
71
+ });
72
+ return;
73
+ }
74
+ const credentialsObject = configObject.addPropertyAssignment({
75
+ name: "credentials",
76
+ initializer: "{}"
77
+ }).getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
78
+ for (const [credentialKey, credentialValue] of Object.entries(credentials)) {
79
+ if (!isPlainObject(credentialValue)) continue;
80
+ writeCredential(credentialsObject.addPropertyAssignment({
81
+ name: formatPropertyName(credentialKey),
82
+ initializer: "{}"
83
+ }).getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression), credentialValue, hasCredentialStoreType);
84
+ }
85
+ }
86
+ function writeCredential(credentialObject, credentialData, hasCredentialStoreType) {
87
+ if (credentialData.id !== void 0) addStringProperty(credentialObject, "id", credentialData.id);
88
+ if (credentialData.name !== void 0 && credentialData.name !== null) addStringProperty(credentialObject, "name", credentialData.name);
89
+ if (credentialData.type !== void 0) if (hasCredentialStoreType && typeof credentialData.type === "string" && [
90
+ "memory",
91
+ "env",
92
+ "keychain"
93
+ ].includes(credentialData.type)) credentialObject.addPropertyAssignment({
94
+ name: "type",
95
+ initializer: `CredentialStoreType.${credentialData.type}`
96
+ });
97
+ else credentialObject.addPropertyAssignment({
98
+ name: "type",
99
+ initializer: formatInlineLiteral(credentialData.type)
100
+ });
101
+ if (credentialData.credentialStoreId !== void 0) addStringProperty(credentialObject, "credentialStoreId", credentialData.credentialStoreId);
102
+ if (credentialData.description !== void 0 && credentialData.description !== null) addStringProperty(credentialObject, "description", credentialData.description);
103
+ addRetrievalParams(credentialObject, credentialData.retrievalParams);
104
+ }
105
+ function addRetrievalParams(credentialObject, retrievalParams) {
106
+ if (!isPlainObject(retrievalParams)) return;
107
+ const retrievalParamsProperty = credentialObject.addPropertyAssignment({
108
+ name: "retrievalParams",
109
+ initializer: "{}"
110
+ });
111
+ const retrievalParamsObject = retrievalParamsProperty.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
112
+ for (const [key, value] of Object.entries(retrievalParams)) {
113
+ if (value === void 0 || value === null) continue;
114
+ retrievalParamsObject.addPropertyAssignment({
115
+ name: formatPropertyName(key),
116
+ initializer: formatInlineLiteral(value)
117
+ });
118
+ }
119
+ if (!retrievalParamsObject.getProperties().length) retrievalParamsProperty.remove();
120
+ }
121
+
122
+ //#endregion
123
+ export { generateEnvironmentIndexDefinition, generateEnvironmentIndexFile, generateEnvironmentIndexImports, generateEnvironmentSettingsDefinition, generateEnvironmentSettingsFile, generateEnvironmentSettingsImports };
@@ -0,0 +1,56 @@
1
+ import { addStringProperty, createFactoryDefinition, toCamelCase } from "./utils.js";
2
+ import { z } from "zod";
3
+ import { SyntaxKind } from "ts-morph";
4
+
5
+ //#region src/commands/pull-v4/external-agent-generator.ts
6
+ const ExternalAgentSchema = z.looseObject({
7
+ externalAgentId: z.string().nonempty(),
8
+ name: z.string().nonempty(),
9
+ description: z.string().nullable().optional(),
10
+ baseUrl: z.string().nonempty(),
11
+ credentialReference: z.union([z.string(), z.looseObject({
12
+ id: z.string().optional(),
13
+ name: z.string().optional(),
14
+ description: z.string().optional()
15
+ })]).optional()
16
+ });
17
+ function generateExternalAgentDefinition(data) {
18
+ const result = ExternalAgentSchema.safeParse(data);
19
+ if (!result.success) throw new Error(`Validation failed for external agent:\n${z.prettifyError(result.error)}`);
20
+ const parsed = result.data;
21
+ const { sourceFile, configObject } = createFactoryDefinition({
22
+ importName: "externalAgent",
23
+ variableName: toCamelCase(parsed.externalAgentId)
24
+ });
25
+ if (typeof parsed.credentialReference === "string") sourceFile.addImportDeclaration({
26
+ namedImports: [toCamelCase(parsed.credentialReference)],
27
+ moduleSpecifier: `../credentials/${parsed.credentialReference}`
28
+ });
29
+ writeExternalAgentConfig(configObject, parsed);
30
+ return sourceFile;
31
+ }
32
+ function writeExternalAgentConfig(configObject, data) {
33
+ addStringProperty(configObject, "id", data.externalAgentId);
34
+ addStringProperty(configObject, "name", data.name);
35
+ if (data.description !== null && data.description !== void 0) addStringProperty(configObject, "description", data.description);
36
+ else addStringProperty(configObject, "description", `External agent ${data.externalAgentId}`);
37
+ addStringProperty(configObject, "baseUrl", data.baseUrl);
38
+ if (typeof data.credentialReference === "string") {
39
+ configObject.addPropertyAssignment({
40
+ name: "credentialReference",
41
+ initializer: toCamelCase(data.credentialReference)
42
+ });
43
+ return;
44
+ }
45
+ if (!data.credentialReference) return;
46
+ const credentialReferenceObject = configObject.addPropertyAssignment({
47
+ name: "credentialReference",
48
+ initializer: "{}"
49
+ }).getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
50
+ if (data.credentialReference.id !== void 0) addStringProperty(credentialReferenceObject, "id", data.credentialReference.id);
51
+ if (data.credentialReference.name !== void 0) addStringProperty(credentialReferenceObject, "name", data.credentialReference.name);
52
+ if (data.credentialReference.description !== void 0) addStringProperty(credentialReferenceObject, "description", data.credentialReference.description);
53
+ }
54
+
55
+ //#endregion
56
+ export { generateExternalAgentDefinition };
@@ -0,0 +1,48 @@
1
+ import { addValueToObject, createFactoryDefinition, toCamelCase } from "./utils.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/commands/pull-v4/function-tool-generator.ts
5
+ const FunctionToolSchema = z.looseObject({
6
+ functionToolId: z.string().nonempty(),
7
+ name: z.string().nonempty(),
8
+ description: z.string().optional(),
9
+ inputSchema: z.unknown().optional(),
10
+ schema: z.unknown().optional(),
11
+ executeCode: z.string().optional(),
12
+ execute: z.string().optional()
13
+ }).superRefine((value, context) => {
14
+ if (value.inputSchema === void 0 && value.schema === void 0) context.addIssue({
15
+ code: "custom",
16
+ message: "inputSchema is required",
17
+ path: ["inputSchema"]
18
+ });
19
+ if (value.executeCode === void 0 && value.execute === void 0) context.addIssue({
20
+ code: "custom",
21
+ message: "executeCode is required",
22
+ path: ["executeCode"]
23
+ });
24
+ });
25
+ function generateFunctionToolDefinition(data) {
26
+ const result = FunctionToolSchema.safeParse(data);
27
+ if (!result.success) throw new Error(`Validation failed for function tool:\n${z.prettifyError(result.error)}`);
28
+ const parsed = result.data;
29
+ const { sourceFile, configObject } = createFactoryDefinition({
30
+ importName: "functionTool",
31
+ variableName: toCamelCase(parsed.functionToolId)
32
+ });
33
+ writeFunctionToolConfig(configObject, parsed);
34
+ return sourceFile;
35
+ }
36
+ function writeFunctionToolConfig(configObject, { functionToolId, executeCode, inputSchema, schema, ...rest }) {
37
+ for (const [k, v] of Object.entries({
38
+ ...rest,
39
+ inputSchema: inputSchema ?? schema
40
+ })) addValueToObject(configObject, k, v);
41
+ if (executeCode) configObject.addPropertyAssignment({
42
+ name: "execute",
43
+ initializer: executeCode
44
+ });
45
+ }
46
+
47
+ //#endregion
48
+ export { generateFunctionToolDefinition };
@@ -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 "../../pull-v3/utils/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-v3 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("../../pull-v3/components/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 };