grimoire-framework 1.7.0 → 1.7.1
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.
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
# - SHA256 hashes for change detection
|
|
8
8
|
# - File types for categorization
|
|
9
9
|
#
|
|
10
|
-
version: 1.7.
|
|
11
|
-
generated_at: "2026-02-22T18:
|
|
10
|
+
version: 1.7.1
|
|
11
|
+
generated_at: "2026-02-22T18:21:15.311Z"
|
|
12
12
|
generator: scripts/generate-install-manifest.js
|
|
13
13
|
file_count: 1011
|
|
14
14
|
files:
|
package/bin/commands/context.js
CHANGED
|
@@ -227,6 +227,117 @@ function regEscape(s) {
|
|
|
227
227
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
// ── Live Status block ──────────────────────────────────────────────────
|
|
231
|
+
const STATUS_START = '<!-- grimoire-MANAGED-START: live-status -->';
|
|
232
|
+
const STATUS_END = '<!-- grimoire-MANAGED-END: live-status -->';
|
|
233
|
+
|
|
234
|
+
function loadActiveStories(grimoireDir) {
|
|
235
|
+
const storiesDir = path.join(grimoireDir, 'stories');
|
|
236
|
+
if (!fs.existsSync(storiesDir)) return { active: [], backlog: [] };
|
|
237
|
+
const stories = fs.readdirSync(storiesDir)
|
|
238
|
+
.filter(f => f.endsWith('.json'))
|
|
239
|
+
.map(f => { try { return JSON.parse(fs.readFileSync(path.join(storiesDir, f), 'utf8')); } catch (_) { return null; } })
|
|
240
|
+
.filter(Boolean);
|
|
241
|
+
return {
|
|
242
|
+
active: stories.filter(s => s.status === 'in_progress'),
|
|
243
|
+
backlog: stories.filter(s => s.status === 'backlog'),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function timeSpentLabel(story) {
|
|
248
|
+
if (!story.startedAt) return '';
|
|
249
|
+
const ms = new Date() - new Date(story.startedAt);
|
|
250
|
+
const h = Math.floor(ms / 3600000);
|
|
251
|
+
const m = Math.floor((ms % 3600000) / 60000);
|
|
252
|
+
return ` ⏱ ${h}h${m}min`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function loadRagStatus(grimoireDir) {
|
|
256
|
+
const cfgF = path.join(grimoireDir, 'config.yaml');
|
|
257
|
+
if (!fs.existsSync(cfgF)) return null;
|
|
258
|
+
const lines = fs.readFileSync(cfgF, 'utf8').split('\n');
|
|
259
|
+
const get = (k) => { const l = lines.find(l => l.startsWith(k + ':')); return l ? l.split(':')[1]?.trim() : null; };
|
|
260
|
+
return get('embedding_provider') || null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function buildLiveStatusBlock(grimoireDir, entries) {
|
|
264
|
+
const now = new Date();
|
|
265
|
+
const dateStr = now.toISOString().replace('T', ' ').slice(0, 16);
|
|
266
|
+
const { active, backlog } = loadActiveStories(grimoireDir);
|
|
267
|
+
const ragProvider = loadRagStatus(grimoireDir);
|
|
268
|
+
|
|
269
|
+
// Count memories
|
|
270
|
+
const todayKey = now.toISOString().split('T')[0];
|
|
271
|
+
const todayCount = entries.filter(e => e.date === todayKey).length;
|
|
272
|
+
const totalCount = entries.length;
|
|
273
|
+
|
|
274
|
+
// Detect sprint from stories or memory tags
|
|
275
|
+
const sprintMem = entries.filter(e => /sprint/i.test(e.content)).slice(-1)[0];
|
|
276
|
+
|
|
277
|
+
const block = [STATUS_START];
|
|
278
|
+
block.push('');
|
|
279
|
+
block.push('## 🟢 Grimoire Ativo');
|
|
280
|
+
block.push('');
|
|
281
|
+
block.push('> Este bloco é auto-gerado pelo `grimoire context update` e confirma que o Grimoire Framework está ativo neste projeto.');
|
|
282
|
+
block.push('');
|
|
283
|
+
block.push('```');
|
|
284
|
+
block.push(`Data: ${dateStr}`);
|
|
285
|
+
|
|
286
|
+
if (active.length) {
|
|
287
|
+
block.push(`\nAtividades em andamento (${active.length}):`);
|
|
288
|
+
active.forEach(s => block.push(` [${s.id}] ${s.title}${timeSpentLabel(s)}`));
|
|
289
|
+
} else {
|
|
290
|
+
block.push(`\nAtividades: nenhuma em andamento`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (backlog.length) {
|
|
294
|
+
block.push(`Backlog: ${backlog.length} atividade(s) aguardando`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const ragLabel = ragProvider && ragProvider !== 'tfidf'
|
|
298
|
+
? `ativo (${ragProvider})`
|
|
299
|
+
: 'tfidf (sem embedding — rode grimoire setup rag)';
|
|
300
|
+
block.push(`\nMemória: ${totalCount} total · ${todayCount} hoje`);
|
|
301
|
+
block.push(`RAG: ${ragLabel}`);
|
|
302
|
+
block.push(`\nComandos úteis:`);
|
|
303
|
+
block.push(` grimoire → dashboard kanban`);
|
|
304
|
+
block.push(` grimoire memory search "query" → busca semântica`);
|
|
305
|
+
block.push(` grimoire context update → atualizar este bloco`);
|
|
306
|
+
block.push(` *status → verificar estado no chat`);
|
|
307
|
+
block.push('```');
|
|
308
|
+
block.push('');
|
|
309
|
+
block.push(STATUS_END);
|
|
310
|
+
return block.join('\n');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function injectLiveStatus(grimoireDir, entries) {
|
|
314
|
+
const cwd = process.cwd();
|
|
315
|
+
const candidates = [
|
|
316
|
+
path.join(cwd, 'GEMINI.md'),
|
|
317
|
+
path.join(path.dirname(grimoireDir), 'GEMINI.md'),
|
|
318
|
+
];
|
|
319
|
+
const geminiPath = candidates.find(p => fs.existsSync(p));
|
|
320
|
+
if (!geminiPath) return false;
|
|
321
|
+
|
|
322
|
+
const original = fs.readFileSync(geminiPath, 'utf8');
|
|
323
|
+
const newBlock = buildLiveStatusBlock(grimoireDir, entries);
|
|
324
|
+
|
|
325
|
+
let updated;
|
|
326
|
+
if (original.includes(STATUS_START)) {
|
|
327
|
+
const re = new RegExp(`${regEscape(STATUS_START)}[\\s\\S]*?${regEscape(STATUS_END)}`, 'g');
|
|
328
|
+
updated = original.replace(re, newBlock);
|
|
329
|
+
} else {
|
|
330
|
+
// Insert at the very end (after all managed blocks)
|
|
331
|
+
updated = original.trimEnd() + '\n\n' + newBlock + '\n';
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (updated !== original) {
|
|
335
|
+
fs.writeFileSync(geminiPath, updated, 'utf8');
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
|
|
230
341
|
// ── Core update logic ─────────────────────────────────────────────────────────
|
|
231
342
|
function doUpdate(grimoireDir, silent = false) {
|
|
232
343
|
const contextDir = getContextDir(grimoireDir);
|
|
@@ -255,16 +366,19 @@ function doUpdate(grimoireDir, silent = false) {
|
|
|
255
366
|
fs.writeFileSync(path.join(contextDir, 'pinned.md'), pinnedLines.join('\n'), 'utf8');
|
|
256
367
|
}
|
|
257
368
|
|
|
258
|
-
// Inject GEMINI.md
|
|
369
|
+
// Inject GEMINI.md memory-context block
|
|
259
370
|
const injected = injectIntoGeminiMd(grimoireDir, entries);
|
|
260
371
|
|
|
372
|
+
// Inject live-status block (separate, always updated)
|
|
373
|
+
const statusInjected = injectLiveStatus(grimoireDir, entries);
|
|
374
|
+
|
|
261
375
|
if (!silent) {
|
|
262
376
|
console.log('\n✅ Contexto atualizado!\n');
|
|
263
377
|
console.log(` 📄 .grimoire/context/CONTEXT.md`);
|
|
264
378
|
if (dec) console.log(` ✅ .grimoire/context/decisions.md`);
|
|
265
379
|
if (pat) console.log(` 🔧 .grimoire/context/patterns.md`);
|
|
266
380
|
if (pinned.length) console.log(` 📌 .grimoire/context/pinned.md`);
|
|
267
|
-
if (injected) console.log(`
|
|
381
|
+
if (injected || statusInjected) console.log(` 🟢 GEMINI.md — bloco live-status + memory-context atualizados`);
|
|
268
382
|
console.log(`\n ${entries.length} entradas indexadas`);
|
|
269
383
|
console.log(` grimoire context show ← ver o resultado\n`);
|
|
270
384
|
}
|