| import { join, normalize, sep } from 'path' |
| import { getProjectRoot } from '../../bootstrap/state.js' |
| import { |
| buildMemoryPrompt, |
| ensureMemoryDirExists, |
| } from '../../memdir/memdir.js' |
| import { getMemoryBaseDir } from '../../memdir/paths.js' |
| import { getCwd } from '../../utils/cwd.js' |
| import { findCanonicalGitRoot } from '../../utils/git.js' |
| import { sanitizePath } from '../../utils/path.js' |
|
|
| |
| export type AgentMemoryScope = 'user' | 'project' | 'local' |
|
|
| |
| |
| |
| |
| |
| function sanitizeAgentTypeForPath(agentType: string): string { |
| return agentType.replace(/:/g, '-') |
| } |
|
|
| |
| |
| |
| |
| |
| function getLocalAgentMemoryDir(dirName: string): string { |
| if (process.env.CLAUDE_CODE_REMOTE_MEMORY_DIR) { |
| return ( |
| join( |
| process.env.CLAUDE_CODE_REMOTE_MEMORY_DIR, |
| 'projects', |
| sanitizePath( |
| findCanonicalGitRoot(getProjectRoot()) ?? getProjectRoot(), |
| ), |
| 'agent-memory-local', |
| dirName, |
| ) + sep |
| ) |
| } |
| return join(getCwd(), '.claude', 'agent-memory-local', dirName) + sep |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function getAgentMemoryDir( |
| agentType: string, |
| scope: AgentMemoryScope, |
| ): string { |
| const dirName = sanitizeAgentTypeForPath(agentType) |
| switch (scope) { |
| case 'project': |
| return join(getCwd(), '.claude', 'agent-memory', dirName) + sep |
| case 'local': |
| return getLocalAgentMemoryDir(dirName) |
| case 'user': |
| return join(getMemoryBaseDir(), 'agent-memory', dirName) + sep |
| } |
| } |
|
|
| |
| export function isAgentMemoryPath(absolutePath: string): boolean { |
| |
| const normalizedPath = normalize(absolutePath) |
| const memoryBase = getMemoryBaseDir() |
|
|
| |
| if (normalizedPath.startsWith(join(memoryBase, 'agent-memory') + sep)) { |
| return true |
| } |
|
|
| |
| if ( |
| normalizedPath.startsWith(join(getCwd(), '.claude', 'agent-memory') + sep) |
| ) { |
| return true |
| } |
|
|
| |
| if (process.env.CLAUDE_CODE_REMOTE_MEMORY_DIR) { |
| if ( |
| normalizedPath.includes(sep + 'agent-memory-local' + sep) && |
| normalizedPath.startsWith( |
| join(process.env.CLAUDE_CODE_REMOTE_MEMORY_DIR, 'projects') + sep, |
| ) |
| ) { |
| return true |
| } |
| } else if ( |
| normalizedPath.startsWith( |
| join(getCwd(), '.claude', 'agent-memory-local') + sep, |
| ) |
| ) { |
| return true |
| } |
|
|
| return false |
| } |
|
|
| |
| |
| |
| export function getAgentMemoryEntrypoint( |
| agentType: string, |
| scope: AgentMemoryScope, |
| ): string { |
| return join(getAgentMemoryDir(agentType, scope), 'MEMORY.md') |
| } |
|
|
| export function getMemoryScopeDisplay( |
| memory: AgentMemoryScope | undefined, |
| ): string { |
| switch (memory) { |
| case 'user': |
| return `User (${join(getMemoryBaseDir(), 'agent-memory')}/)` |
| case 'project': |
| return 'Project (.claude/agent-memory/)' |
| case 'local': |
| return `Local (${getLocalAgentMemoryDir('...')})` |
| default: |
| return 'None' |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function loadAgentMemoryPrompt( |
| agentType: string, |
| scope: AgentMemoryScope, |
| ): string { |
| let scopeNote: string |
| switch (scope) { |
| case 'user': |
| scopeNote = |
| '- Since this memory is user-scope, keep learnings general since they apply across all projects' |
| break |
| case 'project': |
| scopeNote = |
| '- Since this memory is project-scope and shared with your team via version control, tailor your memories to this project' |
| break |
| case 'local': |
| scopeNote = |
| '- Since this memory is local-scope (not checked into version control), tailor your memories to this project and machine' |
| break |
| } |
|
|
| const memoryDir = getAgentMemoryDir(agentType, scope) |
|
|
| |
| |
| |
| |
| |
| void ensureMemoryDirExists(memoryDir) |
|
|
| const coworkExtraGuidelines = |
| process.env.CLAUDE_COWORK_MEMORY_EXTRA_GUIDELINES |
| return buildMemoryPrompt({ |
| displayName: 'Persistent Agent Memory', |
| memoryDir, |
| extraGuidelines: |
| coworkExtraGuidelines && coworkExtraGuidelines.trim().length > 0 |
| ? [scopeNote, coworkExtraGuidelines] |
| : [scopeNote], |
| }) |
| } |
|
|