grimoire-framework 1.0.18 → 1.0.21
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/.grimoire/install-manifest.yaml +2 -2
- package/bin/commands/agent.js +216 -0
- package/bin/commands/memory.js +131 -25
- package/bin/commands/metrics.js +213 -55
- package/bin/commands/sync.js +203 -0
- package/bin/commands/update.js +1 -0
- package/bin/grimoire-cli.js +95 -1
- package/package.json +2 -1
- package/packages/installer/src/utils/grimoire-colors.js +65 -36
- package/squads/.gitkeep +2 -0
- package/squads/README.md +25 -0
- package/squads/devops/squad.yaml +9 -0
- package/squads/devops/workflows/deploy-pipeline.md +22 -0
- package/squads/fullstack/squad.yaml +11 -0
- package/squads/fullstack/workflows/code-review.md +22 -0
- package/squads/fullstack/workflows/new-feature.md +24 -0
- package/squads/planning/squad.yaml +10 -0
- package/squads/planning/workflows/prd-to-stories.md +20 -0
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
# - SHA256 hashes for change detection
|
|
8
8
|
# - File types for categorization
|
|
9
9
|
#
|
|
10
|
-
version: 1.0.
|
|
11
|
-
generated_at: "2026-02-22T14:
|
|
10
|
+
version: 1.0.21
|
|
11
|
+
generated_at: "2026-02-22T14:46:40.983Z"
|
|
12
12
|
generator: scripts/generate-install-manifest.js
|
|
13
13
|
file_count: 1011
|
|
14
14
|
files:
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* grimoire agent — Agent Management CLI
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* grimoire agent create — interative wizard to create a custom agent
|
|
6
|
+
* grimoire agent list — alias for grimoire agents list
|
|
7
|
+
* grimoire agent edit <n> — open agent in $EDITOR
|
|
8
|
+
* grimoire agent remove <n>— delete a custom agent
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const { execSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
// ── Personas catalogue for the wizard ─────────────────────────────────────────
|
|
18
|
+
const BASE_AGENTS = [
|
|
19
|
+
{ id: 'dev', icon: '🎨', name: 'Da Vinci', specialty: 'Full-Stack Development' },
|
|
20
|
+
{ id: 'qa', icon: '🖌️', name: 'Dürer', specialty: 'Quality Assurance' },
|
|
21
|
+
{ id: 'architect', icon: '🏛️', name: 'Gaudí', specialty: 'System Architecture' },
|
|
22
|
+
{ id: 'analyst', icon: '🔍', name: 'Vermeer', specialty: 'Research & Analysis' },
|
|
23
|
+
{ id: 'grimoire-master', icon: '👑', name: 'Michelangelo', specialty: 'Orchestration' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const ICON_OPTIONS = ['🎭', '🎪', '🌟', '⚡', '🔮', '🦊', '🐉', '🌊', '🔥', '🌙', '🎯', '🗡️', '🧙', '🎸', '🦅'];
|
|
27
|
+
|
|
28
|
+
// ── Template generator ─────────────────────────────────────────────────────────
|
|
29
|
+
function generateAgentTemplate({ id, name, icon, specialty, baseAgent, description }) {
|
|
30
|
+
const base = BASE_AGENTS.find(a => a.id === baseAgent);
|
|
31
|
+
const baseRef = base ? `Based on ${base.name} (${base.id})` : 'Custom Agent';
|
|
32
|
+
|
|
33
|
+
return `# ${id}
|
|
34
|
+
|
|
35
|
+
ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
|
|
36
|
+
|
|
37
|
+
CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
|
|
38
|
+
|
|
39
|
+
## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
|
|
40
|
+
|
|
41
|
+
\`\`\`yaml
|
|
42
|
+
activation-instructions:
|
|
43
|
+
- STEP 1: Read THIS ENTIRE FILE to understand your persona
|
|
44
|
+
- STEP 2: Adopt the ${name} persona completely
|
|
45
|
+
- STEP 3: Present your greeting to the user
|
|
46
|
+
- STEP 4: HALT and await user input
|
|
47
|
+
- STAY IN CHARACTER until user types *exit
|
|
48
|
+
|
|
49
|
+
agent:
|
|
50
|
+
name: ${name}
|
|
51
|
+
id: ${id}
|
|
52
|
+
title: ${specialty}
|
|
53
|
+
icon: ${icon}
|
|
54
|
+
base: ${baseRef}
|
|
55
|
+
whenToUse: ${description}
|
|
56
|
+
|
|
57
|
+
persona:
|
|
58
|
+
role: ${specialty} Specialist
|
|
59
|
+
style: Collaborative and focused on ${specialty.toLowerCase()}
|
|
60
|
+
identity: ${name} — ${description}
|
|
61
|
+
|
|
62
|
+
greeting_levels:
|
|
63
|
+
default: |
|
|
64
|
+
${icon} **${name}** (${id}) pronto!
|
|
65
|
+
Especialidade: **${specialty}**
|
|
66
|
+
|
|
67
|
+
Como posso ajudar?
|
|
68
|
+
|
|
69
|
+
commands:
|
|
70
|
+
- "*help — Show available commands"
|
|
71
|
+
- "*exit — Exit agent mode"
|
|
72
|
+
|
|
73
|
+
signature_closing: '— ${name} ${icon}'
|
|
74
|
+
\`\`\`
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Prompt helpers (without @clack/prompts dependency) ─────────────────────────
|
|
79
|
+
const readline = require('readline');
|
|
80
|
+
|
|
81
|
+
function prompt(question) {
|
|
82
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
83
|
+
return new Promise(resolve => {
|
|
84
|
+
rl.question(question, answer => { rl.close(); resolve(answer.trim()); });
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function select(question, options) {
|
|
89
|
+
console.log(`\n${question}`);
|
|
90
|
+
options.forEach((opt, i) => console.log(` ${i + 1}. ${opt.label || opt}`));
|
|
91
|
+
const answer = await prompt(' Escolha (número): ');
|
|
92
|
+
const idx = parseInt(answer) - 1;
|
|
93
|
+
if (idx >= 0 && idx < options.length) return options[idx].value || options[idx];
|
|
94
|
+
return options[0].value || options[0];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── Commands ───────────────────────────────────────────────────────────────────
|
|
98
|
+
async function run(args) {
|
|
99
|
+
const sub = args[0];
|
|
100
|
+
switch (sub) {
|
|
101
|
+
case 'create': await createWizard(); break;
|
|
102
|
+
case 'edit': await editAgent(args[1]); break;
|
|
103
|
+
case 'remove':
|
|
104
|
+
case 'delete': await removeAgent(args[1]); break;
|
|
105
|
+
case 'list':
|
|
106
|
+
default: listAgents(); break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function listAgents() {
|
|
111
|
+
const cwd = process.cwd();
|
|
112
|
+
const agentsDir = path.join(cwd, '.codex', 'agents');
|
|
113
|
+
if (!fs.existsSync(agentsDir)) {
|
|
114
|
+
console.log('❌ Agents directory not found. Run: npx grimoire-framework install');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
118
|
+
console.log(`\n🤖 Grimoire Agents (${agents.length}):\n`);
|
|
119
|
+
agents.forEach(f => {
|
|
120
|
+
const name = f.replace('.md', '');
|
|
121
|
+
const base = BASE_AGENTS.find(a => a.id === name);
|
|
122
|
+
const icon = base ? base.icon : '🎭';
|
|
123
|
+
const persona = base ? ` — ${base.name} (${base.specialty})` : ' — Custom Agent';
|
|
124
|
+
console.log(` ${icon} @${name}${persona}`);
|
|
125
|
+
});
|
|
126
|
+
console.log('\n💡 Para criar um agente customizado: grimoire agent create');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function createWizard() {
|
|
130
|
+
console.log('\n🧙 Grimoire Agent Creator\n');
|
|
131
|
+
|
|
132
|
+
// Step 1: Name/ID
|
|
133
|
+
const id = await prompt('Nome do agente (ex: caravaggio): ');
|
|
134
|
+
if (!id || !/^[a-z0-9-]+$/.test(id)) {
|
|
135
|
+
console.log('❌ Nome inválido. Use apenas letras minúsculas, números e hífens.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const cwd = process.cwd();
|
|
140
|
+
const agentsDir = path.join(cwd, '.codex', 'agents');
|
|
141
|
+
const agentFile = path.join(agentsDir, `${id}.md`);
|
|
142
|
+
|
|
143
|
+
if (fs.existsSync(agentFile)) {
|
|
144
|
+
console.log(`❌ Agente "${id}" já existe em ${agentFile}`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Step 2: Display name
|
|
149
|
+
const name = await prompt(`Nome de exibição (ex: Caravaggio): `);
|
|
150
|
+
|
|
151
|
+
// Step 3: Specialty
|
|
152
|
+
const specialty = await prompt('Especialidade (ex: Arte Generativa e Criatividade): ');
|
|
153
|
+
|
|
154
|
+
// Step 4: Icon
|
|
155
|
+
const iconChoice = await select(
|
|
156
|
+
'Ícone do agente:',
|
|
157
|
+
ICON_OPTIONS.map((i, idx) => ({ label: `${i} (${idx + 1})`, value: i }))
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Step 5: Base agent (inherit style from)
|
|
161
|
+
const baseChoice = await select(
|
|
162
|
+
'Baseado em (herda o estilo de):',
|
|
163
|
+
[...BASE_AGENTS.map(a => ({ label: `${a.icon} ${a.name} — ${a.specialty}`, value: a.id })),
|
|
164
|
+
{ label: '🆕 Custom (do zero)', value: 'custom' }]
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// Step 6: Short description
|
|
168
|
+
const description = await prompt('Descrição curta (ex: Especialista em arte e criatividade visual): ');
|
|
169
|
+
|
|
170
|
+
// Generate & write
|
|
171
|
+
if (!fs.existsSync(agentsDir)) fs.mkdirSync(agentsDir, { recursive: true });
|
|
172
|
+
|
|
173
|
+
const content = generateAgentTemplate({
|
|
174
|
+
id, name: name || id, icon: iconChoice, specialty: specialty || 'Custom Specialist',
|
|
175
|
+
baseAgent: baseChoice !== 'custom' ? baseChoice : null,
|
|
176
|
+
description: description || `Custom agent: ${id}`
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
fs.writeFileSync(agentFile, content, 'utf8');
|
|
180
|
+
|
|
181
|
+
console.log(`
|
|
182
|
+
✅ Agente criado: .codex/agents/${id}.md
|
|
183
|
+
|
|
184
|
+
🎭 ${iconChoice} ${name || id} — ${specialty}
|
|
185
|
+
|
|
186
|
+
Para ativar no Gemini CLI:
|
|
187
|
+
@${id}
|
|
188
|
+
|
|
189
|
+
Para sincronizar com outras IDEs:
|
|
190
|
+
npx grimoire-framework update
|
|
191
|
+
`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function editAgent(id) {
|
|
195
|
+
if (!id) { console.log('Usage: grimoire agent edit <name>'); return; }
|
|
196
|
+
const file = path.join(process.cwd(), '.codex', 'agents', `${id}.md`);
|
|
197
|
+
if (!fs.existsSync(file)) { console.log(`❌ Agent "${id}" not found.`); return; }
|
|
198
|
+
const editor = process.env.EDITOR || process.env.VISUAL || 'notepad';
|
|
199
|
+
try { execSync(`${editor} "${file}"`, { stdio: 'inherit' }); }
|
|
200
|
+
catch (e) { console.log(`❌ Could not open editor. Edit manually: ${file}`); }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function removeAgent(id) {
|
|
204
|
+
if (!id) { console.log('Usage: grimoire agent remove <name>'); return; }
|
|
205
|
+
const file = path.join(process.cwd(), '.codex', 'agents', `${id}.md`);
|
|
206
|
+
if (!fs.existsSync(file)) { console.log(`❌ Agent "${id}" not found.`); return; }
|
|
207
|
+
const confirmed = await prompt(`Remove @${id}? (y/N): `);
|
|
208
|
+
if (confirmed.toLowerCase() === 'y') {
|
|
209
|
+
fs.unlinkSync(file);
|
|
210
|
+
console.log(`✅ Agent "${id}" removed.`);
|
|
211
|
+
} else {
|
|
212
|
+
console.log('Cancelled.');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = { run };
|
package/bin/commands/memory.js
CHANGED
|
@@ -16,13 +16,13 @@ const lockfile = require('proper-lockfile');
|
|
|
16
16
|
*/
|
|
17
17
|
async function run(args) {
|
|
18
18
|
const subCommand = args[0];
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
// Look for .grimoire directory in cwd or in grimoire/ subdirectory
|
|
21
21
|
let baseDir = process.cwd();
|
|
22
22
|
if (!existsSync(path.join(baseDir, '.grimoire')) && existsSync(path.join(baseDir, 'grimoire', '.grimoire'))) {
|
|
23
23
|
baseDir = path.join(baseDir, 'grimoire');
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
const memoryDir = path.join(baseDir, '.grimoire', 'memory');
|
|
27
27
|
|
|
28
28
|
if (!existsSync(memoryDir)) {
|
|
@@ -41,6 +41,15 @@ async function run(args) {
|
|
|
41
41
|
case 'show':
|
|
42
42
|
await showSession(args.slice(1), memoryDir);
|
|
43
43
|
break;
|
|
44
|
+
case 'search':
|
|
45
|
+
await searchMemory(args.slice(1), memoryDir);
|
|
46
|
+
break;
|
|
47
|
+
case 'export':
|
|
48
|
+
await exportMemory(args.slice(1), memoryDir);
|
|
49
|
+
break;
|
|
50
|
+
case 'clear':
|
|
51
|
+
await clearMemory(args.slice(1), memoryDir);
|
|
52
|
+
break;
|
|
44
53
|
case 'digest':
|
|
45
54
|
await digestMemory(args.slice(1), memoryDir);
|
|
46
55
|
break;
|
|
@@ -80,7 +89,7 @@ async function saveMemory(args, memoryDir) {
|
|
|
80
89
|
let release;
|
|
81
90
|
try {
|
|
82
91
|
// Acquire lock with retry logic
|
|
83
|
-
release = await lockfile.lock(sessionFile, {
|
|
92
|
+
release = await lockfile.lock(sessionFile, {
|
|
84
93
|
retries: {
|
|
85
94
|
retries: 5,
|
|
86
95
|
factor: 3,
|
|
@@ -115,8 +124,14 @@ async function listSessions(memoryDir) {
|
|
|
115
124
|
* Shows session parsing JSONL or legacy JSON
|
|
116
125
|
*/
|
|
117
126
|
async function showSession(args, memoryDir) {
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
// Support: grimoire memory show --last 5
|
|
128
|
+
let date, lastN;
|
|
129
|
+
for (let i = 0; i < args.length; i++) {
|
|
130
|
+
if (args[i] === '--last' && args[i + 1]) lastN = parseInt(args[i + 1]);
|
|
131
|
+
else if (!args[i].startsWith('-')) date = args[i];
|
|
132
|
+
}
|
|
133
|
+
date = date || new Date().toISOString().split('T')[0];
|
|
134
|
+
|
|
120
135
|
let sessionFile = path.join(memoryDir, 'sessions', `${date}.jsonl`);
|
|
121
136
|
let isJsonl = true;
|
|
122
137
|
|
|
@@ -131,20 +146,101 @@ async function showSession(args, memoryDir) {
|
|
|
131
146
|
}
|
|
132
147
|
|
|
133
148
|
const rawContent = await fs.readFile(sessionFile, 'utf8');
|
|
134
|
-
|
|
135
|
-
|
|
149
|
+
let entries;
|
|
136
150
|
if (isJsonl) {
|
|
137
|
-
|
|
138
|
-
lines.forEach(line => {
|
|
139
|
-
const e = JSON.parse(line);
|
|
140
|
-
console.log(` [${e.timestamp.split('T')[1].split('.')[0]}] ${e.content}`);
|
|
141
|
-
});
|
|
151
|
+
entries = rawContent.split('\n').filter(l => l.trim()).map(l => JSON.parse(l));
|
|
142
152
|
} else {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
153
|
+
entries = JSON.parse(rawContent).entries;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (lastN) entries = entries.slice(-lastN);
|
|
157
|
+
|
|
158
|
+
console.log(`\n📖 Session: ${date} (${entries.length} entr${entries.length === 1 ? 'y' : 'ies'})`);
|
|
159
|
+
entries.forEach(e => {
|
|
160
|
+
console.log(` [${e.timestamp.split('T')[1].split('.')[0]}] ${e.content}`);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Search entries across all sessions
|
|
166
|
+
*/
|
|
167
|
+
async function searchMemory(args, memoryDir) {
|
|
168
|
+
const keyword = args.join(' ');
|
|
169
|
+
if (!keyword) { console.error('❌ Provide a search term.'); return; }
|
|
170
|
+
|
|
171
|
+
const sessionsDir = path.join(memoryDir, 'sessions');
|
|
172
|
+
const files = (await fs.readdir(sessionsDir)).filter(f => f.endsWith('.jsonl') || f.endsWith('.json'));
|
|
173
|
+
|
|
174
|
+
let matches = [];
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
const raw = await fs.readFile(path.join(sessionsDir, file), 'utf8');
|
|
177
|
+
const entries = file.endsWith('.jsonl')
|
|
178
|
+
? raw.split('\n').filter(l => l.trim()).map(l => JSON.parse(l))
|
|
179
|
+
: JSON.parse(raw).entries || [];
|
|
180
|
+
const date = file.replace(/\.(jsonl|json)$/, '');
|
|
181
|
+
for (const e of entries) {
|
|
182
|
+
if (e.content.toLowerCase().includes(keyword.toLowerCase())) {
|
|
183
|
+
matches.push({ date, time: e.timestamp.split('T')[1].split('.')[0], content: e.content });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log(`\n🔍 Search: "${keyword}" — ${matches.length} result${matches.length === 1 ? '' : 's'}`);
|
|
189
|
+
if (matches.length === 0) { console.log(' (No entries found)'); return; }
|
|
190
|
+
matches.forEach(m => console.log(` [${m.date} ${m.time}] ${m.content}`));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Export all sessions to a Markdown file
|
|
195
|
+
*/
|
|
196
|
+
async function exportMemory(args, memoryDir) {
|
|
197
|
+
const format = args.includes('--format') ? args[args.indexOf('--format') + 1] : 'markdown';
|
|
198
|
+
const sessionsDir = path.join(memoryDir, 'sessions');
|
|
199
|
+
const files = (await fs.readdir(sessionsDir)).filter(f => f.endsWith('.jsonl') || f.endsWith('.json')).sort();
|
|
200
|
+
|
|
201
|
+
let output = '# Grimoire Memory Export\n\n';
|
|
202
|
+
output += `> Exported: ${new Date().toISOString()}\n\n`;
|
|
203
|
+
|
|
204
|
+
for (const file of files) {
|
|
205
|
+
const date = file.replace(/\.(jsonl|json)$/, '');
|
|
206
|
+
const raw = await fs.readFile(path.join(sessionsDir, file), 'utf8');
|
|
207
|
+
const entries = file.endsWith('.jsonl')
|
|
208
|
+
? raw.split('\n').filter(l => l.trim()).map(l => JSON.parse(l))
|
|
209
|
+
: JSON.parse(raw).entries || [];
|
|
210
|
+
|
|
211
|
+
output += `## ${date}\n\n`;
|
|
212
|
+
entries.forEach(e => {
|
|
213
|
+
output += `- \`${e.timestamp.split('T')[1].split('.')[0]}\` ${e.content}\n`;
|
|
146
214
|
});
|
|
215
|
+
output += '\n';
|
|
147
216
|
}
|
|
217
|
+
|
|
218
|
+
const outFile = path.join(process.cwd(), `grimoire-memory-export-${Date.now()}.md`);
|
|
219
|
+
await fs.writeFile(outFile, output, 'utf8');
|
|
220
|
+
console.log(`✅ Memory exported to: ${outFile}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Clear sessions older than N days
|
|
225
|
+
*/
|
|
226
|
+
async function clearMemory(args, memoryDir) {
|
|
227
|
+
const olderThan = args.find(a => a.startsWith('--older-than'));
|
|
228
|
+
const days = olderThan ? parseInt(olderThan.replace('--older-than=', '').replace('--older-than', '') || args[args.indexOf(olderThan) + 1] || '30') : 30;
|
|
229
|
+
|
|
230
|
+
const sessionsDir = path.join(memoryDir, 'sessions');
|
|
231
|
+
const files = (await fs.readdir(sessionsDir)).filter(f => f.match(/^\d{4}-\d{2}-\d{2}/));
|
|
232
|
+
const cutoff = new Date();
|
|
233
|
+
cutoff.setDate(cutoff.getDate() - days);
|
|
234
|
+
|
|
235
|
+
let removed = 0;
|
|
236
|
+
for (const file of files) {
|
|
237
|
+
const datePart = file.replace(/\.(jsonl|json)$/, '');
|
|
238
|
+
if (new Date(datePart) < cutoff) {
|
|
239
|
+
await fs.unlink(path.join(sessionsDir, file));
|
|
240
|
+
removed++;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
console.log(`✅ Cleared ${removed} session${removed === 1 ? '' : 's'} older than ${days} days.`);
|
|
148
244
|
}
|
|
149
245
|
|
|
150
246
|
/**
|
|
@@ -175,7 +271,7 @@ async function digestMemory(args, memoryDir) {
|
|
|
175
271
|
categories.misc = entries.filter(e => !categorizedIds.has(e));
|
|
176
272
|
|
|
177
273
|
console.log(`📊 Analysis complete: ${entries.length} entries processed.`);
|
|
178
|
-
|
|
274
|
+
|
|
179
275
|
if (categories.decisions.length > 0) {
|
|
180
276
|
console.log('\n🏛️ PROPOSED DECISIONS (Update entities/decisions.md):');
|
|
181
277
|
categories.decisions.forEach(e => console.log(` - ${e.content}`));
|
|
@@ -194,21 +290,31 @@ async function digestMemory(args, memoryDir) {
|
|
|
194
290
|
console.log('\n--- SESSION ARCHIVING ---');
|
|
195
291
|
const archiveDir = path.join(memoryDir, 'sessions', 'archived');
|
|
196
292
|
if (!existsSync(archiveDir)) await fs.mkdir(archiveDir);
|
|
197
|
-
|
|
293
|
+
|
|
198
294
|
await fs.rename(sessionFile, path.join(archiveDir, `${date}.jsonl`));
|
|
199
295
|
console.log(`✅ Session ${date} digested and archived.`);
|
|
200
296
|
}
|
|
201
297
|
|
|
202
298
|
function showHelp() {
|
|
203
299
|
console.log(`
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
grimoire memory save "<
|
|
208
|
-
grimoire memory list
|
|
209
|
-
grimoire memory show
|
|
210
|
-
grimoire memory
|
|
211
|
-
grimoire memory
|
|
300
|
+
💾 Grimoire Memory — Gestão de Contexto
|
|
301
|
+
|
|
302
|
+
USO:
|
|
303
|
+
grimoire memory save "<texto>" Salva uma entrada na sessão de hoje
|
|
304
|
+
grimoire memory list Lista todas as sessões
|
|
305
|
+
grimoire memory show [data] Mostra entradas de uma data (padrão: hoje)
|
|
306
|
+
grimoire memory show --last 5 Mostra as últimas 5 entradas de hoje
|
|
307
|
+
grimoire memory search "<termo>" Busca em todas as sessões
|
|
308
|
+
grimoire memory export Exporta tudo para Markdown
|
|
309
|
+
grimoire memory digest [data] Categoriza e arquiva uma sessão
|
|
310
|
+
grimoire memory clear --older-than 30d Remove sessões antigas
|
|
311
|
+
|
|
312
|
+
EXEMPLOS:
|
|
313
|
+
grimoire memory save "Decidimos usar PostgreSQL por performance"
|
|
314
|
+
grimoire memory show --last 10
|
|
315
|
+
grimoire memory search "PostgreSQL"
|
|
316
|
+
grimoire memory export --format markdown
|
|
317
|
+
grimoire memory clear --older-than 30
|
|
212
318
|
`);
|
|
213
319
|
}
|
|
214
320
|
|