engrm 0.1.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/.mcp.json +9 -0
- package/AUTH-DESIGN.md +436 -0
- package/BRIEF.md +197 -0
- package/CLAUDE.md +44 -0
- package/COMPETITIVE.md +174 -0
- package/CONTEXT-OPTIMIZATION.md +305 -0
- package/INFRASTRUCTURE.md +252 -0
- package/LICENSE +105 -0
- package/MARKET.md +230 -0
- package/PLAN.md +278 -0
- package/README.md +121 -0
- package/SENTINEL.md +293 -0
- package/SERVER-API-PLAN.md +553 -0
- package/SPEC.md +843 -0
- package/SWOT.md +148 -0
- package/SYNC-ARCHITECTURE.md +294 -0
- package/VIBE-CODER-STRATEGY.md +250 -0
- package/bun.lock +375 -0
- package/hooks/post-tool-use.ts +144 -0
- package/hooks/session-start.ts +64 -0
- package/hooks/stop.ts +131 -0
- package/mem-page.html +1305 -0
- package/package.json +30 -0
- package/src/capture/dedup.test.ts +103 -0
- package/src/capture/dedup.ts +76 -0
- package/src/capture/extractor.test.ts +245 -0
- package/src/capture/extractor.ts +330 -0
- package/src/capture/quality.test.ts +168 -0
- package/src/capture/quality.ts +104 -0
- package/src/capture/retrospective.test.ts +115 -0
- package/src/capture/retrospective.ts +121 -0
- package/src/capture/scanner.test.ts +131 -0
- package/src/capture/scanner.ts +100 -0
- package/src/capture/scrubber.test.ts +144 -0
- package/src/capture/scrubber.ts +181 -0
- package/src/cli.ts +517 -0
- package/src/config.ts +238 -0
- package/src/context/inject.test.ts +940 -0
- package/src/context/inject.ts +382 -0
- package/src/embeddings/backfill.ts +50 -0
- package/src/embeddings/embedder.test.ts +76 -0
- package/src/embeddings/embedder.ts +139 -0
- package/src/lifecycle/aging.test.ts +103 -0
- package/src/lifecycle/aging.ts +36 -0
- package/src/lifecycle/compaction.test.ts +264 -0
- package/src/lifecycle/compaction.ts +190 -0
- package/src/lifecycle/purge.test.ts +100 -0
- package/src/lifecycle/purge.ts +37 -0
- package/src/lifecycle/scheduler.test.ts +120 -0
- package/src/lifecycle/scheduler.ts +101 -0
- package/src/provisioning/browser-auth.ts +172 -0
- package/src/provisioning/provision.test.ts +198 -0
- package/src/provisioning/provision.ts +94 -0
- package/src/register.test.ts +167 -0
- package/src/register.ts +178 -0
- package/src/server.ts +436 -0
- package/src/storage/migrations.test.ts +244 -0
- package/src/storage/migrations.ts +261 -0
- package/src/storage/outbox.test.ts +229 -0
- package/src/storage/outbox.ts +131 -0
- package/src/storage/projects.test.ts +137 -0
- package/src/storage/projects.ts +184 -0
- package/src/storage/sqlite.test.ts +798 -0
- package/src/storage/sqlite.ts +934 -0
- package/src/storage/vec.test.ts +198 -0
- package/src/sync/auth.test.ts +76 -0
- package/src/sync/auth.ts +68 -0
- package/src/sync/client.ts +183 -0
- package/src/sync/engine.test.ts +94 -0
- package/src/sync/engine.ts +127 -0
- package/src/sync/pull.test.ts +279 -0
- package/src/sync/pull.ts +170 -0
- package/src/sync/push.test.ts +117 -0
- package/src/sync/push.ts +230 -0
- package/src/tools/get.ts +34 -0
- package/src/tools/pin.ts +47 -0
- package/src/tools/save.test.ts +301 -0
- package/src/tools/save.ts +231 -0
- package/src/tools/search.test.ts +69 -0
- package/src/tools/search.ts +181 -0
- package/src/tools/timeline.ts +64 -0
- package/tsconfig.json +22 -0
package/hooks/stop.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Stop hook for Claude Code.
|
|
4
|
+
*
|
|
5
|
+
* Fires when Claude finishes responding. We:
|
|
6
|
+
* 1. Check stop_hook_active to prevent infinite loops
|
|
7
|
+
* 2. Complete the session in the database
|
|
8
|
+
* 3. Generate a retrospective summary from session observations
|
|
9
|
+
* 4. Exit 0 to allow Claude to stop
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { loadConfig, configExists, getDbPath } from "../src/config.js";
|
|
13
|
+
import { MemDatabase } from "../src/storage/sqlite.js";
|
|
14
|
+
import { extractRetrospective } from "../src/capture/retrospective.js";
|
|
15
|
+
|
|
16
|
+
import type { InsertSessionSummary } from "../src/storage/sqlite.js";
|
|
17
|
+
|
|
18
|
+
function printRetrospective(summary: InsertSessionSummary): void {
|
|
19
|
+
const lines: string[] = [];
|
|
20
|
+
lines.push("");
|
|
21
|
+
lines.push("━━━ Engrm Session Summary ━━━");
|
|
22
|
+
lines.push("");
|
|
23
|
+
|
|
24
|
+
if (summary.request) {
|
|
25
|
+
lines.push(`📋 Request: ${summary.request}`);
|
|
26
|
+
lines.push("");
|
|
27
|
+
}
|
|
28
|
+
if (summary.investigated) {
|
|
29
|
+
lines.push("🔍 Investigated:");
|
|
30
|
+
lines.push(summary.investigated);
|
|
31
|
+
lines.push("");
|
|
32
|
+
}
|
|
33
|
+
if (summary.learned) {
|
|
34
|
+
lines.push("💡 Learned:");
|
|
35
|
+
lines.push(summary.learned);
|
|
36
|
+
lines.push("");
|
|
37
|
+
}
|
|
38
|
+
if (summary.completed) {
|
|
39
|
+
lines.push("✅ Completed:");
|
|
40
|
+
lines.push(summary.completed);
|
|
41
|
+
lines.push("");
|
|
42
|
+
}
|
|
43
|
+
if (summary.next_steps) {
|
|
44
|
+
lines.push("➡️ Next Steps:");
|
|
45
|
+
lines.push(summary.next_steps);
|
|
46
|
+
lines.push("");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
lines.push("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
50
|
+
console.log(lines.join("\n"));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface StopEvent {
|
|
54
|
+
session_id: string;
|
|
55
|
+
hook_event_name: string;
|
|
56
|
+
stop_hook_active: boolean;
|
|
57
|
+
last_assistant_message: string;
|
|
58
|
+
cwd: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function main(): Promise<void> {
|
|
62
|
+
// Read stdin
|
|
63
|
+
const chunks: string[] = [];
|
|
64
|
+
for await (const chunk of Bun.stdin.stream()) {
|
|
65
|
+
chunks.push(new TextDecoder().decode(chunk));
|
|
66
|
+
}
|
|
67
|
+
const raw = chunks.join("");
|
|
68
|
+
|
|
69
|
+
if (!raw.trim()) process.exit(0);
|
|
70
|
+
|
|
71
|
+
let event: StopEvent;
|
|
72
|
+
try {
|
|
73
|
+
event = JSON.parse(raw) as StopEvent;
|
|
74
|
+
} catch {
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Prevent infinite loops — if we're already in a stop hook, just exit
|
|
79
|
+
if (event.stop_hook_active) process.exit(0);
|
|
80
|
+
|
|
81
|
+
// Bail if not configured
|
|
82
|
+
if (!configExists()) process.exit(0);
|
|
83
|
+
|
|
84
|
+
let config;
|
|
85
|
+
let db;
|
|
86
|
+
try {
|
|
87
|
+
config = loadConfig();
|
|
88
|
+
db = new MemDatabase(getDbPath());
|
|
89
|
+
} catch {
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Complete the session
|
|
95
|
+
if (event.session_id) {
|
|
96
|
+
db.completeSession(event.session_id);
|
|
97
|
+
|
|
98
|
+
// Generate retrospective — only if we haven't already for this session
|
|
99
|
+
const existing = db.getSessionSummary(event.session_id);
|
|
100
|
+
if (!existing) {
|
|
101
|
+
const observations = db.getObservationsBySession(event.session_id);
|
|
102
|
+
if (observations.length > 0) {
|
|
103
|
+
const session = db.getSessionMetrics(event.session_id);
|
|
104
|
+
const summary = extractRetrospective(
|
|
105
|
+
observations,
|
|
106
|
+
event.session_id,
|
|
107
|
+
session?.project_id ?? null,
|
|
108
|
+
config.user_id
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (summary) {
|
|
112
|
+
const row = db.insertSessionSummary(summary);
|
|
113
|
+
db.addToOutbox("summary", row.id);
|
|
114
|
+
|
|
115
|
+
// Display session retrospective to the user
|
|
116
|
+
printRetrospective(summary);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} finally {
|
|
122
|
+
db.close();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Exit 0 — allow Claude to stop
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
main().catch(() => {
|
|
130
|
+
process.exit(0);
|
|
131
|
+
});
|