ac-framework 1.7.0 → 1.8.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/README.md +26 -0
- package/bin/postinstall.js +8 -1
- package/framework/.agent/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.agent/workflows/ac-lite.md +192 -0
- package/framework/.agent/workflows/ac.md +40 -0
- package/framework/.amazonq/prompts/ac-lite.md +192 -0
- package/framework/.amazonq/prompts/ac.md +40 -0
- package/framework/.amazonq/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.antigravity/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.antigravity/workflows/ac-lite.md +192 -0
- package/framework/.antigravity/workflows/ac.md +40 -0
- package/framework/.augment/commands/ac-lite.md +192 -0
- package/framework/.augment/commands/ac.md +40 -0
- package/framework/.augment/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.claude/commands/opsx/ac-lite.md +192 -0
- package/framework/.claude/commands/opsx/ac.md +40 -0
- package/framework/.claude/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.cline/commands/opsx/ac-lite.md +192 -0
- package/framework/.cline/commands/opsx/ac.md +40 -0
- package/framework/.cline/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.clinerules/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.clinerules/workflows/ac-lite.md +192 -0
- package/framework/.clinerules/workflows/ac.md +40 -0
- package/framework/.codebuddy/commands/opsx/ac-lite.md +192 -0
- package/framework/.codebuddy/commands/opsx/ac.md +40 -0
- package/framework/.codebuddy/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.codex/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.continue/prompts/ac-lite.md +192 -0
- package/framework/.continue/prompts/ac.md +40 -0
- package/framework/.continue/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.cospec/openspec/commands/ac-lite.md +192 -0
- package/framework/.cospec/openspec/commands/ac.md +40 -0
- package/framework/.cospec/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.crush/commands/opsx/ac-lite.md +192 -0
- package/framework/.crush/commands/opsx/ac.md +40 -0
- package/framework/.crush/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.cursor/commands/ac-lite.md +192 -0
- package/framework/.cursor/commands/ac.md +40 -0
- package/framework/.cursor/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.factory/commands/ac-lite.md +192 -0
- package/framework/.factory/commands/ac.md +40 -0
- package/framework/.factory/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.gemini/commands/opsx/ac-lite.md +192 -0
- package/framework/.gemini/commands/opsx/ac.md +40 -0
- package/framework/.gemini/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.github/prompts/ac-lite.md +192 -0
- package/framework/.github/prompts/ac.md +40 -0
- package/framework/.github/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.iflow/commands/ac-lite.md +192 -0
- package/framework/.iflow/commands/ac.md +40 -0
- package/framework/.iflow/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.kilocode/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.kilocode/workflows/ac-lite.md +192 -0
- package/framework/.kilocode/workflows/ac.md +40 -0
- package/framework/.kimi/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.kimi/workflows/ac-lite.md +192 -0
- package/framework/.kimi/workflows/ac.md +40 -0
- package/framework/.opencode/command/ac-lite.md +192 -0
- package/framework/.opencode/command/ac.md +40 -0
- package/framework/.opencode/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.qoder/commands/opsx/ac-lite.md +192 -0
- package/framework/.qoder/commands/opsx/ac.md +40 -0
- package/framework/.qoder/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.qwen/commands/ac-lite.md +192 -0
- package/framework/.qwen/commands/ac.md +40 -0
- package/framework/.qwen/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.roo/commands/ac-lite.md +192 -0
- package/framework/.roo/commands/ac.md +40 -0
- package/framework/.roo/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.trae/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.windsurf/skills/acfm-memory/SKILL.md +312 -0
- package/framework/.windsurf/workflows/ac-lite.md +192 -0
- package/framework/.windsurf/workflows/ac.md +40 -0
- package/framework/AGENTS.md +39 -0
- package/framework/CLAUDE.md +39 -0
- package/framework/GEMINI.md +39 -0
- package/framework/copilot-instructions.md +39 -0
- package/package.json +2 -1
- package/src/cli.js +2 -0
- package/src/commands/memory.js +772 -0
- package/src/index.js +46 -0
- package/src/memory/autosave.js +382 -0
- package/src/memory/database.js +178 -0
- package/src/memory/engine.js +727 -0
- package/src/memory/index.js +62 -0
- package/src/memory/utils.js +128 -0
- package/src/services/spec-engine.js +69 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memory/index.js — API pública del sistema de memoria autónoma
|
|
3
|
+
*
|
|
4
|
+
* Sistema de persistencia de conocimiento para agentes AI.
|
|
5
|
+
* Guarda automáticamente decisiones, patrones, bugfixes y insights.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Database
|
|
9
|
+
export { initDatabase, getDatabase, closeDatabase, isDatabaseInitialized } from './database.js';
|
|
10
|
+
|
|
11
|
+
// Core Engine
|
|
12
|
+
export {
|
|
13
|
+
saveMemory,
|
|
14
|
+
searchMemories,
|
|
15
|
+
getContext,
|
|
16
|
+
getTimeline,
|
|
17
|
+
getMemory,
|
|
18
|
+
updateMemory,
|
|
19
|
+
deleteMemory,
|
|
20
|
+
startSession,
|
|
21
|
+
endSession,
|
|
22
|
+
getStats,
|
|
23
|
+
findPatterns,
|
|
24
|
+
getConnections,
|
|
25
|
+
anticipateNeeds,
|
|
26
|
+
exportMemories,
|
|
27
|
+
importMemories,
|
|
28
|
+
pruneMemories
|
|
29
|
+
} from './engine.js';
|
|
30
|
+
|
|
31
|
+
// Utils
|
|
32
|
+
export {
|
|
33
|
+
redactPrivateContent,
|
|
34
|
+
extractKeywords,
|
|
35
|
+
textSimilarity,
|
|
36
|
+
truncate,
|
|
37
|
+
isCodeContent,
|
|
38
|
+
detectLanguage,
|
|
39
|
+
generateSummary,
|
|
40
|
+
sanitizeFTSQuery
|
|
41
|
+
} from './utils.js';
|
|
42
|
+
|
|
43
|
+
// Auto-save system
|
|
44
|
+
export { createAutoSaveHook, AutoSaveManager } from './autosave.js';
|
|
45
|
+
|
|
46
|
+
// Tipos de memoria válidos para referencia
|
|
47
|
+
export const MEMORY_TYPES = [
|
|
48
|
+
'architectural_decision',
|
|
49
|
+
'bugfix_pattern',
|
|
50
|
+
'api_pattern',
|
|
51
|
+
'performance_insight',
|
|
52
|
+
'security_fix',
|
|
53
|
+
'refactor_technique',
|
|
54
|
+
'dependency_note',
|
|
55
|
+
'workaround',
|
|
56
|
+
'convention',
|
|
57
|
+
'context_boundary',
|
|
58
|
+
'general_insight',
|
|
59
|
+
'session_summary'
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
export const IMPORTANCE_LEVELS = ['critical', 'high', 'medium', 'low'];
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* utils.js — Utilidades para el sistema de memoria
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Redacta contenido entre etiquetas <private>
|
|
7
|
+
*/
|
|
8
|
+
export function redactPrivateContent(content) {
|
|
9
|
+
if (!content) return content;
|
|
10
|
+
|
|
11
|
+
const privateRegex = /<private>[\s\S]*?<\/private>/gi;
|
|
12
|
+
return content.replace(privateRegex, '[REDACTED PRIVATE CONTENT]');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extrae palabras clave de un texto
|
|
17
|
+
*/
|
|
18
|
+
export function extractKeywords(text, maxKeywords = 5) {
|
|
19
|
+
if (!text) return [];
|
|
20
|
+
|
|
21
|
+
const stopWords = new Set([
|
|
22
|
+
'el', 'la', 'los', 'las', 'un', 'una', 'unos', 'unas', 'de', 'del', 'al',
|
|
23
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
24
|
+
'en', 'y', 'o', 'pero', 'por', 'para', 'con', 'sin', 'sobre', 'entre',
|
|
25
|
+
'in', 'and', 'or', 'but', 'for', 'with', 'without', 'on', 'between',
|
|
26
|
+
'que', 'como', 'cuando', 'donde', 'quien', 'cual', 'esto', 'eso',
|
|
27
|
+
'that', 'what', 'when', 'where', 'who', 'which', 'this', 'that'
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
const wordCounts = text.toLowerCase()
|
|
31
|
+
.replace(/[^\w\s]/g, ' ')
|
|
32
|
+
.split(/\s+/)
|
|
33
|
+
.filter(w => w.length > 3 && !stopWords.has(w))
|
|
34
|
+
.reduce((acc, word) => {
|
|
35
|
+
acc[word] = (acc[word] || 0) + 1;
|
|
36
|
+
return acc;
|
|
37
|
+
}, {});
|
|
38
|
+
|
|
39
|
+
return Object.entries(wordCounts)
|
|
40
|
+
.sort((a, b) => b[1] - a[1])
|
|
41
|
+
.slice(0, maxKeywords)
|
|
42
|
+
.map(([word]) => word);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Calcula similitud simple entre dos textos (Jaccard)
|
|
47
|
+
*/
|
|
48
|
+
export function textSimilarity(text1, text2) {
|
|
49
|
+
const set1 = new Set(text1.toLowerCase().split(/\s+/));
|
|
50
|
+
const set2 = new Set(text2.toLowerCase().split(/\s+/));
|
|
51
|
+
|
|
52
|
+
const intersection = new Set([...set1].filter(x => set2.has(x)));
|
|
53
|
+
const union = new Set([...set1, ...set2]);
|
|
54
|
+
|
|
55
|
+
return intersection.size / union.size;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Trunca texto con ellipsis
|
|
60
|
+
*/
|
|
61
|
+
export function truncate(text, maxLength = 100) {
|
|
62
|
+
if (!text || text.length <= maxLength) return text;
|
|
63
|
+
return text.slice(0, maxLength - 3) + '...';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Detecta si un contenido parece código
|
|
68
|
+
*/
|
|
69
|
+
export function isCodeContent(text) {
|
|
70
|
+
const codeIndicators = [
|
|
71
|
+
/function\s+\w+\s*\(/,
|
|
72
|
+
/const\s+\w+\s*=/,
|
|
73
|
+
/let\s+\w+\s*=/,
|
|
74
|
+
/var\s+\w+\s*=/,
|
|
75
|
+
/import\s+.*\s+from/,
|
|
76
|
+
/export\s+(default\s+)?/,
|
|
77
|
+
/class\s+\w+/,
|
|
78
|
+
/if\s*\(.*\)\s*\{/,
|
|
79
|
+
/for\s*\(.*\)\s*\{/,
|
|
80
|
+
/```[\s\S]*```/
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
return codeIndicators.some(pattern => pattern.test(text));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Detecta lenguaje de programación
|
|
88
|
+
*/
|
|
89
|
+
export function detectLanguage(text) {
|
|
90
|
+
if (/\.tsx?/.test(text) || /interface\s+\w+/.test(text) || /:\s*(string|number|boolean)/.test(text)) {
|
|
91
|
+
return 'typescript';
|
|
92
|
+
}
|
|
93
|
+
if (/\.jsx?/.test(text) || /React\./.test(text) || /useState|useEffect/.test(text)) {
|
|
94
|
+
return 'javascript';
|
|
95
|
+
}
|
|
96
|
+
if (/\.py/.test(text) || /def\s+\w+\s*\(/.test(text) || /import\s+\w+/.test(text)) {
|
|
97
|
+
return 'python';
|
|
98
|
+
}
|
|
99
|
+
if (/\.go/.test(text) || /func\s+\w+\s*\(/.test(text) || /package\s+\w+/.test(text)) {
|
|
100
|
+
return 'go';
|
|
101
|
+
}
|
|
102
|
+
if (/\.rs/.test(text) || /fn\s+\w+\s*\(/.test(text) || /let\s+mut/.test(text)) {
|
|
103
|
+
return 'rust';
|
|
104
|
+
}
|
|
105
|
+
return 'unknown';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Genera un resumen automático
|
|
110
|
+
*/
|
|
111
|
+
export function generateSummary(text, maxSentences = 2) {
|
|
112
|
+
if (!text) return '';
|
|
113
|
+
|
|
114
|
+
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 10);
|
|
115
|
+
return sentences.slice(0, maxSentences).join('. ') + '.';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sanitiza input para FTS5
|
|
120
|
+
*/
|
|
121
|
+
export function sanitizeFTSQuery(query) {
|
|
122
|
+
// Escapar caracteres especiales de FTS5
|
|
123
|
+
return query
|
|
124
|
+
.replace(/"/g, '""')
|
|
125
|
+
.replace(/\*/g, '')
|
|
126
|
+
.replace(/^\^/g, '')
|
|
127
|
+
.replace(/\$/g, '');
|
|
128
|
+
}
|
|
@@ -9,6 +9,7 @@ import { readFile, readdir, stat, mkdir, rename, access, writeFile } from 'node:
|
|
|
9
9
|
import { resolve, join, dirname, relative } from 'node:path';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
import yaml from 'js-yaml';
|
|
12
|
+
import { initDatabase, getContext, AutoSaveManager } from '../memory/index.js';
|
|
12
13
|
|
|
13
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
15
|
const SCHEMAS_DIR = resolve(__dirname, '../schemas');
|
|
@@ -475,6 +476,21 @@ export async function getArtifactInstructions(artifactId, changeName, cwd = proc
|
|
|
475
476
|
// Determine what this artifact unlocks
|
|
476
477
|
const unlocks = artifact.unlocks || [];
|
|
477
478
|
|
|
479
|
+
// NUEVO: Recuperar contexto de memoria relevante
|
|
480
|
+
let relevantMemories = [];
|
|
481
|
+
try {
|
|
482
|
+
initDatabase(); // Asegurar DB inicializada
|
|
483
|
+
relevantMemories = getContext({
|
|
484
|
+
projectPath: cwd,
|
|
485
|
+
changeName,
|
|
486
|
+
limit: 5,
|
|
487
|
+
lookbackDays: 30
|
|
488
|
+
});
|
|
489
|
+
} catch {
|
|
490
|
+
// Si memory no está inicializado, continuar sin contexto
|
|
491
|
+
relevantMemories = [];
|
|
492
|
+
}
|
|
493
|
+
|
|
478
494
|
return {
|
|
479
495
|
context,
|
|
480
496
|
rules,
|
|
@@ -483,6 +499,14 @@ export async function getArtifactInstructions(artifactId, changeName, cwd = proc
|
|
|
483
499
|
outputPath,
|
|
484
500
|
dependencies,
|
|
485
501
|
unlocks,
|
|
502
|
+
// NUEVO: Memorias relevantes para el contexto del agente
|
|
503
|
+
relevantMemories: relevantMemories.map(m => ({
|
|
504
|
+
id: m.id,
|
|
505
|
+
type: m.type,
|
|
506
|
+
content: m.content,
|
|
507
|
+
importance: m.importance,
|
|
508
|
+
fromChange: m.changeName
|
|
509
|
+
}))
|
|
486
510
|
};
|
|
487
511
|
}
|
|
488
512
|
|
|
@@ -583,12 +607,56 @@ export async function getApplyInstructions(changeName, cwd = process.cwd()) {
|
|
|
583
607
|
instruction = `${remaining} of ${total} tasks remaining. Implement each pending task, following the specs and design. Mark tasks as [x] when complete.`;
|
|
584
608
|
}
|
|
585
609
|
|
|
610
|
+
// NUEVO: Recuperar contexto de memoria relevante para implementación
|
|
611
|
+
let relevantMemories = [];
|
|
612
|
+
let suggestedPatterns = [];
|
|
613
|
+
try {
|
|
614
|
+
initDatabase();
|
|
615
|
+
|
|
616
|
+
// Buscar patrones similares en memorias
|
|
617
|
+
relevantMemories = getContext({
|
|
618
|
+
projectPath: cwd,
|
|
619
|
+
changeName,
|
|
620
|
+
limit: 5,
|
|
621
|
+
lookbackDays: 30
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
// Buscar patrones de implementación específicos
|
|
625
|
+
const pendingTasks = tasks.filter(t => !t.done).map(t => t.task).join(' ');
|
|
626
|
+
if (pendingTasks) {
|
|
627
|
+
// Buscar memorias relacionadas con las tareas pendientes
|
|
628
|
+
const keywords = pendingTasks.toLowerCase().split(/\s+/).filter(w => w.length > 4);
|
|
629
|
+
if (keywords.length > 0) {
|
|
630
|
+
const { searchMemories } = await import('../memory/index.js');
|
|
631
|
+
suggestedPatterns = searchMemories(keywords.slice(0, 5).join(' OR '), {
|
|
632
|
+
type: 'refactor_technique',
|
|
633
|
+
limit: 3
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
} catch {
|
|
638
|
+
// Continuar sin contexto si hay error
|
|
639
|
+
}
|
|
640
|
+
|
|
586
641
|
return {
|
|
587
642
|
contextFiles,
|
|
588
643
|
progress: { total, complete, remaining },
|
|
589
644
|
state,
|
|
590
645
|
instruction,
|
|
591
646
|
tasks,
|
|
647
|
+
// NUEVO: Contexto de memoria para ayudar en implementación
|
|
648
|
+
relevantMemories: relevantMemories.map(m => ({
|
|
649
|
+
id: m.id,
|
|
650
|
+
type: m.type,
|
|
651
|
+
content: m.content,
|
|
652
|
+
importance: m.importance,
|
|
653
|
+
codeSnippet: m.codeSnippet
|
|
654
|
+
})),
|
|
655
|
+
suggestedPatterns: suggestedPatterns.map(m => ({
|
|
656
|
+
id: m.id,
|
|
657
|
+
content: m.content,
|
|
658
|
+
type: m.type
|
|
659
|
+
}))
|
|
592
660
|
};
|
|
593
661
|
}
|
|
594
662
|
|
|
@@ -607,7 +675,7 @@ export async function archiveChange(name, cwd = process.cwd()) {
|
|
|
607
675
|
throw new Error(`Change "${name}" not found.`);
|
|
608
676
|
}
|
|
609
677
|
|
|
610
|
-
const archiveDir = join(changesDir(cwd), 'archive');
|
|
678
|
+
const archiveDir = join(await changesDir(cwd), 'archive');
|
|
611
679
|
await mkdir(archiveDir, { recursive: true });
|
|
612
680
|
|
|
613
681
|
const dateStr = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|