@inkeep/agents-cli 0.62.0 → 0.62.2

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.
@@ -1,6 +1,6 @@
1
1
  //#region package.json
2
2
  var name = "@inkeep/agents-cli";
3
- var version = "0.62.0";
3
+ var version = "0.62.2";
4
4
 
5
5
  //#endregion
6
6
  export { name, version };
@@ -3,8 +3,8 @@ import { initializeCommand } from "../../../utils/cli-pipeline.js";
3
3
  import { performBackgroundVersionCheck } from "../../../utils/background-version-check.js";
4
4
  import { loadProject } from "../../../utils/project-loader.js";
5
5
  import { readProjectState, writeProjectState } from "../../../utils/state.js";
6
+ import { withLocalStateBranch } from "../../../utils/temp-branch.js";
6
7
  import { introspectGenerate } from "../introspect-generator.js";
7
- import { getTempBranchSuffix } from "@inkeep/agents-core";
8
8
  import { join, resolve } from "node:path";
9
9
  import * as p from "@clack/prompts";
10
10
  import { existsSync, mkdirSync } from "node:fs";
@@ -152,48 +152,44 @@ async function pullV4Command(options) {
152
152
  if (options.debug && currentMainHash) console.log(styleText("gray", ` Current main hash: ${currentMainHash}`));
153
153
  let remoteProject;
154
154
  if (localProjectForId && lastPulledHash) {
155
- const tempBranchName = getTempBranchSuffix("cli-pull");
156
- try {
157
- await apiClient.createBranch(projectId, {
158
- name: tempBranchName,
159
- fromCommit: lastPulledHash
160
- });
161
- const localProjectDefinition = await localProjectForId.getFullDefinition();
162
- await apiClient.pushFullProject(projectId, tempBranchName, localProjectDefinition);
163
- const preview = await apiClient.mergePreview(projectId, {
164
- sourceBranch: "main",
165
- targetBranch: tempBranchName
166
- });
167
- if (preview.hasConflicts) {
168
- const { resolveConflictsInteractive } = await import("../merge-conflicts.js");
169
- const resolutions = await resolveConflictsInteractive(preview.conflicts, options);
170
- if (resolutions === null) {
171
- console.log(styleText("yellow", "Pull cancelled"));
172
- return;
173
- }
174
- await apiClient.mergeExecute(projectId, {
155
+ const localProjectDefinition = await localProjectForId.getFullDefinition();
156
+ remoteProject = await withLocalStateBranch({
157
+ apiClient,
158
+ projectId,
159
+ fromCommit: lastPulledHash,
160
+ localDefinition: localProjectDefinition,
161
+ branchPrefix: "cli-pull",
162
+ fn: async (tempBranchName) => {
163
+ const preview = await apiClient.mergePreview(projectId, {
164
+ sourceBranch: "main",
165
+ targetBranch: tempBranchName
166
+ });
167
+ if (preview.hasConflicts) {
168
+ const { resolveConflictsInteractive } = await import("../merge-conflicts.js");
169
+ const resolutions = await resolveConflictsInteractive(preview.conflicts, options);
170
+ if (resolutions === null) {
171
+ console.log(styleText("yellow", "Pull cancelled"));
172
+ return;
173
+ }
174
+ await apiClient.mergeExecute(projectId, {
175
+ sourceBranch: "main",
176
+ targetBranch: tempBranchName,
177
+ sourceHash: preview.sourceHash,
178
+ targetHash: preview.targetHash,
179
+ resolutions,
180
+ message: "CLI pull: merge main into local state"
181
+ });
182
+ } else await apiClient.mergeExecute(projectId, {
175
183
  sourceBranch: "main",
176
184
  targetBranch: tempBranchName,
177
185
  sourceHash: preview.sourceHash,
178
186
  targetHash: preview.targetHash,
179
- resolutions,
180
187
  message: "CLI pull: merge main into local state"
181
188
  });
182
- } else await apiClient.mergeExecute(projectId, {
183
- sourceBranch: "main",
184
- targetBranch: tempBranchName,
185
- sourceHash: preview.sourceHash,
186
- targetHash: preview.targetHash,
187
- message: "CLI pull: merge main into local state"
188
- });
189
- remoteProject = await apiClient.getFullProject(projectId, tempBranchName);
190
- } finally {
191
- try {
192
- await apiClient.deleteBranch(projectId, tempBranchName, true);
193
- } catch (cleanupError) {
194
- if (options.debug) console.log(styleText("gray", ` Warning: Could not delete temp branch ${tempBranchName}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`));
189
+ return await apiClient.getFullProject(projectId, tempBranchName);
195
190
  }
196
- }
191
+ });
192
+ if (!remoteProject) return;
197
193
  } else remoteProject = await apiClient.getFullProject(projectId);
198
194
  if (options.debug && remoteProject.functions) {
199
195
  console.log(styleText("gray", " 📋 Project-level functions from API:"), Object.keys(remoteProject.functions));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/commands/pull-v4/introspect/index.ts"],"sourcesContent":["/**\n * Pull v3 - Clean, efficient project generation\n *\n * Step 1: Validate and compile existing code\n * Step 2: Compare project with DB to detect ALL changes\n * Step 3: Classify changes as new vs modified components\n * Step 4: Generate new components deterministically\n * Step 5: Use LLM to correct modified components\n */\n\nimport { EventEmitter } from 'node:events';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { styleText } from 'node:util';\nimport * as p from '@clack/prompts';\nimport { type FullProjectDefinition, getTempBranchSuffix } from '@inkeep/agents-core';\n\n// Increase max listeners to prevent warnings during complex CLI flows\n// This is needed because @clack/prompts + multiple interactive prompts + spinners all add listeners\nEventEmitter.defaultMaxListeners = 20;\n\nimport { ManagementApiClient } from '../../../api';\nimport { performBackgroundVersionCheck } from '../../../utils/background-version-check';\nimport { initializeCommand } from '../../../utils/cli-pipeline';\nimport { loadProject } from '../../../utils/project-loader';\nimport { readProjectState, writeProjectState } from '../../../utils/state';\nimport { introspectGenerate } from '../introspect-generator';\n\nexport interface PullV3Options {\n project?: string;\n config?: string;\n profile?: string;\n env?: string;\n json?: boolean;\n debug?: boolean;\n verbose?: boolean;\n force?: boolean;\n introspect?: boolean;\n all?: boolean;\n tag?: string;\n quiet?: boolean;\n conflictStrategy?: 'ours' | 'theirs';\n /** Internal: used for batch operations to return results instead of calling process.exit() */\n _batchMode?: boolean;\n}\n\nexport interface PullResult {\n success: boolean;\n skipped?: boolean;\n upToDate?: boolean;\n error?: string;\n}\n\ninterface BatchPullResult {\n projectId: string;\n projectName?: string;\n targetDir: string;\n success: boolean;\n error?: string;\n}\n\ninterface ProjectPaths {\n projectRoot: string;\n agentsDir: string;\n toolsDir: string;\n dataComponentsDir: string;\n artifactComponentsDir: string;\n statusComponentsDir: string;\n environmentsDir: string;\n credentialsDir: string;\n contextConfigsDir: string;\n externalAgentsDir: string;\n skillsDir: string;\n}\n\n/**\n * Create project directory structure\n */\nexport function createProjectStructure(projectRoot: string): ProjectPaths {\n mkdirSync(projectRoot, { recursive: true });\n return {\n projectRoot,\n agentsDir: join(projectRoot, 'agents'),\n toolsDir: join(projectRoot, 'tools'),\n dataComponentsDir: join(projectRoot, 'data-components'),\n artifactComponentsDir: join(projectRoot, 'artifact-components'),\n statusComponentsDir: join(projectRoot, 'status-components'),\n environmentsDir: join(projectRoot, 'environments'),\n credentialsDir: join(projectRoot, 'credentials'),\n contextConfigsDir: join(projectRoot, 'context-configs'),\n externalAgentsDir: join(projectRoot, 'external-agents'),\n skillsDir: join(projectRoot, 'skills'),\n };\n}\n\n/**\n * Enrich canDelegateTo references with component type information\n */\nexport function enrichCanDelegateToWithTypes(project: FullProjectDefinition): void {\n const { agents } = project;\n // Get all available component IDs by type\n const agentsIdSet = new Set(Object.keys(agents));\n const subAgentsIdSet = new Set(\n Object.values(agents).flatMap((agentData) => Object.keys(agentData.subAgents))\n );\n const externalAgentsIdSet = new Set(\n project.externalAgents ? Object.keys(project.externalAgents) : []\n );\n\n // Function to enrich a canDelegateTo array\n\n function enrichCanDelegateToArray(canDelegateTo: unknown[]): unknown[] {\n return canDelegateTo.map((item) => {\n // Skip if it's already an object (already has type info)\n if (typeof item !== 'string') return item;\n if (agentsIdSet.has(item)) return { agentId: item };\n if (subAgentsIdSet.has(item)) return { subAgentId: item };\n if (externalAgentsIdSet.has(item)) return { externalAgentId: item };\n return item;\n });\n }\n\n // Process all agents\n for (const { subAgents } of Object.values(project.agents)) {\n // Process subAgents within agents\n for (const subAgentData of Object.values(subAgents)) {\n if (Array.isArray(subAgentData.canDelegateTo)) {\n // @ts-expect-error\n subAgentData.canDelegateTo = enrichCanDelegateToArray(subAgentData.canDelegateTo);\n }\n }\n }\n}\n\n/**\n * Main pull v4 command\n * @returns PullResult when in batch mode, otherwise void (exits process)\n */\nexport async function pullV4Command(options: PullV3Options): Promise<PullResult | undefined> {\n // Handle --all flag for batch operations\n if (options.all) {\n await pullAllProjects(options);\n return;\n }\n\n const batchMode = options._batchMode ?? false;\n\n // Suppress SDK logging for cleaner output\n const originalLogLevel = process.env.LOG_LEVEL;\n process.env.LOG_LEVEL = 'silent';\n\n const restoreLogLevel = () => {\n if (originalLogLevel !== undefined) {\n process.env.LOG_LEVEL = originalLogLevel;\n } else {\n delete process.env.LOG_LEVEL;\n }\n };\n\n // Background version check (skip in batch mode - already done)\n if (!batchMode) {\n performBackgroundVersionCheck();\n }\n\n console.log(styleText('blue', '\\nInkeep Pull:'));\n if (options.introspect) {\n console.log(\n styleText('gray', ' Introspect mode • Complete regeneration • No comparison needed')\n );\n } else {\n console.log(styleText('gray', ' Smart comparison • Detect all changes • Targeted updates'));\n }\n\n try {\n // Step 1: Load configuration (same as push command)\n const { config, isCI } = await initializeCommand({\n configPath: options.config,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: true,\n spinnerText: 'Loading configuration...',\n logConfig: true,\n quiet: options.quiet,\n });\n let projectDir: string;\n let projectId: string;\n let localProjectForId: any = null;\n\n const currentDir = process.cwd();\n const hasIndexInCurrent = existsSync(join(currentDir, 'index.ts'));\n\n if (hasIndexInCurrent) {\n // We're in a project directory\n projectDir = currentDir;\n\n try {\n localProjectForId = await loadProject(projectDir);\n const localProjectId = localProjectForId.getId();\n\n if (options.project) {\n // Validate that --project matches local project ID\n if (localProjectId !== options.project) {\n console.error(\n styleText(\n 'red',\n `Local project ID \"${localProjectId}\" doesn't match --project \"${options.project}\"`\n )\n );\n console.error(\n styleText(\n 'yellow',\n 'Either remove --project flag or ensure it matches the local project ID'\n )\n );\n if (batchMode) {\n return { success: false, error: 'Project ID mismatch' };\n }\n process.exit(1);\n }\n }\n\n projectId = localProjectId;\n console.log(styleText('green', `◆ Using local project: ${projectId}`));\n } catch (error) {\n throw new Error(\n `Could not load local project: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n } else {\n // No index.ts in current directory\n if (!options.project) {\n console.error(\n styleText(\n 'yellow',\n 'Please run this command from a directory containing index.ts or use --project <project-id>'\n )\n );\n if (batchMode) {\n return { success: false, error: 'No index.ts found and no --project specified' };\n }\n process.exit(1);\n }\n\n // Try --project as directory path first\n const projectPath = resolve(currentDir, options.project);\n const hasIndexInPath = existsSync(join(projectPath, 'index.ts'));\n\n if (hasIndexInPath) {\n // --project is a valid directory path\n projectDir = projectPath;\n try {\n localProjectForId = await loadProject(projectDir);\n projectId = localProjectForId.getId();\n console.log(styleText('green', `◆ Using project from path: ${projectId}`));\n } catch (error) {\n throw new Error(\n `Could not load project from ${projectPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n } else {\n // Treat --project as project ID, create subdirectory\n projectId = options.project;\n projectDir = join(currentDir, projectId);\n console.log(styleText('green', `◆ Creating new project directory: ${projectDir}`));\n }\n }\n\n const existingState = readProjectState(projectId);\n const lastPulledHash = existingState?.lastPulledHash;\n\n if (options.debug && lastPulledHash) {\n console.log(styleText('gray', ` Last pulled hash: ${lastPulledHash}`));\n }\n\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n projectId,\n isCI,\n config.agentsApiKey\n );\n\n let currentMainHash: string | undefined;\n try {\n const mainBranch = await apiClient.getBranch(projectId, 'main');\n currentMainHash = mainBranch.hash;\n } catch (error) {\n if (options.debug) {\n console.log(\n styleText(\n 'gray',\n ` Could not fetch main branch hash: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n }\n // Non-fatal: if we can't get the hash, fall through to direct pull\n }\n\n if (options.debug && currentMainHash) {\n console.log(styleText('gray', ` Current main hash: ${currentMainHash}`));\n }\n\n let remoteProject: Awaited<ReturnType<typeof apiClient.getFullProject>> | undefined;\n\n if (localProjectForId && lastPulledHash) {\n const tempBranchName = getTempBranchSuffix('cli-pull');\n\n try {\n await apiClient.createBranch(projectId, {\n name: tempBranchName,\n fromCommit: lastPulledHash,\n });\n\n const localProjectDefinition = await localProjectForId.getFullDefinition();\n await apiClient.pushFullProject(projectId, tempBranchName, localProjectDefinition);\n\n // Merge main INTO temp branch so the temp branch gets a reconciled result\n // (main's changes + user's local changes). We then pull from the temp branch.\n // We must NOT merge temp into main — that would push local edits to main.\n const preview = await apiClient.mergePreview(projectId, {\n sourceBranch: 'main',\n targetBranch: tempBranchName,\n });\n\n if (preview.hasConflicts) {\n const { resolveConflictsInteractive } = await import('../merge-conflicts');\n const resolutions = await resolveConflictsInteractive(preview.conflicts, options);\n\n if (resolutions === null) {\n console.log(styleText('yellow', 'Pull cancelled'));\n return;\n }\n\n await apiClient.mergeExecute(projectId, {\n sourceBranch: 'main',\n targetBranch: tempBranchName,\n sourceHash: preview.sourceHash,\n targetHash: preview.targetHash,\n resolutions,\n message: 'CLI pull: merge main into local state',\n });\n } else {\n await apiClient.mergeExecute(projectId, {\n sourceBranch: 'main',\n targetBranch: tempBranchName,\n sourceHash: preview.sourceHash,\n targetHash: preview.targetHash,\n message: 'CLI pull: merge main into local state',\n });\n }\n // Fetch the reconciled project from the temp branch before cleanup\n remoteProject = await apiClient.getFullProject(projectId, tempBranchName);\n } finally {\n try {\n await apiClient.deleteBranch(projectId, tempBranchName, true);\n } catch (cleanupError) {\n if (options.debug) {\n console.log(\n styleText(\n 'gray',\n ` Warning: Could not delete temp branch ${tempBranchName}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`\n )\n );\n }\n }\n }\n } else {\n // Todo: we can probably just exit here because there is nothing new to pull\n remoteProject = await apiClient.getFullProject(projectId);\n }\n\n if (options.debug && remoteProject.functions) {\n console.log(\n styleText('gray', ' 📋 Project-level functions from API:'),\n Object.keys(remoteProject.functions)\n );\n Object.entries(remoteProject.functions).forEach(([id, data]: [string, any]) => {\n console.log(\n styleText(\n 'gray',\n ` ${id}: has name=${!!data.name}, has description=${!!data.description}`\n )\n );\n });\n }\n\n // Normalize remote project (same as pull-v2 - hoist agent-level functionTools)\n if (remoteProject.agents) {\n for (const [agentId, agentData] of Object.entries(remoteProject.agents) as any[]) {\n if (agentData.functionTools) {\n remoteProject.functionTools = remoteProject.functionTools || {};\n Object.assign(remoteProject.functionTools, agentData.functionTools);\n if (options.debug) {\n console.log(\n styleText(\n 'gray',\n ` Hoisted functionTools from agent ${agentId}: ${Object.keys(agentData.functionTools).join(', ')}`\n )\n );\n }\n }\n if (agentData.functions) {\n remoteProject.functions ||= {};\n const { functions } = remoteProject;\n // Only hoist agent functions if project-level functions don't already exist (clean function data)\n Object.entries(agentData.functions).forEach(([funcId, funcData]: [string, any]) => {\n // Clean function data - remove functionTool metadata that shouldn't be in functions collection\n functions[funcId] ||= {\n id: funcData.id,\n inputSchema: funcData.inputSchema,\n executeCode: funcData.executeCode,\n dependencies: funcData.dependencies,\n createdAt: '',\n updatedAt: '',\n };\n });\n }\n }\n }\n\n // Filter out project-level tools from individual agents\n // The API includes project-level tools in each agent's tools field, but our generated\n // code structure keeps tools separate and imports them via canUse relationships\n if (remoteProject.agents && remoteProject.tools) {\n const projectToolIds = Object.keys(remoteProject.tools);\n\n for (const agentData of Object.values(remoteProject.agents) as any[]) {\n if (agentData.tools) {\n // Filter out any tools that are defined at project level\n const agentSpecificTools = Object.fromEntries(\n Object.entries(agentData.tools).filter(([toolId]) => !projectToolIds.includes(toolId))\n );\n\n // Only keep tools field if there are agent-specific tools remaining\n if (Object.keys(agentSpecificTools).length > 0) {\n agentData.tools = agentSpecificTools;\n } else {\n // Remove the tools field entirely if all tools were project-level\n delete agentData.tools;\n }\n }\n }\n }\n\n // Enrich canDelegateTo references with component type information\n // @ts-expect-error -- fixme Types of property `models` are incompatible.\n enrichCanDelegateToWithTypes(remoteProject);\n\n console.log(styleText('green', '◆ Project data fetched'));\n\n if (options.json) {\n console.log(JSON.stringify(remoteProject, null, 2));\n restoreLogLevel();\n return;\n }\n\n // Step 5: Set up project structure\n const paths = createProjectStructure(projectDir);\n\n await generateProjectSkillsIfPresent(remoteProject, paths.skillsDir);\n\n console.log(styleText('gray', 'Generating files...'));\n await introspectGenerate({\n // @ts-expect-error -- ignore Types of property 'models' are incompatible.\n project: remoteProject,\n paths,\n debug: options.debug,\n });\n console.log(styleText('green', '◆ All files generated'));\n\n try {\n const mainBranch = await apiClient.getBranch(projectId, 'main');\n writeProjectState(projectId, mainBranch.hash);\n } catch (error) {\n console.warn(\n styleText(\n 'yellow',\n `Warning: Could not save pull state: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n console.warn(styleText('yellow', 'Future pulls may re-prompt for conflict resolution.'));\n }\n\n console.log(styleText('green', '\\nProject synced successfully!'));\n console.log(styleText('gray', ` Location: ${paths.projectRoot}`));\n console.log(styleText('gray', ` Environment: ${options.env || 'development'}`));\n console.log(\n styleText(\n 'yellow',\n '⚠️ If you encounter broken code after running `inkeep pull`, please report it at https://github.com/inkeep/agents/issues.'\n )\n );\n\n restoreLogLevel();\n if (batchMode) {\n return { success: true };\n }\n process.exit(0);\n } catch (error) {\n const message = error instanceof Error ? error.stack : String(error);\n console.error(styleText('red', `\\nError: ${message}`));\n if (options.debug && error instanceof Error) {\n console.error(styleText('red', error.stack || ''));\n }\n restoreLogLevel();\n if (batchMode) {\n return { success: false, error: message };\n }\n process.exit(1);\n }\n}\n\n/**\n * Pull all projects for the current tenant\n * Uses smart comparison with LLM merging for existing projects, introspect for new projects\n */\nasync function pullAllProjects(options: PullV3Options): Promise<void> {\n console.log(styleText('blue', '\\n🔄 Batch Pull: Sequential processing with smart comparison\\n'));\n console.log(\n styleText(\n 'gray',\n ' • Existing projects: Smart comparison + AST merging + confirmation prompts'\n )\n );\n console.log(styleText('gray', ' • New projects: Fresh generation with introspect mode\\n'));\n\n // Background version check (only once for batch)\n performBackgroundVersionCheck();\n\n // Load configuration first\n const { config, isCI } = await initializeCommand({\n configPath: options.config,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: true,\n spinnerText: 'Loading configuration...',\n logConfig: true,\n quiet: options.quiet,\n });\n\n const s = p.spinner();\n\n try {\n // Fetch all projects from the API\n s.start('Fetching project list from API...');\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n undefined,\n isCI,\n config.agentsApiKey\n );\n\n const projects = await apiClient.listAllProjects();\n s.stop(`Found ${projects.length} project(s)`);\n\n if (!projects.length) {\n console.log(styleText('yellow', 'No projects found for this tenant.'));\n process.exit(0);\n }\n\n // Categorize projects\n const existingProjects: typeof projects = [];\n const newProjects: typeof projects = [];\n\n for (const project of projects) {\n const targetDir = join(process.cwd(), project.id);\n if (existsSync(join(targetDir, 'index.ts'))) {\n existingProjects.push(project);\n } else {\n newProjects.push(project);\n }\n }\n\n console.log(styleText('gray', '\\nProjects to pull:\\n'));\n if (existingProjects.length > 0) {\n console.log(styleText('cyan', ' Existing (smart comparison):'));\n for (const project of existingProjects) {\n console.log(styleText('gray', ` • ${project.name || project.id} (${project.id})`));\n }\n }\n if (newProjects.length > 0) {\n console.log(styleText('cyan', ' New (introspect):'));\n for (const project of newProjects) {\n console.log(styleText('gray', ` • ${project.name || project.id} (${project.id})`));\n }\n }\n console.log();\n\n const results: BatchPullResult[] = [];\n const total = projects.length;\n\n for (let i = 0; i < projects.length; i++) {\n const project = projects[i];\n const progress = `[${i + 1}/${total}]`;\n\n console.log(styleText('cyan', `\\n${'─'.repeat(60)}`));\n console.log(styleText('cyan', `${progress} Pulling ${project.name || project.id}...`));\n\n const result = await pullSingleProject(project.id, project.name, options, config, isCI);\n results.push(result);\n\n if (result.success) {\n console.log(\n styleText(\n 'green',\n `\\n ✓ ${result.projectName || result.projectId} → ${result.targetDir}`\n )\n );\n } else {\n console.log(\n styleText('red', `\\n ✗ ${result.projectName || result.projectId}: ${result.error}`)\n );\n }\n }\n\n // Print summary\n const succeeded = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n console.log(styleText('cyan', `\\n${'═'.repeat(60)}`));\n console.log(styleText('cyan', '📊 Batch Pull Summary:'));\n console.log(styleText('green', ` ✓ Succeeded: ${succeeded}`));\n if (failed > 0) {\n console.log(styleText('red', ` ✗ Failed: ${failed}`));\n\n console.log(styleText('red', '\\nFailed projects:'));\n for (const result of results) {\n if (!result.success) {\n console.log(styleText('red', ` • ${result.projectId}: ${result.error}`));\n }\n }\n }\n\n process.exit(failed > 0 ? 1 : 0);\n } catch (error) {\n s.stop();\n console.error(\n styleText('red', `\\nError: ${error instanceof Error ? error.message : String(error)}`)\n );\n process.exit(1);\n }\n}\n\n/**\n * Pull a single project (used by batch operations)\n * Uses smart comparison flow for existing projects, introspect for new projects\n */\nexport async function pullSingleProject(\n projectId: string,\n projectName: string | undefined,\n options: PullV3Options,\n config: any,\n isCI?: boolean\n): Promise<BatchPullResult> {\n const targetDir = join(process.cwd(), projectId);\n const hasExistingProject = existsSync(join(targetDir, 'index.ts'));\n\n try {\n if (hasExistingProject) {\n // Project exists locally - use smart comparison flow with LLM merging and user prompts\n console.log(styleText('gray', ` 📂 Existing project found - using smart comparison mode`));\n\n // Save current directory and change to project directory\n const originalDir = process.cwd();\n process.chdir(targetDir);\n\n try {\n // Call the main pull command in batch mode (returns results instead of exiting)\n const result = await pullV4Command({\n ...options,\n project: projectId,\n all: false, // Don't recurse into batch mode\n _batchMode: true,\n });\n\n // Restore original directory\n process.chdir(originalDir);\n\n if (result && typeof result === 'object') {\n return {\n projectId,\n projectName,\n targetDir,\n success: result.success,\n error: result.error,\n };\n }\n\n return {\n projectId,\n projectName,\n targetDir,\n success: true,\n };\n } catch (error) {\n // Restore original directory even on error\n process.chdir(originalDir);\n throw error;\n }\n }\n console.log(styleText('gray', ' New project'));\n\n // Suppress SDK logging\n const originalLogLevel = process.env.LOG_LEVEL;\n process.env.LOG_LEVEL = 'silent';\n\n const restoreLogLevel = () => {\n if (originalLogLevel !== undefined) {\n process.env.LOG_LEVEL = originalLogLevel;\n } else {\n delete process.env.LOG_LEVEL;\n }\n };\n\n // Fetch project data from API\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n projectId,\n isCI,\n config.agentsApiKey\n );\n\n const remoteProject = await apiClient.getFullProject(projectId);\n // Create project structure\n const paths = createProjectStructure(targetDir);\n await generateProjectSkillsIfPresent(remoteProject, paths.skillsDir);\n\n // Generate all files using introspect mode for new projects\n await introspectGenerate({\n // @ts-expect-error -- ignore Types of property 'models' are incompatible.\n project: remoteProject,\n paths,\n });\n\n restoreLogLevel();\n\n return {\n projectId,\n projectName: projectName || remoteProject.name,\n targetDir,\n success: true,\n };\n } catch (error) {\n return {\n projectId,\n projectName,\n targetDir,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nasync function generateProjectSkillsIfPresent(\n remoteProject: any,\n skillsDir: string\n): Promise<void> {\n const skills = remoteProject.skills ?? {};\n if (!Object.keys(skills).length) {\n return;\n }\n\n const { generateSkills } = await import('../skill');\n await generateSkills(skills, skillsDir);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/commands/pull-v4/introspect/index.ts"],"sourcesContent":["/**\n * Pull v3 - Clean, efficient project generation\n *\n * Step 1: Validate and compile existing code\n * Step 2: Compare project with DB to detect ALL changes\n * Step 3: Classify changes as new vs modified components\n * Step 4: Generate new components deterministically\n * Step 5: Use LLM to correct modified components\n */\n\nimport { EventEmitter } from 'node:events';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { styleText } from 'node:util';\nimport * as p from '@clack/prompts';\nimport type { FullProjectDefinition } from '@inkeep/agents-core';\n\n// Increase max listeners to prevent warnings during complex CLI flows\n// This is needed because @clack/prompts + multiple interactive prompts + spinners all add listeners\nEventEmitter.defaultMaxListeners = 20;\n\nimport { ManagementApiClient } from '../../../api';\nimport { performBackgroundVersionCheck } from '../../../utils/background-version-check';\nimport { initializeCommand } from '../../../utils/cli-pipeline';\nimport { loadProject } from '../../../utils/project-loader';\nimport { readProjectState, writeProjectState } from '../../../utils/state';\nimport { withLocalStateBranch } from '../../../utils/temp-branch';\nimport { introspectGenerate } from '../introspect-generator';\n\nexport interface PullV3Options {\n project?: string;\n config?: string;\n profile?: string;\n env?: string;\n json?: boolean;\n debug?: boolean;\n verbose?: boolean;\n force?: boolean;\n introspect?: boolean;\n all?: boolean;\n tag?: string;\n quiet?: boolean;\n conflictStrategy?: 'ours' | 'theirs';\n /** Internal: used for batch operations to return results instead of calling process.exit() */\n _batchMode?: boolean;\n}\n\nexport interface PullResult {\n success: boolean;\n skipped?: boolean;\n upToDate?: boolean;\n error?: string;\n}\n\ninterface BatchPullResult {\n projectId: string;\n projectName?: string;\n targetDir: string;\n success: boolean;\n error?: string;\n}\n\ninterface ProjectPaths {\n projectRoot: string;\n agentsDir: string;\n toolsDir: string;\n dataComponentsDir: string;\n artifactComponentsDir: string;\n statusComponentsDir: string;\n environmentsDir: string;\n credentialsDir: string;\n contextConfigsDir: string;\n externalAgentsDir: string;\n skillsDir: string;\n}\n\n/**\n * Create project directory structure\n */\nexport function createProjectStructure(projectRoot: string): ProjectPaths {\n mkdirSync(projectRoot, { recursive: true });\n return {\n projectRoot,\n agentsDir: join(projectRoot, 'agents'),\n toolsDir: join(projectRoot, 'tools'),\n dataComponentsDir: join(projectRoot, 'data-components'),\n artifactComponentsDir: join(projectRoot, 'artifact-components'),\n statusComponentsDir: join(projectRoot, 'status-components'),\n environmentsDir: join(projectRoot, 'environments'),\n credentialsDir: join(projectRoot, 'credentials'),\n contextConfigsDir: join(projectRoot, 'context-configs'),\n externalAgentsDir: join(projectRoot, 'external-agents'),\n skillsDir: join(projectRoot, 'skills'),\n };\n}\n\n/**\n * Enrich canDelegateTo references with component type information\n */\nexport function enrichCanDelegateToWithTypes(project: FullProjectDefinition): void {\n const { agents } = project;\n // Get all available component IDs by type\n const agentsIdSet = new Set(Object.keys(agents));\n const subAgentsIdSet = new Set(\n Object.values(agents).flatMap((agentData) => Object.keys(agentData.subAgents))\n );\n const externalAgentsIdSet = new Set(\n project.externalAgents ? Object.keys(project.externalAgents) : []\n );\n\n // Function to enrich a canDelegateTo array\n\n function enrichCanDelegateToArray(canDelegateTo: unknown[]): unknown[] {\n return canDelegateTo.map((item) => {\n // Skip if it's already an object (already has type info)\n if (typeof item !== 'string') return item;\n if (agentsIdSet.has(item)) return { agentId: item };\n if (subAgentsIdSet.has(item)) return { subAgentId: item };\n if (externalAgentsIdSet.has(item)) return { externalAgentId: item };\n return item;\n });\n }\n\n // Process all agents\n for (const { subAgents } of Object.values(project.agents)) {\n // Process subAgents within agents\n for (const subAgentData of Object.values(subAgents)) {\n if (Array.isArray(subAgentData.canDelegateTo)) {\n // @ts-expect-error\n subAgentData.canDelegateTo = enrichCanDelegateToArray(subAgentData.canDelegateTo);\n }\n }\n }\n}\n\n/**\n * Main pull v4 command\n * @returns PullResult when in batch mode, otherwise void (exits process)\n */\nexport async function pullV4Command(options: PullV3Options): Promise<PullResult | undefined> {\n // Handle --all flag for batch operations\n if (options.all) {\n await pullAllProjects(options);\n return;\n }\n\n const batchMode = options._batchMode ?? false;\n\n // Suppress SDK logging for cleaner output\n const originalLogLevel = process.env.LOG_LEVEL;\n process.env.LOG_LEVEL = 'silent';\n\n const restoreLogLevel = () => {\n if (originalLogLevel !== undefined) {\n process.env.LOG_LEVEL = originalLogLevel;\n } else {\n delete process.env.LOG_LEVEL;\n }\n };\n\n // Background version check (skip in batch mode - already done)\n if (!batchMode) {\n performBackgroundVersionCheck();\n }\n\n console.log(styleText('blue', '\\nInkeep Pull:'));\n if (options.introspect) {\n console.log(\n styleText('gray', ' Introspect mode • Complete regeneration • No comparison needed')\n );\n } else {\n console.log(styleText('gray', ' Smart comparison • Detect all changes • Targeted updates'));\n }\n\n try {\n // Step 1: Load configuration (same as push command)\n const { config, isCI } = await initializeCommand({\n configPath: options.config,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: true,\n spinnerText: 'Loading configuration...',\n logConfig: true,\n quiet: options.quiet,\n });\n let projectDir: string;\n let projectId: string;\n let localProjectForId: any = null;\n\n const currentDir = process.cwd();\n const hasIndexInCurrent = existsSync(join(currentDir, 'index.ts'));\n\n if (hasIndexInCurrent) {\n // We're in a project directory\n projectDir = currentDir;\n\n try {\n localProjectForId = await loadProject(projectDir);\n const localProjectId = localProjectForId.getId();\n\n if (options.project) {\n // Validate that --project matches local project ID\n if (localProjectId !== options.project) {\n console.error(\n styleText(\n 'red',\n `Local project ID \"${localProjectId}\" doesn't match --project \"${options.project}\"`\n )\n );\n console.error(\n styleText(\n 'yellow',\n 'Either remove --project flag or ensure it matches the local project ID'\n )\n );\n if (batchMode) {\n return { success: false, error: 'Project ID mismatch' };\n }\n process.exit(1);\n }\n }\n\n projectId = localProjectId;\n console.log(styleText('green', `◆ Using local project: ${projectId}`));\n } catch (error) {\n throw new Error(\n `Could not load local project: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n } else {\n // No index.ts in current directory\n if (!options.project) {\n console.error(\n styleText(\n 'yellow',\n 'Please run this command from a directory containing index.ts or use --project <project-id>'\n )\n );\n if (batchMode) {\n return { success: false, error: 'No index.ts found and no --project specified' };\n }\n process.exit(1);\n }\n\n // Try --project as directory path first\n const projectPath = resolve(currentDir, options.project);\n const hasIndexInPath = existsSync(join(projectPath, 'index.ts'));\n\n if (hasIndexInPath) {\n // --project is a valid directory path\n projectDir = projectPath;\n try {\n localProjectForId = await loadProject(projectDir);\n projectId = localProjectForId.getId();\n console.log(styleText('green', `◆ Using project from path: ${projectId}`));\n } catch (error) {\n throw new Error(\n `Could not load project from ${projectPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n } else {\n // Treat --project as project ID, create subdirectory\n projectId = options.project;\n projectDir = join(currentDir, projectId);\n console.log(styleText('green', `◆ Creating new project directory: ${projectDir}`));\n }\n }\n\n const existingState = readProjectState(projectId);\n const lastPulledHash = existingState?.lastPulledHash;\n\n if (options.debug && lastPulledHash) {\n console.log(styleText('gray', ` Last pulled hash: ${lastPulledHash}`));\n }\n\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n projectId,\n isCI,\n config.agentsApiKey\n );\n\n let currentMainHash: string | undefined;\n try {\n const mainBranch = await apiClient.getBranch(projectId, 'main');\n currentMainHash = mainBranch.hash;\n } catch (error) {\n if (options.debug) {\n console.log(\n styleText(\n 'gray',\n ` Could not fetch main branch hash: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n }\n // Non-fatal: if we can't get the hash, fall through to direct pull\n }\n\n if (options.debug && currentMainHash) {\n console.log(styleText('gray', ` Current main hash: ${currentMainHash}`));\n }\n\n let remoteProject: Awaited<ReturnType<typeof apiClient.getFullProject>> | undefined;\n\n if (localProjectForId && lastPulledHash) {\n const localProjectDefinition = await localProjectForId.getFullDefinition();\n\n // Merge main INTO temp branch so the temp branch gets a reconciled result\n // (main's changes + user's local changes). We then pull from the temp branch.\n // We must NOT merge temp into main — that would push local edits to main.\n remoteProject = await withLocalStateBranch({\n apiClient,\n projectId,\n fromCommit: lastPulledHash,\n localDefinition: localProjectDefinition,\n branchPrefix: 'cli-pull',\n fn: async (tempBranchName) => {\n const preview = await apiClient.mergePreview(projectId, {\n sourceBranch: 'main',\n targetBranch: tempBranchName,\n });\n\n if (preview.hasConflicts) {\n const { resolveConflictsInteractive } = await import('../merge-conflicts');\n const resolutions = await resolveConflictsInteractive(preview.conflicts, options);\n\n if (resolutions === null) {\n console.log(styleText('yellow', 'Pull cancelled'));\n return undefined;\n }\n\n await apiClient.mergeExecute(projectId, {\n sourceBranch: 'main',\n targetBranch: tempBranchName,\n sourceHash: preview.sourceHash,\n targetHash: preview.targetHash,\n resolutions,\n message: 'CLI pull: merge main into local state',\n });\n } else {\n await apiClient.mergeExecute(projectId, {\n sourceBranch: 'main',\n targetBranch: tempBranchName,\n sourceHash: preview.sourceHash,\n targetHash: preview.targetHash,\n message: 'CLI pull: merge main into local state',\n });\n }\n\n return await apiClient.getFullProject(projectId, tempBranchName);\n },\n });\n\n if (!remoteProject) {\n return;\n }\n } else {\n // Todo: we can probably just exit here because there is nothing new to pull\n remoteProject = await apiClient.getFullProject(projectId);\n }\n\n if (options.debug && remoteProject.functions) {\n console.log(\n styleText('gray', ' 📋 Project-level functions from API:'),\n Object.keys(remoteProject.functions)\n );\n Object.entries(remoteProject.functions).forEach(([id, data]: [string, any]) => {\n console.log(\n styleText(\n 'gray',\n ` ${id}: has name=${!!data.name}, has description=${!!data.description}`\n )\n );\n });\n }\n\n // Normalize remote project (same as pull-v2 - hoist agent-level functionTools)\n if (remoteProject.agents) {\n for (const [agentId, agentData] of Object.entries(remoteProject.agents) as any[]) {\n if (agentData.functionTools) {\n remoteProject.functionTools = remoteProject.functionTools || {};\n Object.assign(remoteProject.functionTools, agentData.functionTools);\n if (options.debug) {\n console.log(\n styleText(\n 'gray',\n ` Hoisted functionTools from agent ${agentId}: ${Object.keys(agentData.functionTools).join(', ')}`\n )\n );\n }\n }\n if (agentData.functions) {\n remoteProject.functions ||= {};\n const { functions } = remoteProject;\n // Only hoist agent functions if project-level functions don't already exist (clean function data)\n Object.entries(agentData.functions).forEach(([funcId, funcData]: [string, any]) => {\n // Clean function data - remove functionTool metadata that shouldn't be in functions collection\n functions[funcId] ||= {\n id: funcData.id,\n inputSchema: funcData.inputSchema,\n executeCode: funcData.executeCode,\n dependencies: funcData.dependencies,\n createdAt: '',\n updatedAt: '',\n };\n });\n }\n }\n }\n\n // Filter out project-level tools from individual agents\n // The API includes project-level tools in each agent's tools field, but our generated\n // code structure keeps tools separate and imports them via canUse relationships\n if (remoteProject.agents && remoteProject.tools) {\n const projectToolIds = Object.keys(remoteProject.tools);\n\n for (const agentData of Object.values(remoteProject.agents) as any[]) {\n if (agentData.tools) {\n // Filter out any tools that are defined at project level\n const agentSpecificTools = Object.fromEntries(\n Object.entries(agentData.tools).filter(([toolId]) => !projectToolIds.includes(toolId))\n );\n\n // Only keep tools field if there are agent-specific tools remaining\n if (Object.keys(agentSpecificTools).length > 0) {\n agentData.tools = agentSpecificTools;\n } else {\n // Remove the tools field entirely if all tools were project-level\n delete agentData.tools;\n }\n }\n }\n }\n\n // Enrich canDelegateTo references with component type information\n // @ts-expect-error -- fixme Types of property `models` are incompatible.\n enrichCanDelegateToWithTypes(remoteProject);\n\n console.log(styleText('green', '◆ Project data fetched'));\n\n if (options.json) {\n console.log(JSON.stringify(remoteProject, null, 2));\n restoreLogLevel();\n return;\n }\n\n // Step 5: Set up project structure\n const paths = createProjectStructure(projectDir);\n\n await generateProjectSkillsIfPresent(remoteProject, paths.skillsDir);\n\n console.log(styleText('gray', 'Generating files...'));\n await introspectGenerate({\n // @ts-expect-error -- ignore Types of property 'models' are incompatible.\n project: remoteProject,\n paths,\n debug: options.debug,\n });\n console.log(styleText('green', '◆ All files generated'));\n\n try {\n const mainBranch = await apiClient.getBranch(projectId, 'main');\n writeProjectState(projectId, mainBranch.hash);\n } catch (error) {\n console.warn(\n styleText(\n 'yellow',\n `Warning: Could not save pull state: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n console.warn(styleText('yellow', 'Future pulls may re-prompt for conflict resolution.'));\n }\n\n console.log(styleText('green', '\\nProject synced successfully!'));\n console.log(styleText('gray', ` Location: ${paths.projectRoot}`));\n console.log(styleText('gray', ` Environment: ${options.env || 'development'}`));\n console.log(\n styleText(\n 'yellow',\n '⚠️ If you encounter broken code after running `inkeep pull`, please report it at https://github.com/inkeep/agents/issues.'\n )\n );\n\n restoreLogLevel();\n if (batchMode) {\n return { success: true };\n }\n process.exit(0);\n } catch (error) {\n const message = error instanceof Error ? error.stack : String(error);\n console.error(styleText('red', `\\nError: ${message}`));\n if (options.debug && error instanceof Error) {\n console.error(styleText('red', error.stack || ''));\n }\n restoreLogLevel();\n if (batchMode) {\n return { success: false, error: message };\n }\n process.exit(1);\n }\n}\n\n/**\n * Pull all projects for the current tenant\n * Uses smart comparison with LLM merging for existing projects, introspect for new projects\n */\nasync function pullAllProjects(options: PullV3Options): Promise<void> {\n console.log(styleText('blue', '\\n🔄 Batch Pull: Sequential processing with smart comparison\\n'));\n console.log(\n styleText(\n 'gray',\n ' • Existing projects: Smart comparison + AST merging + confirmation prompts'\n )\n );\n console.log(styleText('gray', ' • New projects: Fresh generation with introspect mode\\n'));\n\n // Background version check (only once for batch)\n performBackgroundVersionCheck();\n\n // Load configuration first\n const { config, isCI } = await initializeCommand({\n configPath: options.config,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: true,\n spinnerText: 'Loading configuration...',\n logConfig: true,\n quiet: options.quiet,\n });\n\n const s = p.spinner();\n\n try {\n // Fetch all projects from the API\n s.start('Fetching project list from API...');\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n undefined,\n isCI,\n config.agentsApiKey\n );\n\n const projects = await apiClient.listAllProjects();\n s.stop(`Found ${projects.length} project(s)`);\n\n if (!projects.length) {\n console.log(styleText('yellow', 'No projects found for this tenant.'));\n process.exit(0);\n }\n\n // Categorize projects\n const existingProjects: typeof projects = [];\n const newProjects: typeof projects = [];\n\n for (const project of projects) {\n const targetDir = join(process.cwd(), project.id);\n if (existsSync(join(targetDir, 'index.ts'))) {\n existingProjects.push(project);\n } else {\n newProjects.push(project);\n }\n }\n\n console.log(styleText('gray', '\\nProjects to pull:\\n'));\n if (existingProjects.length > 0) {\n console.log(styleText('cyan', ' Existing (smart comparison):'));\n for (const project of existingProjects) {\n console.log(styleText('gray', ` • ${project.name || project.id} (${project.id})`));\n }\n }\n if (newProjects.length > 0) {\n console.log(styleText('cyan', ' New (introspect):'));\n for (const project of newProjects) {\n console.log(styleText('gray', ` • ${project.name || project.id} (${project.id})`));\n }\n }\n console.log();\n\n const results: BatchPullResult[] = [];\n const total = projects.length;\n\n for (let i = 0; i < projects.length; i++) {\n const project = projects[i];\n const progress = `[${i + 1}/${total}]`;\n\n console.log(styleText('cyan', `\\n${'─'.repeat(60)}`));\n console.log(styleText('cyan', `${progress} Pulling ${project.name || project.id}...`));\n\n const result = await pullSingleProject(project.id, project.name, options, config, isCI);\n results.push(result);\n\n if (result.success) {\n console.log(\n styleText(\n 'green',\n `\\n ✓ ${result.projectName || result.projectId} → ${result.targetDir}`\n )\n );\n } else {\n console.log(\n styleText('red', `\\n ✗ ${result.projectName || result.projectId}: ${result.error}`)\n );\n }\n }\n\n // Print summary\n const succeeded = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n console.log(styleText('cyan', `\\n${'═'.repeat(60)}`));\n console.log(styleText('cyan', '📊 Batch Pull Summary:'));\n console.log(styleText('green', ` ✓ Succeeded: ${succeeded}`));\n if (failed > 0) {\n console.log(styleText('red', ` ✗ Failed: ${failed}`));\n\n console.log(styleText('red', '\\nFailed projects:'));\n for (const result of results) {\n if (!result.success) {\n console.log(styleText('red', ` • ${result.projectId}: ${result.error}`));\n }\n }\n }\n\n process.exit(failed > 0 ? 1 : 0);\n } catch (error) {\n s.stop();\n console.error(\n styleText('red', `\\nError: ${error instanceof Error ? error.message : String(error)}`)\n );\n process.exit(1);\n }\n}\n\n/**\n * Pull a single project (used by batch operations)\n * Uses smart comparison flow for existing projects, introspect for new projects\n */\nexport async function pullSingleProject(\n projectId: string,\n projectName: string | undefined,\n options: PullV3Options,\n config: any,\n isCI?: boolean\n): Promise<BatchPullResult> {\n const targetDir = join(process.cwd(), projectId);\n const hasExistingProject = existsSync(join(targetDir, 'index.ts'));\n\n try {\n if (hasExistingProject) {\n // Project exists locally - use smart comparison flow with LLM merging and user prompts\n console.log(styleText('gray', ` 📂 Existing project found - using smart comparison mode`));\n\n // Save current directory and change to project directory\n const originalDir = process.cwd();\n process.chdir(targetDir);\n\n try {\n // Call the main pull command in batch mode (returns results instead of exiting)\n const result = await pullV4Command({\n ...options,\n project: projectId,\n all: false, // Don't recurse into batch mode\n _batchMode: true,\n });\n\n // Restore original directory\n process.chdir(originalDir);\n\n if (result && typeof result === 'object') {\n return {\n projectId,\n projectName,\n targetDir,\n success: result.success,\n error: result.error,\n };\n }\n\n return {\n projectId,\n projectName,\n targetDir,\n success: true,\n };\n } catch (error) {\n // Restore original directory even on error\n process.chdir(originalDir);\n throw error;\n }\n }\n console.log(styleText('gray', ' New project'));\n\n // Suppress SDK logging\n const originalLogLevel = process.env.LOG_LEVEL;\n process.env.LOG_LEVEL = 'silent';\n\n const restoreLogLevel = () => {\n if (originalLogLevel !== undefined) {\n process.env.LOG_LEVEL = originalLogLevel;\n } else {\n delete process.env.LOG_LEVEL;\n }\n };\n\n // Fetch project data from API\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n projectId,\n isCI,\n config.agentsApiKey\n );\n\n const remoteProject = await apiClient.getFullProject(projectId);\n // Create project structure\n const paths = createProjectStructure(targetDir);\n await generateProjectSkillsIfPresent(remoteProject, paths.skillsDir);\n\n // Generate all files using introspect mode for new projects\n await introspectGenerate({\n // @ts-expect-error -- ignore Types of property 'models' are incompatible.\n project: remoteProject,\n paths,\n });\n\n restoreLogLevel();\n\n return {\n projectId,\n projectName: projectName || remoteProject.name,\n targetDir,\n success: true,\n };\n } catch (error) {\n return {\n projectId,\n projectName,\n targetDir,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nasync function generateProjectSkillsIfPresent(\n remoteProject: any,\n skillsDir: string\n): Promise<void> {\n const skills = remoteProject.skills ?? {};\n if (!Object.keys(skills).length) {\n return;\n }\n\n const { generateSkills } = await import('../skill');\n await generateSkills(skills, skillsDir);\n}\n"],"mappings":"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"}
@@ -1,8 +1,11 @@
1
+ import { ManagementApiClient } from "../api.js";
1
2
  import { env } from "../env.js";
2
3
  import { findAllConfigFiles, findConfigFile } from "../utils/config.js";
3
4
  import { initializeCommand } from "../utils/cli-pipeline.js";
4
5
  import { performBackgroundVersionCheck } from "../utils/background-version-check.js";
5
6
  import { loadProject } from "../utils/project-loader.js";
7
+ import { readProjectState } from "../utils/state.js";
8
+ import { withLocalStateBranch } from "../utils/temp-branch.js";
6
9
  import { loadEnvironmentCredentials } from "../utils/environment-loader.js";
7
10
  import { basename, dirname, join, resolve } from "node:path";
8
11
  import * as p from "@clack/prompts";
@@ -112,9 +115,39 @@ async function pushCommand(options) {
112
115
  process.exit(1);
113
116
  }
114
117
  }
118
+ const projectId = project.getId();
119
+ if (!options.force) {
120
+ const lastPulledHash = readProjectState(projectId)?.lastPulledHash;
121
+ if (lastPulledHash) {
122
+ s.start("Checking for conflicts with remote...");
123
+ const apiClient = await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, projectId, void 0, config.agentsApiKey);
124
+ try {
125
+ const preview = await withLocalStateBranch({
126
+ apiClient,
127
+ projectId,
128
+ fromCommit: lastPulledHash,
129
+ localDefinition: await project.getFullDefinition(),
130
+ branchPrefix: "cli-push-check",
131
+ fn: (tempBranchName) => apiClient.mergePreview(projectId, {
132
+ sourceBranch: tempBranchName,
133
+ targetBranch: "main"
134
+ })
135
+ });
136
+ if (preview.hasConflicts) {
137
+ s.stop("Conflicts detected");
138
+ console.error(chalk.red(`\n✗ Push aborted: ${preview.conflicts.length} conflict(s) detected between your local state and remote.`));
139
+ console.log(chalk.yellow("\nRun `inkeep pull` to resolve conflicts before pushing, or use `inkeep push --force` to overwrite remote."));
140
+ process.exit(1);
141
+ }
142
+ s.stop("No conflicts detected");
143
+ } catch {
144
+ s.stop("Could not check for conflicts, proceeding with push");
145
+ console.log(chalk.yellow(`\n⚠ Conflict detection failed. Run \`inkeep pull\` first if you want to ensure no conflicts exist.`));
146
+ }
147
+ }
148
+ }
115
149
  s.start("Initializing project...");
116
150
  await project.init();
117
- const projectId = project.getId();
118
151
  const projectName = project.getName();
119
152
  const stats = project.getStats();
120
153
  s.stop(`Project "${projectName}" (${projectId}) pushed successfully`);
@@ -285,8 +318,9 @@ async function pushAllProjects(options) {
285
318
  */
286
319
  async function pushSingleProject(projectDir, options) {
287
320
  try {
321
+ const configFile = findConfigFile(projectDir, options.tag);
288
322
  const { config } = await initializeCommand({
289
- configPath: findConfigFile(projectDir, options.tag) || void 0,
323
+ configPath: configFile || void 0,
290
324
  profileName: options.profile,
291
325
  tag: options.tag,
292
326
  showSpinner: false,
@@ -306,10 +340,35 @@ async function pushSingleProject(projectDir, options) {
306
340
  const credentials = await loadEnvironmentCredentials(projectDir, options.env);
307
341
  project.setCredentials(credentials);
308
342
  }
343
+ const projectId = project.getId();
344
+ if (!options.force) {
345
+ const lastPulledHash = readProjectState(projectId)?.lastPulledHash;
346
+ if (lastPulledHash) {
347
+ const apiClient = await ManagementApiClient.create(config.agentsApiUrl, configFile || void 0, config.tenantId, projectId, void 0, config.agentsApiKey);
348
+ const preview = await withLocalStateBranch({
349
+ apiClient,
350
+ projectId,
351
+ fromCommit: lastPulledHash,
352
+ localDefinition: await project.getFullDefinition(),
353
+ branchPrefix: "cli-push-check",
354
+ fn: (tempBranchName) => apiClient.mergePreview(projectId, {
355
+ sourceBranch: tempBranchName,
356
+ targetBranch: "main"
357
+ })
358
+ });
359
+ if (preview.hasConflicts) return {
360
+ projectDir,
361
+ projectId,
362
+ projectName: project.getName(),
363
+ success: false,
364
+ error: `${preview.conflicts.length} conflict(s) detected — run \`inkeep pull\` to resolve or use \`--force\``
365
+ };
366
+ }
367
+ }
309
368
  await project.init();
310
369
  return {
311
370
  projectDir,
312
- projectId: project.getId(),
371
+ projectId,
313
372
  projectName: project.getName(),
314
373
  success: true
315
374
  };
@@ -1 +1 @@
1
- {"version":3,"file":"push.js","names":[],"sources":["../../src/commands/push.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport { env } from '../env';\nimport { performBackgroundVersionCheck } from '../utils/background-version-check';\nimport { initializeCommand } from '../utils/cli-pipeline';\nimport { findAllConfigFiles, findConfigFile } from '../utils/config';\nimport { loadEnvironmentCredentials } from '../utils/environment-loader';\nimport { loadProject } from '../utils/project-loader';\n\nexport interface PushOptions {\n project?: string;\n config?: string;\n profile?: string;\n env?: string;\n json?: boolean;\n all?: boolean;\n tag?: string;\n quiet?: boolean;\n}\n\ninterface BatchPushResult {\n projectDir: string;\n projectId?: string;\n projectName?: string;\n success: boolean;\n error?: string;\n}\n\nexport async function pushCommand(options: PushOptions): Promise<void> {\n // Perform background version check (non-blocking)\n performBackgroundVersionCheck();\n\n // Handle --all flag for batch operations\n if (options.all) {\n await pushAllProjects(options);\n return;\n }\n\n // Use standardized CLI pipeline for initialization\n const { config } = await initializeCommand({\n configPath: options.config,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: true,\n spinnerText: 'Loading configuration...',\n logConfig: true,\n quiet: options.quiet,\n });\n\n // Declare spinner at function scope so it's accessible in catch block\n const s = p.spinner();\n\n try {\n // Determine project directory - look for index.ts in current directory\n s.start('Detecting project...');\n let projectDir: string;\n\n if (options.project) {\n // If project path is explicitly specified, use it\n projectDir = resolve(process.cwd(), options.project);\n if (!existsSync(join(projectDir, 'index.ts'))) {\n s.stop(`No index.ts found in specified project directory: ${projectDir}`);\n process.exit(1);\n }\n } else {\n // Look for index.ts in current directory first\n const currentDir = process.cwd();\n if (existsSync(join(currentDir, 'index.ts'))) {\n projectDir = currentDir;\n } else {\n // Try to find config file and use its directory\n const configFile = findConfigFile(currentDir, options.tag);\n if (configFile) {\n const configDir = dirname(configFile);\n if (existsSync(join(configDir, 'index.ts'))) {\n projectDir = configDir;\n } else {\n s.stop('No index.ts found in config directory');\n console.error(\n chalk.yellow(\n 'Please run this command from a directory containing index.ts or use --project <path>'\n )\n );\n process.exit(1);\n }\n } else {\n s.stop('No index.ts found in current directory');\n console.error(\n chalk.yellow(\n 'Please run this command from a directory containing index.ts or use --project <path>'\n )\n );\n process.exit(1);\n }\n }\n }\n\n s.stop(`Project found: ${projectDir}`);\n\n // Set environment if provided\n if (options.env) {\n // Note: Setting process.env directly here because it needs to be available for child processes\n process.env.INKEEP_ENV = options.env;\n s.start(`Setting environment to '${options.env}'...`);\n }\n\n // Set environment variables for the SDK to use during project construction\n // This ensures the project is created with the correct tenant ID from the start\n const originalTenantId = process.env.INKEEP_TENANT_ID;\n const originalApiUrl = process.env.INKEEP_API_URL;\n\n process.env.INKEEP_TENANT_ID = config.tenantId;\n process.env.INKEEP_API_URL = config.agentsApiUrl;\n\n // Load project from index.ts\n s.start('Loading project from index.ts...');\n const project = await loadProject(projectDir);\n\n // Restore original environment variables\n if (originalTenantId !== undefined) {\n process.env.INKEEP_TENANT_ID = originalTenantId;\n } else {\n delete process.env.INKEEP_TENANT_ID;\n }\n if (originalApiUrl !== undefined) {\n process.env.INKEEP_API_URL = originalApiUrl;\n } else {\n delete process.env.INKEEP_API_URL;\n }\n\n s.stop('Project loaded successfully');\n\n // Set configuration on the project (still needed for consistency)\n if (typeof project.setConfig === 'function') {\n project.setConfig(\n config.tenantId,\n config.agentsApiUrl,\n undefined, // models - not needed here as they come from the project definition\n config.agentsApiKey\n );\n }\n\n // Load environment credentials if --env flag is provided\n if (options.env && typeof project.setCredentials === 'function') {\n s.start(`Loading credentials for environment '${options.env}'...`);\n\n try {\n const credentials = await loadEnvironmentCredentials(projectDir, options.env);\n project.setCredentials(credentials);\n\n s.stop('Project loaded with credentials');\n console.log(chalk.gray(` • Environment: ${options.env}`));\n console.log(chalk.gray(` • Credentials loaded: ${Object.keys(credentials).length}`));\n } catch (error: unknown) {\n s.stop('Failed to load environment credentials');\n console.error(chalk.red('Error:'), (error as Error).message);\n process.exit(1);\n }\n }\n\n // Dump project data to JSON file if --json flag is set\n if (options.json) {\n s.start('Generating project data JSON...');\n\n try {\n // Generate the project definition without initializing\n const projectDefinition = await project.getFullDefinition();\n\n // Create the JSON file path\n const jsonFilePath = join(projectDir, `project.json`);\n\n // Write the project data to JSON file\n const fs = await import('node:fs/promises');\n await fs.writeFile(jsonFilePath, JSON.stringify(projectDefinition, null, 2));\n\n s.stop(`Project data saved to ${jsonFilePath}`);\n console.log(chalk.gray(` • File: ${jsonFilePath}`));\n console.log(chalk.gray(` • Size: ${JSON.stringify(projectDefinition).length} bytes`));\n\n // Show a summary of what was saved\n const agentCount = Object.keys(projectDefinition.agents || {}).length;\n const toolCount = Object.keys(projectDefinition.tools || {}).length;\n const subAgentCount = Object.values(projectDefinition.agents || {}).reduce(\n (total, agent) => {\n return total + Object.keys(agent.subAgents || {}).length;\n },\n 0\n );\n\n console.log(chalk.cyan('\\n📊 Project Data Summary:'));\n console.log(chalk.gray(` • Agent: ${agentCount}`));\n console.log(chalk.gray(` • Tools: ${toolCount}`));\n console.log(chalk.gray(` • SubAgent: ${subAgentCount}`));\n\n // Exit after generating JSON (don't initialize the project)\n console.log(chalk.green('\\n✨ JSON file generated successfully!'));\n process.exit(0);\n } catch (error: unknown) {\n s.stop('Failed to generate JSON file');\n console.error(chalk.red('Error:'), (error as Error).message);\n process.exit(1);\n }\n }\n\n // Initialize the project (this will push to the backend)\n s.start('Initializing project...');\n await project.init();\n\n // Get project details\n const projectId = project.getId();\n const projectName = project.getName();\n const stats = project.getStats();\n\n s.stop(`Project \"${projectName}\" (${projectId}) pushed successfully`);\n\n // Display summary\n console.log(chalk.cyan('\\n📊 Project Summary:'));\n console.log(chalk.gray(` • Project ID: ${projectId}`));\n console.log(chalk.gray(` • Name: ${projectName}`));\n console.log(chalk.gray(` • Agent: ${stats.agentCount}`));\n console.log(chalk.gray(` • Tenant: ${stats.tenantId}`));\n\n // Display agent details if exsits\n const agents = project.getAgents();\n if (agents.length > 0) {\n console.log(chalk.cyan('\\n📊 Agent Details:'));\n for (const agent of agents) {\n const agentStats = agent.getStats();\n console.log(\n chalk.gray(` • ${agent.getName()} (${agent.getId()}): ${agentStats.agentCount} agents`)\n );\n }\n }\n\n // Display credential tracking information\n try {\n const credentialTracking = await project.getCredentialTracking();\n const credentialCount = Object.keys(credentialTracking.credentials).length;\n\n if (credentialCount > 0) {\n console.log(chalk.cyan('\\n🔐 Credentials:'));\n console.log(chalk.gray(` • Total credentials: ${credentialCount}`));\n\n // Show credential details\n for (const [credId, credData] of Object.entries(credentialTracking.credentials)) {\n const usageInfo = credentialTracking.usage[credId] || [];\n const credType = credData.type || 'unknown';\n const storeId = credData.credentialStoreId || 'unknown';\n\n console.log(chalk.gray(` • ${credId} (${credType}, store: ${storeId})`));\n\n if (usageInfo.length > 0) {\n const usageByType: Record<string, number> = {};\n for (const usage of usageInfo) {\n usageByType[usage.type] = (usageByType[usage.type] || 0) + 1;\n }\n\n const usageSummary = Object.entries(usageByType)\n .map(([type, count]) => `${count} ${type}${count > 1 ? 's' : ''}`)\n .join(', ');\n\n console.log(chalk.gray(` Used by: ${usageSummary}`));\n }\n }\n }\n } catch (_error) {\n // Silently fail if credential tracking is not available\n if (env.DEBUG) {\n console.error(chalk.yellow('Could not retrieve credential tracking information'));\n }\n }\n\n // Display project URL if available\n if (config.manageUiUrl) {\n const projectUrl = `${config.manageUiUrl}/${config.tenantId}/projects/${projectId}`;\n console.log(chalk.cyan('\\n🔗 Project URL:'));\n console.log(chalk.blue.underline(` ${projectUrl}`));\n }\n\n // Provide next steps\n console.log(chalk.green('\\n✨ Next steps:'));\n console.log(chalk.gray(` • View all agents: inkeep list-agent`));\n\n // Force exit to avoid hanging due to OpenTelemetry or other background tasks\n process.exit(0);\n } catch (_error: unknown) {\n s.stop('Failed to push project');\n const error = _error as Error;\n console.error(chalk.red('Error:'), error.message);\n\n if (error.stack && env.DEBUG) {\n console.error(chalk.gray(error.stack));\n }\n\n process.exit(1);\n }\n}\n\n/**\n * Check if an index.ts file exports a project (has __type = 'project')\n */\nasync function isProjectDirectory(dir: string): Promise<boolean> {\n const indexPath = join(dir, 'index.ts');\n if (!existsSync(indexPath)) {\n return false;\n }\n\n try {\n // Dynamically import to check for project export\n const { importWithTypeScriptSupport } = await import('../utils/tsx-loader');\n const module = await importWithTypeScriptSupport(indexPath);\n\n // Check if any export has __type = 'project'\n for (const key of Object.keys(module)) {\n const value = module[key];\n if (value && typeof value === 'object' && value.__type === 'project') {\n return true;\n }\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Find all directories containing index.ts that export a project\n */\nasync function findAllProjectDirs(\n rootDir: string,\n excludeDirs: string[] = ['node_modules', '.git', 'dist', 'build', '.temp-validation']\n): Promise<string[]> {\n const projectDirs: string[] = [];\n\n async function scanDirectory(dir: string): Promise<void> {\n if (!existsSync(dir)) {\n return;\n }\n\n let items: string[];\n try {\n items = readdirSync(dir);\n } catch {\n return;\n }\n\n // Check if this directory has an index.ts that exports a project\n if (existsSync(join(dir, 'index.ts'))) {\n const isProject = await isProjectDirectory(dir);\n if (isProject) {\n projectDirs.push(dir);\n // Don't recurse into subdirectories of a project\n return;\n }\n }\n\n // Recurse into subdirectories\n for (const item of items) {\n const fullPath = join(dir, item);\n\n // Skip excluded directories\n if (excludeDirs.includes(item)) {\n continue;\n }\n\n try {\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n await scanDirectory(fullPath);\n }\n } catch {\n // Skip files/directories we can't stat\n }\n }\n }\n\n await scanDirectory(rootDir);\n return projectDirs.sort();\n}\n\n/**\n * Push all projects found in current directory tree\n */\nasync function pushAllProjects(options: PushOptions): Promise<void> {\n console.log(chalk.blue('\\n🚀 Batch Push: Finding all projects...\\n'));\n\n // Strategy 1: Find all config files and check for index.ts in same directory\n const configFiles = findAllConfigFiles(process.cwd(), options.tag);\n const projectDirsFromConfig: string[] = [];\n for (const configFile of configFiles) {\n const dir = dirname(configFile);\n if (existsSync(join(dir, 'index.ts'))) {\n projectDirsFromConfig.push(dir);\n }\n }\n\n // Strategy 2: Find all index.ts files that export a project and can find a config (supports shared config)\n const allIndexDirs = await findAllProjectDirs(process.cwd());\n const projectDirsFromIndex: string[] = [];\n for (const dir of allIndexDirs) {\n // Skip if already found via config file in same directory\n if (projectDirsFromConfig.includes(dir)) {\n continue;\n }\n // Check if this directory can find a config file (walking up the tree)\n const configFile = findConfigFile(dir, options.tag);\n if (configFile) {\n projectDirsFromIndex.push(dir);\n }\n }\n\n // Combine both strategies\n const projectDirs = [...projectDirsFromConfig, ...projectDirsFromIndex].sort();\n\n if (projectDirs.length === 0) {\n const configPattern = options.tag ? `${options.tag}.__inkeep.config.ts__` : 'inkeep.config.ts';\n console.error(chalk.red('No valid projects found.'));\n console.log(\n chalk.yellow(\n `\\nHint: Projects must have an index.ts file and access to an ${configPattern} file`\n )\n );\n console.log(chalk.yellow(' (either in the same directory or in a parent directory).'));\n process.exit(1);\n }\n\n console.log(chalk.gray(`Found ${projectDirs.length} project(s) to push:\\n`));\n for (const dir of projectDirs) {\n const relativePath = dir === process.cwd() ? '.' : dir.replace(`${process.cwd()}/`, '');\n console.log(chalk.gray(` • ${relativePath}`));\n }\n console.log();\n\n const results: BatchPushResult[] = [];\n const total = projectDirs.length;\n\n for (let i = 0; i < projectDirs.length; i++) {\n const projectDir = projectDirs[i];\n const relativePath =\n projectDir === process.cwd() ? '.' : projectDir.replace(`${process.cwd()}/`, '');\n const progress = `[${i + 1}/${total}]`;\n\n console.log(chalk.cyan(`${progress} Pushing ${relativePath}...`));\n\n const result = await pushSingleProject(projectDir, options);\n results.push(result);\n\n if (result.success) {\n console.log(\n chalk.green(` ✓ ${result.projectName || result.projectId || basename(projectDir)}`)\n );\n } else {\n console.log(chalk.red(` ✗ ${basename(projectDir)}: ${result.error}`));\n }\n }\n\n // Print summary\n const succeeded = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n console.log(chalk.cyan('\\n📊 Batch Push Summary:'));\n console.log(chalk.green(` ✓ Succeeded: ${succeeded}`));\n if (failed > 0) {\n console.log(chalk.red(` ✗ Failed: ${failed}`));\n\n console.log(chalk.red('\\nFailed projects:'));\n for (const result of results) {\n if (!result.success) {\n const relativePath =\n result.projectDir === process.cwd()\n ? '.'\n : result.projectDir.replace(`${process.cwd()}/`, '');\n console.log(chalk.red(` • ${relativePath}: ${result.error}`));\n }\n }\n }\n\n process.exit(failed > 0 ? 1 : 0);\n}\n\n/**\n * Push a single project (used by batch operations)\n */\nasync function pushSingleProject(\n projectDir: string,\n options: PushOptions\n): Promise<BatchPushResult> {\n try {\n // Find config file for this project directory\n const configFile = findConfigFile(projectDir, options.tag);\n\n // Use standardized CLI pipeline for initialization\n const { config } = await initializeCommand({\n configPath: configFile || undefined,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: false,\n logConfig: false,\n });\n\n // Set environment variables for the SDK\n const originalTenantId = process.env.INKEEP_TENANT_ID;\n const originalApiUrl = process.env.INKEEP_API_URL;\n\n process.env.INKEEP_TENANT_ID = config.tenantId;\n process.env.INKEEP_API_URL = config.agentsApiUrl;\n\n // Load project from index.ts\n const project = await loadProject(projectDir);\n\n // Restore original environment variables\n if (originalTenantId !== undefined) {\n process.env.INKEEP_TENANT_ID = originalTenantId;\n } else {\n delete process.env.INKEEP_TENANT_ID;\n }\n if (originalApiUrl !== undefined) {\n process.env.INKEEP_API_URL = originalApiUrl;\n } else {\n delete process.env.INKEEP_API_URL;\n }\n\n // Set configuration on the project\n if (typeof project.setConfig === 'function') {\n project.setConfig(config.tenantId, config.agentsApiUrl, undefined, config.agentsApiKey);\n }\n\n // Load environment credentials if --env flag is provided\n if (options.env && typeof project.setCredentials === 'function') {\n const credentials = await loadEnvironmentCredentials(projectDir, options.env);\n project.setCredentials(credentials);\n }\n\n // Initialize the project (this will push to the backend)\n await project.init();\n\n return {\n projectDir,\n projectId: project.getId(),\n projectName: project.getName(),\n success: true,\n };\n } catch (error) {\n return {\n projectDir,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"push.js","names":[],"sources":["../../src/commands/push.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport { ManagementApiClient } from '../api';\nimport { env } from '../env';\nimport { performBackgroundVersionCheck } from '../utils/background-version-check';\nimport { initializeCommand } from '../utils/cli-pipeline';\nimport { findAllConfigFiles, findConfigFile } from '../utils/config';\nimport { loadEnvironmentCredentials } from '../utils/environment-loader';\nimport { loadProject } from '../utils/project-loader';\nimport { readProjectState } from '../utils/state';\nimport { withLocalStateBranch } from '../utils/temp-branch';\n\nexport interface PushOptions {\n project?: string;\n config?: string;\n profile?: string;\n env?: string;\n json?: boolean;\n all?: boolean;\n tag?: string;\n quiet?: boolean;\n force?: boolean;\n}\n\ninterface BatchPushResult {\n projectDir: string;\n projectId?: string;\n projectName?: string;\n success: boolean;\n error?: string;\n}\n\nexport async function pushCommand(options: PushOptions): Promise<void> {\n // Perform background version check (non-blocking)\n performBackgroundVersionCheck();\n\n // Handle --all flag for batch operations\n if (options.all) {\n await pushAllProjects(options);\n return;\n }\n\n // Use standardized CLI pipeline for initialization\n const { config } = await initializeCommand({\n configPath: options.config,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: true,\n spinnerText: 'Loading configuration...',\n logConfig: true,\n quiet: options.quiet,\n });\n\n // Declare spinner at function scope so it's accessible in catch block\n const s = p.spinner();\n\n try {\n // Determine project directory - look for index.ts in current directory\n s.start('Detecting project...');\n let projectDir: string;\n\n if (options.project) {\n // If project path is explicitly specified, use it\n projectDir = resolve(process.cwd(), options.project);\n if (!existsSync(join(projectDir, 'index.ts'))) {\n s.stop(`No index.ts found in specified project directory: ${projectDir}`);\n process.exit(1);\n }\n } else {\n // Look for index.ts in current directory first\n const currentDir = process.cwd();\n if (existsSync(join(currentDir, 'index.ts'))) {\n projectDir = currentDir;\n } else {\n // Try to find config file and use its directory\n const configFile = findConfigFile(currentDir, options.tag);\n if (configFile) {\n const configDir = dirname(configFile);\n if (existsSync(join(configDir, 'index.ts'))) {\n projectDir = configDir;\n } else {\n s.stop('No index.ts found in config directory');\n console.error(\n chalk.yellow(\n 'Please run this command from a directory containing index.ts or use --project <path>'\n )\n );\n process.exit(1);\n }\n } else {\n s.stop('No index.ts found in current directory');\n console.error(\n chalk.yellow(\n 'Please run this command from a directory containing index.ts or use --project <path>'\n )\n );\n process.exit(1);\n }\n }\n }\n\n s.stop(`Project found: ${projectDir}`);\n\n // Set environment if provided\n if (options.env) {\n // Note: Setting process.env directly here because it needs to be available for child processes\n process.env.INKEEP_ENV = options.env;\n s.start(`Setting environment to '${options.env}'...`);\n }\n\n // Set environment variables for the SDK to use during project construction\n // This ensures the project is created with the correct tenant ID from the start\n const originalTenantId = process.env.INKEEP_TENANT_ID;\n const originalApiUrl = process.env.INKEEP_API_URL;\n\n process.env.INKEEP_TENANT_ID = config.tenantId;\n process.env.INKEEP_API_URL = config.agentsApiUrl;\n\n // Load project from index.ts\n s.start('Loading project from index.ts...');\n const project = await loadProject(projectDir);\n\n // Restore original environment variables\n if (originalTenantId !== undefined) {\n process.env.INKEEP_TENANT_ID = originalTenantId;\n } else {\n delete process.env.INKEEP_TENANT_ID;\n }\n if (originalApiUrl !== undefined) {\n process.env.INKEEP_API_URL = originalApiUrl;\n } else {\n delete process.env.INKEEP_API_URL;\n }\n\n s.stop('Project loaded successfully');\n\n // Set configuration on the project (still needed for consistency)\n if (typeof project.setConfig === 'function') {\n project.setConfig(\n config.tenantId,\n config.agentsApiUrl,\n undefined, // models - not needed here as they come from the project definition\n config.agentsApiKey\n );\n }\n\n // Load environment credentials if --env flag is provided\n if (options.env && typeof project.setCredentials === 'function') {\n s.start(`Loading credentials for environment '${options.env}'...`);\n\n try {\n const credentials = await loadEnvironmentCredentials(projectDir, options.env);\n project.setCredentials(credentials);\n\n s.stop('Project loaded with credentials');\n console.log(chalk.gray(` • Environment: ${options.env}`));\n console.log(chalk.gray(` • Credentials loaded: ${Object.keys(credentials).length}`));\n } catch (error: unknown) {\n s.stop('Failed to load environment credentials');\n console.error(chalk.red('Error:'), (error as Error).message);\n process.exit(1);\n }\n }\n\n // Dump project data to JSON file if --json flag is set\n if (options.json) {\n s.start('Generating project data JSON...');\n\n try {\n // Generate the project definition without initializing\n const projectDefinition = await project.getFullDefinition();\n\n // Create the JSON file path\n const jsonFilePath = join(projectDir, `project.json`);\n\n // Write the project data to JSON file\n const fs = await import('node:fs/promises');\n await fs.writeFile(jsonFilePath, JSON.stringify(projectDefinition, null, 2));\n\n s.stop(`Project data saved to ${jsonFilePath}`);\n console.log(chalk.gray(` • File: ${jsonFilePath}`));\n console.log(chalk.gray(` • Size: ${JSON.stringify(projectDefinition).length} bytes`));\n\n // Show a summary of what was saved\n const agentCount = Object.keys(projectDefinition.agents || {}).length;\n const toolCount = Object.keys(projectDefinition.tools || {}).length;\n const subAgentCount = Object.values(projectDefinition.agents || {}).reduce(\n (total, agent) => {\n return total + Object.keys(agent.subAgents || {}).length;\n },\n 0\n );\n\n console.log(chalk.cyan('\\n📊 Project Data Summary:'));\n console.log(chalk.gray(` • Agent: ${agentCount}`));\n console.log(chalk.gray(` • Tools: ${toolCount}`));\n console.log(chalk.gray(` • SubAgent: ${subAgentCount}`));\n\n // Exit after generating JSON (don't initialize the project)\n console.log(chalk.green('\\n✨ JSON file generated successfully!'));\n process.exit(0);\n } catch (error: unknown) {\n s.stop('Failed to generate JSON file');\n console.error(chalk.red('Error:'), (error as Error).message);\n process.exit(1);\n }\n }\n\n // Check for conflicts before pushing (unless --force is set)\n const projectId = project.getId();\n if (!options.force) {\n const existingState = readProjectState(projectId);\n const lastPulledHash = existingState?.lastPulledHash;\n\n if (lastPulledHash) {\n s.start('Checking for conflicts with remote...');\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n options.config,\n config.tenantId,\n projectId,\n undefined,\n config.agentsApiKey\n );\n\n try {\n const projectDefinition = await project.getFullDefinition();\n\n const preview = await withLocalStateBranch({\n apiClient,\n projectId,\n fromCommit: lastPulledHash,\n localDefinition: projectDefinition,\n branchPrefix: 'cli-push-check',\n fn: (tempBranchName) =>\n apiClient.mergePreview(projectId, {\n sourceBranch: tempBranchName,\n targetBranch: 'main',\n }),\n });\n\n if (preview.hasConflicts) {\n s.stop('Conflicts detected');\n console.error(\n chalk.red(\n `\\n✗ Push aborted: ${preview.conflicts.length} conflict(s) detected between your local state and remote.`\n )\n );\n console.log(\n chalk.yellow(\n '\\nRun `inkeep pull` to resolve conflicts before pushing, or use `inkeep push --force` to overwrite remote.'\n )\n );\n process.exit(1);\n }\n\n s.stop('No conflicts detected');\n } catch {\n s.stop('Could not check for conflicts, proceeding with push');\n console.log(\n chalk.yellow(\n `\\n⚠ Conflict detection failed. Run \\`inkeep pull\\` first if you want to ensure no conflicts exist.`\n )\n );\n }\n }\n }\n\n // Initialize the project (this will push to the backend)\n s.start('Initializing project...');\n await project.init();\n\n const projectName = project.getName();\n const stats = project.getStats();\n\n s.stop(`Project \"${projectName}\" (${projectId}) pushed successfully`);\n\n // Display summary\n console.log(chalk.cyan('\\n📊 Project Summary:'));\n console.log(chalk.gray(` • Project ID: ${projectId}`));\n console.log(chalk.gray(` • Name: ${projectName}`));\n console.log(chalk.gray(` • Agent: ${stats.agentCount}`));\n console.log(chalk.gray(` • Tenant: ${stats.tenantId}`));\n\n // Display agent details if exsits\n const agents = project.getAgents();\n if (agents.length > 0) {\n console.log(chalk.cyan('\\n📊 Agent Details:'));\n for (const agent of agents) {\n const agentStats = agent.getStats();\n console.log(\n chalk.gray(` • ${agent.getName()} (${agent.getId()}): ${agentStats.agentCount} agents`)\n );\n }\n }\n\n // Display credential tracking information\n try {\n const credentialTracking = await project.getCredentialTracking();\n const credentialCount = Object.keys(credentialTracking.credentials).length;\n\n if (credentialCount > 0) {\n console.log(chalk.cyan('\\n🔐 Credentials:'));\n console.log(chalk.gray(` • Total credentials: ${credentialCount}`));\n\n // Show credential details\n for (const [credId, credData] of Object.entries(credentialTracking.credentials)) {\n const usageInfo = credentialTracking.usage[credId] || [];\n const credType = credData.type || 'unknown';\n const storeId = credData.credentialStoreId || 'unknown';\n\n console.log(chalk.gray(` • ${credId} (${credType}, store: ${storeId})`));\n\n if (usageInfo.length > 0) {\n const usageByType: Record<string, number> = {};\n for (const usage of usageInfo) {\n usageByType[usage.type] = (usageByType[usage.type] || 0) + 1;\n }\n\n const usageSummary = Object.entries(usageByType)\n .map(([type, count]) => `${count} ${type}${count > 1 ? 's' : ''}`)\n .join(', ');\n\n console.log(chalk.gray(` Used by: ${usageSummary}`));\n }\n }\n }\n } catch (_error) {\n // Silently fail if credential tracking is not available\n if (env.DEBUG) {\n console.error(chalk.yellow('Could not retrieve credential tracking information'));\n }\n }\n\n // Display project URL if available\n if (config.manageUiUrl) {\n const projectUrl = `${config.manageUiUrl}/${config.tenantId}/projects/${projectId}`;\n console.log(chalk.cyan('\\n🔗 Project URL:'));\n console.log(chalk.blue.underline(` ${projectUrl}`));\n }\n\n // Provide next steps\n console.log(chalk.green('\\n✨ Next steps:'));\n console.log(chalk.gray(` • View all agents: inkeep list-agent`));\n\n // Force exit to avoid hanging due to OpenTelemetry or other background tasks\n process.exit(0);\n } catch (_error: unknown) {\n s.stop('Failed to push project');\n const error = _error as Error;\n console.error(chalk.red('Error:'), error.message);\n\n if (error.stack && env.DEBUG) {\n console.error(chalk.gray(error.stack));\n }\n\n process.exit(1);\n }\n}\n\n/**\n * Check if an index.ts file exports a project (has __type = 'project')\n */\nasync function isProjectDirectory(dir: string): Promise<boolean> {\n const indexPath = join(dir, 'index.ts');\n if (!existsSync(indexPath)) {\n return false;\n }\n\n try {\n // Dynamically import to check for project export\n const { importWithTypeScriptSupport } = await import('../utils/tsx-loader');\n const module = await importWithTypeScriptSupport(indexPath);\n\n // Check if any export has __type = 'project'\n for (const key of Object.keys(module)) {\n const value = module[key];\n if (value && typeof value === 'object' && value.__type === 'project') {\n return true;\n }\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Find all directories containing index.ts that export a project\n */\nasync function findAllProjectDirs(\n rootDir: string,\n excludeDirs: string[] = ['node_modules', '.git', 'dist', 'build', '.temp-validation']\n): Promise<string[]> {\n const projectDirs: string[] = [];\n\n async function scanDirectory(dir: string): Promise<void> {\n if (!existsSync(dir)) {\n return;\n }\n\n let items: string[];\n try {\n items = readdirSync(dir);\n } catch {\n return;\n }\n\n // Check if this directory has an index.ts that exports a project\n if (existsSync(join(dir, 'index.ts'))) {\n const isProject = await isProjectDirectory(dir);\n if (isProject) {\n projectDirs.push(dir);\n // Don't recurse into subdirectories of a project\n return;\n }\n }\n\n // Recurse into subdirectories\n for (const item of items) {\n const fullPath = join(dir, item);\n\n // Skip excluded directories\n if (excludeDirs.includes(item)) {\n continue;\n }\n\n try {\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n await scanDirectory(fullPath);\n }\n } catch {\n // Skip files/directories we can't stat\n }\n }\n }\n\n await scanDirectory(rootDir);\n return projectDirs.sort();\n}\n\n/**\n * Push all projects found in current directory tree\n */\nasync function pushAllProjects(options: PushOptions): Promise<void> {\n console.log(chalk.blue('\\n🚀 Batch Push: Finding all projects...\\n'));\n\n // Strategy 1: Find all config files and check for index.ts in same directory\n const configFiles = findAllConfigFiles(process.cwd(), options.tag);\n const projectDirsFromConfig: string[] = [];\n for (const configFile of configFiles) {\n const dir = dirname(configFile);\n if (existsSync(join(dir, 'index.ts'))) {\n projectDirsFromConfig.push(dir);\n }\n }\n\n // Strategy 2: Find all index.ts files that export a project and can find a config (supports shared config)\n const allIndexDirs = await findAllProjectDirs(process.cwd());\n const projectDirsFromIndex: string[] = [];\n for (const dir of allIndexDirs) {\n // Skip if already found via config file in same directory\n if (projectDirsFromConfig.includes(dir)) {\n continue;\n }\n // Check if this directory can find a config file (walking up the tree)\n const configFile = findConfigFile(dir, options.tag);\n if (configFile) {\n projectDirsFromIndex.push(dir);\n }\n }\n\n // Combine both strategies\n const projectDirs = [...projectDirsFromConfig, ...projectDirsFromIndex].sort();\n\n if (projectDirs.length === 0) {\n const configPattern = options.tag ? `${options.tag}.__inkeep.config.ts__` : 'inkeep.config.ts';\n console.error(chalk.red('No valid projects found.'));\n console.log(\n chalk.yellow(\n `\\nHint: Projects must have an index.ts file and access to an ${configPattern} file`\n )\n );\n console.log(chalk.yellow(' (either in the same directory or in a parent directory).'));\n process.exit(1);\n }\n\n console.log(chalk.gray(`Found ${projectDirs.length} project(s) to push:\\n`));\n for (const dir of projectDirs) {\n const relativePath = dir === process.cwd() ? '.' : dir.replace(`${process.cwd()}/`, '');\n console.log(chalk.gray(` • ${relativePath}`));\n }\n console.log();\n\n const results: BatchPushResult[] = [];\n const total = projectDirs.length;\n\n for (let i = 0; i < projectDirs.length; i++) {\n const projectDir = projectDirs[i];\n const relativePath =\n projectDir === process.cwd() ? '.' : projectDir.replace(`${process.cwd()}/`, '');\n const progress = `[${i + 1}/${total}]`;\n\n console.log(chalk.cyan(`${progress} Pushing ${relativePath}...`));\n\n const result = await pushSingleProject(projectDir, options);\n results.push(result);\n\n if (result.success) {\n console.log(\n chalk.green(` ✓ ${result.projectName || result.projectId || basename(projectDir)}`)\n );\n } else {\n console.log(chalk.red(` ✗ ${basename(projectDir)}: ${result.error}`));\n }\n }\n\n // Print summary\n const succeeded = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n console.log(chalk.cyan('\\n📊 Batch Push Summary:'));\n console.log(chalk.green(` ✓ Succeeded: ${succeeded}`));\n if (failed > 0) {\n console.log(chalk.red(` ✗ Failed: ${failed}`));\n\n console.log(chalk.red('\\nFailed projects:'));\n for (const result of results) {\n if (!result.success) {\n const relativePath =\n result.projectDir === process.cwd()\n ? '.'\n : result.projectDir.replace(`${process.cwd()}/`, '');\n console.log(chalk.red(` • ${relativePath}: ${result.error}`));\n }\n }\n }\n\n process.exit(failed > 0 ? 1 : 0);\n}\n\n/**\n * Push a single project (used by batch operations)\n */\nasync function pushSingleProject(\n projectDir: string,\n options: PushOptions\n): Promise<BatchPushResult> {\n try {\n // Find config file for this project directory\n const configFile = findConfigFile(projectDir, options.tag);\n\n // Use standardized CLI pipeline for initialization\n const { config } = await initializeCommand({\n configPath: configFile || undefined,\n profileName: options.profile,\n tag: options.tag,\n showSpinner: false,\n logConfig: false,\n });\n\n // Set environment variables for the SDK\n const originalTenantId = process.env.INKEEP_TENANT_ID;\n const originalApiUrl = process.env.INKEEP_API_URL;\n\n process.env.INKEEP_TENANT_ID = config.tenantId;\n process.env.INKEEP_API_URL = config.agentsApiUrl;\n\n // Load project from index.ts\n const project = await loadProject(projectDir);\n\n // Restore original environment variables\n if (originalTenantId !== undefined) {\n process.env.INKEEP_TENANT_ID = originalTenantId;\n } else {\n delete process.env.INKEEP_TENANT_ID;\n }\n if (originalApiUrl !== undefined) {\n process.env.INKEEP_API_URL = originalApiUrl;\n } else {\n delete process.env.INKEEP_API_URL;\n }\n\n // Set configuration on the project\n if (typeof project.setConfig === 'function') {\n project.setConfig(config.tenantId, config.agentsApiUrl, undefined, config.agentsApiKey);\n }\n\n // Load environment credentials if --env flag is provided\n if (options.env && typeof project.setCredentials === 'function') {\n const credentials = await loadEnvironmentCredentials(projectDir, options.env);\n project.setCredentials(credentials);\n }\n\n const projectId = project.getId();\n\n if (!options.force) {\n const existingState = readProjectState(projectId);\n const lastPulledHash = existingState?.lastPulledHash;\n\n if (lastPulledHash) {\n const apiClient = await ManagementApiClient.create(\n config.agentsApiUrl,\n configFile || undefined,\n config.tenantId,\n projectId,\n undefined,\n config.agentsApiKey\n );\n\n const projectDefinition = await project.getFullDefinition();\n\n const preview = await withLocalStateBranch({\n apiClient,\n projectId,\n fromCommit: lastPulledHash,\n localDefinition: projectDefinition,\n branchPrefix: 'cli-push-check',\n fn: (tempBranchName) =>\n apiClient.mergePreview(projectId, {\n sourceBranch: tempBranchName,\n targetBranch: 'main',\n }),\n });\n\n if (preview.hasConflicts) {\n return {\n projectDir,\n projectId,\n projectName: project.getName(),\n success: false,\n error: `${preview.conflicts.length} conflict(s) detected — run \\`inkeep pull\\` to resolve or use \\`--force\\``,\n };\n }\n }\n }\n\n await project.init();\n\n return {\n projectDir,\n projectId,\n projectName: project.getName(),\n success: true,\n };\n } catch (error) {\n return {\n projectDir,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -44,7 +44,7 @@ configCommand.command("set <key> <value>").description("Set a configuration valu
44
44
  configCommand.command("list").description("List all configuration values").option("--config <path>", "Path to configuration file").option("--config-file-path <path>", "Path to configuration file (deprecated, use --config)").action(async (options) => {
45
45
  await configListCommand({ config: options.config || options.configFilePath });
46
46
  });
47
- program.command("push").description("Push a project configuration to the backend").option("--project <project-id>", "Project ID or path to project directory").option("--config <path>", "Path to configuration file").option("--profile <name>", "Profile to use for remote URLs and authentication").option("--tenant-id <id>", "Override tenant ID").option("--agents-api-url <url>", "Override agents API URL").option("--env <environment>", "Environment to use for credential resolution (e.g., development, production)").option("--json", "Generate project data JSON file instead of pushing to backend").option("--all", "Push all projects found in current directory tree").option("--tag <tag>", "Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)").option("--quiet", "Suppress profile/config logging").action(pushCommand);
47
+ program.command("push").description("Push a project configuration to the backend").option("--project <project-id>", "Project ID or path to project directory").option("--config <path>", "Path to configuration file").option("--profile <name>", "Profile to use for remote URLs and authentication").option("--tenant-id <id>", "Override tenant ID").option("--agents-api-url <url>", "Override agents API URL").option("--env <environment>", "Environment to use for credential resolution (e.g., development, production)").option("--json", "Generate project data JSON file instead of pushing to backend").option("--all", "Push all projects found in current directory tree").option("--tag <tag>", "Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)").option("--quiet", "Suppress profile/config logging").option("--force", "Skip conflict detection and push directly to remote").action(pushCommand);
48
48
  program.command("pull").description("Pull project configuration with clean, efficient code generation").option("--project <project-id>", "Project ID to pull (or path to project directory). If in project directory, validates against local project ID.").option("--config <path>", "Path to configuration file").option("--profile <name>", "Profile to use for remote URLs and authentication").option("--env <environment>", "Environment file to generate (development, staging, production). Defaults to development").option("--json", "Output project data as JSON instead of generating files").option("--debug", "Enable debug logging").option("--verbose", "Enable verbose logging").option("--force", "Force regeneration even if no changes detected").option("--all", "Pull all projects for current tenant").option("--tag <tag>", "Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)").option("--quiet", "Suppress profile/config logging").addOption(new Option("--conflict-strategy <strategy>", "Auto-resolve merge conflicts: ours (keep local) or theirs (accept remote). Skips interactive prompts.").choices(["ours", "theirs"])).action(async (options) => {
49
49
  await pullV4Command(options);
50
50
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport './env'; // Load environment files first (needed by instrumentation)\nimport './instrumentation'; // Initialize Langfuse tracing second\n\n// Silence config loading logs for cleaner CLI output\nimport { getLogger } from '@inkeep/agents-core';\n\nconst configLogger = getLogger('config');\nconfigLogger.updateOptions({ level: 'silent' });\n\nimport { Command, Option } from 'commander';\nimport { addCommand } from './commands/add';\nimport { configGetCommand, configListCommand, configSetCommand } from './commands/config';\nimport { devCommand } from './commands/dev';\nimport { initCommand } from './commands/init';\nimport { listAgentsCommand } from './commands/list-agents';\nimport { loginCommand } from './commands/login';\nimport { logoutCommand } from './commands/logout';\nimport {\n profileAddCommand,\n profileCurrentCommand,\n profileListCommand,\n profileRemoveCommand,\n profileUseCommand,\n} from './commands/profile';\nimport { pullV4Command } from './commands/pull-v4/introspect';\nimport { pushCommand } from './commands/push';\nimport { statusCommand } from './commands/status';\nimport { updateCommand } from './commands/update';\nimport { whoamiCommand } from './commands/whoami';\nimport { PACKAGE_VERSION } from './utils/version-check';\n\nconst program = new Command();\n\nprogram.name('inkeep').description('CLI tool for Inkeep Agent Framework').version(PACKAGE_VERSION);\n\nprogram\n .command('add [template]')\n .description('Add a new template to the project')\n .option('--project <template>', 'Project template to add')\n .option('--mcp <template>', 'MCP template to add')\n .option(\n '--ui [component-id]',\n 'Add UI component(s) to apps/agents-ui/src/ui (omit id to add all)'\n )\n .option('--list', 'List available UI components (use with --ui)')\n .option('--target-path <path>', 'Target path to add the template to')\n .option('--local-prefix <path_prefix>', 'Use local templates from the given path prefix')\n .option('--config <path>', 'Path to configuration file')\n .option('--profile <name>', 'Profile to use for authentication')\n .option('--quiet', 'Suppress profile/config logging')\n .action(async (template, options) => {\n await addCommand({ template, ...options });\n });\n\nprogram\n .command('init [path]')\n .description('Initialize a new Inkeep project (runs cloud onboarding wizard by default)')\n .option('--local', 'Use local/self-hosted mode instead of cloud onboarding')\n .option('--no-interactive', 'Skip interactive prompts')\n .option('--config <path>', 'Path to use as template for new configuration')\n .action(async (path, options) => {\n await initCommand({ path, ...options });\n });\n\nconst configCommand = program.command('config').description('Manage Inkeep configuration');\n\nconfigCommand\n .command('get [key]')\n .description('Get configuration value(s)')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (key, options) => {\n const config = options.config || options.configFilePath;\n await configGetCommand(key, { config });\n });\n\nconfigCommand\n .command('set <key> <value>')\n .description('Set a configuration value')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (key, value, options) => {\n const config = options.config || options.configFilePath;\n await configSetCommand(key, value, { config });\n });\n\nconfigCommand\n .command('list')\n .description('List all configuration values')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (options) => {\n const config = options.config || options.configFilePath;\n await configListCommand({ config });\n });\n\nprogram\n .command('push')\n .description('Push a project configuration to the backend')\n .option('--project <project-id>', 'Project ID or path to project directory')\n .option('--config <path>', 'Path to configuration file')\n .option('--profile <name>', 'Profile to use for remote URLs and authentication')\n .option('--tenant-id <id>', 'Override tenant ID')\n .option('--agents-api-url <url>', 'Override agents API URL')\n .option(\n '--env <environment>',\n 'Environment to use for credential resolution (e.g., development, production)'\n )\n .option('--json', 'Generate project data JSON file instead of pushing to backend')\n .option('--all', 'Push all projects found in current directory tree')\n .option(\n '--tag <tag>',\n 'Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)'\n )\n .option('--quiet', 'Suppress profile/config logging')\n .action(pushCommand);\n\nprogram\n .command('pull')\n .description('Pull project configuration with clean, efficient code generation')\n .option(\n '--project <project-id>',\n 'Project ID to pull (or path to project directory). If in project directory, validates against local project ID.'\n )\n .option('--config <path>', 'Path to configuration file')\n .option('--profile <name>', 'Profile to use for remote URLs and authentication')\n .option(\n '--env <environment>',\n 'Environment file to generate (development, staging, production). Defaults to development'\n )\n .option('--json', 'Output project data as JSON instead of generating files')\n .option('--debug', 'Enable debug logging')\n .option('--verbose', 'Enable verbose logging')\n .option('--force', 'Force regeneration even if no changes detected')\n .option('--all', 'Pull all projects for current tenant')\n .option(\n '--tag <tag>',\n 'Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)'\n )\n .option('--quiet', 'Suppress profile/config logging')\n .addOption(\n new Option(\n '--conflict-strategy <strategy>',\n 'Auto-resolve merge conflicts: ours (keep local) or theirs (accept remote). Skips interactive prompts.'\n ).choices(['ours', 'theirs'])\n )\n .action(async (options) => {\n await pullV4Command(options);\n });\n\nprogram\n .command('list-agent')\n .description('List all available agents for a specific project')\n .requiredOption('--project <project-id>', 'Project ID to list agent for')\n .option('--tenant-id <tenant-id>', 'Tenant ID')\n .option('--agents-api-url <url>', 'Agents API URL')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (options) => {\n const config = options.config || options.configFilePath;\n await listAgentsCommand({ ...options, config });\n });\n\nprogram\n .command('dev')\n .description('Start the Inkeep dashboard server')\n .option('--port <port>', 'Port to run the server on', '3000')\n .option('--host <host>', 'Host to bind the server to', 'localhost')\n .option('--build', 'Build the Dashboard UI for production', false)\n .option('--export', 'Export the Next.js project source files', false)\n .option('--output-dir <dir>', 'Output directory for build files', './inkeep-dev')\n .option('--path', 'Output the path to the Dashboard UI', false)\n .option('--open-browser', 'Open the browser', false)\n .action(async (options) => {\n await devCommand({\n port: parseInt(options.port, 10),\n host: options.host,\n build: options.build,\n outputDir: options.outputDir,\n path: options.path,\n export: options.export,\n openBrowser: options.openBrowser,\n });\n });\n\nprogram\n .command('update')\n .description('Update @inkeep/agents-cli to the latest version')\n .option('--check', 'Check for updates without installing')\n .option('--force', 'Force update even if already on latest version')\n .action(updateCommand);\n\n// Authentication commands\nprogram\n .command('login')\n .description('Authenticate with Inkeep Cloud')\n .option('--profile <name>', 'Profile to authenticate (defaults to active profile)')\n .action(loginCommand);\n\nprogram\n .command('logout')\n .description('Log out of Inkeep Cloud')\n .option('--profile <name>', 'Profile to log out (defaults to active profile)')\n .action(logoutCommand);\n\nprogram\n .command('status')\n .description('Show current profile, authentication state, and remote URLs')\n .option('--profile <name>', 'Profile to show status for (defaults to active profile)')\n .action(statusCommand);\n\nprogram\n .command('whoami')\n .description('Display current authentication status (alias for status)')\n .action(whoamiCommand);\n\n// Profile management commands\nconst profileCommand = program\n .command('profile')\n .description('Manage CLI profiles for connecting to different remotes');\n\nprofileCommand.command('list').description('List all profiles').action(profileListCommand);\n\nprofileCommand.command('add [name]').description('Add a new profile').action(profileAddCommand);\n\nprofileCommand\n .command('use <name>')\n .description('Set the active profile')\n .action(profileUseCommand);\n\nprofileCommand\n .command('current')\n .description('Display the active profile details')\n .action(profileCurrentCommand);\n\nprofileCommand\n .command('remove <name>')\n .description('Remove a profile')\n .action(profileRemoveCommand);\n\nprogram.parse();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport './env'; // Load environment files first (needed by instrumentation)\nimport './instrumentation'; // Initialize Langfuse tracing second\n\n// Silence config loading logs for cleaner CLI output\nimport { getLogger } from '@inkeep/agents-core';\n\nconst configLogger = getLogger('config');\nconfigLogger.updateOptions({ level: 'silent' });\n\nimport { Command, Option } from 'commander';\nimport { addCommand } from './commands/add';\nimport { configGetCommand, configListCommand, configSetCommand } from './commands/config';\nimport { devCommand } from './commands/dev';\nimport { initCommand } from './commands/init';\nimport { listAgentsCommand } from './commands/list-agents';\nimport { loginCommand } from './commands/login';\nimport { logoutCommand } from './commands/logout';\nimport {\n profileAddCommand,\n profileCurrentCommand,\n profileListCommand,\n profileRemoveCommand,\n profileUseCommand,\n} from './commands/profile';\nimport { pullV4Command } from './commands/pull-v4/introspect';\nimport { pushCommand } from './commands/push';\nimport { statusCommand } from './commands/status';\nimport { updateCommand } from './commands/update';\nimport { whoamiCommand } from './commands/whoami';\nimport { PACKAGE_VERSION } from './utils/version-check';\n\nconst program = new Command();\n\nprogram.name('inkeep').description('CLI tool for Inkeep Agent Framework').version(PACKAGE_VERSION);\n\nprogram\n .command('add [template]')\n .description('Add a new template to the project')\n .option('--project <template>', 'Project template to add')\n .option('--mcp <template>', 'MCP template to add')\n .option(\n '--ui [component-id]',\n 'Add UI component(s) to apps/agents-ui/src/ui (omit id to add all)'\n )\n .option('--list', 'List available UI components (use with --ui)')\n .option('--target-path <path>', 'Target path to add the template to')\n .option('--local-prefix <path_prefix>', 'Use local templates from the given path prefix')\n .option('--config <path>', 'Path to configuration file')\n .option('--profile <name>', 'Profile to use for authentication')\n .option('--quiet', 'Suppress profile/config logging')\n .action(async (template, options) => {\n await addCommand({ template, ...options });\n });\n\nprogram\n .command('init [path]')\n .description('Initialize a new Inkeep project (runs cloud onboarding wizard by default)')\n .option('--local', 'Use local/self-hosted mode instead of cloud onboarding')\n .option('--no-interactive', 'Skip interactive prompts')\n .option('--config <path>', 'Path to use as template for new configuration')\n .action(async (path, options) => {\n await initCommand({ path, ...options });\n });\n\nconst configCommand = program.command('config').description('Manage Inkeep configuration');\n\nconfigCommand\n .command('get [key]')\n .description('Get configuration value(s)')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (key, options) => {\n const config = options.config || options.configFilePath;\n await configGetCommand(key, { config });\n });\n\nconfigCommand\n .command('set <key> <value>')\n .description('Set a configuration value')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (key, value, options) => {\n const config = options.config || options.configFilePath;\n await configSetCommand(key, value, { config });\n });\n\nconfigCommand\n .command('list')\n .description('List all configuration values')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (options) => {\n const config = options.config || options.configFilePath;\n await configListCommand({ config });\n });\n\nprogram\n .command('push')\n .description('Push a project configuration to the backend')\n .option('--project <project-id>', 'Project ID or path to project directory')\n .option('--config <path>', 'Path to configuration file')\n .option('--profile <name>', 'Profile to use for remote URLs and authentication')\n .option('--tenant-id <id>', 'Override tenant ID')\n .option('--agents-api-url <url>', 'Override agents API URL')\n .option(\n '--env <environment>',\n 'Environment to use for credential resolution (e.g., development, production)'\n )\n .option('--json', 'Generate project data JSON file instead of pushing to backend')\n .option('--all', 'Push all projects found in current directory tree')\n .option(\n '--tag <tag>',\n 'Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)'\n )\n .option('--quiet', 'Suppress profile/config logging')\n .option('--force', 'Skip conflict detection and push directly to remote')\n .action(pushCommand);\n\nprogram\n .command('pull')\n .description('Pull project configuration with clean, efficient code generation')\n .option(\n '--project <project-id>',\n 'Project ID to pull (or path to project directory). If in project directory, validates against local project ID.'\n )\n .option('--config <path>', 'Path to configuration file')\n .option('--profile <name>', 'Profile to use for remote URLs and authentication')\n .option(\n '--env <environment>',\n 'Environment file to generate (development, staging, production). Defaults to development'\n )\n .option('--json', 'Output project data as JSON instead of generating files')\n .option('--debug', 'Enable debug logging')\n .option('--verbose', 'Enable verbose logging')\n .option('--force', 'Force regeneration even if no changes detected')\n .option('--all', 'Pull all projects for current tenant')\n .option(\n '--tag <tag>',\n 'Use tagged config file (e.g., --tag prod loads prod.__inkeep.config.ts__)'\n )\n .option('--quiet', 'Suppress profile/config logging')\n .addOption(\n new Option(\n '--conflict-strategy <strategy>',\n 'Auto-resolve merge conflicts: ours (keep local) or theirs (accept remote). Skips interactive prompts.'\n ).choices(['ours', 'theirs'])\n )\n .action(async (options) => {\n await pullV4Command(options);\n });\n\nprogram\n .command('list-agent')\n .description('List all available agents for a specific project')\n .requiredOption('--project <project-id>', 'Project ID to list agent for')\n .option('--tenant-id <tenant-id>', 'Tenant ID')\n .option('--agents-api-url <url>', 'Agents API URL')\n .option('--config <path>', 'Path to configuration file')\n .option('--config-file-path <path>', 'Path to configuration file (deprecated, use --config)')\n .action(async (options) => {\n const config = options.config || options.configFilePath;\n await listAgentsCommand({ ...options, config });\n });\n\nprogram\n .command('dev')\n .description('Start the Inkeep dashboard server')\n .option('--port <port>', 'Port to run the server on', '3000')\n .option('--host <host>', 'Host to bind the server to', 'localhost')\n .option('--build', 'Build the Dashboard UI for production', false)\n .option('--export', 'Export the Next.js project source files', false)\n .option('--output-dir <dir>', 'Output directory for build files', './inkeep-dev')\n .option('--path', 'Output the path to the Dashboard UI', false)\n .option('--open-browser', 'Open the browser', false)\n .action(async (options) => {\n await devCommand({\n port: parseInt(options.port, 10),\n host: options.host,\n build: options.build,\n outputDir: options.outputDir,\n path: options.path,\n export: options.export,\n openBrowser: options.openBrowser,\n });\n });\n\nprogram\n .command('update')\n .description('Update @inkeep/agents-cli to the latest version')\n .option('--check', 'Check for updates without installing')\n .option('--force', 'Force update even if already on latest version')\n .action(updateCommand);\n\n// Authentication commands\nprogram\n .command('login')\n .description('Authenticate with Inkeep Cloud')\n .option('--profile <name>', 'Profile to authenticate (defaults to active profile)')\n .action(loginCommand);\n\nprogram\n .command('logout')\n .description('Log out of Inkeep Cloud')\n .option('--profile <name>', 'Profile to log out (defaults to active profile)')\n .action(logoutCommand);\n\nprogram\n .command('status')\n .description('Show current profile, authentication state, and remote URLs')\n .option('--profile <name>', 'Profile to show status for (defaults to active profile)')\n .action(statusCommand);\n\nprogram\n .command('whoami')\n .description('Display current authentication status (alias for status)')\n .action(whoamiCommand);\n\n// Profile management commands\nconst profileCommand = program\n .command('profile')\n .description('Manage CLI profiles for connecting to different remotes');\n\nprofileCommand.command('list').description('List all profiles').action(profileListCommand);\n\nprofileCommand.command('add [name]').description('Add a new profile').action(profileAddCommand);\n\nprofileCommand\n .command('use <name>')\n .description('Set the active profile')\n .action(profileUseCommand);\n\nprofileCommand\n .command('current')\n .description('Display the active profile details')\n .action(profileCurrentCommand);\n\nprofileCommand\n .command('remove <name>')\n .description('Remove a profile')\n .action(profileRemoveCommand);\n\nprogram.parse();\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { getTempBranchSuffix } from "@inkeep/agents-core";
2
+
3
+ //#region src/utils/temp-branch.ts
4
+ async function withLocalStateBranch({ apiClient, projectId, fromCommit, localDefinition, branchPrefix, fn }) {
5
+ const tempBranchName = getTempBranchSuffix(branchPrefix);
6
+ try {
7
+ await apiClient.createBranch(projectId, {
8
+ name: tempBranchName,
9
+ fromCommit
10
+ });
11
+ await apiClient.pushFullProject(projectId, tempBranchName, localDefinition);
12
+ return await fn(tempBranchName);
13
+ } finally {
14
+ try {
15
+ await apiClient.deleteBranch(projectId, tempBranchName, true);
16
+ } catch {}
17
+ }
18
+ }
19
+
20
+ //#endregion
21
+ export { withLocalStateBranch };
22
+ //# sourceMappingURL=temp-branch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temp-branch.js","names":[],"sources":["../../src/utils/temp-branch.ts"],"sourcesContent":["import { getTempBranchSuffix } from '@inkeep/agents-core';\nimport type { ManagementApiClient } from '../api';\n\nexport interface WithLocalStateBranchParams<T> {\n apiClient: ManagementApiClient;\n projectId: string;\n fromCommit: string;\n localDefinition: unknown;\n branchPrefix: string;\n fn: (branchName: string) => Promise<T>;\n}\n\nexport async function withLocalStateBranch<T>({\n apiClient,\n projectId,\n fromCommit,\n localDefinition,\n branchPrefix,\n fn,\n}: WithLocalStateBranchParams<T>): Promise<T> {\n const tempBranchName = getTempBranchSuffix(branchPrefix);\n\n try {\n await apiClient.createBranch(projectId, {\n name: tempBranchName,\n fromCommit,\n });\n\n await apiClient.pushFullProject(projectId, tempBranchName, localDefinition);\n\n return await fn(tempBranchName);\n } finally {\n try {\n await apiClient.deleteBranch(projectId, tempBranchName, true);\n } catch {\n // Best-effort cleanup\n }\n }\n}\n"],"mappings":";;;AAYA,eAAsB,qBAAwB,EAC5C,WACA,WACA,YACA,iBACA,cACA,MAC4C;CAC5C,MAAM,iBAAiB,oBAAoB,aAAa;AAExD,KAAI;AACF,QAAM,UAAU,aAAa,WAAW;GACtC,MAAM;GACN;GACD,CAAC;AAEF,QAAM,UAAU,gBAAgB,WAAW,gBAAgB,gBAAgB;AAE3E,SAAO,MAAM,GAAG,eAAe;WACvB;AACR,MAAI;AACF,SAAM,UAAU,aAAa,WAAW,gBAAgB,KAAK;UACvD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-cli",
3
- "version": "0.62.0",
3
+ "version": "0.62.2",
4
4
  "description": "Inkeep CLI tool",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,8 +39,8 @@
39
39
  "tsx": "^4.20.5",
40
40
  "yaml": "^2.7.0",
41
41
  "zod": "^4.3.6",
42
- "@inkeep/agents-core": "^0.62.0",
43
- "@inkeep/agents-sdk": "^0.62.0"
42
+ "@inkeep/agents-core": "^0.62.2",
43
+ "@inkeep/agents-sdk": "^0.62.2"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/degit": "^2.8.6",