ai-hist 0.2.3 → 0.3.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.
@@ -0,0 +1,471 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ai-hist MCP server — exposes AI coding agent history as MCP tools.
4
+ *
5
+ * Covers Claude Code, Codex, Cursor, and Agent Relay in a single index.
6
+ * Uses the ai-hist SQLite database when present ($AI_HIST_DB or the
7
+ * default ~/.local/share/ai-hist/ai-history.db), falling back to
8
+ * scanning local JSONL source files directly so the server works without
9
+ * running `ai-hist sync` first.
10
+ */
11
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import { z } from "zod";
14
+ import { openAiHist, resumeCommand } from "./index.js";
15
+ // ---------------------------------------------------------------------------
16
+ // Lazy singleton — opens on first tool call and reuses across all calls.
17
+ // ---------------------------------------------------------------------------
18
+ let _histPromise = null;
19
+ function getHist() {
20
+ if (!_histPromise) {
21
+ _histPromise = openAiHist({ fallback: "jsonl" }).catch((err) => {
22
+ _histPromise = null;
23
+ throw err;
24
+ });
25
+ }
26
+ return _histPromise;
27
+ }
28
+ function fmtEntry(e, maxChars = 300) {
29
+ const dt = new Date(e.timestampMs).toISOString().slice(0, 16).replace("T", " ");
30
+ const proj = e.project ? ` [${e.project}]` : "";
31
+ const text = e.prompt.length > maxChars
32
+ ? e.prompt.slice(0, maxChars).replace(/\n/g, " ") + "..."
33
+ : e.prompt.replace(/\n/g, " ");
34
+ return `#${e.id} ${dt} (${e.source})${proj}\n session_id: ${e.sessionId ?? "(none)"}\n ${text}`;
35
+ }
36
+ function fmtTrajectory(t, maxChars = 500) {
37
+ const dt = new Date(t.timestampMs).toISOString().slice(0, 16).replace("T", " ");
38
+ const title = t.task.title ?? "(untitled task)";
39
+ const project = t.projectId ? ` [${t.projectId}]` : "";
40
+ const persona = t.personaId ? ` persona: ${t.personaId}` : "";
41
+ const decisions = t.decisions
42
+ .map((d, index) => {
43
+ const alternatives = d.alternatives.length > 0 ? ` alternatives: ${d.alternatives.join(", ")}` : "";
44
+ return `${index + 1}. ${d.question}\n chosen: ${d.chosen}\n reasoning: ${d.reasoning}${alternatives}`;
45
+ })
46
+ .join("\n");
47
+ const retroParts = [
48
+ t.retrospective.summary ? `summary: ${t.retrospective.summary}` : "",
49
+ t.retrospective.approach ? `approach: ${t.retrospective.approach}` : "",
50
+ t.retrospective.learnings.length > 0 ? `learnings: ${t.retrospective.learnings.join("; ")}` : "",
51
+ t.retrospective.confidence != null ? `confidence: ${String(t.retrospective.confidence)}` : "",
52
+ ].filter(Boolean);
53
+ const body = [
54
+ `trajectory_id: ${t.id}`,
55
+ `${dt}${project}${persona}`,
56
+ `task: ${title}`,
57
+ t.task.description ? `description: ${t.task.description}` : "",
58
+ decisions ? `decisions:\n${decisions}` : "",
59
+ retroParts.length > 0 ? `retrospective:\n${retroParts.join("\n")}` : "",
60
+ ].filter(Boolean).join("\n");
61
+ return body.length > maxChars ? body.slice(0, maxChars).replace(/\n/g, " ") + "..." : body;
62
+ }
63
+ const READ_ONLY = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };
64
+ // ---------------------------------------------------------------------------
65
+ // Server
66
+ // ---------------------------------------------------------------------------
67
+ const server = new McpServer({ name: "ai-hist", version: "1.0.0" }, { capabilities: { tools: {}, prompts: {} } });
68
+ // ---------------------------------------------------------------------------
69
+ // System prompt
70
+ // ---------------------------------------------------------------------------
71
+ server.prompt("agent-history-guide", "How to search and use your AI coding agent history via ai-hist", () => ({
72
+ messages: [
73
+ {
74
+ role: "user",
75
+ content: {
76
+ type: "text",
77
+ text: `You are connected to the ai-hist MCP server, which gives you access to a
78
+ unified history of AI coding agent sessions across Claude Code, Codex, Cursor,
79
+ and Agent Relay — all searchable in a single index.
80
+
81
+ ## Available tools
82
+
83
+ - **search_history** — Full-text search across all prompts. Start here when looking
84
+ for past work on a specific topic, bug, feature, or keyword. Supports boolean
85
+ operators (AND, OR, NOT) and prefix wildcards (*).
86
+
87
+ - **get_session** — Read the full conversation thread for a session_id. Use after
88
+ search_history or recent_history to see the complete context of a session, and
89
+ to get the exact CLI command to resume it.
90
+
91
+ - **get_context** — Reconstruct what you were working on at a specific moment in
92
+ time. Shows the full session the entry belongs to, plus nearby entries from other
93
+ sessions within a configurable time window.
94
+
95
+ - **recent_history** — Browse what was worked on recently across all agents, or
96
+ filter by source and project.
97
+
98
+ - **pack_evidence** — Assemble a concise, token-budget-aware summary of the most
99
+ relevant past sessions before starting a new task. Each entry includes a resume
100
+ command so you can continue where you left off.
101
+
102
+ - **history_stats** — Get a quick overview of what is indexed: total counts by
103
+ source, date range, and top projects.
104
+
105
+ - **search_trajectories** — Search compacted per-run decision trajectories: the
106
+ WHY behind persona work, including decisions and retrospectives.
107
+
108
+ - **why_for_task** — Return the best matching trajectory's decisions and
109
+ retrospective for a task query.
110
+
111
+ ## Tips
112
+
113
+ - If a tool returns "database not found", the user should run \`ai-hist sync\` to
114
+ populate the database from their local history files.
115
+ - session_id values from search results can be passed directly to get_session.
116
+ - Use pack_evidence before starting a complex task to pull in relevant prior context.`,
117
+ },
118
+ },
119
+ ],
120
+ }));
121
+ // ---------------------------------------------------------------------------
122
+ // Tools
123
+ // ---------------------------------------------------------------------------
124
+ server.tool("search_history", "Search your AI coding agent history using full-text search across all prompts " +
125
+ "from Claude Code, Codex, Cursor, and Agent Relay. Returns matching entries with " +
126
+ "source, project path, session ID, and timestamp ordered by most recent first. " +
127
+ "Supports FTS5 boolean operators (AND, OR, NOT), leading - to exclude a term, and " +
128
+ "trailing * for prefix matching. Use get_session with a returned session_id to read " +
129
+ "the full conversation.", {
130
+ query: z
131
+ .string()
132
+ .describe("Search query. Plain terms are matched literally. Use AND/OR/NOT (uppercase) for " +
133
+ 'boolean, leading - to exclude, trailing * for prefix. ' +
134
+ 'Examples: "authentication", "auth AND login", "deploy*", "refactor -test"'),
135
+ source: z
136
+ .enum(["claude", "codex", "cursor", "relay"])
137
+ .optional()
138
+ .describe("Filter to a single agent source. Omit to search all sources."),
139
+ project: z
140
+ .string()
141
+ .optional()
142
+ .describe('Filter by project directory path. Substring match — use a partial path like "/myproject" or "src/api".'),
143
+ limit: z
144
+ .number()
145
+ .int()
146
+ .min(1)
147
+ .max(100)
148
+ .optional()
149
+ .default(20)
150
+ .describe("Maximum number of results to return. Default: 20."),
151
+ }, READ_ONLY, async ({ query, source, project, limit }) => {
152
+ try {
153
+ const hist = await getHist();
154
+ const results = hist.search(query, { source, project, limit });
155
+ if (results.length === 0)
156
+ return { content: [{ type: "text", text: "No results found." }] };
157
+ const lines = [`Found ${results.length} result(s):\n`];
158
+ for (const e of results)
159
+ lines.push(fmtEntry(e));
160
+ return { content: [{ type: "text", text: lines.join("\n\n") }] };
161
+ }
162
+ catch (err) {
163
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
164
+ }
165
+ });
166
+ server.tool("search_trajectories", "Search compacted per-run decision trajectories: task title/description, decisions, " +
167
+ "alternatives, reasoning, and retrospective summaries/learnings. Use this for the WHY " +
168
+ "behind prior persona work.", {
169
+ query: z.string().describe("Search query for decisions, task text, personaId, projectId, or retrospectives."),
170
+ limit: z
171
+ .number()
172
+ .int()
173
+ .min(1)
174
+ .max(50)
175
+ .optional()
176
+ .default(10)
177
+ .describe("Maximum number of trajectory results to return. Default: 10."),
178
+ }, READ_ONLY, async ({ query, limit }) => {
179
+ try {
180
+ const hist = await getHist();
181
+ const results = hist.searchTrajectories(query, { limit });
182
+ if (results.length === 0) {
183
+ return { content: [{ type: "text", text: "No trajectories found." }] };
184
+ }
185
+ const lines = [`Found ${results.length} trajectory result(s):\n`];
186
+ for (const t of results)
187
+ lines.push(fmtTrajectory(t));
188
+ return { content: [{ type: "text", text: lines.join("\n\n") }] };
189
+ }
190
+ catch (err) {
191
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
192
+ }
193
+ });
194
+ server.tool("why_for_task", "Return the decisions and retrospective for the best-matching compacted trajectory. " +
195
+ "Use this when starting a task and you need the prior WHY: question, chosen option, " +
196
+ "reasoning, alternatives, summary, approach, learnings, and confidence.", {
197
+ query: z.string().describe("Task or decision query to match against compacted trajectories."),
198
+ }, READ_ONLY, async ({ query }) => {
199
+ try {
200
+ const hist = await getHist();
201
+ const trajectory = hist.whyForTask(query);
202
+ if (!trajectory) {
203
+ return { content: [{ type: "text", text: "No matching trajectory found." }] };
204
+ }
205
+ return { content: [{ type: "text", text: JSON.stringify(trajectory, null, 2) }] };
206
+ }
207
+ catch (err) {
208
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
209
+ }
210
+ });
211
+ server.tool("get_session", "Retrieve all prompts from a specific session ordered oldest to newest. " +
212
+ "Use this after search_history or recent_history to read the full conversation " +
213
+ "thread for a session_id. Returns all prompts with timestamps and includes the " +
214
+ "exact CLI command (claude --resume, codex resume, etc.) to continue that session.", {
215
+ session_id: z
216
+ .string()
217
+ .describe("Session ID to retrieve. Obtain from the session_id field in search_history or recent_history results."),
218
+ }, READ_ONLY, async ({ session_id }) => {
219
+ try {
220
+ const hist = await getHist();
221
+ const entries = hist.getSession(session_id);
222
+ if (entries.length === 0) {
223
+ return { content: [{ type: "text", text: `No entries found for session ${session_id}.` }] };
224
+ }
225
+ const first = entries[0];
226
+ const resume = resumeCommand(first);
227
+ const lines = [
228
+ `Session ${session_id} — ${entries.length} entries (${first.source}${first.project ? ", " + first.project : ""})`,
229
+ ];
230
+ if (resume)
231
+ lines.push(`Resume: ${resume}`);
232
+ lines.push("");
233
+ for (const e of entries) {
234
+ const dt = new Date(e.timestampMs).toISOString().slice(0, 16).replace("T", " ");
235
+ lines.push(`[${dt}] #${e.id}\n${e.prompt}`);
236
+ }
237
+ return { content: [{ type: "text", text: lines.join("\n\n") }] };
238
+ }
239
+ catch (err) {
240
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
241
+ }
242
+ });
243
+ server.tool("get_context", "Get temporal context around a specific history entry: all prompts from the same " +
244
+ "session, plus prompts from other sessions within a configurable time window. " +
245
+ "Use this when you remember roughly when you worked on something but not the exact " +
246
+ "search terms — useful for reconstructing the full picture of a working session. " +
247
+ "Obtain an entry ID from search_history or recent_history.", {
248
+ id: z
249
+ .number()
250
+ .int()
251
+ .describe("History entry ID. Obtain from the id field in search_history or recent_history results."),
252
+ window_minutes: z
253
+ .number()
254
+ .int()
255
+ .min(0)
256
+ .max(60)
257
+ .optional()
258
+ .default(5)
259
+ .describe("Minutes before and after the entry to include from other sessions. Default: 5."),
260
+ }, READ_ONLY, async ({ id, window_minutes }) => {
261
+ try {
262
+ const hist = await getHist();
263
+ const entry = hist.getEntry(id);
264
+ if (!entry) {
265
+ return { content: [{ type: "text", text: `No entry with id ${id}.` }] };
266
+ }
267
+ const lines = [];
268
+ if (entry.sessionId) {
269
+ const sessionEntries = hist.getSession(entry.sessionId);
270
+ lines.push(`=== Session ${entry.sessionId} (${sessionEntries.length} entries) ===`);
271
+ for (const e of sessionEntries) {
272
+ const dt = new Date(e.timestampMs).toISOString().slice(0, 16).replace("T", " ");
273
+ const marker = e.id === id ? ">>>" : " ";
274
+ lines.push(`${marker} [${dt}] #${e.id} (${e.source}) ${e.prompt.slice(0, 150).replace(/\n/g, " ")}`);
275
+ }
276
+ }
277
+ const windowMs = window_minutes * 60 * 1000;
278
+ const nearby = hist
279
+ .getInTimeWindow(entry.timestampMs, windowMs)
280
+ .filter((e) => e.sessionId !== entry.sessionId && e.id !== id);
281
+ if (nearby.length > 0) {
282
+ lines.push(`\n=== Nearby (±${window_minutes}min, other sessions) ===`);
283
+ for (const e of nearby) {
284
+ const dt = new Date(e.timestampMs).toISOString().slice(0, 16).replace("T", " ");
285
+ lines.push(` [${dt}] #${e.id} (${e.source}) ${e.prompt.slice(0, 150).replace(/\n/g, " ")}`);
286
+ }
287
+ }
288
+ return {
289
+ content: [{ type: "text", text: lines.length > 0 ? lines.join("\n") : "No context found." }],
290
+ };
291
+ }
292
+ catch (err) {
293
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
294
+ }
295
+ });
296
+ server.tool("recent_history", "List the most recent AI coding agent history entries across all sources, newest first. " +
297
+ "Use this to see what was worked on recently, to get a history entry ID for use with " +
298
+ "get_context, or to browse history without a specific keyword in mind. " +
299
+ "Optionally filter by agent source or project path.", {
300
+ n: z
301
+ .number()
302
+ .int()
303
+ .min(1)
304
+ .max(100)
305
+ .optional()
306
+ .default(20)
307
+ .describe("Number of entries to return. Default: 20."),
308
+ source: z
309
+ .enum(["claude", "codex", "cursor", "relay"])
310
+ .optional()
311
+ .describe("Filter to a specific agent source. Omit for all sources."),
312
+ project: z
313
+ .string()
314
+ .optional()
315
+ .describe('Filter by project directory path (substring match). Example: "/my-app" or "work/api".'),
316
+ }, READ_ONLY, async ({ n, source, project }) => {
317
+ try {
318
+ const hist = await getHist();
319
+ const entries = hist.recent({ limit: n, source, project });
320
+ if (entries.length === 0)
321
+ return { content: [{ type: "text", text: "No history entries found." }] };
322
+ const lines = [`Most recent ${entries.length} entries:\n`];
323
+ for (const e of entries)
324
+ lines.push(fmtEntry(e, 150));
325
+ return { content: [{ type: "text", text: lines.join("\n\n") }] };
326
+ }
327
+ catch (err) {
328
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
329
+ }
330
+ });
331
+ server.tool("recent_entries", "List the most recent AI coding agent history entries across all sources, newest first. " +
332
+ "This is the contract alias for recent_history.", {
333
+ limit: z
334
+ .number()
335
+ .int()
336
+ .min(1)
337
+ .max(100)
338
+ .optional()
339
+ .default(20)
340
+ .describe("Number of entries to return. Default: 20."),
341
+ project: z
342
+ .string()
343
+ .optional()
344
+ .describe('Filter by project directory/path or projectId (exact match in the SDK).'),
345
+ }, READ_ONLY, async ({ limit, project }) => {
346
+ try {
347
+ const hist = await getHist();
348
+ const entries = hist.recent({ limit, project });
349
+ if (entries.length === 0)
350
+ return { content: [{ type: "text", text: "No history entries found." }] };
351
+ const lines = [`Most recent ${entries.length} entries:\n`];
352
+ for (const e of entries)
353
+ lines.push(fmtEntry(e, 150));
354
+ return { content: [{ type: "text", text: lines.join("\n\n") }] };
355
+ }
356
+ catch (err) {
357
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
358
+ }
359
+ });
360
+ server.tool("pack_evidence", "Search history and assemble a concise evidence bundle ready to paste into a new " +
361
+ "LLM context window. Returns numbered entries with timestamps, source, project path, " +
362
+ "truncated prompt text, and the exact resume command for each session. " +
363
+ "Use this before starting work on a task to pull in relevant context from past sessions " +
364
+ "without exceeding token limits. Adjust tokens_per_entry to control how much of each " +
365
+ "prompt is included.", {
366
+ query: z.string().describe("Search query to find relevant past sessions."),
367
+ limit: z
368
+ .number()
369
+ .int()
370
+ .min(1)
371
+ .max(50)
372
+ .optional()
373
+ .default(10)
374
+ .describe("Maximum number of entries in the bundle. Default: 10."),
375
+ tokens_per_entry: z
376
+ .number()
377
+ .int()
378
+ .min(50)
379
+ .max(2000)
380
+ .optional()
381
+ .default(200)
382
+ .describe("Approximate token budget per entry's prompt text (~4 chars/token). Default: 200."),
383
+ }, READ_ONLY, async ({ query, limit, tokens_per_entry }) => {
384
+ try {
385
+ const hist = await getHist();
386
+ const entries = hist.search(query, { limit });
387
+ if (entries.length === 0)
388
+ return { content: [{ type: "text", text: `No results for "${query}".` }] };
389
+ const charsPerEntry = tokens_per_entry * 4;
390
+ const now = new Date().toISOString().slice(0, 16).replace("T", " ");
391
+ const lines = [`=== ai-hist pack: "${query}" | ${now} | ${entries.length} entries ===\n`];
392
+ for (let i = 0; i < entries.length; i++) {
393
+ const e = entries[i];
394
+ const dt = new Date(e.timestampMs).toISOString().slice(0, 16).replace("T", " ");
395
+ const proj = e.project ? ` ${e.project}` : "";
396
+ const text = e.prompt.length > charsPerEntry
397
+ ? e.prompt.slice(0, charsPerEntry).replace(/\n/g, " ") + "..."
398
+ : e.prompt.replace(/\n/g, " ");
399
+ const resume = resumeCommand(e);
400
+ let entry = `[${i + 1}/${entries.length}] #${e.id} ${dt} ${e.source}${proj}\n ${text}`;
401
+ if (resume)
402
+ entry += `\n Resume: ${resume}`;
403
+ lines.push(entry);
404
+ }
405
+ return { content: [{ type: "text", text: lines.join("\n\n") }] };
406
+ }
407
+ catch (err) {
408
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
409
+ }
410
+ });
411
+ server.tool("history_stats", "Return a summary of your AI coding agent history: total entry count broken down by " +
412
+ "source, the date range of recorded sessions, and the ten most-active projects. " +
413
+ "Use this to confirm that ai-hist sync has run successfully, to see which agents have " +
414
+ "the most history, or to get an overview before deciding where to search.", READ_ONLY, async () => {
415
+ try {
416
+ const hist = await getHist();
417
+ const s = hist.stats();
418
+ const lines = [`Total entries: ${s.total.toLocaleString()}\n`];
419
+ lines.push("By source:");
420
+ for (const [src, count] of Object.entries(s.bySource)) {
421
+ lines.push(` ${src}: ${(count ?? 0).toLocaleString()}`);
422
+ }
423
+ if (s.firstTimestampMs && s.lastTimestampMs) {
424
+ const first = new Date(s.firstTimestampMs).toISOString().slice(0, 10);
425
+ const last = new Date(s.lastTimestampMs).toISOString().slice(0, 10);
426
+ lines.push(`\nDate range: ${first} → ${last}`);
427
+ }
428
+ if (s.byProject.length > 0) {
429
+ lines.push("\nTop projects:");
430
+ for (const p of s.byProject) {
431
+ lines.push(` ${String(p.count).padStart(6)} ${p.project}`);
432
+ }
433
+ }
434
+ lines.push(`\nData source: ${hist.sourceKind} (${hist.dbPath})`);
435
+ return { content: [{ type: "text", text: lines.join("\n") }] };
436
+ }
437
+ catch (err) {
438
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
439
+ }
440
+ });
441
+ server.tool("stats", "Contract alias for history_stats. Return total counts by source, date range, top projects, and data source.", READ_ONLY, async () => {
442
+ try {
443
+ const hist = await getHist();
444
+ const s = hist.stats();
445
+ return {
446
+ content: [
447
+ {
448
+ type: "text",
449
+ text: JSON.stringify({
450
+ total: s.total,
451
+ bySource: s.bySource,
452
+ byProject: s.byProject,
453
+ firstTimestampMs: s.firstTimestampMs,
454
+ lastTimestampMs: s.lastTimestampMs,
455
+ sourceKind: hist.sourceKind,
456
+ dbPath: hist.dbPath,
457
+ }, null, 2),
458
+ },
459
+ ],
460
+ };
461
+ }
462
+ catch (err) {
463
+ return { content: [{ type: "text", text: `Error: ${String(err)}` }], isError: true };
464
+ }
465
+ });
466
+ // ---------------------------------------------------------------------------
467
+ // Start
468
+ // ---------------------------------------------------------------------------
469
+ const transport = new StdioServerTransport();
470
+ await server.connect(transport);
471
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-smoke.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-smoke.test.d.ts","sourceRoot":"","sources":["../src/mcp-smoke.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,151 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawn } from 'node:child_process';
3
+ import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { test } from 'node:test';
7
+ import { openAiHist } from './index.js';
8
+ test('SDK fallback ingests compacted per-run trajectories from TRAJECTORY_ROOT', async () => {
9
+ const root = await mkdtemp(join(tmpdir(), 'ai-hist-trajectory-'));
10
+ const compacted = join(root, 'planner', 'compacted');
11
+ await mkdir(compacted, { recursive: true });
12
+ await writeFile(join(compacted, 'run-1.json'), JSON.stringify({
13
+ id: 'run-1',
14
+ version: 1,
15
+ personaId: 'planner',
16
+ projectId: 'agent-workforce',
17
+ task: { title: 'Latency budget', description: 'Choose retry behavior for API calls.' },
18
+ status: 'completed',
19
+ startedAt: '2026-06-06T10:00:00.000Z',
20
+ completedAt: '2026-06-06T10:05:00.000Z',
21
+ decisions: [
22
+ {
23
+ question: 'How should retries behave?',
24
+ chosen: 'Use capped exponential backoff',
25
+ reasoning: 'It protects downstream services while preserving UX.',
26
+ alternatives: ['fixed delay', 'no retry'],
27
+ },
28
+ ],
29
+ retrospective: {
30
+ summary: 'Retry policy selected.',
31
+ approach: 'Compared failure modes and downstream pressure.',
32
+ learnings: ['Bound retries by elapsed time.'],
33
+ confidence: 0.82,
34
+ },
35
+ }));
36
+ const previousRoot = process.env.TRAJECTORY_ROOT;
37
+ const previousDb = process.env.AI_HIST_DB;
38
+ process.env.TRAJECTORY_ROOT = root;
39
+ process.env.AI_HIST_DB = join(root, 'missing.db');
40
+ const hist = await openAiHist({ dbPath: join(root, 'missing.db') });
41
+ try {
42
+ const results = hist.searchTrajectories('exponential backoff', { limit: 5 });
43
+ assert.equal(results.length, 1);
44
+ assert.equal(results[0].id, 'run-1');
45
+ assert.equal(results[0].decisions[0].chosen, 'Use capped exponential backoff');
46
+ assert.equal(hist.whyForTask('retry policy')?.retrospective.summary, 'Retry policy selected.');
47
+ assert.ok(hist.search('Latency budget', { source: 'trajectory', limit: 5 }).length >= 1);
48
+ }
49
+ finally {
50
+ hist.close();
51
+ if (previousRoot === undefined)
52
+ delete process.env.TRAJECTORY_ROOT;
53
+ else
54
+ process.env.TRAJECTORY_ROOT = previousRoot;
55
+ if (previousDb === undefined)
56
+ delete process.env.AI_HIST_DB;
57
+ else
58
+ process.env.AI_HIST_DB = previousDb;
59
+ }
60
+ });
61
+ test('MCP server exposes history and trajectory tools over stdio', async () => {
62
+ const root = await mkdtemp(join(tmpdir(), 'ai-hist-mcp-'));
63
+ const child = spawn(process.execPath, [new URL('./mcp-server.js', import.meta.url).pathname], {
64
+ env: {
65
+ ...process.env,
66
+ AI_HIST_DB: join(root, 'missing.db'),
67
+ TRAJECTORY_ROOT: root,
68
+ },
69
+ stdio: ['pipe', 'pipe', 'pipe'],
70
+ });
71
+ const stderr = [];
72
+ child.stderr.on('data', (chunk) => stderr.push(chunk));
73
+ try {
74
+ const tools = await new Promise((resolve, reject) => {
75
+ const timer = setTimeout(() => reject(new Error('timed out waiting for MCP tools/list')), 5000);
76
+ let buffer = '';
77
+ child.stdout.on('data', (chunk) => {
78
+ buffer += chunk.toString('utf8');
79
+ while (true) {
80
+ const marker = buffer.indexOf('\n');
81
+ if (marker === -1)
82
+ return;
83
+ const body = buffer.slice(0, marker).trim();
84
+ buffer = buffer.slice(marker + 1);
85
+ if (!body)
86
+ continue;
87
+ const message = JSON.parse(body);
88
+ if (message.error) {
89
+ clearTimeout(timer);
90
+ reject(new Error(`MCP error: ${JSON.stringify(message.error)}`));
91
+ return;
92
+ }
93
+ if (message.id === 2) {
94
+ clearTimeout(timer);
95
+ resolve(new Set((message.result?.tools ?? []).map((tool) => tool.name)));
96
+ return;
97
+ }
98
+ }
99
+ });
100
+ child.on('error', (err) => {
101
+ clearTimeout(timer);
102
+ reject(err);
103
+ });
104
+ child.on('exit', (code) => {
105
+ if (code !== null && code !== 0) {
106
+ clearTimeout(timer);
107
+ reject(new Error(`MCP server exited ${code}: ${Buffer.concat(stderr).toString('utf8')}`));
108
+ }
109
+ });
110
+ writeJsonRpc(child.stdin, {
111
+ jsonrpc: '2.0',
112
+ id: 1,
113
+ method: 'initialize',
114
+ params: {
115
+ protocolVersion: '2025-06-18',
116
+ capabilities: {},
117
+ clientInfo: { name: 'ai-hist-smoke', version: '0.0.0' },
118
+ },
119
+ });
120
+ writeJsonRpc(child.stdin, {
121
+ jsonrpc: '2.0',
122
+ method: 'notifications/initialized',
123
+ params: {},
124
+ });
125
+ writeJsonRpc(child.stdin, {
126
+ jsonrpc: '2.0',
127
+ id: 2,
128
+ method: 'tools/list',
129
+ params: {},
130
+ });
131
+ });
132
+ for (const name of [
133
+ 'search_history',
134
+ 'recent_entries',
135
+ 'get_session',
136
+ 'get_context',
137
+ 'stats',
138
+ 'search_trajectories',
139
+ 'why_for_task',
140
+ ]) {
141
+ assert.ok(tools.has(name), `missing MCP tool ${name}`);
142
+ }
143
+ }
144
+ finally {
145
+ child.kill();
146
+ }
147
+ });
148
+ function writeJsonRpc(stdin, payload) {
149
+ stdin.write(`${JSON.stringify(payload)}\n`);
150
+ }
151
+ //# sourceMappingURL=mcp-smoke.test.js.map