@gi4nks/ph 1.4.0 → 1.6.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/CHANGELOG.md +7 -0
- package/README.md +147 -58
- package/dist/cli.js +2292 -1021
- package/dist/cli.js.map +1 -1
- package/docs/evals/context-retrieval-golden.json +26 -0
- package/docs/evals/context-retrieval.md +27 -0
- package/docs/hooks.md +13 -7
- package/docs/ph-analysis.html +145 -0
- package/docs/ph-manual.md +352 -231
- package/docs/specs/SPEC-001-architecture-cli.md +82 -0
- package/docs/specs/SPEC-002-database-layer.md +105 -0
- package/docs/specs/SPEC-003-capture-modes.md +110 -0
- package/docs/specs/SPEC-004-filter-metadata.md +82 -0
- package/docs/specs/SPEC-005-search.md +102 -0
- package/docs/specs/SPEC-006-analysis-pipeline.md +98 -0
- package/docs/specs/SPEC-007-memory-summaries.md +96 -0
- package/docs/specs/SPEC-008-embeddings.md +90 -0
- package/docs/specs/SPEC-009-retention-archive.md +91 -0
- package/docs/specs/SPEC-010-remote-sync.md +106 -0
- package/docs/specs/SPEC-011-mcp-server.md +94 -0
- package/docs/specs/SPEC-012-tui-browser.md +98 -0
- package/docs/specs/SPEC-013-importers.md +109 -0
- package/docs/specs/SPEC-014-analytics-commands.md +109 -0
- package/docs/specs/SPEC-015-config-env.md +85 -0
- package/docs/specs/SPEC-INDEX.md +35 -0
- package/docs/specs/SPEC-ISSUES.md +122 -0
- package/docs/specs/_TEMPLATE.md +65 -0
- package/docs/superpowers/plans/2026-06-12-ph-evolution-phase1.md +466 -0
- package/docs/superpowers/plans/2026-06-12-ph-evolution-phase2.md +351 -0
- package/docs/superpowers/specs/2026-06-12-ph-evolution-design.md +173 -0
- package/hooks/codex/README.md +54 -0
- package/hooks/codex/ph-hook.sh +14 -0
- package/hooks/opencode/ph-plugin.ts +60 -57
- package/package.json +13 -12
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
# Phase 1: Memory Merging — Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use `subagent-driven-development` or `executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax.
|
|
4
|
+
|
|
5
|
+
**Goal:** Create `project_summaries` table (1 row per project, merged/deduped knowledge), migrate existing `memories` into it, update analysis pipeline and MCP tools to use it.
|
|
6
|
+
|
|
7
|
+
**Architecture:** New table `project_summaries` alongside existing `memories`. Analysis writes to BOTH tables (append-only `memories` for timeline, merged `project_summaries` for curated knowledge). MCP reads from `project_summaries` by default. One-time migration aggregates existing per-project memories into single rows.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript 5.9 ESM, better-sqlite3, sqlite-vec
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- ESM only — all imports use `.js` extension
|
|
14
|
+
- `better-sqlite3` for DB operations (synchronous API)
|
|
15
|
+
- All new methods on `PhDB` class in `src/db/index.ts`
|
|
16
|
+
- Follow existing patterns: snake_case column names, camelCase JS methods
|
|
17
|
+
- Existing `memories` table and `MemoryEntry` type remain unchanged
|
|
18
|
+
- Build passes after every task: `npm run build`
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
### Task 1: `ProjectSummary` type + `project_summaries` table schema + auto-migration
|
|
22
|
+
|
|
23
|
+
**Files:**
|
|
24
|
+
- Modify: `src/types.ts` (add `ProjectSummary` interface)
|
|
25
|
+
- Modify: `src/db/index.ts` (add table creation in `ensureSchema`, add `PROJECT_SUMMARIES_SCHEMA`)
|
|
26
|
+
|
|
27
|
+
**Interfaces:**
|
|
28
|
+
- Consumes: nothing other than the existing `PhDB` constructor pattern
|
|
29
|
+
- Produces: `ProjectSummary` type, `project_summaries` table created on DB open
|
|
30
|
+
|
|
31
|
+
- [ ] **Step 1: Add `ProjectSummary` interface to `src/types.ts`**
|
|
32
|
+
|
|
33
|
+
Append after `MemoryEntry` interface:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
export interface ProjectSummary {
|
|
37
|
+
project: string;
|
|
38
|
+
summary: string;
|
|
39
|
+
key_insights: string[];
|
|
40
|
+
technical_decisions: string[];
|
|
41
|
+
prompt_count: number;
|
|
42
|
+
first_analyzed: string;
|
|
43
|
+
last_analyzed: string;
|
|
44
|
+
git_context_snapshot?: string;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- [ ] **Step 2: Add SQL CREATE + migration to `src/db/index.ts`**
|
|
49
|
+
|
|
50
|
+
At the top of the PhDB class, add the schema constant:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
private static readonly PROJECT_SUMMARIES_SCHEMA = `
|
|
54
|
+
CREATE TABLE IF NOT EXISTS project_summaries (
|
|
55
|
+
project TEXT PRIMARY KEY,
|
|
56
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
57
|
+
key_insights TEXT NOT NULL DEFAULT '[]',
|
|
58
|
+
technical_decisions TEXT NOT NULL DEFAULT '[]',
|
|
59
|
+
prompt_count INTEGER NOT NULL DEFAULT 0,
|
|
60
|
+
first_analyzed TEXT NOT NULL,
|
|
61
|
+
last_analyzed TEXT NOT NULL,
|
|
62
|
+
git_context_snapshot TEXT
|
|
63
|
+
);
|
|
64
|
+
`;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
In the `ensureSchema()` method, add after the `memories` table creation:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
this.db.exec(PhDB.PROJECT_SUMMARIES_SCHEMA);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- [ ] **Step 3: Build + verify**
|
|
74
|
+
|
|
75
|
+
Run: `npm run build`
|
|
76
|
+
Expected: Build succeeds
|
|
77
|
+
|
|
78
|
+
- [ ] **Step 4: Commit**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
git add src/types.ts src/db/index.ts
|
|
82
|
+
git commit -m "feat: add project_summaries table and ProjectSummary type"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
### Task 2: `upsertProjectSummary()` + `getProjectSummary()` methods on PhDB
|
|
87
|
+
|
|
88
|
+
**Files:**
|
|
89
|
+
- Modify: `src/db/index.ts` (add methods, add private hydrate helper)
|
|
90
|
+
|
|
91
|
+
**Interfaces:**
|
|
92
|
+
- Produces: `db.upsertProjectSummary(params)` — merges into existing row or inserts new; `db.getProjectSummary(project)` — returns single row or null; `db.getAllProjectsWithSummaries()` — for migration
|
|
93
|
+
|
|
94
|
+
- [ ] **Step 1: Add `upsertProjectSummary()` and `getProjectSummary()`**
|
|
95
|
+
|
|
96
|
+
Add after `getAllProjectsWithMemories()` (around line 527):
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
upsertProjectSummary(params: {
|
|
100
|
+
project: string;
|
|
101
|
+
summary: string;
|
|
102
|
+
key_insights: string[];
|
|
103
|
+
technical_decisions: string[];
|
|
104
|
+
git_context_snapshot?: string;
|
|
105
|
+
}): void {
|
|
106
|
+
const existing = this.getProjectSummary(params.project);
|
|
107
|
+
const now = new Date().toISOString();
|
|
108
|
+
|
|
109
|
+
if (existing) {
|
|
110
|
+
// Merge insights — dedup by string equality
|
|
111
|
+
const allInsights = new Set([...existing.key_insights, ...params.key_insights]);
|
|
112
|
+
// Merge decisions — dedup by string equality
|
|
113
|
+
const allDecisions = new Set([...existing.technical_decisions, ...params.technical_decisions]);
|
|
114
|
+
|
|
115
|
+
this.db.prepare(`
|
|
116
|
+
UPDATE project_summaries
|
|
117
|
+
SET summary = ?,
|
|
118
|
+
key_insights = ?,
|
|
119
|
+
technical_decisions = ?,
|
|
120
|
+
prompt_count = prompt_count + 1,
|
|
121
|
+
last_analyzed = ?,
|
|
122
|
+
git_context_snapshot = COALESCE(?, git_context_snapshot)
|
|
123
|
+
WHERE project = ?
|
|
124
|
+
`).run(
|
|
125
|
+
params.summary,
|
|
126
|
+
JSON.stringify([...allInsights]),
|
|
127
|
+
JSON.stringify([...allDecisions]),
|
|
128
|
+
now,
|
|
129
|
+
params.git_context_snapshot || null,
|
|
130
|
+
params.project
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
this.db.prepare(`
|
|
134
|
+
INSERT INTO project_summaries (project, summary, key_insights, technical_decisions, prompt_count, first_analyzed, last_analyzed, git_context_snapshot)
|
|
135
|
+
VALUES (?, ?, ?, ?, 1, ?, ?, ?)
|
|
136
|
+
`).run(
|
|
137
|
+
params.project,
|
|
138
|
+
params.summary,
|
|
139
|
+
JSON.stringify(params.key_insights),
|
|
140
|
+
JSON.stringify(params.technical_decisions),
|
|
141
|
+
now,
|
|
142
|
+
now,
|
|
143
|
+
params.git_context_snapshot || null
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
getProjectSummary(project: string): ProjectSummary | null {
|
|
149
|
+
const row = this.db.prepare('SELECT * FROM project_summaries WHERE project = ?').get(project) as Record<string, unknown> | undefined;
|
|
150
|
+
if (!row) return null;
|
|
151
|
+
return this.hydrateProjectSummary(row);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
getAllProjectsWithSummaries(): string[] {
|
|
155
|
+
const rows = this.db.prepare('SELECT project FROM project_summaries ORDER BY project').all() as { project: string }[];
|
|
156
|
+
return rows.map(r => r.project);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
- [ ] **Step 2: Add `hydrateProjectSummary()` private method**
|
|
161
|
+
|
|
162
|
+
Add after `hydrateMemory()`:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
private hydrateProjectSummary(row: Record<string, unknown>): ProjectSummary {
|
|
166
|
+
return {
|
|
167
|
+
project: row.project as string,
|
|
168
|
+
summary: row.summary as string,
|
|
169
|
+
key_insights: JSON.parse(row.key_insights as string),
|
|
170
|
+
technical_decisions: JSON.parse(row.technical_decisions as string),
|
|
171
|
+
prompt_count: row.prompt_count as number,
|
|
172
|
+
first_analyzed: row.first_analyzed as string,
|
|
173
|
+
last_analyzed: row.last_analyzed as string,
|
|
174
|
+
git_context_snapshot: row.git_context_snapshot as string | undefined,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- [ ] **Step 3: Build + verify**
|
|
180
|
+
|
|
181
|
+
Run: `npm run build`
|
|
182
|
+
Expected: Build succeeds
|
|
183
|
+
|
|
184
|
+
- [ ] **Step 4: Commit**
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
git add src/db/index.ts
|
|
188
|
+
git commit -m "feat: add upsertProjectSummary and getProjectSummary to PhDB"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
### Task 3: One-time migration command — merge existing memories into summaries
|
|
193
|
+
|
|
194
|
+
**Files:**
|
|
195
|
+
- Create: `src/commands/memory-migrate.ts`
|
|
196
|
+
- Modify: `src/cli.ts` (register `memory-migrate` command)
|
|
197
|
+
|
|
198
|
+
**Interfaces:**
|
|
199
|
+
- Consumes: `db.upsertProjectSummary()`, `db.searchMemories()` — already exist
|
|
200
|
+
- Produces: `ph memory-migrate` CLI command that aggregates all existing memories into project_summaries
|
|
201
|
+
|
|
202
|
+
- [ ] **Step 1: Create `src/commands/memory-migrate.ts`**
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { PhDB } from '../db/index.js';
|
|
206
|
+
|
|
207
|
+
export function cmdMemoryMigrate(db: PhDB): void {
|
|
208
|
+
const projects = db.getAllProjectsWithMemories();
|
|
209
|
+
if (projects.length === 0) {
|
|
210
|
+
console.log('No memories found. Nothing to migrate.');
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let count = 0;
|
|
215
|
+
for (const project of projects) {
|
|
216
|
+
const memories = db.searchMemories(project, 1000);
|
|
217
|
+
const allInsights = new Set<string>();
|
|
218
|
+
const allDecisions = new Set<string>();
|
|
219
|
+
let lastSummary = '';
|
|
220
|
+
let gitCtx: string | undefined;
|
|
221
|
+
|
|
222
|
+
for (const mem of memories) {
|
|
223
|
+
if (mem.summary) lastSummary = mem.summary;
|
|
224
|
+
for (const i of mem.key_insights) allInsights.add(i);
|
|
225
|
+
for (const d of mem.technical_decisions) allDecisions.add(d);
|
|
226
|
+
if (mem.git_context_snapshot) gitCtx = mem.git_context_snapshot;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
db.upsertProjectSummary({
|
|
230
|
+
project,
|
|
231
|
+
summary: lastSummary,
|
|
232
|
+
key_insights: [...allInsights],
|
|
233
|
+
technical_decisions: [...allDecisions],
|
|
234
|
+
git_context_snapshot: gitCtx,
|
|
235
|
+
});
|
|
236
|
+
count++;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log(`Migrated ${count} project(s) into project_summaries.`);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
- [ ] **Step 2: Register `memory-migrate` in `src/cli.ts`**
|
|
244
|
+
|
|
245
|
+
Add import at top:
|
|
246
|
+
```typescript
|
|
247
|
+
import { cmdMemoryMigrate } from './commands/memory-migrate.js';
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Add to usage string (after `mcp` line):
|
|
251
|
+
```
|
|
252
|
+
ph memory-migrate Merge existing memories into project_summaries
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Add case before `case 'mcp'`:
|
|
256
|
+
```typescript
|
|
257
|
+
case 'memory-migrate':
|
|
258
|
+
cmdMemoryMigrate(db);
|
|
259
|
+
break;
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- [ ] **Step 3: Build + verify**
|
|
263
|
+
|
|
264
|
+
Run: `npm run build`
|
|
265
|
+
Expected: Build succeeds
|
|
266
|
+
|
|
267
|
+
- [ ] **Step 4: Run migration**
|
|
268
|
+
|
|
269
|
+
Run: `node dist/cli.js memory-migrate`
|
|
270
|
+
Expected: "Migrated X project(s) into project_summaries."
|
|
271
|
+
|
|
272
|
+
- [ ] **Step 5: Commit**
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
git add src/commands/memory-migrate.ts src/cli.ts
|
|
276
|
+
git commit -m "feat: add ph memory-migrate command"
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
### Task 4: Update analysis pipeline to write to BOTH tables
|
|
281
|
+
|
|
282
|
+
**Files:**
|
|
283
|
+
- Modify: `src/analyzer/index.ts` (update `analyzeAll`)
|
|
284
|
+
- Modify: `src/commands/background-analyze.ts` (update `cmdBackgroundAnalyze`)
|
|
285
|
+
|
|
286
|
+
**Interfaces:**
|
|
287
|
+
- Consumes: `db.upsertProjectSummary()` from Task 2
|
|
288
|
+
- Produces: After each analysis, both `memories` (append-only) AND `project_summaries` (merged) get updated
|
|
289
|
+
|
|
290
|
+
- [ ] **Step 1: Update `analyzeAll` in `src/analyzer/index.ts`**
|
|
291
|
+
|
|
292
|
+
Find the block around line 225-234 where `db.upsertProjectMemory()` is called. Add `db.upsertProjectSummary()` call after it:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
if (result.project && result.summary) {
|
|
296
|
+
db.upsertProjectMemory({
|
|
297
|
+
project: result.project,
|
|
298
|
+
prompt_id: entry.id,
|
|
299
|
+
summary: result.summary,
|
|
300
|
+
key_insights: result.key_insights ?? [],
|
|
301
|
+
technical_decisions: result.technical_decisions ?? [],
|
|
302
|
+
});
|
|
303
|
+
// Also update the merged project summary
|
|
304
|
+
db.upsertProjectSummary({
|
|
305
|
+
project: result.project,
|
|
306
|
+
summary: result.summary,
|
|
307
|
+
key_insights: result.key_insights ?? [],
|
|
308
|
+
technical_decisions: result.technical_decisions ?? [],
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
- [ ] **Step 2: Update `cmdBackgroundAnalyze` in `src/commands/background-analyze.ts`**
|
|
314
|
+
|
|
315
|
+
Find the block around line 36-43 where `db.upsertProjectMemory()` is called. Add `db.upsertProjectSummary()` after it:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
if (result.project && result.summary) {
|
|
319
|
+
db.upsertProjectMemory({
|
|
320
|
+
project: result.project,
|
|
321
|
+
prompt_id: id,
|
|
322
|
+
summary: result.summary,
|
|
323
|
+
key_insights: result.key_insights ?? [],
|
|
324
|
+
technical_decisions: result.technical_decisions ?? [],
|
|
325
|
+
});
|
|
326
|
+
db.upsertProjectSummary({
|
|
327
|
+
project: result.project,
|
|
328
|
+
summary: result.summary,
|
|
329
|
+
key_insights: result.key_insights ?? [],
|
|
330
|
+
technical_decisions: result.technical_decisions ?? [],
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
- [ ] **Step 3: Build + verify**
|
|
336
|
+
|
|
337
|
+
Run: `npm run build`
|
|
338
|
+
Expected: Build succeeds
|
|
339
|
+
|
|
340
|
+
- [ ] **Step 4: Commit**
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
git add src/analyzer/index.ts src/commands/background-analyze.ts
|
|
344
|
+
git commit -m "feat: write to project_summaries from analysis pipeline"
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
### Task 5: Update MCP tools to read from `project_summaries`
|
|
349
|
+
|
|
350
|
+
**Files:**
|
|
351
|
+
- Modify: `src/mcp/server.ts` (update `get_project_summary` and `get_project_context` tools)
|
|
352
|
+
|
|
353
|
+
**Interfaces:**
|
|
354
|
+
- Consumes: `db.getProjectSummary()` from Task 2
|
|
355
|
+
- Produces: MCP tools return merged knowledge from `project_summaries` instead of raw `memories`
|
|
356
|
+
|
|
357
|
+
- [ ] **Step 1: Update `get_project_summary` tool handler**
|
|
358
|
+
|
|
359
|
+
Replace the current implementation (reads from `memories`) with code that reads from `project_summaries`:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
if (name === "get_project_summary") {
|
|
363
|
+
const { project } = z.object({
|
|
364
|
+
project: z.string(),
|
|
365
|
+
}).parse(args);
|
|
366
|
+
|
|
367
|
+
const summary = db.getProjectSummary(project);
|
|
368
|
+
|
|
369
|
+
if (!summary) {
|
|
370
|
+
return {
|
|
371
|
+
content: [{ type: "text", text: `No accumulated knowledge for project "${project}". Run "ph analyze" to generate insights.` }],
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const parts: string[] = [];
|
|
376
|
+
parts.push(`## ${summary.summary || 'Project Memory'}\n`);
|
|
377
|
+
parts.push(`Based on ${summary.prompt_count} interactions.\n`);
|
|
378
|
+
if (summary.key_insights.length > 0) {
|
|
379
|
+
parts.push('**Key Insights:**');
|
|
380
|
+
for (const i of summary.key_insights) parts.push(`- ${i}`);
|
|
381
|
+
parts.push('');
|
|
382
|
+
}
|
|
383
|
+
if (summary.technical_decisions.length > 0) {
|
|
384
|
+
parts.push('**Technical Decisions:**');
|
|
385
|
+
for (const d of summary.technical_decisions) parts.push(`- ${d}`);
|
|
386
|
+
parts.push('');
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
content: [{ type: "text", text: parts.join('\n') }],
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- [ ] **Step 2: Update `get_project_context` tool handler**
|
|
396
|
+
|
|
397
|
+
Modify to also include merged summary from `project_summaries`. Around line 107-143, before reading memories, check for merged summary:
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
if (name === "get_project_context") {
|
|
401
|
+
const { project, limit = 10 } = z.object({
|
|
402
|
+
project: z.string(),
|
|
403
|
+
limit: z.number().optional(),
|
|
404
|
+
}).parse(args);
|
|
405
|
+
|
|
406
|
+
const parts: string[] = [];
|
|
407
|
+
|
|
408
|
+
// Start with merged project summary if available
|
|
409
|
+
const merged = db.getProjectSummary(project);
|
|
410
|
+
if (merged) {
|
|
411
|
+
parts.push('## Project Knowledge (merged)\n');
|
|
412
|
+
if (merged.summary) parts.push(`${merged.summary}\n`);
|
|
413
|
+
if (merged.key_insights.length > 0) {
|
|
414
|
+
parts.push('Key Insights:');
|
|
415
|
+
for (const i of merged.key_insights) parts.push(` - ${i}`);
|
|
416
|
+
parts.push('');
|
|
417
|
+
}
|
|
418
|
+
if (merged.technical_decisions.length > 0) {
|
|
419
|
+
parts.push('Technical Decisions:');
|
|
420
|
+
for (const d of merged.technical_decisions) parts.push(` - ${d}`);
|
|
421
|
+
parts.push('');
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Also pull recent memories (detailed entries)
|
|
426
|
+
const memories = db.searchMemories(project, 3);
|
|
427
|
+
if (memories.length > 0) {
|
|
428
|
+
if (parts.length > 0) parts.push('---\n');
|
|
429
|
+
parts.push('## Recent Memory Entries\n');
|
|
430
|
+
for (const mem of memories) {
|
|
431
|
+
if (mem.summary) parts.push(`- ${mem.summary}`);
|
|
432
|
+
}
|
|
433
|
+
parts.push('');
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const prompts = db.getProjectMemory(project, limit);
|
|
437
|
+
if (prompts.length > 0) {
|
|
438
|
+
if (parts.length > 0) parts.push('---\n');
|
|
439
|
+
parts.push('## Recent Interactions\n');
|
|
440
|
+
parts.push(formatResultsAsMarkdown(prompts));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return {
|
|
444
|
+
content: [{ type: "text", text: parts.join('\n') || 'No context found for this project.' }],
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
- [ ] **Step 3: Build + verify**
|
|
450
|
+
|
|
451
|
+
Run: `npm run build`
|
|
452
|
+
Expected: Build succeeds
|
|
453
|
+
|
|
454
|
+
- [ ] **Step 4: Commit**
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
git add src/mcp/server.ts
|
|
458
|
+
git commit -m "feat: MCP tools read from project_summaries"
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
## Self-Review Checklist
|
|
463
|
+
|
|
464
|
+
- **Spec coverage:** All Phase 1 items covered: table creation complete, upsert/get methods complete, migration complete, analysis pipeline updates complete, MCP tool updates complete
|
|
465
|
+
- **Placeholder scan:** No TBD, TODO, or incomplete code blocks
|
|
466
|
+
- **Type consistency:** `ProjectSummary` interface consistent across all tasks: `project`, `summary`, `key_insights[]`, `technical_decisions[]`, `prompt_count`, `first_analyzed`, `last_analyzed`, `git_context_snapshot?`
|