/** * Project Memory Service * * Manages project-level persistent memory stored in project/.crewly/knowledge/ * Provides storage for patterns, decisions, gotchas, and relationships. * * @module services/memory/project-memory.service */ import { ProjectMemory, PatternEntry, DecisionEntry, GotchaEntry, RelationshipEntry, TaskHistoryEntry, type PatternCategory, type GotchaSeverity } from '../../types/memory.types.js'; /** * Search results from cross-entity search */ export interface SearchResults { patterns: PatternEntry[]; decisions: DecisionEntry[]; gotchas: GotchaEntry[]; relationships: RelationshipEntry[]; totalCount: number; } /** * Interface for the Project Memory Service */ export interface IProjectMemoryService { initializeProject(projectPath: string): Promise; addPattern(projectPath: string, pattern: Omit): Promise; getPatterns(projectPath: string, category?: PatternCategory): Promise; searchPatterns(projectPath: string, query: string): Promise; addDecision(projectPath: string, decision: Omit): Promise; getDecisions(projectPath: string): Promise; addGotcha(projectPath: string, gotcha: Omit): Promise; getGotchas(projectPath: string, severity?: GotchaSeverity): Promise; addRelationship(projectPath: string, relationship: Omit): Promise; getRelationships(projectPath: string, componentName?: string): Promise; recordLearning(projectPath: string, agentId: string, agentRole: string, learning: string, metadata?: Record): Promise; getRecentLearnings(projectPath: string, limit?: number): Promise; generateProjectContext(projectPath: string): Promise; searchAll(projectPath: string, query: string): Promise; getProjectMemory(projectPath: string): Promise; addTaskHistory(projectPath: string, entry: TaskHistoryEntry): Promise; getTaskHistory(projectPath: string, capability?: string): Promise; archiveTaskCompletionLogs(projectPath: string): Promise; } /** * How many task-completion entries one archive pass moved out of memory. */ export interface TaskLogArchiveResult { /** Entries moved out of decisions.json */ decisions: number; /** Entries moved out of learnings.md */ learnings: number; } /** * Service for managing project-level persistent memory * * Follows singleton pattern for consistent state management. * Uses atomic file writes to prevent data corruption. * * @example * ```typescript * const memoryService = ProjectMemoryService.getInstance(); * await memoryService.initializeProject('/path/to/project'); * await memoryService.addPattern('/path/to/project', { * category: 'api', * title: 'Error Handling Wrapper', * description: 'All API endpoints use handleApiError() wrapper', * discoveredBy: 'backend-dev-001' * }); * ``` */ export declare class ProjectMemoryService implements IProjectMemoryService { private static instance; private readonly logger; private readonly memoryCache; private readonly CACHE_TTL_MS; /** * Creates a new ProjectMemoryService instance */ constructor(); /** * Gets the singleton instance of ProjectMemoryService * * @returns The singleton ProjectMemoryService instance */ static getInstance(): ProjectMemoryService; /** * Clears the singleton instance (useful for testing) */ static clearInstance(): void; /** * Gets the path to a project's knowledge directory * * @param projectPath - Absolute path to the project * @returns Path to the knowledge directory */ private getKnowledgePath; /** * Gets the path to a specific memory file for a project * * @param projectPath - Absolute path to the project * @param fileName - The memory file name * @returns Absolute path to the memory file */ private getFilePath; /** * Checks if a file exists * * @param filePath - Path to check * @returns true if file exists */ private fileExists; /** * Invalidates the cache for a project * * @param projectPath - Project path */ private invalidateCache; /** * Checks if content is similar (simple substring matching) * * @param existing - Existing content * @param newContent - New content to compare * @returns true if content is similar */ private isSimilarContent; /** * Initializes memory storage for a project * * @param projectPath - Absolute path to the project * * @example * ```typescript * await memoryService.initializeProject('/home/user/projects/my-app'); * ``` */ initializeProject(projectPath: string): Promise; /** * Moves task-completion summaries out of decisions.json and learnings.md * into knowledge/archive/ (#833). * * Older complete-task / report-status skills saved every finished task as a * project decision (mirrored into learnings.md as "Decision made: …") and * as a "Task completed: …" learning. These crowded real decisions out of * recall. The entries are kept, readable, in the archive files; the * summaries themselves also remain on their WorkItems. * * Idempotent: a second run finds nothing to move and writes nothing. * * @param projectPath - Project path * @returns How many decisions and learnings were moved * * @example * ```typescript * const moved = await projectMemory.archiveTaskCompletionLogs('/projects/app'); * // { decisions: 29, learnings: 58 } * ``` */ archiveTaskCompletionLogs(projectPath: string): Promise; /** * Whether one learnings.md entry is a task-completion log. The learning * text is everything after the entry's `### [role/agent] time` line. * * @param entry - One entry from learnings.md (without its trailing rule) * @returns true when the entry's learning text is a task log */ private isTaskLogLearningEntry; /** * Adds a new pattern entry * * @param projectPath - Project path * @param pattern - Pattern data (without id and createdAt) * @returns ID of the created or existing pattern */ addPattern(projectPath: string, pattern: Omit): Promise; /** * Gets all patterns, optionally filtered by category * * @param projectPath - Project path * @param category - Optional category filter * @returns Array of patterns */ getPatterns(projectPath: string, category?: PatternCategory): Promise; /** * Saves patterns to disk */ private savePatterns; /** * Searches patterns by query * * @param projectPath - Project path * @param query - Search query * @returns Matching patterns */ searchPatterns(projectPath: string, query: string): Promise; /** * Adds a new decision entry * * @param projectPath - Project path * @param decision - Decision data (without id and decidedAt) * @param options - `supersedes`: ids (bare or `dec:`-prefixed) of decisions * this one replaces; each is marked `superseded` with `supersededBy` set, * so it leaves the standing-answer scope and default recall (#884) * @returns ID of the created decision */ addDecision(projectPath: string, decision: Omit, options?: { supersedes?: string[]; }): Promise; /** * Mark the decisions named in `supersedes` as superseded by `newId` (#884). * Unknown ids are logged and skipped; the new decision itself is never * marked. * * @param projectPath - Project path (for logging) * @param decisions - Loaded decisions, mutated in place * @param newId - Id of the decision that replaces them * @param supersedes - Ids, bare or `dec:`-prefixed * @returns True when any entry changed */ private markDecisionsSuperseded; /** * Gets all decisions * * @param projectPath - Project path * @returns Array of decisions (active ones first) */ getDecisions(projectPath: string): Promise; /** * Saves decisions to disk */ private saveDecisions; /** * Adds a new gotcha entry * * @param projectPath - Project path * @param gotcha - Gotcha data (without id and createdAt) * @returns ID of the created gotcha */ addGotcha(projectPath: string, gotcha: Omit): Promise; /** * Gets all gotchas, optionally filtered by severity * * @param projectPath - Project path * @param severity - Optional severity filter * @returns Array of gotchas (high severity first) */ getGotchas(projectPath: string, severity?: GotchaSeverity): Promise; /** * Saves gotchas to disk */ private saveGotchas; /** * Adds a new relationship entry * * @param projectPath - Project path * @param relationship - Relationship data (without id) * @returns ID of the created relationship */ addRelationship(projectPath: string, relationship: Omit): Promise; /** * Gets relationships, optionally filtered by component name * * @param projectPath - Project path * @param componentName - Optional component name filter * @returns Array of relationships */ getRelationships(projectPath: string, componentName?: string): Promise; /** * Saves relationships to disk */ private saveRelationships; /** * Append a task-history entry. Dedup on `id`; if an existing entry * with the same id is found, this is a no-op (subscriber emits a * stable id per workitem so a redelivered event collapses cleanly). * * @param projectPath - Project path * @param entry - The TaskHistoryEntry to record * @returns The id of the recorded entry (echoes input.id) */ addTaskHistory(projectPath: string, entry: TaskHistoryEntry): Promise; /** * Get the full task-history ledger for a project. Optionally filter * by canonical capability string (e.g. `'gmail:read'`); when filter * is set, only entries whose `capabilities[]` contains an exact * match are returned, sorted most-recent first. * * @param projectPath - Project path * @param capability - Optional capability string filter * @returns Array of entries (most recent first when filtered) */ getTaskHistory(projectPath: string, capability?: string): Promise; private saveTaskHistory; /** * Records a learning entry to the append-only log * * @param projectPath - Project path * @param agentId - Agent that made the learning * @param agentRole - Agent's role * @param learning - The learning content * @param metadata - Optional metadata */ recordLearning(projectPath: string, agentId: string, agentRole: string, learning: string, metadata?: Record): Promise; /** * Gets recent learnings from the log * * @param projectPath - Project path * @param limit - Maximum number of entries to return * @returns Recent learnings as markdown */ getRecentLearnings(projectPath: string, limit?: number): Promise; /** * Generates a context string for prompt injection * * @param projectPath - Project path * @returns Formatted context string */ generateProjectContext(projectPath: string): Promise; /** * Searches across all entity types * * @param projectPath - Project path * @param query - Search query * @returns Search results from all categories */ searchAll(projectPath: string, query: string): Promise; /** * Gets the complete project memory object * * @param projectPath - Project path * @returns Full project memory or null if not initialized */ getProjectMemory(projectPath: string): Promise; } //# sourceMappingURL=project-memory.service.d.ts.map