src — advanced
src — advanced
The src/advanced module provides a suite of sophisticated functionalities designed to enhance the core capabilities of the system, offering features typically found in advanced development environments. These components address complex challenges such as collaborative development, intelligent code assistance, and robust version control.
This document details each major component within the src/advanced module, explaining its purpose, internal workings, key APIs, and how it integrates with other parts of the codebase.
Module Overview
The src/advanced module encapsulates several distinct, high-value features:
- Conversation Branching and Merging: Manage divergent conversation paths and integrate them.
- Distributed Caching: Provide a shared, performant cache for team environments.
- Project Style Learning: Automatically adapt to and enforce project-specific coding styles.
- Selective File Rollback: Offer granular version control for individual files.
- Deterministic Session Replay: Record and replay user interactions for debugging and analysis.
- Specialized Language/Framework Agents: Utilize AI agents optimized for specific tech stacks.
- Team Mode with Shared Context: Enable collaborative AI assistance with shared knowledge.
- Three-Way Diff for Conflict Resolution: Facilitate advanced merging and conflict handling.
Most components follow a singleton pattern, providing a get factory function to ensure a single instance across the application, and extend EventEmitter for event-driven communication.
Conversation Branching and Merging (conversation-branching.ts)
This module provides a mechanism to manage divergent conversation threads, allowing users to explore alternative responses or ideas without losing the original context, similar to how version control systems handle code branches.
Purpose
To enable non-linear conversation flows, allowing users to:
- Branch off a conversation at any message.
- Explore different paths or prompts.
- Merge successful branches back into a main or target branch.
- Maintain a clear history of conversation evolution.
How it Works
The ConversationBranchManager class is the central orchestrator. It maintains a collection of ConversationBranch objects, each representing a distinct conversation path.
- Branch Creation: When
createBranchorbranchFromMessageis called, a newConversationBranchis created. If aparentBranchIdandbranchPointMessageIdare provided, the new branch inherits all messages from its parent up to and including the branch point message. - Message Management: Messages are added to the
currentBranchusingaddMessage. Each message is assigned a unique ID. - Branch Switching:
switchBranchchanges the active conversation context. - Merging: The
mergeBranchesmethod attempts to combine messages from asourceBranchinto atargetBranch. Currently, it primarily adds unique messages from the source to the target and sorts them by timestamp. Conflict detection is outlined in theMergeConflictinterface but not fully implemented for resolution inmergeBranches. - History:
getHistorytraces a branch back to its root parent.
Key Components
ConversationBranchManager: The main class for managing branches. ExtendsEventEmitterto signal branch and message events.ConversationBranch: Represents a single conversation thread, including its ID, name, parent, branch point, and an array ofMessageobjects.Message: Defines the structure of a single message within a conversation, including its role, content, and timestamp.MergeResult,MergeConflict: Interfaces for defining the outcome of a merge operation and any identified conflicts.
Usage
import { getConversationBranchManager } from 39;./conversation-branching39;;
const manager = getConversationBranchManager();
class="hl-cmt">// Initial branch is 39;main39;
const mainBranch = manager.getCurrentBranch();
manager.addMessage(39;user39;, 39;What is the capital of France?39;);
manager.addMessage(39;assistant39;, 39;Paris.39;);
class="hl-cmt">// Branch off from the assistant39;s message
const newBranch = manager.branchFromMessage(mainBranch.messages[1].id, 39;explore-germany39;);
manager.switchBranch(newBranch.id);
manager.addMessage(39;user39;, 39;And Germany?39;);
manager.addMessage(39;assistant39;, 39;Berlin.39;);
class="hl-cmt">// Switch back to main and add more messages
manager.switchBranch(mainBranch.id);
manager.addMessage(39;user39;, 39;What about Italy?39;);
manager.addMessage(39;assistant39;, 39;Rome.39;);
class="hl-cmt">// Attempt to merge 39;explore-germany39; into 39;main39;
const mergeResult = manager.mergeBranches(newBranch.id, mainBranch.id);
console.log(39;Merged branch messages:39;, mergeResult.mergedBranch.messages);
Integration
EventEmitter: Emits events likebranch-created,branch-switched,message-added,branches-merged,branch-deleted,branch-renamedfor external listeners.crypto: Used for generating unique IDs for branches and messages.
Architecture Diagram
graph TD
A[ConversationBranchManager] --> B{createBranch/branchFromMessage}
B --> C[ConversationBranch]
A --> D{addMessage}
D --> E[Message]
A --> F{switchBranch}
A --> G{mergeBranches}
G -- Copies & Sorts --> C
C -- Contains --> E
A -- Emits Events --> H[Listeners]
Distributed Caching (distributed-cache.ts)
This module provides a local, in-memory cache designed for shared use within a team context, offering performance benefits by storing frequently accessed data.
Purpose
To provide a fast, temporary storage for responses or computed values, reducing redundant computations and improving response times. It includes features like Time-To-Live (TTL) and size-based eviction to manage memory usage.
How it Works
The DistributedCache class manages a Map of CacheEntry objects.
- Configuration: The cache is initialized with
maxSize(total cache size),ttl(entry expiration), andsyncInterval(for periodic cleanup). - Key Generation: All keys are hashed using SHA256 to ensure consistency and fixed-size storage.
- Setting Entries:
setadds a new entry. It checks if the entry is too large or if adding it would exceed themaxSize. If necessary, it triggersevictIfNeededto remove older entries. - Retrieving Entries:
getretrieves an entry. It checks for expiration and increments ahitscounter. If expired or not found, it incrementsmisses. - Eviction:
evictIfNeededimplements a basic Least Recently Hit (LRH) eviction strategy, removing entries with the lowest hit count until space is available. - Cleanup:
startSyncinitiates a timer that periodically callscleanupto remove expired entries and emits cache statistics.
Key Components
DistributedCache: The main class managing cache operations. ExtendsEventEmitter.CacheEntry: Defines the structure of a cached item, including its key, value, and metadata (createdBy, createdAt, expiresAt, hits, size).DistributedCacheConfig: Configuration options for the cache.CacheStats: Provides metrics like total entries, total size, hit rate, and miss rate.
Usage
import { getDistributedCache } from 39;./distributed-cache39;;
const cache = getDistributedCache({ maxSize: 10 * 1024 * 1024, ttl: 60000 }); class="hl-cmt">// 10MB, 1 minute TTL
cache.on(39;set39;, ({ key, size }) => console.log(`Cache set: ${key}, size: ${size}`));
cache.on(39;hit39;, ({ key }) => console.log(`Cache hit: ${key}`));
cache.on(39;sync39;, (stats) => console.log(39;Cache sync stats:39;, stats));
cache.set(39;my-data-key39;, 39;some important data39;, 39;user12339;);
console.log(39;Retrieved:39;, cache.get(39;my-data-key39;));
cache.startSync(); class="hl-cmt">// Start periodic cleanup and stats emission
class="hl-cmt">// Later...
cache.dispose(); class="hl-cmt">// Clean up resources
Integration
EventEmitter: Emitsset,hit,cleared, andsyncevents.crypto: Used to generate SHA256 hashes for cache keys.NodeJS.Timeout: Used for thesyncIntervaltimer.
Project Style Learning (project-style-learning.ts)
This module enables the system to learn and adapt to the specific coding style of a given project by analyzing its source code.
Purpose
To automatically infer and document a project's coding conventions (e.g., naming, formatting, quote style, semicolon usage, indentation) and apply these preferences when generating or modifying code.
How it Works
The ProjectStyleLearner class performs a deep analysis of a project's codebase.
- File Discovery:
analyzeProjectfirst callsfindSourceFilesto recursively scan the project directory for common source code files (.ts,.js,.py, etc.), ignoring common non-source directories like.gitornode_modules. - Content Analysis: For each discovered file, its content is read, and
extractPatternsis invoked. This method uses regular expressions to detect prevalent patterns:
- Naming Conventions: Compares occurrences of
camelCasevs.snake_casevariables. - Quote Style: Counts single vs. double quotes.
- Semicolon Usage: Checks for semicolons at the end of lines.
- Indentation: Detects tabs vs. spaces (specifically 2 spaces).
- Style Storage: The inferred preferences are stored in a
ProjectStyleobject associated with theprojectPath. - Style Application:
applyStyleToCodecan take a string of code and modify it to conform to the learned preferences (e.g., changing double quotes to single quotes, removing semicolons). - Style Guide Generation:
generateStyleGuideproduces a human-readable summary of the learned style.
Key Components
ProjectStyleLearner: The main class for analyzing projects and applying styles. ExtendsEventEmitter.ProjectStyle: Stores the learned preferences, analyzed file count, and last analysis timestamp for a project.StylePattern: An interface for more granular style patterns, though the current implementation focuses onpreferences.
Usage
import { getProjectStyleLearner } from 39;./project-style-learning39;;
const learner = getProjectStyleLearner();
learner.on(39;analysis-complete39;, (style) => {
console.log(`Analysis complete for ${style.projectPath}. Preferences:`, style.preferences);
});
async function runAnalysis() {
const projectPath = 39;/path/to/your/project39;;
const style = await learner.analyzeProject(projectPath);
const styleGuide = learner.generateStyleGuide(projectPath);
console.log(styleGuide);
const originalCode = 39;const myVar = "hello";\nconsole.log(myVar);39;;
const styledCode = learner.applyStyleToCode(originalCode, projectPath);
console.log(39;Original:\n39;, originalCode);
console.log(39;Styled:\n39;, styledCode);
}
runAnalysis();
Integration
fs-extra: Used for asynchronous file system operations (readFile,readdir,ensureDir,pathExists).path: Used for path manipulation (join,normalize).EventEmitter: Emitsanalysis-completewhen a project's style has been fully analyzed.
Selective File Rollback (selective-rollback.ts)
This module provides a lightweight versioning system for individual files, allowing users to save snapshots and revert to previous states without relying on a full-fledged version control system like Git.
Purpose
To offer granular control over file versions, enabling users to:
- Save specific versions of files as checkpoints.
- View a history of changes for any tracked file.
- Roll back a file to any saved version.
- Compare different versions of a file.
How it Works
The SelectiveRollbackManager stores an array of FileVersion objects for each tracked file.
- Saving Versions:
saveVersiontakes a file path and its content, creates aFileVersionwith a unique ID, hash, and timestamp, and adds it to the beginning of the file's version history. It avoids saving duplicate content. - Retrieving Versions:
getVersionsreturns all saved versions for a given file, whilegetVersionretrieves a specific version by ID. - Rolling Back:
rollbackFileis the core rollback mechanism. Before overwriting the file, it first saves the current state of the file (if it exists) as a new version. Then, it writes the content of the targetversionIdto the file system. - Multiple Rollbacks:
rollbackMultipleallows rolling back several files in a single operation. - Comparison:
compareVersionsprovides a basic line-by-line comparison between two specified versions of a file, counting added, removed, and changed lines.
Key Components
SelectiveRollbackManager: The main class for managing file versions and rollbacks. ExtendsEventEmitter.FileVersion: Represents a snapshot of a file at a specific point in time, including its content, hash, timestamp, and source (e.g., 'manual', 'checkpoint').RollbackResult: Provides the outcome of a rollback operation, indicating success or failure.
Usage
import { getSelectiveRollbackManager } from 39;./selective-rollback39;;
import fs from 39;fs-extra39;;
const manager = getSelectiveRollbackManager();
manager.on(39;version-saved39;, (version) => console.log(`Version saved for ${version.path}: ${version.id}`));
manager.on(39;file-rolled-back39;, ({ path, versionId }) => console.log(`File ${path} rolled back to ${versionId}`));
async function demonstrateRollback() {
const filePath = 39;temp_file.txt39;;
await fs.writeFile(filePath, 39;Initial content\nLine 239;, 39;utf-839;);
class="hl-cmt">// Save initial version
const v1 = manager.saveVersion(filePath, await fs.readFile(filePath, 39;utf-839;));
class="hl-cmt">// Modify file and save new version
await fs.writeFile(filePath, 39;Modified content\nNew Line 2\nLine 339;, 39;utf-839;);
const v2 = manager.saveVersion(filePath, await fs.readFile(filePath, 39;utf-839;));
console.log(39;Current file content:39;, await fs.readFile(filePath, 39;utf-839;));
class="hl-cmt">// Rollback to v1
const result = await manager.rollbackFile(filePath, v1.id);
if (result.success) {
console.log(39;File rolled back successfully.39;);
console.log(39;Content after rollback:39;, await fs.readFile(filePath, 39;utf-839;));
}
class="hl-cmt">// Compare versions
const comparison = manager.compareVersions(filePath, v1.id, v2.id);
console.log(39;Comparison v1 vs v2:39;, comparison);
class="hl-cmt">// Clean up
await fs.remove(filePath);
}
demonstrateRollback();
Integration
fs-extra: Used for file system operations (pathExists,readFile,ensureDir,writeFile).path: Used for normalizing file paths.EventEmitter: Emitsversion-saved,file-rolled-back, andversions-clearedevents.crypto: Used for generating unique IDs and content hashes for versions.
Architecture Diagram
graph TD
A[SelectiveRollbackManager] --> B{saveVersion}
B -- Stores --> C[FileVersion]
A --> D{rollbackFile}
D -- Reads/Writes --> E[File System]
D -- Saves Current State --> B
A --> F{getVersions/getVersion}
A --> G{compareVersions}
G -- Compares --> C
A -- Emits Events --> H[Listeners]
Deterministic Session Replay (session-replay.ts)
This module provides functionality to record and replay user interaction sessions, capturing a sequence of events for debugging, analysis, or demonstration purposes.
Purpose
To enable the capture of a user's interaction flow with the system, including inputs, outputs, tool calls, and state changes. These recorded sessions can then be deterministically replayed to reproduce issues, understand user behavior, or demonstrate features.
How it Works
The SessionReplayManager manages the recording, storage, and replay of ReplaySession objects.
- Recording:
startRecordinginitializes a newReplaySessionand sets the manager to a recording state.recordEventcaptures individual actions or state changes asReplayEventobjects, adding them to thecurrentSession. Each event includes a timestamp, type, data, and a hash of the data for integrity verification.stopRecordingfinalizes the current session.
- Storage:
saveSessionserializes aReplaySessionto a JSON file within a dedicated.codebuddy/replaysdirectory.loadSessionandlistSessionshandle retrieving and listing saved sessions. - Replay: The
replaymethod takes asessionIdand iterates through its recorded events. It introduces delays between events to simulate the original timing (adjustable viaspeedoption) and emits each event for external processing (e.g., UI updates). - Integrity:
verifyIntegrityre-computes the hash for each event's data and compares it to the stored hash, ensuring the session data has not been tampered with.
Key Components
SessionReplayManager: The main class for managing session recording and replay. ExtendsEventEmitter.ReplaySession: Represents a complete recorded session, including its ID, name, start/end times, a list ofReplayEvents, and metadata.ReplayEvent: Defines a single event within a session, capturing its type (e.g., 'input', 'output', 'tool'), data, timestamp, and a content hash.
Usage
import { getSessionReplayManager } from 39;./session-replay39;;
import fs from 39;fs-extra39;;
const manager = getSessionReplayManager();
manager.on(39;recording-started39;, (sessionId) => console.log(`Recording session ${sessionId}`));
manager.on(39;event-recorded39;, (event) => console.log(`Recorded event: ${event.type}`));
manager.on(39;replay-event39;, (event) => console.log(`Replaying event: ${event.type} - ${JSON.stringify(event.data)}`));
async function demonstrateReplay() {
const metadata = { model: 39;gpt-439;, systemPrompt: 39;You are a helpful AI.39;, toolsEnabled: [39;search39;] };
const session = manager.startRecording(39;My Test Session39;, metadata);
manager.recordEvent(39;input39;, { text: 39;Hello AI39; });
await new Promise(r => setTimeout(r, 100));
manager.recordEvent(39;output39;, { text: 39;Hello user!39; });
await new Promise(r => setTimeout(r, 50));
manager.recordEvent(39;tool39;, { name: 39;search39;, query: 39;latest news39; });
const savedSession = manager.stopRecording();
if (savedSession) {
const filePath = await manager.saveSession(savedSession);
console.log(`Session saved to ${filePath}`);
console.log(39;\nStarting replay...39;);
await manager.replay(savedSession.id, { speed: 2, onEvent: (e) => console.log(`Custom handler: ${e.type}`) });
console.log(39;Replay completed.39;);
const integrity = manager.verifyIntegrity(savedSession);
console.log(`Session integrity verified: ${integrity}`);
}
class="hl-cmt">// Clean up
await fs.remove(39;.codebuddy/replays39;);
}
demonstrateReplay();
Integration
fs-extra: Used for file system operations (ensureDir,writeJson,readJson,readdir,pathExists) to persist and load sessions.path: Used for constructing file paths for session storage.EventEmitter: Emitsrecording-started,recording-stopped,event-recorded,replay-started,replay-event, andreplay-completedevents.crypto: Used for generating unique IDs for sessions and events, and for hashing event data for integrity checks.../utils/logger.js: Used for logging potential errors during session file parsing.
Architecture Diagram
graph TD
A[SessionReplayManager] --> B{startRecording}
B -- Creates --> C[ReplaySession]
A --> D{recordEvent}
D -- Adds to --> C
A --> E{stopRecording}
E -- Finalizes --> C
A --> F{saveSession}
F -- Writes JSON --> G[File System (.codebuddy/replays)]
A --> H{loadSession}
H -- Reads JSON --> G
A --> I{replay}
I -- Reads Events --> C
I -- Emits Events --> J[Listeners]
A --> K{verifyIntegrity}
K -- Checks Hashes --> C
Specialized Language/Framework Agents (specialized-agents.ts)
This module manages a registry of AI agents that are specifically optimized for different programming languages and frameworks.
Purpose
To allow the system to select and utilize AI agents that possess deep expertise in a particular technology stack, leading to more accurate, context-aware, and high-quality code generation, analysis, and refactoring.
How it Works
The SpecializedAgentManager maintains a collection of SpecializedAgent objects.
- Agent Registry: The manager is initialized with a predefined set of
SPECIALIZED_AGENTS(e.g., TypeScript Expert, Python Expert, React Expert), each detailing itscapabilities(languages, frameworks, specialties) and asystemPrompt. Additional agents can be registered dynamically usingregisterAgent. - Agent Selection:
getAgentretrieves an agent by its unique ID.selectAgentForLanguageandselectAgentForFrameworkfind the first agent that supports the specified language or framework.autoSelectAgentattempts to select an agent based on a provided context, prioritizing framework-specific agents over language-specific ones.
- Current Agent:
setCurrentAgentsets an agent as the active one, andgetCurrentAgentretrieves it.
Key Components
SpecializedAgentManager: The main class for managing and selecting specialized agents. ExtendsEventEmitter.SpecializedAgent: Defines an AI agent, including its ID, name, description,AgentCapability,systemPrompt, and examples.AgentCapability: Specifies the languages, frameworks, and other specialties an agent possesses.Language,Framework: Type definitions for supported languages and frameworks.
Usage
import { getSpecializedAgentManager } from 39;./specialized-agents39;;
const manager = getSpecializedAgentManager();
manager.on(39;agent-selected39;, (agent) => console.log(`Selected agent: ${agent.name}`));
class="hl-cmt">// Get all available agents
console.log(39;Available agents:39;, manager.getAgents().map(a => a.name));
class="hl-cmt">// Select an agent for a specific language
const tsAgent = manager.selectAgentForLanguage(39;typescript39;);
console.log(39;TypeScript agent:39;, tsAgent?.name);
class="hl-cmt">// Auto-select based on context
const reactContextAgent = manager.autoSelectAgent({ language: 39;typescript39;, framework: 39;react39; });
console.log(39;Auto-selected for React context:39;, reactContextAgent?.name);
class="hl-cmt">// Set a specific agent as current
manager.setCurrentAgent(39;python-expert39;);
console.log(39;Current agent:39;, manager.getCurrentAgent()?.name);
class="hl-cmt">// Register a new custom agent
manager.registerAgent({
id: 39;vue-expert39;,
name: 39;Vue.js Expert39;,
description: 39;Specialized in Vue.js and frontend development39;,
capabilities: { languages: [39;javascript39;, 39;typescript39;], frameworks: [39;vue39;], specialties: [39;composition API39;, 39;state management39;] },
systemPrompt: 39;You are a Vue.js expert. Focus on Vue 3, Composition API, and reactivity.39;,
examples: [],
});
console.log(39;New agent registered:39;, manager.getAgent(39;vue-expert39;)?.name);
Integration
EventEmitter: Emitsagent-selectedwhen an agent is set as current, andagent-registeredwhen a new agent is added.
Team Mode with Shared Context (team-mode.ts)
This module facilitates collaborative development by providing a shared context and communication mechanisms for a team working with the AI.
Purpose
To enable multiple team members to interact with the AI in a shared environment, where the AI maintains a consistent understanding of the project, shared knowledge, and team activities. This fosters better collaboration and more relevant AI assistance.
How it Works
The TeamModeManager orchestrates shared context and team member management.
- Initialization: The manager is created with
TeamConfig(e.g.,teamId,syncInterval,maxMembers). It initializes aSharedTeamContext. - Member Management:
addMemberandremoveMembermanage the team roster, assigning roles and tracking activity. - Shared Context:
addKnowledge: Allows team members to contribute key-value pairs to a shared knowledge base.addPattern,addConvention: Enables the team to define and share common code patterns and conventions.recordAction: Logs significant team activities (queries, edits, commits, reviews) to a shared history.
- Synchronization:
startSyncinitiates a timer that periodically emits the entireSharedTeamContext, allowing connected clients or other modules to stay updated. - Access:
getContextandgetMembersprovide read-only access to the current shared state.
Key Components
TeamModeManager: The main class for managing team collaboration and shared context. ExtendsEventEmitter.TeamMember: Defines a team member with ID, name, role, and activity timestamps.SharedTeamContext: The central object holding all shared information: project details, knowledge base, code patterns, conventions, and action history.TeamAction: Records a specific action performed by a team member.TeamConfig: Configuration options for the team mode.
Usage
import { createTeamMode } from 39;./team-mode39;;
const teamManager = createTeamMode({ teamId: 39;dev-team-alpha39;, maxMembers: 10 });
teamManager.on(39;member-joined39;, (member) => console.log(`${member.name} joined the team.`));
teamManager.on(39;knowledge-updated39;, ({ key, value }) => console.log(`Shared knowledge updated: ${key} = ${value}`));
teamManager.on(39;sync39;, (context) => console.log(39;Team context synced:39;, context.history.length, 39;actions39;));
const member1 = teamManager.addMember(39;Alice39;, 39;admin39;);
const member2 = teamManager.addMember(39;Bob39;);
teamManager.addKnowledge(39;project-goal39;, 39;Build a scalable microservice architecture.39;);
teamManager.addPattern(39;use-async-await39;, 39;Prefer async/await over callbacks.39;);
teamManager.addConvention(39;commit-message-format39;, 39;feat: (scope) message39;);
teamManager.recordAction(member1.id, 39;query39;, 39;How to implement feature X?39;);
teamManager.recordAction(member2.id, 39;edit39;, 39;Refactored auth module.39;);
console.log(39;Current team members:39;, teamManager.getMembers().map(m => m.name));
console.log(39;Shared knowledge:39;, teamManager.getContext().sharedKnowledge.get(39;project-goal39;));
teamManager.startSync(); class="hl-cmt">// Start periodic context synchronization
class="hl-cmt">// Later...
teamManager.dispose(); class="hl-cmt">// Clean up resources
Integration
EventEmitter: Emitsmember-joined,member-left,knowledge-updated,action-recorded, andsyncevents.crypto: Used for generating unique IDs for team members and actions.NodeJS.Timeout: Used for thesyncIntervaltimer.
Architecture Diagram
graph TD
A[TeamModeManager] --> B{addMember/removeMember}
B -- Manages --> C[TeamMember]
A --> D{addKnowledge/addPattern/addConvention}
D -- Updates --> E[SharedTeamContext]
A --> F{recordAction}
F -- Adds to History --> E
A --> G{startSync}
G -- Periodically Emits --> E
E -- Accessed by --> H[AI Agents/Clients]
A -- Emits Events --> I[Listeners]
Three-Way Diff for Conflict Resolution (three-way-diff.ts)
This module provides a robust implementation of a three-way diff algorithm, essential for identifying and resolving merge conflicts between different versions of text content.
Purpose
To accurately compare three versions of a file (a common ancestor, "ours," and "theirs") to:
- Identify changes made in "ours" and "theirs" relative to the "base."
- Automatically merge non-conflicting changes.
- Clearly mark conflicting sections where "ours" and "theirs" diverge from the base in incompatible ways.
- Provide tools for programmatic conflict resolution.
How it Works
The ThreeWayDiff class implements the core diffing logic.
- Diffing (
diff):
- Takes three strings (
base,ours,theirs) representing the content. - Splits each string into lines.
- Iterates through the lines, comparing
oursandtheirsagainstbase. - Identifies "hunks" of changes. A
DiffHunkcaptures a contiguous block of lines where at least one ofoursortheirsdiffers frombase. - Each hunk is assigned a
status: clean: No changes in this hunk (not captured bydiffdirectly, but implied by lines outside hunks).auto-merged: Changes were made inoursORtheirs(but not both in conflicting ways), or both made the same change.conflict: Changes were made in bothoursANDtheirsto the samebaselines, and the resultingourLineandtheirLineare different.- If no conflicts are found,
autoMergeis called to produce a fully merged result.
- Conflict Formatting (
formatConflictMarkers): Generates a string with standard Git-style conflict markers (<<<<<<< OURS,=======,>>>>>>> THEIRS) for a givenDiffHunk. - Conflict Parsing (
parseConflictMarkers): ExtractsDiffHunkobjects from a string containing Git-style conflict markers. - Conflict Resolution (
resolveConflicts): Takes aThreeWayDiffResult(which contains conflicts) and an array ofConflictResolutionobjects. For each specified hunk, it applies the chosen resolution strategy ('ours', 'theirs', 'both', or 'custom content') and then reconstructs the merged string.
Key Components
ThreeWayDiff: The main class for performing three-way diffs and conflict resolution. ExtendsEventEmitter.DiffHunk: Represents a block of changes, containing thebase,ours, andtheirslines for that block, and itsstatus.ThreeWayDiffResult: The overall result of a diff operation, including allDiffHunks, a flag for conflicts, and the auto-merged content if no conflicts exist.ConflictResolution: Specifies how a particularDiffHunkshould be resolved.
Usage
import { getThreeWayDiff } from 39;./three-way-diff39;;
const diffManager = getThreeWayDiff();
const base = `Line 1
Line 2
Line 3
Line 4`;
const ours = `Line 1
Our change on Line 2
Line 3
Line 4 added by ours`;
const theirs = `Line 1
Their change on Line 2
Line 3
Line 4 added by theirs`;
class="hl-cmt">// Perform a diff
const result = diffManager.diff(base, ours, theirs);
console.log(39;Has conflicts:39;, result.hasConflicts);
console.log(39;Conflict count:39;, result.conflictCount);
if (result.hasConflicts) {
console.log(39;\nConflicts found:39;);
result.hunks.filter(h => h.status === 39;conflict39;).forEach((hunk, index) => {
console.log(`--- Hunk ${index + 1} ---`);
console.log(diffManager.formatConflictMarkers(hunk));
});
class="hl-cmt">// Resolve conflicts (e.g., choose 39;ours39; for the first conflict)
const resolutions = [{ hunkIndex: 0, choice: 39;ours39; }];
const resolvedContent = diffManager.resolveConflicts(result, resolutions);
console(39;\nResolved content (choosing ours for first conflict):39;);
console.log(resolvedContent);
} else {
console.log(39;\nAuto-merged content:39;);
console.log(result.merged);
}
class="hl-cmt">// Example of parsing conflict markers
const conflictString = `Line A
<<<<<<< OURS
Our version of B
=======
Their version of B
>>>>>>> THEIRS
Line C`;
const parsedHunks = diffManager.parseConflictMarkers(conflictString);
console(39;\nParsed conflict hunks:39;, parsedHunks);
Integration
EventEmitter: WhileThreeWayDiffextendsEventEmitter, the current implementation does not emit any events. This could be extended to emit events fordiff-completed,conflict-resolved, etc.
Architecture Diagram
graph TD
A[ThreeWayDiff] --> B{diff(base, ours, theirs)}
B -- Generates --> C[ThreeWayDiffResult]
C -- Contains --> D[DiffHunk]
D -- Status --> E{clean, auto-merged, conflict}
A --> F{autoMerge}
F -- If no conflicts --> C
A --> G{resolveConflicts}
G -- Takes --> C & H[ConflictResolution]
G -- Produces --> I[Merged Content]
A --> J{formatConflictMarkers}
J -- Formats --> D
A --> K{parseConflictMarkers}
K -- Parses --> D