nodebench-mcp 2.11.0 → 2.13.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/NODEBENCH_AGENTS.md +809 -809
- package/README.md +443 -431
- package/STYLE_GUIDE.md +477 -477
- package/dist/__tests__/gaiaCapabilityMediaEval.test.js +153 -5
- package/dist/__tests__/gaiaCapabilityMediaEval.test.js.map +1 -1
- package/dist/__tests__/helpers/textLlm.d.ts +1 -1
- package/dist/__tests__/presetRealWorldBench.test.d.ts +1 -0
- package/dist/__tests__/presetRealWorldBench.test.js +839 -0
- package/dist/__tests__/presetRealWorldBench.test.js.map +1 -0
- package/dist/__tests__/tools.test.js +8 -5
- package/dist/__tests__/tools.test.js.map +1 -1
- package/dist/__tests__/toolsetGatingEval.test.js +11 -11
- package/dist/__tests__/toolsetGatingEval.test.js.map +1 -1
- package/dist/index.js +397 -327
- package/dist/index.js.map +1 -1
- package/dist/tools/agentBootstrapTools.js +258 -258
- package/dist/tools/boilerplateTools.js +144 -144
- package/dist/tools/cCompilerBenchmarkTools.js +33 -33
- package/dist/tools/documentationTools.js +59 -59
- package/dist/tools/flywheelTools.js +6 -6
- package/dist/tools/learningTools.js +26 -26
- package/dist/tools/localFileTools.d.ts +3 -0
- package/dist/tools/localFileTools.js +3164 -125
- package/dist/tools/localFileTools.js.map +1 -1
- package/dist/tools/reconTools.js +31 -31
- package/dist/tools/selfEvalTools.js +44 -44
- package/dist/tools/sessionMemoryTools.d.ts +15 -0
- package/dist/tools/sessionMemoryTools.js +348 -0
- package/dist/tools/sessionMemoryTools.js.map +1 -0
- package/dist/tools/toolRegistry.d.ts +4 -0
- package/dist/tools/toolRegistry.js +229 -0
- package/dist/tools/toolRegistry.js.map +1 -1
- package/dist/tools/verificationTools.js +41 -41
- package/dist/tools/visionTools.js +17 -17
- package/dist/tools/webTools.js +18 -18
- package/package.json +101 -101
package/dist/tools/reconTools.js
CHANGED
|
@@ -443,21 +443,21 @@ export const reconTools = [
|
|
|
443
443
|
let learnings = [];
|
|
444
444
|
try {
|
|
445
445
|
learnings = db
|
|
446
|
-
.prepare(`SELECT l.key, l.content, l.category, l.tags, l.source_cycle, l.created_at
|
|
447
|
-
FROM learnings_fts
|
|
448
|
-
JOIN learnings l ON l.id = learnings_fts.rowid
|
|
449
|
-
WHERE learnings_fts MATCH ?
|
|
450
|
-
ORDER BY rank
|
|
446
|
+
.prepare(`SELECT l.key, l.content, l.category, l.tags, l.source_cycle, l.created_at
|
|
447
|
+
FROM learnings_fts
|
|
448
|
+
JOIN learnings l ON l.id = learnings_fts.rowid
|
|
449
|
+
WHERE learnings_fts MATCH ?
|
|
450
|
+
ORDER BY rank
|
|
451
451
|
LIMIT ?`)
|
|
452
452
|
.all(query, limit);
|
|
453
453
|
}
|
|
454
454
|
catch {
|
|
455
455
|
// FTS5 syntax error (e.g., special chars in query) — fall back to LIKE
|
|
456
456
|
learnings = db
|
|
457
|
-
.prepare(`SELECT key, content, category, tags, source_cycle, created_at
|
|
458
|
-
FROM learnings
|
|
459
|
-
WHERE content LIKE ? OR key LIKE ?
|
|
460
|
-
ORDER BY created_at DESC
|
|
457
|
+
.prepare(`SELECT key, content, category, tags, source_cycle, created_at
|
|
458
|
+
FROM learnings
|
|
459
|
+
WHERE content LIKE ? OR key LIKE ?
|
|
460
|
+
ORDER BY created_at DESC
|
|
461
461
|
LIMIT ?`)
|
|
462
462
|
.all(`%${query}%`, `%${query}%`, limit);
|
|
463
463
|
}
|
|
@@ -470,38 +470,38 @@ export const reconTools = [
|
|
|
470
470
|
if (categories && categories.length > 0) {
|
|
471
471
|
const placeholders = categories.map(() => "?").join(", ");
|
|
472
472
|
reconFindings = db
|
|
473
|
-
.prepare(`SELECT f.id, f.session_id, f.source_url, f.category, f.summary,
|
|
474
|
-
f.relevance, f.action_items, f.created_at,
|
|
475
|
-
s.target as session_target
|
|
476
|
-
FROM recon_findings f
|
|
477
|
-
JOIN recon_sessions s ON s.id = f.session_id
|
|
478
|
-
WHERE (f.summary LIKE ? OR f.relevance LIKE ? OR f.action_items LIKE ?)
|
|
479
|
-
AND f.category IN (${placeholders})
|
|
480
|
-
ORDER BY f.created_at DESC
|
|
473
|
+
.prepare(`SELECT f.id, f.session_id, f.source_url, f.category, f.summary,
|
|
474
|
+
f.relevance, f.action_items, f.created_at,
|
|
475
|
+
s.target as session_target
|
|
476
|
+
FROM recon_findings f
|
|
477
|
+
JOIN recon_sessions s ON s.id = f.session_id
|
|
478
|
+
WHERE (f.summary LIKE ? OR f.relevance LIKE ? OR f.action_items LIKE ?)
|
|
479
|
+
AND f.category IN (${placeholders})
|
|
480
|
+
ORDER BY f.created_at DESC
|
|
481
481
|
LIMIT ?`)
|
|
482
482
|
.all(`%${query}%`, `%${query}%`, `%${query}%`, ...categories, limit);
|
|
483
483
|
}
|
|
484
484
|
else {
|
|
485
485
|
reconFindings = db
|
|
486
|
-
.prepare(`SELECT f.id, f.session_id, f.source_url, f.category, f.summary,
|
|
487
|
-
f.relevance, f.action_items, f.created_at,
|
|
488
|
-
s.target as session_target
|
|
489
|
-
FROM recon_findings f
|
|
490
|
-
JOIN recon_sessions s ON s.id = f.session_id
|
|
491
|
-
WHERE f.summary LIKE ? OR f.relevance LIKE ? OR f.action_items LIKE ?
|
|
492
|
-
ORDER BY f.created_at DESC
|
|
486
|
+
.prepare(`SELECT f.id, f.session_id, f.source_url, f.category, f.summary,
|
|
487
|
+
f.relevance, f.action_items, f.created_at,
|
|
488
|
+
s.target as session_target
|
|
489
|
+
FROM recon_findings f
|
|
490
|
+
JOIN recon_sessions s ON s.id = f.session_id
|
|
491
|
+
WHERE f.summary LIKE ? OR f.relevance LIKE ? OR f.action_items LIKE ?
|
|
492
|
+
ORDER BY f.created_at DESC
|
|
493
493
|
LIMIT ?`)
|
|
494
494
|
.all(`%${query}%`, `%${query}%`, `%${query}%`, limit);
|
|
495
495
|
}
|
|
496
496
|
// 3. Search ALL gaps from past verification cycles (resolved + open)
|
|
497
497
|
const matchedGaps = db
|
|
498
|
-
.prepare(`SELECT g.id, g.cycle_id, g.title, g.description, g.severity,
|
|
499
|
-
g.status, g.fix_strategy as resolution, g.resolved_at,
|
|
500
|
-
c.title as cycle_target
|
|
501
|
-
FROM gaps g
|
|
502
|
-
JOIN verification_cycles c ON c.id = g.cycle_id
|
|
503
|
-
WHERE (g.description LIKE ? OR g.fix_strategy LIKE ? OR g.title LIKE ?)
|
|
504
|
-
ORDER BY g.created_at DESC
|
|
498
|
+
.prepare(`SELECT g.id, g.cycle_id, g.title, g.description, g.severity,
|
|
499
|
+
g.status, g.fix_strategy as resolution, g.resolved_at,
|
|
500
|
+
c.title as cycle_target
|
|
501
|
+
FROM gaps g
|
|
502
|
+
JOIN verification_cycles c ON c.id = g.cycle_id
|
|
503
|
+
WHERE (g.description LIKE ? OR g.fix_strategy LIKE ? OR g.title LIKE ?)
|
|
504
|
+
ORDER BY g.created_at DESC
|
|
505
505
|
LIMIT ?`)
|
|
506
506
|
.all(`%${query}%`, `%${query}%`, `%${query}%`, limit);
|
|
507
507
|
const totalResults = learnings.length + reconFindings.length + matchedGaps.length;
|
|
@@ -1160,28 +1160,28 @@ export const selfEvalTools = [
|
|
|
1160
1160
|
handler: async (args) => {
|
|
1161
1161
|
const db = getDb();
|
|
1162
1162
|
// Ensure table exists
|
|
1163
|
-
db.exec(`CREATE TABLE IF NOT EXISTS eval_task_bank (
|
|
1164
|
-
id TEXT PRIMARY KEY,
|
|
1165
|
-
task_id TEXT UNIQUE NOT NULL,
|
|
1166
|
-
title TEXT NOT NULL,
|
|
1167
|
-
category TEXT NOT NULL,
|
|
1168
|
-
difficulty TEXT NOT NULL,
|
|
1169
|
-
prompt TEXT NOT NULL,
|
|
1170
|
-
initial_state TEXT,
|
|
1171
|
-
success_criteria TEXT NOT NULL,
|
|
1172
|
-
forbidden_behaviors TEXT,
|
|
1173
|
-
expected_tools TEXT,
|
|
1174
|
-
time_budget_minutes INTEGER DEFAULT 30,
|
|
1175
|
-
token_budget INTEGER,
|
|
1176
|
-
created_at TEXT DEFAULT (datetime('now')),
|
|
1177
|
-
run_count INTEGER DEFAULT 0,
|
|
1178
|
-
pass_count INTEGER DEFAULT 0
|
|
1163
|
+
db.exec(`CREATE TABLE IF NOT EXISTS eval_task_bank (
|
|
1164
|
+
id TEXT PRIMARY KEY,
|
|
1165
|
+
task_id TEXT UNIQUE NOT NULL,
|
|
1166
|
+
title TEXT NOT NULL,
|
|
1167
|
+
category TEXT NOT NULL,
|
|
1168
|
+
difficulty TEXT NOT NULL,
|
|
1169
|
+
prompt TEXT NOT NULL,
|
|
1170
|
+
initial_state TEXT,
|
|
1171
|
+
success_criteria TEXT NOT NULL,
|
|
1172
|
+
forbidden_behaviors TEXT,
|
|
1173
|
+
expected_tools TEXT,
|
|
1174
|
+
time_budget_minutes INTEGER DEFAULT 30,
|
|
1175
|
+
token_budget INTEGER,
|
|
1176
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
1177
|
+
run_count INTEGER DEFAULT 0,
|
|
1178
|
+
pass_count INTEGER DEFAULT 0
|
|
1179
1179
|
)`);
|
|
1180
1180
|
const existing = db.prepare("SELECT * FROM eval_task_bank WHERE task_id = ?").get(args.taskId);
|
|
1181
1181
|
if (existing) {
|
|
1182
1182
|
// Update existing task
|
|
1183
|
-
db.prepare(`UPDATE eval_task_bank SET title = ?, category = ?, difficulty = ?, prompt = ?,
|
|
1184
|
-
initial_state = ?, success_criteria = ?, forbidden_behaviors = ?, expected_tools = ?,
|
|
1183
|
+
db.prepare(`UPDATE eval_task_bank SET title = ?, category = ?, difficulty = ?, prompt = ?,
|
|
1184
|
+
initial_state = ?, success_criteria = ?, forbidden_behaviors = ?, expected_tools = ?,
|
|
1185
1185
|
time_budget_minutes = ?, token_budget = ? WHERE task_id = ?`).run(args.title, args.category, args.difficulty, args.prompt, args.initialState ?? null, JSON.stringify(args.successCriteria), args.forbiddenBehaviors ? JSON.stringify(args.forbiddenBehaviors) : null, args.expectedTools ? JSON.stringify(args.expectedTools) : null, args.timeBudgetMinutes ?? 30, args.tokenBudget ?? null, args.taskId);
|
|
1186
1186
|
return {
|
|
1187
1187
|
action: "updated",
|
|
@@ -1190,8 +1190,8 @@ export const selfEvalTools = [
|
|
|
1190
1190
|
};
|
|
1191
1191
|
}
|
|
1192
1192
|
// Insert new task
|
|
1193
|
-
db.prepare(`INSERT INTO eval_task_bank (id, task_id, title, category, difficulty, prompt,
|
|
1194
|
-
initial_state, success_criteria, forbidden_behaviors, expected_tools, time_budget_minutes, token_budget)
|
|
1193
|
+
db.prepare(`INSERT INTO eval_task_bank (id, task_id, title, category, difficulty, prompt,
|
|
1194
|
+
initial_state, success_criteria, forbidden_behaviors, expected_tools, time_budget_minutes, token_budget)
|
|
1195
1195
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(genId("etb"), args.taskId, args.title, args.category, args.difficulty, args.prompt, args.initialState ?? null, JSON.stringify(args.successCriteria), args.forbiddenBehaviors ? JSON.stringify(args.forbiddenBehaviors) : null, args.expectedTools ? JSON.stringify(args.expectedTools) : null, args.timeBudgetMinutes ?? 30, args.tokenBudget ?? null);
|
|
1196
1196
|
const total = db.prepare("SELECT COUNT(*) as cnt FROM eval_task_bank").get().cnt;
|
|
1197
1197
|
return {
|
|
@@ -1275,30 +1275,30 @@ export const selfEvalTools = [
|
|
|
1275
1275
|
handler: async (args) => {
|
|
1276
1276
|
const db = getDb();
|
|
1277
1277
|
// Ensure results table exists
|
|
1278
|
-
db.exec(`CREATE TABLE IF NOT EXISTS eval_run_results (
|
|
1279
|
-
id TEXT PRIMARY KEY,
|
|
1280
|
-
task_id TEXT NOT NULL,
|
|
1281
|
-
session_id TEXT,
|
|
1282
|
-
condition TEXT NOT NULL,
|
|
1283
|
-
trial_number INTEGER DEFAULT 1,
|
|
1284
|
-
outcome_score REAL,
|
|
1285
|
-
process_score REAL,
|
|
1286
|
-
combined_score REAL,
|
|
1287
|
-
outcome_results TEXT,
|
|
1288
|
-
forbidden_violations TEXT,
|
|
1289
|
-
duration_minutes REAL,
|
|
1290
|
-
total_tool_calls INTEGER,
|
|
1291
|
-
total_tokens INTEGER,
|
|
1292
|
-
notes TEXT,
|
|
1293
|
-
created_at TEXT DEFAULT (datetime('now'))
|
|
1278
|
+
db.exec(`CREATE TABLE IF NOT EXISTS eval_run_results (
|
|
1279
|
+
id TEXT PRIMARY KEY,
|
|
1280
|
+
task_id TEXT NOT NULL,
|
|
1281
|
+
session_id TEXT,
|
|
1282
|
+
condition TEXT NOT NULL,
|
|
1283
|
+
trial_number INTEGER DEFAULT 1,
|
|
1284
|
+
outcome_score REAL,
|
|
1285
|
+
process_score REAL,
|
|
1286
|
+
combined_score REAL,
|
|
1287
|
+
outcome_results TEXT,
|
|
1288
|
+
forbidden_violations TEXT,
|
|
1289
|
+
duration_minutes REAL,
|
|
1290
|
+
total_tool_calls INTEGER,
|
|
1291
|
+
total_tokens INTEGER,
|
|
1292
|
+
notes TEXT,
|
|
1293
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1294
1294
|
)`);
|
|
1295
1295
|
// Load task from bank (optional — if it exists, validate)
|
|
1296
|
-
db.exec(`CREATE TABLE IF NOT EXISTS eval_task_bank (
|
|
1297
|
-
id TEXT PRIMARY KEY, task_id TEXT UNIQUE NOT NULL, title TEXT NOT NULL,
|
|
1298
|
-
category TEXT NOT NULL, difficulty TEXT NOT NULL, prompt TEXT NOT NULL,
|
|
1299
|
-
initial_state TEXT, success_criteria TEXT NOT NULL, forbidden_behaviors TEXT,
|
|
1300
|
-
expected_tools TEXT, time_budget_minutes INTEGER DEFAULT 30, token_budget INTEGER,
|
|
1301
|
-
created_at TEXT DEFAULT (datetime('now')), run_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0
|
|
1296
|
+
db.exec(`CREATE TABLE IF NOT EXISTS eval_task_bank (
|
|
1297
|
+
id TEXT PRIMARY KEY, task_id TEXT UNIQUE NOT NULL, title TEXT NOT NULL,
|
|
1298
|
+
category TEXT NOT NULL, difficulty TEXT NOT NULL, prompt TEXT NOT NULL,
|
|
1299
|
+
initial_state TEXT, success_criteria TEXT NOT NULL, forbidden_behaviors TEXT,
|
|
1300
|
+
expected_tools TEXT, time_budget_minutes INTEGER DEFAULT 30, token_budget INTEGER,
|
|
1301
|
+
created_at TEXT DEFAULT (datetime('now')), run_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0
|
|
1302
1302
|
)`);
|
|
1303
1303
|
const task = db.prepare("SELECT * FROM eval_task_bank WHERE task_id = ?").get(args.taskId);
|
|
1304
1304
|
// ── Outcome scoring (50pts) ──
|
|
@@ -1383,8 +1383,8 @@ export const selfEvalTools = [
|
|
|
1383
1383
|
grade = "F (Non-Compliant)";
|
|
1384
1384
|
// Persist result
|
|
1385
1385
|
const resultId = genId("err");
|
|
1386
|
-
db.prepare(`INSERT INTO eval_run_results (id, task_id, session_id, condition, trial_number,
|
|
1387
|
-
outcome_score, process_score, combined_score, outcome_results, forbidden_violations,
|
|
1386
|
+
db.prepare(`INSERT INTO eval_run_results (id, task_id, session_id, condition, trial_number,
|
|
1387
|
+
outcome_score, process_score, combined_score, outcome_results, forbidden_violations,
|
|
1388
1388
|
duration_minutes, total_tool_calls, total_tokens, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(resultId, args.taskId, args.sessionId ?? null, args.condition, args.trialNumber ?? 1, totalOutcomeScore, totalProcessScore, combinedScore, JSON.stringify(outcomes), violations.length > 0 ? JSON.stringify(violations) : null, args.durationMinutes ?? null, args.totalToolCalls ?? null, args.totalTokens ?? null, args.notes ?? null);
|
|
1389
1389
|
// Update task bank stats
|
|
1390
1390
|
if (task) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Memory Tools — Compaction-resilient notes, attention refresh, and session recovery.
|
|
3
|
+
*
|
|
4
|
+
* Inspired by:
|
|
5
|
+
* - claude-mem (thedotmack): 3-layer progressive disclosure, compaction-resilient notepad
|
|
6
|
+
* - planning-with-files (OthmanAdi): Manus-style filesystem-as-memory, attention refresh
|
|
7
|
+
* - oh-my-claudecode (Yeachan-Heo): .omc/notepad.md compaction-resilient state
|
|
8
|
+
*
|
|
9
|
+
* 3 tools:
|
|
10
|
+
* - save_session_note: Persist findings to filesystem (survives context compaction)
|
|
11
|
+
* - load_session_notes: Retrieve notes from filesystem
|
|
12
|
+
* - refresh_task_context: Re-inject current goals mid-session (attention management)
|
|
13
|
+
*/
|
|
14
|
+
import type { McpTool } from "../types.js";
|
|
15
|
+
export declare const sessionMemoryTools: McpTool[];
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Memory Tools — Compaction-resilient notes, attention refresh, and session recovery.
|
|
3
|
+
*
|
|
4
|
+
* Inspired by:
|
|
5
|
+
* - claude-mem (thedotmack): 3-layer progressive disclosure, compaction-resilient notepad
|
|
6
|
+
* - planning-with-files (OthmanAdi): Manus-style filesystem-as-memory, attention refresh
|
|
7
|
+
* - oh-my-claudecode (Yeachan-Heo): .omc/notepad.md compaction-resilient state
|
|
8
|
+
*
|
|
9
|
+
* 3 tools:
|
|
10
|
+
* - save_session_note: Persist findings to filesystem (survives context compaction)
|
|
11
|
+
* - load_session_notes: Retrieve notes from filesystem
|
|
12
|
+
* - refresh_task_context: Re-inject current goals mid-session (attention management)
|
|
13
|
+
*/
|
|
14
|
+
import { getDb, genId } from "../db.js";
|
|
15
|
+
import * as fs from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
import * as os from "os";
|
|
18
|
+
const NOTES_DIR = path.join(os.homedir(), ".nodebench", "notes");
|
|
19
|
+
function ensureNotesDir() {
|
|
20
|
+
if (!fs.existsSync(NOTES_DIR)) {
|
|
21
|
+
fs.mkdirSync(NOTES_DIR, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const sessionMemoryTools = [
|
|
25
|
+
// ─── Tool 1: save_session_note ───────────────────────────────────────────
|
|
26
|
+
{
|
|
27
|
+
name: "save_session_note",
|
|
28
|
+
description: "Persist a critical finding, decision, or progress note to the filesystem. Notes survive context compaction — call this after every major finding or decision so state is never lost. Writes to ~/.nodebench/notes/ as dated markdown files.",
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
title: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Short headline for the note (e.g. 'Auth bug root cause', 'Migration decision: JWT over sessions')",
|
|
35
|
+
},
|
|
36
|
+
content: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Full note content. Include facts, decisions, file paths, error messages — anything needed to reconstruct context after compaction.",
|
|
39
|
+
},
|
|
40
|
+
category: {
|
|
41
|
+
type: "string",
|
|
42
|
+
enum: [
|
|
43
|
+
"finding",
|
|
44
|
+
"decision",
|
|
45
|
+
"progress",
|
|
46
|
+
"blocker",
|
|
47
|
+
"learning",
|
|
48
|
+
"architecture",
|
|
49
|
+
"debugging",
|
|
50
|
+
],
|
|
51
|
+
description: "Type of note (default: finding)",
|
|
52
|
+
},
|
|
53
|
+
tags: {
|
|
54
|
+
type: "array",
|
|
55
|
+
items: { type: "string" },
|
|
56
|
+
description: "Tags for searchability (e.g. ['auth', 'jwt', 'security'])",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
required: ["title", "content"],
|
|
60
|
+
},
|
|
61
|
+
handler: async (args) => {
|
|
62
|
+
ensureNotesDir();
|
|
63
|
+
const { title, content, category = "finding", tags = [], } = args;
|
|
64
|
+
const now = new Date();
|
|
65
|
+
const dateStr = now.toISOString().slice(0, 10);
|
|
66
|
+
const timeStr = now.toISOString().slice(11, 19).replace(/:/g, "");
|
|
67
|
+
const safeTitle = title
|
|
68
|
+
.toLowerCase()
|
|
69
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
70
|
+
.slice(0, 50);
|
|
71
|
+
const filename = `${dateStr}-${timeStr}-${safeTitle}.md`;
|
|
72
|
+
const filePath = path.join(NOTES_DIR, filename);
|
|
73
|
+
const markdown = [
|
|
74
|
+
`# ${title}`,
|
|
75
|
+
"",
|
|
76
|
+
`**Category:** ${category}`,
|
|
77
|
+
`**Date:** ${now.toISOString()}`,
|
|
78
|
+
tags.length > 0 ? `**Tags:** ${tags.join(", ")}` : "",
|
|
79
|
+
"",
|
|
80
|
+
"---",
|
|
81
|
+
"",
|
|
82
|
+
content,
|
|
83
|
+
"",
|
|
84
|
+
]
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.join("\n");
|
|
87
|
+
fs.writeFileSync(filePath, markdown, "utf-8");
|
|
88
|
+
// Also persist to SQLite for cross-session search
|
|
89
|
+
try {
|
|
90
|
+
const db = getDb();
|
|
91
|
+
db.prepare(`INSERT INTO learnings (id, key, content, category, tags, source_cycle_id, created_at)
|
|
92
|
+
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`).run(genId("note"), `session_note:${safeTitle}`, `[Session Note] ${title}\n\n${content}`, category === "finding" ? "pattern" : category === "debugging" ? "gotcha" : "convention", JSON.stringify(tags), null);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
/* SQLite backup is best-effort */
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
saved: true,
|
|
99
|
+
filePath,
|
|
100
|
+
filename,
|
|
101
|
+
title,
|
|
102
|
+
category,
|
|
103
|
+
tip: "Notes persist to filesystem and survive context compaction. Call load_session_notes to retrieve after /clear or /compact.",
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
// ─── Tool 2: load_session_notes ──────────────────────────────────────────
|
|
108
|
+
{
|
|
109
|
+
name: "load_session_notes",
|
|
110
|
+
description: "Load session notes from the filesystem. Use after context compaction, /clear, or session resume to recover state. Returns notes sorted by recency. Supports filtering by date, category, or keyword.",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
date: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "Filter by date (YYYY-MM-DD). Default: today. Use 'all' for all notes.",
|
|
117
|
+
},
|
|
118
|
+
category: {
|
|
119
|
+
type: "string",
|
|
120
|
+
enum: [
|
|
121
|
+
"finding",
|
|
122
|
+
"decision",
|
|
123
|
+
"progress",
|
|
124
|
+
"blocker",
|
|
125
|
+
"learning",
|
|
126
|
+
"architecture",
|
|
127
|
+
"debugging",
|
|
128
|
+
],
|
|
129
|
+
description: "Filter by note category (optional)",
|
|
130
|
+
},
|
|
131
|
+
keyword: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Search notes containing this keyword (case-insensitive)",
|
|
134
|
+
},
|
|
135
|
+
limit: {
|
|
136
|
+
type: "number",
|
|
137
|
+
description: "Max notes to return (default: 10)",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
required: [],
|
|
141
|
+
},
|
|
142
|
+
handler: async (args) => {
|
|
143
|
+
ensureNotesDir();
|
|
144
|
+
const { date, category, keyword, limit = 10 } = args;
|
|
145
|
+
const files = fs.readdirSync(NOTES_DIR).filter((f) => f.endsWith(".md"));
|
|
146
|
+
// Sort by filename (date-time prefix) descending (most recent first)
|
|
147
|
+
files.sort((a, b) => b.localeCompare(a));
|
|
148
|
+
// Filter by date
|
|
149
|
+
let filtered = files;
|
|
150
|
+
if (date && date !== "all") {
|
|
151
|
+
filtered = filtered.filter((f) => f.startsWith(date));
|
|
152
|
+
}
|
|
153
|
+
else if (!date) {
|
|
154
|
+
// Default: today
|
|
155
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
156
|
+
filtered = filtered.filter((f) => f.startsWith(today));
|
|
157
|
+
}
|
|
158
|
+
// Read file contents and apply filters
|
|
159
|
+
const notes = [];
|
|
160
|
+
for (const file of filtered) {
|
|
161
|
+
if (notes.length >= limit)
|
|
162
|
+
break;
|
|
163
|
+
const content = fs.readFileSync(path.join(NOTES_DIR, file), "utf-8");
|
|
164
|
+
// Extract metadata from markdown
|
|
165
|
+
const titleMatch = content.match(/^# (.+)$/m);
|
|
166
|
+
const categoryMatch = content.match(/\*\*Category:\*\* (.+)$/m);
|
|
167
|
+
const dateMatch = content.match(/\*\*Date:\*\* (.+)$/m);
|
|
168
|
+
const noteCategory = categoryMatch?.[1] || "unknown";
|
|
169
|
+
const noteTitle = titleMatch?.[1] || file;
|
|
170
|
+
const noteDate = dateMatch?.[1] || "";
|
|
171
|
+
// Category filter
|
|
172
|
+
if (category && noteCategory !== category)
|
|
173
|
+
continue;
|
|
174
|
+
// Keyword filter
|
|
175
|
+
if (keyword && !content.toLowerCase().includes(keyword.toLowerCase()))
|
|
176
|
+
continue;
|
|
177
|
+
notes.push({
|
|
178
|
+
filename: file,
|
|
179
|
+
title: noteTitle,
|
|
180
|
+
category: noteCategory,
|
|
181
|
+
content,
|
|
182
|
+
date: noteDate,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
noteCount: notes.length,
|
|
187
|
+
totalFiles: files.length,
|
|
188
|
+
notes: notes.map((n) => ({
|
|
189
|
+
filename: n.filename,
|
|
190
|
+
title: n.title,
|
|
191
|
+
category: n.category,
|
|
192
|
+
preview: n.content.slice(0, 300),
|
|
193
|
+
fullContent: n.content,
|
|
194
|
+
})),
|
|
195
|
+
tip: notes.length === 0
|
|
196
|
+
? "No notes found. Use save_session_note to persist findings during your session."
|
|
197
|
+
: "Notes loaded. Review findings and continue where you left off.",
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
// ─── Tool 3: refresh_task_context ────────────────────────────────────────
|
|
202
|
+
{
|
|
203
|
+
name: "refresh_task_context",
|
|
204
|
+
description: "Re-inject the current task context to combat attention drift. After 30+ tool calls, models lose sight of original goals ('lost in the middle' problem). This tool gathers your active verification cycle, open gaps, recent learnings, and session notes into a compact refresher. Based on Manus's 'Manipulate Attention Through Recitation' principle.",
|
|
205
|
+
inputSchema: {
|
|
206
|
+
type: "object",
|
|
207
|
+
properties: {
|
|
208
|
+
taskDescription: {
|
|
209
|
+
type: "string",
|
|
210
|
+
description: "What you're currently working on (re-state the original goal to anchor attention)",
|
|
211
|
+
},
|
|
212
|
+
includeNotes: {
|
|
213
|
+
type: "boolean",
|
|
214
|
+
description: "Include today's session notes in the refresher (default: true)",
|
|
215
|
+
},
|
|
216
|
+
includeGaps: {
|
|
217
|
+
type: "boolean",
|
|
218
|
+
description: "Include open verification gaps (default: true)",
|
|
219
|
+
},
|
|
220
|
+
includeLearnings: {
|
|
221
|
+
type: "boolean",
|
|
222
|
+
description: "Include recent relevant learnings (default: true)",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
required: [],
|
|
226
|
+
},
|
|
227
|
+
handler: async (args) => {
|
|
228
|
+
const { taskDescription = "", includeNotes = true, includeGaps = true, includeLearnings = true, } = args;
|
|
229
|
+
const db = getDb();
|
|
230
|
+
const context = {};
|
|
231
|
+
// 1. Active verification cycle
|
|
232
|
+
try {
|
|
233
|
+
const activeCycle = db
|
|
234
|
+
.prepare("SELECT * FROM verification_cycles WHERE status = 'active' ORDER BY created_at DESC LIMIT 1")
|
|
235
|
+
.get();
|
|
236
|
+
if (activeCycle) {
|
|
237
|
+
const phases = db
|
|
238
|
+
.prepare("SELECT phase, status, summary FROM phase_findings WHERE cycle_id = ? ORDER BY phase ASC")
|
|
239
|
+
.all(activeCycle.id);
|
|
240
|
+
context.activeCycle = {
|
|
241
|
+
id: activeCycle.id,
|
|
242
|
+
title: activeCycle.title,
|
|
243
|
+
currentPhase: activeCycle.current_phase,
|
|
244
|
+
status: activeCycle.status,
|
|
245
|
+
phases: phases.map((p) => ({
|
|
246
|
+
phase: p.phase,
|
|
247
|
+
status: p.status,
|
|
248
|
+
summary: p.summary?.slice(0, 100),
|
|
249
|
+
})),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
/* table may not exist yet */
|
|
255
|
+
}
|
|
256
|
+
// 2. Open gaps
|
|
257
|
+
if (includeGaps) {
|
|
258
|
+
try {
|
|
259
|
+
const gaps = db
|
|
260
|
+
.prepare("SELECT id, description, severity, status FROM gaps WHERE status = 'open' ORDER BY CASE severity WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 ELSE 4 END LIMIT 10")
|
|
261
|
+
.all();
|
|
262
|
+
if (gaps.length > 0) {
|
|
263
|
+
context.openGaps = gaps.map((g) => ({
|
|
264
|
+
id: g.id,
|
|
265
|
+
description: g.description?.slice(0, 100),
|
|
266
|
+
severity: g.severity,
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
/* table may not exist yet */
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// 3. Recent learnings
|
|
275
|
+
if (includeLearnings) {
|
|
276
|
+
try {
|
|
277
|
+
const learnings = db
|
|
278
|
+
.prepare("SELECT key, content, category FROM learnings ORDER BY created_at DESC LIMIT 5")
|
|
279
|
+
.all();
|
|
280
|
+
if (learnings.length > 0) {
|
|
281
|
+
context.recentLearnings = learnings.map((l) => ({
|
|
282
|
+
key: l.key,
|
|
283
|
+
category: l.category,
|
|
284
|
+
preview: l.content?.slice(0, 100),
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
/* table may not exist yet */
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// 4. Today's session notes
|
|
293
|
+
if (includeNotes) {
|
|
294
|
+
ensureNotesDir();
|
|
295
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
296
|
+
const files = fs
|
|
297
|
+
.readdirSync(NOTES_DIR)
|
|
298
|
+
.filter((f) => f.endsWith(".md") && f.startsWith(today))
|
|
299
|
+
.sort((a, b) => b.localeCompare(a))
|
|
300
|
+
.slice(0, 5);
|
|
301
|
+
if (files.length > 0) {
|
|
302
|
+
context.todayNotes = files.map((f) => {
|
|
303
|
+
const content = fs.readFileSync(path.join(NOTES_DIR, f), "utf-8");
|
|
304
|
+
const titleMatch = content.match(/^# (.+)$/m);
|
|
305
|
+
return {
|
|
306
|
+
title: titleMatch?.[1] || f,
|
|
307
|
+
preview: content.slice(0, 200),
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// 5. Tool call stats for this session
|
|
313
|
+
try {
|
|
314
|
+
const stats = db
|
|
315
|
+
.prepare("SELECT COUNT(*) as total, SUM(CASE WHEN result_status = 'error' THEN 1 ELSE 0 END) as errors FROM tool_call_log WHERE session_id = (SELECT session_id FROM tool_call_log ORDER BY created_at DESC LIMIT 1)")
|
|
316
|
+
.get();
|
|
317
|
+
if (stats) {
|
|
318
|
+
context.sessionStats = {
|
|
319
|
+
totalToolCalls: stats.total,
|
|
320
|
+
errors: stats.errors,
|
|
321
|
+
attentionWarning: stats.total > 30
|
|
322
|
+
? "HIGH DRIFT RISK: 30+ tool calls. Recite your original goal before proceeding."
|
|
323
|
+
: stats.total > 15
|
|
324
|
+
? "MODERATE: 15+ tool calls. Consider re-reading your task plan."
|
|
325
|
+
: "LOW: Fresh context, proceed normally.",
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
/* table may not exist yet */
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
taskDescription: taskDescription ||
|
|
334
|
+
"(Not specified — re-state your original goal to anchor attention)",
|
|
335
|
+
context,
|
|
336
|
+
refreshedAt: new Date().toISOString(),
|
|
337
|
+
guideline: "Re-read the taskDescription and activeCycle goal. Focus on open gaps by severity. Check todayNotes for decisions made earlier. Avoid repeating solved problems.",
|
|
338
|
+
antiDrift: [
|
|
339
|
+
"Does my current action serve the original goal?",
|
|
340
|
+
"Am I repeating something I already tried?",
|
|
341
|
+
"Have I checked learnings before implementing?",
|
|
342
|
+
"Am I within scope or drifting to tangents?",
|
|
343
|
+
],
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
];
|
|
348
|
+
//# sourceMappingURL=sessionMemoryTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionMemoryTools.js","sourceRoot":"","sources":["../../src/tools/sessionMemoryTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,6 +26,8 @@ export interface ToolRegistryEntry {
|
|
|
26
26
|
quickRef: ToolQuickRef;
|
|
27
27
|
/** Where this tool sits in a typical workflow: research, implement, test, verify, ship */
|
|
28
28
|
phase: "research" | "implement" | "test" | "verify" | "ship" | "meta" | "utility";
|
|
29
|
+
/** Recommended model tier: low=Haiku, medium=Sonnet, high=Opus. Used for cost-aware routing. */
|
|
30
|
+
complexity?: "low" | "medium" | "high";
|
|
29
31
|
}
|
|
30
32
|
/** Map of tool name → registry entry for O(1) lookup */
|
|
31
33
|
export declare const TOOL_REGISTRY: Map<string, ToolRegistryEntry>;
|
|
@@ -37,6 +39,8 @@ export declare function getQuickRef(toolName: string): ToolQuickRef | null;
|
|
|
37
39
|
export declare function getToolsByCategory(category: string): ToolRegistryEntry[];
|
|
38
40
|
/** Get all tools in a workflow phase */
|
|
39
41
|
export declare function getToolsByPhase(phase: ToolRegistryEntry["phase"]): ToolRegistryEntry[];
|
|
42
|
+
/** Get the recommended model complexity tier for a tool */
|
|
43
|
+
export declare function getToolComplexity(toolName: string): "low" | "medium" | "high";
|
|
40
44
|
export interface SearchResult {
|
|
41
45
|
name: string;
|
|
42
46
|
description: string;
|