@inkeep/agents-cli 0.59.4 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents-cli/package.js +1 -1
- package/dist/api.js +74 -2
- package/dist/api.js.map +1 -1
- package/dist/commands/pull-v4/generators/agent-generator.js +2 -2
- package/dist/commands/pull-v4/generators/agent-generator.js.map +1 -1
- package/dist/commands/pull-v4/generators/context-config-generator.js.map +1 -1
- package/dist/commands/pull-v4/introspect/index.js +70 -17
- package/dist/commands/pull-v4/introspect/index.js.map +1 -1
- package/dist/commands/pull-v4/merge-conflicts.js +37 -0
- package/dist/commands/pull-v4/merge-conflicts.js.map +1 -0
- package/dist/commands/pull-v4/merge-ui/column-row.js +63 -0
- package/dist/commands/pull-v4/merge-ui/column-row.js.map +1 -0
- package/dist/commands/pull-v4/merge-ui/conflict-view.js +135 -0
- package/dist/commands/pull-v4/merge-ui/conflict-view.js.map +1 -0
- package/dist/commands/pull-v4/merge-ui/help-bar.js +79 -0
- package/dist/commands/pull-v4/merge-ui/help-bar.js.map +1 -0
- package/dist/commands/pull-v4/merge-ui/merge-app.js +239 -0
- package/dist/commands/pull-v4/merge-ui/merge-app.js.map +1 -0
- package/dist/commands/pull-v4/merge-ui/resolution-summary.js +106 -0
- package/dist/commands/pull-v4/merge-ui/resolution-summary.js.map +1 -0
- package/dist/commands/pull-v4/merge-ui/types.js +1 -0
- package/dist/commands/pull-v4/merge-ui/utils.js +43 -0
- package/dist/commands/pull-v4/merge-ui/utils.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/state.js +46 -0
- package/dist/utils/state.js.map +1 -0
- package/package.json +7 -4
|
@@ -2,7 +2,9 @@ import { ManagementApiClient } from "../../../api.js";
|
|
|
2
2
|
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
|
+
import { readProjectState, writeProjectState } from "../../../utils/state.js";
|
|
5
6
|
import { introspectGenerate } from "../introspect-generator.js";
|
|
7
|
+
import { getTempBranchSuffix } from "@inkeep/agents-core";
|
|
6
8
|
import { join, resolve } from "node:path";
|
|
7
9
|
import * as p from "@clack/prompts";
|
|
8
10
|
import { existsSync, mkdirSync } from "node:fs";
|
|
@@ -78,7 +80,6 @@ async function pullV4Command(options) {
|
|
|
78
80
|
console.log(styleText("blue", "\nInkeep Pull:"));
|
|
79
81
|
if (options.introspect) console.log(styleText("gray", " Introspect mode • Complete regeneration • No comparison needed"));
|
|
80
82
|
else console.log(styleText("gray", " Smart comparison • Detect all changes • Targeted updates"));
|
|
81
|
-
const s = p.spinner();
|
|
82
83
|
try {
|
|
83
84
|
const { config, isCI } = await initializeCommand({
|
|
84
85
|
configPath: options.config,
|
|
@@ -89,20 +90,17 @@ async function pullV4Command(options) {
|
|
|
89
90
|
logConfig: true,
|
|
90
91
|
quiet: options.quiet
|
|
91
92
|
});
|
|
92
|
-
s.start("Detecting project...");
|
|
93
93
|
let projectDir;
|
|
94
94
|
let projectId;
|
|
95
95
|
let localProjectForId = null;
|
|
96
96
|
const currentDir = process.cwd();
|
|
97
97
|
if (existsSync(join(currentDir, "index.ts"))) {
|
|
98
98
|
projectDir = currentDir;
|
|
99
|
-
s.start("Loading local project...");
|
|
100
99
|
try {
|
|
101
100
|
localProjectForId = await loadProject(projectDir);
|
|
102
101
|
const localProjectId = localProjectForId.getId();
|
|
103
102
|
if (options.project) {
|
|
104
103
|
if (localProjectId !== options.project) {
|
|
105
|
-
s.stop("Project ID mismatch");
|
|
106
104
|
console.error(styleText("red", `Local project ID "${localProjectId}" doesn't match --project "${options.project}"`));
|
|
107
105
|
console.error(styleText("yellow", "Either remove --project flag or ensure it matches the local project ID"));
|
|
108
106
|
if (batchMode) return {
|
|
@@ -113,14 +111,12 @@ async function pullV4Command(options) {
|
|
|
113
111
|
}
|
|
114
112
|
}
|
|
115
113
|
projectId = localProjectId;
|
|
116
|
-
|
|
114
|
+
console.log(styleText("green", `◆ Using local project: ${projectId}`));
|
|
117
115
|
} catch (error) {
|
|
118
|
-
s.stop("Failed to load local project");
|
|
119
116
|
throw new Error(`Could not load local project: ${error instanceof Error ? error.message : String(error)}`);
|
|
120
117
|
}
|
|
121
118
|
} else {
|
|
122
119
|
if (!options.project) {
|
|
123
|
-
s.stop("No index.ts found in current directory");
|
|
124
120
|
console.error(styleText("yellow", "Please run this command from a directory containing index.ts or use --project <project-id>"));
|
|
125
121
|
if (batchMode) return {
|
|
126
122
|
success: false,
|
|
@@ -131,23 +127,74 @@ async function pullV4Command(options) {
|
|
|
131
127
|
const projectPath = resolve(currentDir, options.project);
|
|
132
128
|
if (existsSync(join(projectPath, "index.ts"))) {
|
|
133
129
|
projectDir = projectPath;
|
|
134
|
-
s.start("Loading project from specified path...");
|
|
135
130
|
try {
|
|
136
131
|
localProjectForId = await loadProject(projectDir);
|
|
137
132
|
projectId = localProjectForId.getId();
|
|
138
|
-
|
|
133
|
+
console.log(styleText("green", `◆ Using project from path: ${projectId}`));
|
|
139
134
|
} catch (error) {
|
|
140
|
-
s.stop("Failed to load project from path");
|
|
141
135
|
throw new Error(`Could not load project from ${projectPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
142
136
|
}
|
|
143
137
|
} else {
|
|
144
138
|
projectId = options.project;
|
|
145
139
|
projectDir = join(currentDir, projectId);
|
|
146
|
-
|
|
140
|
+
console.log(styleText("green", `◆ Creating new project directory: ${projectDir}`));
|
|
147
141
|
}
|
|
148
142
|
}
|
|
149
|
-
|
|
150
|
-
|
|
143
|
+
const lastPulledHash = readProjectState(projectId)?.lastPulledHash;
|
|
144
|
+
if (options.debug && lastPulledHash) console.log(styleText("gray", ` Last pulled hash: ${lastPulledHash}`));
|
|
145
|
+
const apiClient = await ManagementApiClient.create(config.agentsApiUrl, options.config, config.tenantId, projectId, isCI, config.agentsApiKey);
|
|
146
|
+
let currentMainHash;
|
|
147
|
+
try {
|
|
148
|
+
currentMainHash = (await apiClient.getBranch(projectId, "main")).hash;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (options.debug) console.log(styleText("gray", ` Could not fetch main branch hash: ${error instanceof Error ? error.message : String(error)}`));
|
|
151
|
+
}
|
|
152
|
+
if (options.debug && currentMainHash) console.log(styleText("gray", ` Current main hash: ${currentMainHash}`));
|
|
153
|
+
let remoteProject;
|
|
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, {
|
|
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, {
|
|
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)}`));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} else remoteProject = await apiClient.getFullProject(projectId);
|
|
151
198
|
if (options.debug && remoteProject.functions) {
|
|
152
199
|
console.log(styleText("gray", " 📋 Project-level functions from API:"), Object.keys(remoteProject.functions));
|
|
153
200
|
Object.entries(remoteProject.functions).forEach(([id, data]) => {
|
|
@@ -184,7 +231,7 @@ async function pullV4Command(options) {
|
|
|
184
231
|
}
|
|
185
232
|
}
|
|
186
233
|
enrichCanDelegateToWithTypes(remoteProject);
|
|
187
|
-
|
|
234
|
+
console.log(styleText("green", "◆ Project data fetched"));
|
|
188
235
|
if (options.json) {
|
|
189
236
|
console.log(JSON.stringify(remoteProject, null, 2));
|
|
190
237
|
restoreLogLevel();
|
|
@@ -192,13 +239,20 @@ async function pullV4Command(options) {
|
|
|
192
239
|
}
|
|
193
240
|
const paths = createProjectStructure(projectDir);
|
|
194
241
|
await generateProjectSkillsIfPresent(remoteProject, paths.skillsDir);
|
|
195
|
-
|
|
242
|
+
console.log(styleText("gray", "Generating files..."));
|
|
196
243
|
await introspectGenerate({
|
|
197
244
|
project: remoteProject,
|
|
198
245
|
paths,
|
|
199
246
|
debug: options.debug
|
|
200
247
|
});
|
|
201
|
-
|
|
248
|
+
console.log(styleText("green", "◆ All files generated"));
|
|
249
|
+
try {
|
|
250
|
+
const mainBranch = await apiClient.getBranch(projectId, "main");
|
|
251
|
+
writeProjectState(projectId, mainBranch.hash);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.warn(styleText("yellow", `Warning: Could not save pull state: ${error instanceof Error ? error.message : String(error)}`));
|
|
254
|
+
console.warn(styleText("yellow", "Future pulls may re-prompt for conflict resolution."));
|
|
255
|
+
}
|
|
202
256
|
console.log(styleText("green", "\nProject synced successfully!"));
|
|
203
257
|
console.log(styleText("gray", ` Location: ${paths.projectRoot}`));
|
|
204
258
|
console.log(styleText("gray", ` Environment: ${options.env || "development"}`));
|
|
@@ -208,7 +262,6 @@ async function pullV4Command(options) {
|
|
|
208
262
|
process.exit(0);
|
|
209
263
|
} catch (error) {
|
|
210
264
|
const message = error instanceof Error ? error.stack : String(error);
|
|
211
|
-
s.stop();
|
|
212
265
|
console.error(styleText("red", `\nError: ${message}`));
|
|
213
266
|
if (options.debug && error instanceof Error) console.error(styleText("red", error.stack || ""));
|
|
214
267
|
restoreLogLevel();
|
|
@@ -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 } 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 { 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 /** 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 const s = p.spinner();\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\n // Step 2: Determine project directory and ID\n s.start('Detecting project...');\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 s.start('Loading local project...');\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 s.stop('Project ID mismatch');\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 s.stop(`Using local project: ${projectId}`);\n } catch (error) {\n s.stop('Failed to load local project');\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 s.stop('No index.ts found in current directory');\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 s.start('Loading project from specified path...');\n try {\n localProjectForId = await loadProject(projectDir);\n projectId = localProjectForId.getId();\n s.stop(`Using project from path: ${projectId}`);\n } catch (error) {\n s.stop('Failed to load project from path');\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 s.stop(`Creating new project directory: ${projectDir}`);\n }\n }\n\n // Step 4: Fetch project data from API\n s.start(`Fetching project: ${projectId}`);\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 const remoteProject = await apiClient.getFullProject(projectId);\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 s.message('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 s.start('Starting 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 s.stop('All files generated');\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 s.stop();\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, 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":";;;;;;;;;;;;;;;;;;;;;;;AAmBA,aAAa,sBAAsB;;;;AA2DnC,SAAgB,uBAAuB,aAAmC;AACxE,WAAU,aAAa,EAAE,WAAW,MAAM,CAAC;AAC3C,QAAO;EACL;EACA,WAAW,KAAK,aAAa,SAAS;EACtC,UAAU,KAAK,aAAa,QAAQ;EACpC,mBAAmB,KAAK,aAAa,kBAAkB;EACvD,uBAAuB,KAAK,aAAa,sBAAsB;EAC/D,qBAAqB,KAAK,aAAa,oBAAoB;EAC3D,iBAAiB,KAAK,aAAa,eAAe;EAClD,gBAAgB,KAAK,aAAa,cAAc;EAChD,mBAAmB,KAAK,aAAa,kBAAkB;EACvD,mBAAmB,KAAK,aAAa,kBAAkB;EACvD,WAAW,KAAK,aAAa,SAAS;EACvC;;;;;AAMH,SAAgB,6BAA6B,SAAsC;CACjF,MAAM,EAAE,WAAW;CAEnB,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,OAAO,CAAC;CAChD,MAAM,iBAAiB,IAAI,IACzB,OAAO,OAAO,OAAO,CAAC,SAAS,cAAc,OAAO,KAAK,UAAU,UAAU,CAAC,CAC/E;CACD,MAAM,sBAAsB,IAAI,IAC9B,QAAQ,iBAAiB,OAAO,KAAK,QAAQ,eAAe,GAAG,EAAE,CAClE;CAID,SAAS,yBAAyB,eAAqC;AACrE,SAAO,cAAc,KAAK,SAAS;AAEjC,OAAI,OAAO,SAAS,SAAU,QAAO;AACrC,OAAI,YAAY,IAAI,KAAK,CAAE,QAAO,EAAE,SAAS,MAAM;AACnD,OAAI,eAAe,IAAI,KAAK,CAAE,QAAO,EAAE,YAAY,MAAM;AACzD,OAAI,oBAAoB,IAAI,KAAK,CAAE,QAAO,EAAE,iBAAiB,MAAM;AACnE,UAAO;IACP;;AAIJ,MAAK,MAAM,EAAE,eAAe,OAAO,OAAO,QAAQ,OAAO,CAEvD,MAAK,MAAM,gBAAgB,OAAO,OAAO,UAAU,CACjD,KAAI,MAAM,QAAQ,aAAa,cAAc,CAE3C,cAAa,gBAAgB,yBAAyB,aAAa,cAAc;;;;;;AAUzF,eAAsB,cAAc,SAAyD;AAE3F,KAAI,QAAQ,KAAK;AACf,QAAM,gBAAgB,QAAQ;AAC9B;;CAGF,MAAM,YAAY,QAAQ,cAAc;CAGxC,MAAM,mBAAmB,QAAQ,IAAI;AACrC,SAAQ,IAAI,YAAY;CAExB,MAAM,wBAAwB;AAC5B,MAAI,qBAAqB,OACvB,SAAQ,IAAI,YAAY;MAExB,QAAO,QAAQ,IAAI;;AAKvB,KAAI,CAAC,UACH,gCAA+B;AAGjC,SAAQ,IAAI,UAAU,QAAQ,iBAAiB,CAAC;AAChD,KAAI,QAAQ,WACV,SAAQ,IACN,UAAU,QAAQ,mEAAmE,CACtF;KAED,SAAQ,IAAI,UAAU,QAAQ,6DAA6D,CAAC;AAG9F,KAAI;EAEF,MAAM,EAAE,QAAQ,SAAS,MAAM,kBAAkB;GAC/C,YAAY,QAAQ;GACpB,aAAa,QAAQ;GACrB,KAAK,QAAQ;GACb,aAAa;GACb,aAAa;GACb,WAAW;GACX,OAAO,QAAQ;GAChB,CAAC;EACF,IAAI;EACJ,IAAI;EACJ,IAAI,oBAAyB;EAE7B,MAAM,aAAa,QAAQ,KAAK;AAGhC,MAF0B,WAAW,KAAK,YAAY,WAAW,CAAC,EAE3C;AAErB,gBAAa;AAEb,OAAI;AACF,wBAAoB,MAAM,YAAY,WAAW;IACjD,MAAM,iBAAiB,kBAAkB,OAAO;AAEhD,QAAI,QAAQ,SAEV;SAAI,mBAAmB,QAAQ,SAAS;AACtC,cAAQ,MACN,UACE,OACA,qBAAqB,eAAe,6BAA6B,QAAQ,QAAQ,GAClF,CACF;AACD,cAAQ,MACN,UACE,UACA,yEACD,CACF;AACD,UAAI,UACF,QAAO;OAAE,SAAS;OAAO,OAAO;OAAuB;AAEzD,cAAQ,KAAK,EAAE;;;AAInB,gBAAY;AACZ,YAAQ,IAAI,UAAU,SAAS,0BAA0B,YAAY,CAAC;YAC/D,OAAO;AACd,UAAM,IAAI,MACR,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACxF;;SAEE;AAEL,OAAI,CAAC,QAAQ,SAAS;AACpB,YAAQ,MACN,UACE,UACA,6FACD,CACF;AACD,QAAI,UACF,QAAO;KAAE,SAAS;KAAO,OAAO;KAAgD;AAElF,YAAQ,KAAK,EAAE;;GAIjB,MAAM,cAAc,QAAQ,YAAY,QAAQ,QAAQ;AAGxD,OAFuB,WAAW,KAAK,aAAa,WAAW,CAAC,EAE5C;AAElB,iBAAa;AACb,QAAI;AACF,yBAAoB,MAAM,YAAY,WAAW;AACjD,iBAAY,kBAAkB,OAAO;AACrC,aAAQ,IAAI,UAAU,SAAS,8BAA8B,YAAY,CAAC;aACnE,OAAO;AACd,WAAM,IAAI,MACR,+BAA+B,YAAY,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACtG;;UAEE;AAEL,gBAAY,QAAQ;AACpB,iBAAa,KAAK,YAAY,UAAU;AACxC,YAAQ,IAAI,UAAU,SAAS,qCAAqC,aAAa,CAAC;;;EAKtF,MAAM,iBADgB,iBAAiB,UAAU,EACX;AAEtC,MAAI,QAAQ,SAAS,eACnB,SAAQ,IAAI,UAAU,QAAQ,wBAAwB,iBAAiB,CAAC;EAG1E,MAAM,YAAY,MAAM,oBAAoB,OAC1C,OAAO,cACP,QAAQ,QACR,OAAO,UACP,WACA,MACA,OAAO,aACR;EAED,IAAI;AACJ,MAAI;AAEF,sBADmB,MAAM,UAAU,UAAU,WAAW,OAAO,EAClC;WACtB,OAAO;AACd,OAAI,QAAQ,MACV,SAAQ,IACN,UACE,QACA,wCAAwC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GAC/F,CACF;;AAKL,MAAI,QAAQ,SAAS,gBACnB,SAAQ,IAAI,UAAU,QAAQ,yBAAyB,kBAAkB,CAAC;EAG5E,IAAI;AAEJ,MAAI,qBAAqB,gBAAgB;GACvC,MAAM,iBAAiB,oBAAoB,WAAW;AAEtD,OAAI;AACF,UAAM,UAAU,aAAa,WAAW;KACtC,MAAM;KACN,YAAY;KACb,CAAC;IAEF,MAAM,yBAAyB,MAAM,kBAAkB,mBAAmB;AAC1E,UAAM,UAAU,gBAAgB,WAAW,gBAAgB,uBAAuB;IAKlF,MAAM,UAAU,MAAM,UAAU,aAAa,WAAW;KACtD,cAAc;KACd,cAAc;KACf,CAAC;AAEF,QAAI,QAAQ,cAAc;KACxB,MAAM,EAAE,gCAAgC,MAAM,OAAO;KACrD,MAAM,cAAc,MAAM,4BAA4B,QAAQ,WAAW,QAAQ;AAEjF,SAAI,gBAAgB,MAAM;AACxB,cAAQ,IAAI,UAAU,UAAU,iBAAiB,CAAC;AAClD;;AAGF,WAAM,UAAU,aAAa,WAAW;MACtC,cAAc;MACd,cAAc;MACd,YAAY,QAAQ;MACpB,YAAY,QAAQ;MACpB;MACA,SAAS;MACV,CAAC;UAEF,OAAM,UAAU,aAAa,WAAW;KACtC,cAAc;KACd,cAAc;KACd,YAAY,QAAQ;KACpB,YAAY,QAAQ;KACpB,SAAS;KACV,CAAC;AAGJ,oBAAgB,MAAM,UAAU,eAAe,WAAW,eAAe;aACjE;AACR,QAAI;AACF,WAAM,UAAU,aAAa,WAAW,gBAAgB,KAAK;aACtD,cAAc;AACrB,SAAI,QAAQ,MACV,SAAQ,IACN,UACE,QACA,4CAA4C,eAAe,IAAI,wBAAwB,QAAQ,aAAa,UAAU,OAAO,aAAa,GAC3I,CACF;;;QAMP,iBAAgB,MAAM,UAAU,eAAe,UAAU;AAG3D,MAAI,QAAQ,SAAS,cAAc,WAAW;AAC5C,WAAQ,IACN,UAAU,QAAQ,0CAA0C,EAC5D,OAAO,KAAK,cAAc,UAAU,CACrC;AACD,UAAO,QAAQ,cAAc,UAAU,CAAC,SAAS,CAAC,IAAI,UAAyB;AAC7E,YAAQ,IACN,UACE,QACA,SAAS,GAAG,aAAa,CAAC,CAAC,KAAK,KAAK,oBAAoB,CAAC,CAAC,KAAK,cACjE,CACF;KACD;;AAIJ,MAAI,cAAc,OAChB,MAAK,MAAM,CAAC,SAAS,cAAc,OAAO,QAAQ,cAAc,OAAO,EAAW;AAChF,OAAI,UAAU,eAAe;AAC3B,kBAAc,gBAAgB,cAAc,iBAAiB,EAAE;AAC/D,WAAO,OAAO,cAAc,eAAe,UAAU,cAAc;AACnE,QAAI,QAAQ,MACV,SAAQ,IACN,UACE,QACA,uCAAuC,QAAQ,IAAI,OAAO,KAAK,UAAU,cAAc,CAAC,KAAK,KAAK,GACnG,CACF;;AAGL,OAAI,UAAU,WAAW;AACvB,kBAAc,cAAc,EAAE;IAC9B,MAAM,EAAE,cAAc;AAEtB,WAAO,QAAQ,UAAU,UAAU,CAAC,SAAS,CAAC,QAAQ,cAA6B;AAEjF,eAAU,YAAY;MACpB,IAAI,SAAS;MACb,aAAa,SAAS;MACtB,aAAa,SAAS;MACtB,cAAc,SAAS;MACvB,WAAW;MACX,WAAW;MACZ;MACD;;;AAQR,MAAI,cAAc,UAAU,cAAc,OAAO;GAC/C,MAAM,iBAAiB,OAAO,KAAK,cAAc,MAAM;AAEvD,QAAK,MAAM,aAAa,OAAO,OAAO,cAAc,OAAO,CACzD,KAAI,UAAU,OAAO;IAEnB,MAAM,qBAAqB,OAAO,YAChC,OAAO,QAAQ,UAAU,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,eAAe,SAAS,OAAO,CAAC,CACvF;AAGD,QAAI,OAAO,KAAK,mBAAmB,CAAC,SAAS,EAC3C,WAAU,QAAQ;QAGlB,QAAO,UAAU;;;AAQzB,+BAA6B,cAAc;AAE3C,UAAQ,IAAI,UAAU,SAAS,yBAAyB,CAAC;AAEzD,MAAI,QAAQ,MAAM;AAChB,WAAQ,IAAI,KAAK,UAAU,eAAe,MAAM,EAAE,CAAC;AACnD,oBAAiB;AACjB;;EAIF,MAAM,QAAQ,uBAAuB,WAAW;AAEhD,QAAM,+BAA+B,eAAe,MAAM,UAAU;AAEpE,UAAQ,IAAI,UAAU,QAAQ,sBAAsB,CAAC;AACrD,QAAM,mBAAmB;GAEvB,SAAS;GACT;GACA,OAAO,QAAQ;GAChB,CAAC;AACF,UAAQ,IAAI,UAAU,SAAS,wBAAwB,CAAC;AAExD,MAAI;GACF,MAAM,aAAa,MAAM,UAAU,UAAU,WAAW,OAAO;AAC/D,qBAAkB,WAAW,WAAW,KAAK;WACtC,OAAO;AACd,WAAQ,KACN,UACE,UACA,uCAAuC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GAC9F,CACF;AACD,WAAQ,KAAK,UAAU,UAAU,sDAAsD,CAAC;;AAG1F,UAAQ,IAAI,UAAU,SAAS,iCAAiC,CAAC;AACjE,UAAQ,IAAI,UAAU,QAAQ,gBAAgB,MAAM,cAAc,CAAC;AACnE,UAAQ,IAAI,UAAU,QAAQ,mBAAmB,QAAQ,OAAO,gBAAgB,CAAC;AACjF,UAAQ,IACN,UACE,UACA,6HACD,CACF;AAED,mBAAiB;AACjB,MAAI,UACF,QAAO,EAAE,SAAS,MAAM;AAE1B,UAAQ,KAAK,EAAE;UACR,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,QAAQ,OAAO,MAAM;AACpE,UAAQ,MAAM,UAAU,OAAO,YAAY,UAAU,CAAC;AACtD,MAAI,QAAQ,SAAS,iBAAiB,MACpC,SAAQ,MAAM,UAAU,OAAO,MAAM,SAAS,GAAG,CAAC;AAEpD,mBAAiB;AACjB,MAAI,UACF,QAAO;GAAE,SAAS;GAAO,OAAO;GAAS;AAE3C,UAAQ,KAAK,EAAE;;;;;;;AAQnB,eAAe,gBAAgB,SAAuC;AACpE,SAAQ,IAAI,UAAU,QAAQ,iEAAiE,CAAC;AAChG,SAAQ,IACN,UACE,QACA,+EACD,CACF;AACD,SAAQ,IAAI,UAAU,QAAQ,4DAA4D,CAAC;AAG3F,gCAA+B;CAG/B,MAAM,EAAE,QAAQ,SAAS,MAAM,kBAAkB;EAC/C,YAAY,QAAQ;EACpB,aAAa,QAAQ;EACrB,KAAK,QAAQ;EACb,aAAa;EACb,aAAa;EACb,WAAW;EACX,OAAO,QAAQ;EAChB,CAAC;CAEF,MAAM,IAAI,EAAE,SAAS;AAErB,KAAI;AAEF,IAAE,MAAM,oCAAoC;EAU5C,MAAM,WAAW,OATC,MAAM,oBAAoB,OAC1C,OAAO,cACP,QAAQ,QACR,OAAO,UACP,QACA,MACA,OAAO,aACR,EAEgC,iBAAiB;AAClD,IAAE,KAAK,SAAS,SAAS,OAAO,aAAa;AAE7C,MAAI,CAAC,SAAS,QAAQ;AACpB,WAAQ,IAAI,UAAU,UAAU,qCAAqC,CAAC;AACtE,WAAQ,KAAK,EAAE;;EAIjB,MAAM,mBAAoC,EAAE;EAC5C,MAAM,cAA+B,EAAE;AAEvC,OAAK,MAAM,WAAW,SAEpB,KAAI,WAAW,KADG,KAAK,QAAQ,KAAK,EAAE,QAAQ,GAAG,EAClB,WAAW,CAAC,CACzC,kBAAiB,KAAK,QAAQ;MAE9B,aAAY,KAAK,QAAQ;AAI7B,UAAQ,IAAI,UAAU,QAAQ,wBAAwB,CAAC;AACvD,MAAI,iBAAiB,SAAS,GAAG;AAC/B,WAAQ,IAAI,UAAU,QAAQ,iCAAiC,CAAC;AAChE,QAAK,MAAM,WAAW,iBACpB,SAAQ,IAAI,UAAU,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,GAAG,IAAI,QAAQ,GAAG,GAAG,CAAC;;AAGzF,MAAI,YAAY,SAAS,GAAG;AAC1B,WAAQ,IAAI,UAAU,QAAQ,sBAAsB,CAAC;AACrD,QAAK,MAAM,WAAW,YACpB,SAAQ,IAAI,UAAU,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,GAAG,IAAI,QAAQ,GAAG,GAAG,CAAC;;AAGzF,UAAQ,KAAK;EAEb,MAAM,UAA6B,EAAE;EACrC,MAAM,QAAQ,SAAS;AAEvB,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,UAAU,SAAS;GACzB,MAAM,WAAW,IAAI,IAAI,EAAE,GAAG,MAAM;AAEpC,WAAQ,IAAI,UAAU,QAAQ,KAAK,IAAI,OAAO,GAAG,GAAG,CAAC;AACrD,WAAQ,IAAI,UAAU,QAAQ,GAAG,SAAS,WAAW,QAAQ,QAAQ,QAAQ,GAAG,KAAK,CAAC;GAEtF,MAAM,SAAS,MAAM,kBAAkB,QAAQ,IAAI,QAAQ,MAAM,SAAS,QAAQ,KAAK;AACvF,WAAQ,KAAK,OAAO;AAEpB,OAAI,OAAO,QACT,SAAQ,IACN,UACE,SACA,SAAS,OAAO,eAAe,OAAO,UAAU,KAAK,OAAO,YAC7D,CACF;OAED,SAAQ,IACN,UAAU,OAAO,SAAS,OAAO,eAAe,OAAO,UAAU,IAAI,OAAO,QAAQ,CACrF;;EAKL,MAAM,YAAY,QAAQ,QAAQ,MAAM,EAAE,QAAQ,CAAC;EACnD,MAAM,SAAS,QAAQ,QAAQ,MAAM,CAAC,EAAE,QAAQ,CAAC;AAEjD,UAAQ,IAAI,UAAU,QAAQ,KAAK,IAAI,OAAO,GAAG,GAAG,CAAC;AACrD,UAAQ,IAAI,UAAU,QAAQ,yBAAyB,CAAC;AACxD,UAAQ,IAAI,UAAU,SAAS,kBAAkB,YAAY,CAAC;AAC9D,MAAI,SAAS,GAAG;AACd,WAAQ,IAAI,UAAU,OAAO,eAAe,SAAS,CAAC;AAEtD,WAAQ,IAAI,UAAU,OAAO,qBAAqB,CAAC;AACnD,QAAK,MAAM,UAAU,QACnB,KAAI,CAAC,OAAO,QACV,SAAQ,IAAI,UAAU,OAAO,OAAO,OAAO,UAAU,IAAI,OAAO,QAAQ,CAAC;;AAK/E,UAAQ,KAAK,SAAS,IAAI,IAAI,EAAE;UACzB,OAAO;AACd,IAAE,MAAM;AACR,UAAQ,MACN,UAAU,OAAO,YAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GAAG,CACvF;AACD,UAAQ,KAAK,EAAE;;;;;;;AAQnB,eAAsB,kBACpB,WACA,aACA,SACA,QACA,MAC0B;CAC1B,MAAM,YAAY,KAAK,QAAQ,KAAK,EAAE,UAAU;CAChD,MAAM,qBAAqB,WAAW,KAAK,WAAW,WAAW,CAAC;AAElE,KAAI;AACF,MAAI,oBAAoB;AAEtB,WAAQ,IAAI,UAAU,QAAQ,6DAA6D,CAAC;GAG5F,MAAM,cAAc,QAAQ,KAAK;AACjC,WAAQ,MAAM,UAAU;AAExB,OAAI;IAEF,MAAM,SAAS,MAAM,cAAc;KACjC,GAAG;KACH,SAAS;KACT,KAAK;KACL,YAAY;KACb,CAAC;AAGF,YAAQ,MAAM,YAAY;AAE1B,QAAI,UAAU,OAAO,WAAW,SAC9B,QAAO;KACL;KACA;KACA;KACA,SAAS,OAAO;KAChB,OAAO,OAAO;KACf;AAGH,WAAO;KACL;KACA;KACA;KACA,SAAS;KACV;YACM,OAAO;AAEd,YAAQ,MAAM,YAAY;AAC1B,UAAM;;;AAGV,UAAQ,IAAI,UAAU,QAAQ,iBAAiB,CAAC;EAGhD,MAAM,mBAAmB,QAAQ,IAAI;AACrC,UAAQ,IAAI,YAAY;EAExB,MAAM,wBAAwB;AAC5B,OAAI,qBAAqB,OACvB,SAAQ,IAAI,YAAY;OAExB,QAAO,QAAQ,IAAI;;EAcvB,MAAM,gBAAgB,OATJ,MAAM,oBAAoB,OAC1C,OAAO,cACP,QAAQ,QACR,OAAO,UACP,WACA,MACA,OAAO,aACR,EAEqC,eAAe,UAAU;EAE/D,MAAM,QAAQ,uBAAuB,UAAU;AAC/C,QAAM,+BAA+B,eAAe,MAAM,UAAU;AAGpE,QAAM,mBAAmB;GAEvB,SAAS;GACT;GACD,CAAC;AAEF,mBAAiB;AAEjB,SAAO;GACL;GACA,aAAa,eAAe,cAAc;GAC1C;GACA,SAAS;GACV;UACM,OAAO;AACd,SAAO;GACL;GACA;GACA;GACA,SAAS;GACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC9D;;;AAIL,eAAe,+BACb,eACA,WACe;CACf,MAAM,SAAS,cAAc,UAAU,EAAE;AACzC,KAAI,CAAC,OAAO,KAAK,OAAO,CAAC,OACvB;CAGF,MAAM,EAAE,mBAAmB,MAAM,OAAO;AACxC,OAAM,eAAe,QAAQ,UAAU"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { formatEntityId } from "./merge-ui/utils.js";
|
|
2
|
+
import { MergeApp } from "./merge-ui/merge-app.js";
|
|
3
|
+
import { styleText } from "node:util";
|
|
4
|
+
import { render } from "ink";
|
|
5
|
+
import { createElement } from "react";
|
|
6
|
+
|
|
7
|
+
//#region src/commands/pull-v4/merge-conflicts.ts
|
|
8
|
+
async function resolveConflictsInteractive(conflicts, options) {
|
|
9
|
+
if (options.conflictStrategy) {
|
|
10
|
+
const pick = options.conflictStrategy;
|
|
11
|
+
console.log(styleText("gray", `\nAuto-resolving ${conflicts.length} conflict(s) with strategy: ${pick}`));
|
|
12
|
+
return conflicts.map((conflict) => ({
|
|
13
|
+
table: conflict.table,
|
|
14
|
+
primaryKey: conflict.primaryKey,
|
|
15
|
+
rowDefaultPick: pick
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
const result = await render(createElement(MergeApp, { conflicts })).waitUntilExit();
|
|
19
|
+
if (result === null) {
|
|
20
|
+
console.log(styleText("yellow", "\nMerge cancelled."));
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const resolutions = result;
|
|
24
|
+
console.log(styleText("green", `\n✓ Resolved ${resolutions.length} conflict(s):`));
|
|
25
|
+
for (const res of resolutions) {
|
|
26
|
+
const entity = formatEntityId(res.primaryKey);
|
|
27
|
+
const overrides = Object.values(res.columns ?? {}).filter((pick) => pick !== res.rowDefaultPick);
|
|
28
|
+
const overrideNote = overrides.length > 0 ? ` (${overrides.length} column override(s))` : "";
|
|
29
|
+
console.log(` ${styleText("cyan", res.table)} ${styleText("bold", entity)} → ${res.rowDefaultPick}${overrideNote}`);
|
|
30
|
+
}
|
|
31
|
+
console.log();
|
|
32
|
+
return resolutions;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { resolveConflictsInteractive };
|
|
37
|
+
//# sourceMappingURL=merge-conflicts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-conflicts.js","names":[],"sources":["../../../src/commands/pull-v4/merge-conflicts.ts"],"sourcesContent":["import { styleText } from 'node:util';\nimport type { ConflictItem, ConflictResolution } from '@inkeep/agents-core';\nimport { render } from 'ink';\nimport { createElement } from 'react';\nimport { MergeApp } from './merge-ui/merge-app';\nimport { formatEntityId } from './merge-ui/utils';\n\nexport interface ResolveConflictsOptions {\n conflictStrategy?: 'ours' | 'theirs';\n}\n\nexport async function resolveConflictsInteractive(\n conflicts: ConflictItem[],\n options: ResolveConflictsOptions\n): Promise<ConflictResolution[] | null> {\n if (options.conflictStrategy) {\n const pick = options.conflictStrategy;\n console.log(\n styleText('gray', `\\nAuto-resolving ${conflicts.length} conflict(s) with strategy: ${pick}`)\n );\n return conflicts.map((conflict) => ({\n table: conflict.table,\n primaryKey: conflict.primaryKey,\n rowDefaultPick: pick,\n }));\n }\n\n const instance = render(createElement(MergeApp, { conflicts }));\n const result = await instance.waitUntilExit();\n\n if (result === null) {\n console.log(styleText('yellow', '\\nMerge cancelled.'));\n return null;\n }\n\n const resolutions = result as ConflictResolution[];\n\n console.log(styleText('green', `\\n✓ Resolved ${resolutions.length} conflict(s):`));\n for (const res of resolutions) {\n const entity = formatEntityId(res.primaryKey);\n const overrides = Object.values(res.columns ?? {}).filter(\n (pick) => pick !== res.rowDefaultPick\n );\n const overrideNote = overrides.length > 0 ? ` (${overrides.length} column override(s))` : '';\n console.log(\n ` ${styleText('cyan', res.table)} ${styleText('bold', entity)} → ${res.rowDefaultPick}${overrideNote}`\n );\n }\n console.log();\n\n return resolutions;\n}\n"],"mappings":";;;;;;;AAWA,eAAsB,4BACpB,WACA,SACsC;AACtC,KAAI,QAAQ,kBAAkB;EAC5B,MAAM,OAAO,QAAQ;AACrB,UAAQ,IACN,UAAU,QAAQ,oBAAoB,UAAU,OAAO,8BAA8B,OAAO,CAC7F;AACD,SAAO,UAAU,KAAK,cAAc;GAClC,OAAO,SAAS;GAChB,YAAY,SAAS;GACrB,gBAAgB;GACjB,EAAE;;CAIL,MAAM,SAAS,MADE,OAAO,cAAc,UAAU,EAAE,WAAW,CAAC,CAAC,CACjC,eAAe;AAE7C,KAAI,WAAW,MAAM;AACnB,UAAQ,IAAI,UAAU,UAAU,qBAAqB,CAAC;AACtD,SAAO;;CAGT,MAAM,cAAc;AAEpB,SAAQ,IAAI,UAAU,SAAS,gBAAgB,YAAY,OAAO,eAAe,CAAC;AAClF,MAAK,MAAM,OAAO,aAAa;EAC7B,MAAM,SAAS,eAAe,IAAI,WAAW;EAC7C,MAAM,YAAY,OAAO,OAAO,IAAI,WAAW,EAAE,CAAC,CAAC,QAChD,SAAS,SAAS,IAAI,eACxB;EACD,MAAM,eAAe,UAAU,SAAS,IAAI,KAAK,UAAU,OAAO,wBAAwB;AAC1F,UAAQ,IACN,KAAK,UAAU,QAAQ,IAAI,MAAM,CAAC,GAAG,UAAU,QAAQ,OAAO,CAAC,KAAK,IAAI,iBAAiB,eAC1F;;AAEH,SAAQ,KAAK;AAEb,QAAO"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { formatValue } from "./utils.js";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/commands/pull-v4/merge-ui/column-row.tsx
|
|
6
|
+
function ValueLine({ label, value, isPicked }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, {
|
|
8
|
+
color: isPicked ? "green" : void 0,
|
|
9
|
+
dimColor: !isPicked,
|
|
10
|
+
children: [
|
|
11
|
+
" ",
|
|
12
|
+
label,
|
|
13
|
+
" ",
|
|
14
|
+
formatValue(value)
|
|
15
|
+
]
|
|
16
|
+
}) });
|
|
17
|
+
}
|
|
18
|
+
function ColumnRow({ columnName, oursValue, theirsValue, pick, isFocused, isLast }) {
|
|
19
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
20
|
+
flexDirection: "column",
|
|
21
|
+
marginBottom: isLast ? 0 : 1,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
24
|
+
justifyContent: "space-between",
|
|
25
|
+
children: [/* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
26
|
+
color: "cyan",
|
|
27
|
+
children: isFocused ? "▸ " : " "
|
|
28
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
29
|
+
bold: isFocused,
|
|
30
|
+
children: columnName
|
|
31
|
+
})] }), /* @__PURE__ */ jsxs(Box, { children: [
|
|
32
|
+
/* @__PURE__ */ jsx(Text, {
|
|
33
|
+
dimColor: !isFocused,
|
|
34
|
+
children: "pick: "
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ jsx(Text, {
|
|
37
|
+
bold: isFocused,
|
|
38
|
+
color: pick === "ours" ? "blue" : "magenta",
|
|
39
|
+
children: pick
|
|
40
|
+
}),
|
|
41
|
+
isFocused ? /* @__PURE__ */ jsx(Text, {
|
|
42
|
+
color: "green",
|
|
43
|
+
children: " ◀"
|
|
44
|
+
}) : null
|
|
45
|
+
] })]
|
|
46
|
+
}),
|
|
47
|
+
/* @__PURE__ */ jsx(ValueLine, {
|
|
48
|
+
label: "ours: ",
|
|
49
|
+
value: oursValue,
|
|
50
|
+
isPicked: pick === "ours"
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ jsx(ValueLine, {
|
|
53
|
+
label: "theirs:",
|
|
54
|
+
value: theirsValue,
|
|
55
|
+
isPicked: pick === "theirs"
|
|
56
|
+
})
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { ColumnRow };
|
|
63
|
+
//# sourceMappingURL=column-row.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-row.js","names":[],"sources":["../../../../src/commands/pull-v4/merge-ui/column-row.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport type { Side } from './types';\nimport { formatValue } from './utils';\n\ninterface ColumnRowProps {\n columnName: string;\n oursValue: unknown;\n theirsValue: unknown;\n pick: Side;\n isFocused: boolean;\n isLast: boolean;\n}\n\nfunction ValueLine({\n label,\n value,\n isPicked,\n}: {\n label: string;\n value: unknown;\n isPicked: boolean;\n}) {\n return (\n <Box>\n <Text color={isPicked ? 'green' : undefined} dimColor={!isPicked}>\n {' '}\n {label} {formatValue(value)}\n </Text>\n </Box>\n );\n}\n\nexport function ColumnRow({\n columnName,\n oursValue,\n theirsValue,\n pick,\n isFocused,\n isLast,\n}: ColumnRowProps) {\n return (\n <Box flexDirection=\"column\" marginBottom={isLast ? 0 : 1}>\n <Box justifyContent=\"space-between\">\n <Box>\n <Text color=\"cyan\">{isFocused ? '▸ ' : ' '}</Text>\n <Text bold={isFocused}>{columnName}</Text>\n </Box>\n <Box>\n <Text dimColor={!isFocused}>pick: </Text>\n <Text bold={isFocused} color={pick === 'ours' ? 'blue' : 'magenta'}>\n {pick}\n </Text>\n {isFocused ? <Text color=\"green\"> ◀</Text> : null}\n </Box>\n </Box>\n\n <ValueLine label=\"ours: \" value={oursValue} isPicked={pick === 'ours'} />\n <ValueLine label=\"theirs:\" value={theirsValue} isPicked={pick === 'theirs'} />\n </Box>\n );\n}\n"],"mappings":";;;;;AAaA,SAAS,UAAU,EACjB,OACA,OACA,YAKC;AACD,QACE,oBAAC,iBACC,qBAAC;EAAK,OAAO,WAAW,UAAU;EAAW,UAAU,CAAC;;GACrD;GACA;GAAM;GAAE,YAAY,MAAM;;GACtB,GACH;;AAIV,SAAgB,UAAU,EACxB,YACA,WACA,aACA,MACA,WACA,UACiB;AACjB,QACE,qBAAC;EAAI,eAAc;EAAS,cAAc,SAAS,IAAI;;GACrD,qBAAC;IAAI,gBAAe;eAClB,qBAAC,kBACC,oBAAC;KAAK,OAAM;eAAQ,YAAY,OAAO;MAAY,EACnD,oBAAC;KAAK,MAAM;eAAY;MAAkB,IACtC,EACN,qBAAC;KACC,oBAAC;MAAK,UAAU,CAAC;gBAAW;OAAa;KACzC,oBAAC;MAAK,MAAM;MAAW,OAAO,SAAS,SAAS,SAAS;gBACtD;OACI;KACN,YAAY,oBAAC;MAAK,OAAM;gBAAQ;OAAS,GAAG;QACzC;KACF;GAEN,oBAAC;IAAU,OAAM;IAAU,OAAO;IAAW,UAAU,SAAS;KAAU;GAC1E,oBAAC;IAAU,OAAM;IAAU,OAAO;IAAa,UAAU,SAAS;KAAY;;GAC1E"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { diffTypeColor, formatDiffType, formatEntityId } from "./utils.js";
|
|
2
|
+
import { ColumnRow } from "./column-row.js";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/pull-v4/merge-ui/conflict-view.tsx
|
|
7
|
+
function ConflictView({ conflict, resolution, changedColumns, focusedColumnIndex, conflictIndex, totalConflicts }) {
|
|
8
|
+
const entityId = formatEntityId(conflict.primaryKey);
|
|
9
|
+
const isNullOurs = conflict.ours === null;
|
|
10
|
+
const isNullTheirs = conflict.theirs === null;
|
|
11
|
+
function getPickForColumn(col) {
|
|
12
|
+
return resolution.columnOverrides[col] ?? resolution.rowDefaultPick;
|
|
13
|
+
}
|
|
14
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
15
|
+
flexDirection: "column",
|
|
16
|
+
children: /* @__PURE__ */ jsxs(Box, {
|
|
17
|
+
borderStyle: "round",
|
|
18
|
+
borderColor: "cyan",
|
|
19
|
+
paddingX: 1,
|
|
20
|
+
flexDirection: "column",
|
|
21
|
+
children: [/* @__PURE__ */ jsxs(Box, {
|
|
22
|
+
marginBottom: 1,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
25
|
+
bold: true,
|
|
26
|
+
children: [
|
|
27
|
+
"Conflict ",
|
|
28
|
+
conflictIndex + 1,
|
|
29
|
+
"/",
|
|
30
|
+
totalConflicts,
|
|
31
|
+
":",
|
|
32
|
+
" "
|
|
33
|
+
]
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ jsx(Text, {
|
|
36
|
+
color: "cyan",
|
|
37
|
+
children: conflict.table
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
40
|
+
bold: true,
|
|
41
|
+
children: [
|
|
42
|
+
" \"",
|
|
43
|
+
entityId,
|
|
44
|
+
"\""
|
|
45
|
+
]
|
|
46
|
+
}),
|
|
47
|
+
/* @__PURE__ */ jsx(Text, { children: " — local: " }),
|
|
48
|
+
/* @__PURE__ */ jsx(Text, {
|
|
49
|
+
color: diffTypeColor(conflict.ourDiffType),
|
|
50
|
+
children: formatDiffType(conflict.ourDiffType)
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ jsx(Text, { children: " | remote: " }),
|
|
53
|
+
/* @__PURE__ */ jsx(Text, {
|
|
54
|
+
color: diffTypeColor(conflict.theirDiffType),
|
|
55
|
+
children: formatDiffType(conflict.theirDiffType)
|
|
56
|
+
})
|
|
57
|
+
]
|
|
58
|
+
}), isNullOurs || isNullTheirs ? /* @__PURE__ */ jsxs(Box, {
|
|
59
|
+
flexDirection: "column",
|
|
60
|
+
children: [/* @__PURE__ */ jsxs(Box, {
|
|
61
|
+
marginBottom: 1,
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsx(Text, { children: " Pick: " }),
|
|
64
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
65
|
+
bold: true,
|
|
66
|
+
color: "cyan",
|
|
67
|
+
children: [
|
|
68
|
+
"[",
|
|
69
|
+
resolution.rowDefaultPick,
|
|
70
|
+
"]"
|
|
71
|
+
]
|
|
72
|
+
}),
|
|
73
|
+
/* @__PURE__ */ jsx(Text, {
|
|
74
|
+
dimColor: true,
|
|
75
|
+
children: " (← for ours, → for theirs)"
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsx(Text, {
|
|
78
|
+
color: "cyan",
|
|
79
|
+
children: " ◂"
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
}), /* @__PURE__ */ jsxs(Box, {
|
|
83
|
+
flexDirection: "column",
|
|
84
|
+
marginLeft: 2,
|
|
85
|
+
children: [/* @__PURE__ */ jsxs(Text, {
|
|
86
|
+
color: resolution.rowDefaultPick === "ours" ? "green" : void 0,
|
|
87
|
+
dimColor: resolution.rowDefaultPick !== "ours",
|
|
88
|
+
children: ["ours: ", isNullOurs ? "Delete this row (keep local deletion)" : "Keep local version"]
|
|
89
|
+
}), /* @__PURE__ */ jsxs(Text, {
|
|
90
|
+
color: resolution.rowDefaultPick === "theirs" ? "green" : void 0,
|
|
91
|
+
dimColor: resolution.rowDefaultPick !== "theirs",
|
|
92
|
+
children: [
|
|
93
|
+
"theirs:",
|
|
94
|
+
" ",
|
|
95
|
+
isNullTheirs ? "Delete this row (keep remote deletion)" : "Keep remote version"
|
|
96
|
+
]
|
|
97
|
+
})]
|
|
98
|
+
})]
|
|
99
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Box, {
|
|
100
|
+
marginBottom: 1,
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ jsx(Text, { children: " Row default: " }),
|
|
103
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
104
|
+
bold: true,
|
|
105
|
+
color: focusedColumnIndex === -1 ? "cyan" : void 0,
|
|
106
|
+
children: [
|
|
107
|
+
"[",
|
|
108
|
+
resolution.rowDefaultPick,
|
|
109
|
+
"]"
|
|
110
|
+
]
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ jsx(Text, {
|
|
113
|
+
dimColor: true,
|
|
114
|
+
children: " (← for ours, → for theirs)"
|
|
115
|
+
}),
|
|
116
|
+
focusedColumnIndex === -1 && /* @__PURE__ */ jsx(Text, {
|
|
117
|
+
color: "cyan",
|
|
118
|
+
children: " ◂"
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}), changedColumns.map((col, i) => /* @__PURE__ */ jsx(ColumnRow, {
|
|
122
|
+
columnName: col,
|
|
123
|
+
oursValue: conflict.ours?.[col],
|
|
124
|
+
theirsValue: conflict.theirs?.[col],
|
|
125
|
+
pick: getPickForColumn(col),
|
|
126
|
+
isFocused: focusedColumnIndex === i,
|
|
127
|
+
isLast: i === changedColumns.length - 1
|
|
128
|
+
}, col))] })]
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
export { ConflictView };
|
|
135
|
+
//# sourceMappingURL=conflict-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflict-view.js","names":[],"sources":["../../../../src/commands/pull-v4/merge-ui/conflict-view.tsx"],"sourcesContent":["import type { ConflictItem } from '@inkeep/agents-core';\nimport { Box, Text } from 'ink';\nimport { ColumnRow } from './column-row';\nimport type { ConflictResolutionState, Side } from './types';\nimport { diffTypeColor, formatDiffType, formatEntityId } from './utils';\n\ninterface ConflictViewProps {\n conflict: ConflictItem;\n resolution: ConflictResolutionState;\n changedColumns: string[];\n focusedColumnIndex: number;\n conflictIndex: number;\n totalConflicts: number;\n}\n\nexport function ConflictView({\n conflict,\n resolution,\n changedColumns,\n focusedColumnIndex,\n conflictIndex,\n totalConflicts,\n}: ConflictViewProps) {\n const entityId = formatEntityId(conflict.primaryKey);\n const isNullOurs = conflict.ours === null;\n const isNullTheirs = conflict.theirs === null;\n\n function getPickForColumn(col: string): Side {\n return resolution.columnOverrides[col] ?? resolution.rowDefaultPick;\n }\n\n return (\n <Box flexDirection=\"column\">\n <Box borderStyle=\"round\" borderColor=\"cyan\" paddingX={1} flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold>\n Conflict {conflictIndex + 1}/{totalConflicts}:{' '}\n </Text>\n <Text color=\"cyan\">{conflict.table}</Text>\n <Text bold> "{entityId}"</Text>\n <Text> — local: </Text>\n <Text color={diffTypeColor(conflict.ourDiffType)}>\n {formatDiffType(conflict.ourDiffType)}\n </Text>\n <Text> | remote: </Text>\n <Text color={diffTypeColor(conflict.theirDiffType)}>\n {formatDiffType(conflict.theirDiffType)}\n </Text>\n </Box>\n\n {isNullOurs || isNullTheirs ? (\n <Box flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text> Pick: </Text>\n <Text bold color=\"cyan\">\n [{resolution.rowDefaultPick}]\n </Text>\n <Text dimColor> (← for ours, → for theirs)</Text>\n <Text color=\"cyan\"> ◂</Text>\n </Box>\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text\n color={resolution.rowDefaultPick === 'ours' ? 'green' : undefined}\n dimColor={resolution.rowDefaultPick !== 'ours'}\n >\n ours: {isNullOurs ? 'Delete this row (keep local deletion)' : 'Keep local version'}\n </Text>\n <Text\n color={resolution.rowDefaultPick === 'theirs' ? 'green' : undefined}\n dimColor={resolution.rowDefaultPick !== 'theirs'}\n >\n theirs:{' '}\n {isNullTheirs ? 'Delete this row (keep remote deletion)' : 'Keep remote version'}\n </Text>\n </Box>\n </Box>\n ) : (\n <>\n <Box marginBottom={1}>\n <Text> Row default: </Text>\n <Text bold color={focusedColumnIndex === -1 ? 'cyan' : undefined}>\n [{resolution.rowDefaultPick}]\n </Text>\n <Text dimColor> (← for ours, → for theirs)</Text>\n {focusedColumnIndex === -1 && <Text color=\"cyan\"> ◂</Text>}\n </Box>\n\n {changedColumns.map((col, i) => (\n <ColumnRow\n key={col}\n columnName={col}\n oursValue={conflict.ours?.[col]}\n theirsValue={conflict.theirs?.[col]}\n pick={getPickForColumn(col)}\n isFocused={focusedColumnIndex === i}\n isLast={i === changedColumns.length - 1}\n />\n ))}\n </>\n )}\n </Box>\n </Box>\n );\n}\n"],"mappings":";;;;;;AAeA,SAAgB,aAAa,EAC3B,UACA,YACA,gBACA,oBACA,eACA,kBACoB;CACpB,MAAM,WAAW,eAAe,SAAS,WAAW;CACpD,MAAM,aAAa,SAAS,SAAS;CACrC,MAAM,eAAe,SAAS,WAAW;CAEzC,SAAS,iBAAiB,KAAmB;AAC3C,SAAO,WAAW,gBAAgB,QAAQ,WAAW;;AAGvD,QACE,oBAAC;EAAI,eAAc;YACjB,qBAAC;GAAI,aAAY;GAAQ,aAAY;GAAO,UAAU;GAAG,eAAc;cACrE,qBAAC;IAAI,cAAc;;KACjB,qBAAC;MAAK;;OAAK;OACC,gBAAgB;OAAE;OAAE;OAAe;OAAE;;OAC1C;KACP,oBAAC;MAAK,OAAM;gBAAQ,SAAS;OAAa;KAC1C,qBAAC;MAAK;;OAAK;OAAQ;OAAS;;OAAa;KACzC,oBAAC,kBAAK,eAAiB;KACvB,oBAAC;MAAK,OAAO,cAAc,SAAS,YAAY;gBAC7C,eAAe,SAAS,YAAY;OAChC;KACP,oBAAC,kBAAK,gBAAkB;KACxB,oBAAC;MAAK,OAAO,cAAc,SAAS,cAAc;gBAC/C,eAAe,SAAS,cAAc;OAClC;;KACH,EAEL,cAAc,eACb,qBAAC;IAAI,eAAc;eACjB,qBAAC;KAAI,cAAc;;MACjB,oBAAC,kBAAK,YAAc;MACpB,qBAAC;OAAK;OAAK,OAAM;;QAAO;QACpB,WAAW;QAAe;;QACvB;MACP,oBAAC;OAAK;iBAAS;QAAkC;MACjD,oBAAC;OAAK,OAAM;iBAAO;QAAS;;MACxB,EACN,qBAAC;KAAI,eAAc;KAAS,YAAY;gBACtC,qBAAC;MACC,OAAO,WAAW,mBAAmB,SAAS,UAAU;MACxD,UAAU,WAAW,mBAAmB;iBACzC,UACQ,aAAa,0CAA0C;OACzD,EACP,qBAAC;MACC,OAAO,WAAW,mBAAmB,WAAW,UAAU;MAC1D,UAAU,WAAW,mBAAmB;;OACzC;OACS;OACP,eAAe,2CAA2C;;OACtD;MACH;KACF,GAEN,4CACE,qBAAC;IAAI,cAAc;;KACjB,oBAAC,kBAAK,mBAAqB;KAC3B,qBAAC;MAAK;MAAK,OAAO,uBAAuB,KAAK,SAAS;;OAAW;OAC9D,WAAW;OAAe;;OACvB;KACP,oBAAC;MAAK;gBAAS;OAAkC;KAChD,uBAAuB,MAAM,oBAAC;MAAK,OAAM;gBAAO;OAAS;;KACtD,EAEL,eAAe,KAAK,KAAK,MACxB,oBAAC;IAEC,YAAY;IACZ,WAAW,SAAS,OAAO;IAC3B,aAAa,SAAS,SAAS;IAC/B,MAAM,iBAAiB,IAAI;IAC3B,WAAW,uBAAuB;IAClC,QAAQ,MAAM,eAAe,SAAS;MANjC,IAOL,CACF,IACD;IAED;GACF"}
|