@contextstream/mcp-server 0.4.49 → 0.4.51
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/README.md +27 -0
- package/dist/hooks/auto-rules.js +136 -25
- package/dist/hooks/on-bash.js +190 -0
- package/dist/hooks/on-read.js +163 -0
- package/dist/hooks/on-save-intent.js +132 -0
- package/dist/hooks/on-task.js +139 -0
- package/dist/hooks/on-web.js +155 -0
- package/dist/hooks/post-compact.js +172 -0
- package/dist/hooks/post-write.js +0 -0
- package/dist/hooks/pre-compact.js +100 -11
- package/dist/hooks/runner.js +2889 -0
- package/dist/hooks/session-end.js +191 -0
- package/dist/hooks/session-init.js +174 -0
- package/dist/index.js +2458 -252
- package/dist/test-server.js +3 -0
- package/package.json +7 -4
- package/scripts/postinstall.js +56 -0
|
@@ -68,6 +68,9 @@ function parseTranscript(transcriptPath) {
|
|
|
68
68
|
const activeFiles = /* @__PURE__ */ new Set();
|
|
69
69
|
const recentMessages = [];
|
|
70
70
|
const toolCalls = [];
|
|
71
|
+
const messages = [];
|
|
72
|
+
let startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
73
|
+
let firstTimestamp = true;
|
|
71
74
|
try {
|
|
72
75
|
const content = fs.readFileSync(transcriptPath, "utf-8");
|
|
73
76
|
const lines = content.split("\n");
|
|
@@ -76,6 +79,11 @@ function parseTranscript(transcriptPath) {
|
|
|
76
79
|
try {
|
|
77
80
|
const entry = JSON.parse(line);
|
|
78
81
|
const msgType = entry.type || "";
|
|
82
|
+
const timestamp = entry.timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
83
|
+
if (firstTimestamp && entry.timestamp) {
|
|
84
|
+
startedAt = entry.timestamp;
|
|
85
|
+
firstTimestamp = false;
|
|
86
|
+
}
|
|
79
87
|
if (msgType === "tool_use") {
|
|
80
88
|
const toolName = entry.name || "";
|
|
81
89
|
const toolInput = entry.input || {};
|
|
@@ -91,11 +99,40 @@ function parseTranscript(transcriptPath) {
|
|
|
91
99
|
activeFiles.add(`[glob:${pattern}]`);
|
|
92
100
|
}
|
|
93
101
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
messages.push({
|
|
103
|
+
role: "assistant",
|
|
104
|
+
content: `[Tool: ${toolName}]`,
|
|
105
|
+
timestamp,
|
|
106
|
+
tool_calls: { name: toolName, input: toolInput }
|
|
107
|
+
});
|
|
108
|
+
} else if (msgType === "tool_result") {
|
|
109
|
+
const resultContent = typeof entry.content === "string" ? entry.content.slice(0, 2e3) : JSON.stringify(entry.content || {}).slice(0, 2e3);
|
|
110
|
+
messages.push({
|
|
111
|
+
role: "tool",
|
|
112
|
+
content: resultContent,
|
|
113
|
+
timestamp,
|
|
114
|
+
tool_results: { name: entry.name }
|
|
115
|
+
});
|
|
116
|
+
} else if (msgType === "user" || entry.role === "user") {
|
|
117
|
+
const userContent = typeof entry.content === "string" ? entry.content : "";
|
|
118
|
+
if (userContent) {
|
|
119
|
+
messages.push({
|
|
120
|
+
role: "user",
|
|
121
|
+
content: userContent,
|
|
122
|
+
timestamp
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
} else if (msgType === "assistant" || entry.role === "assistant") {
|
|
126
|
+
const assistantContent = typeof entry.content === "string" ? entry.content : "";
|
|
127
|
+
if (assistantContent) {
|
|
128
|
+
messages.push({
|
|
129
|
+
role: "assistant",
|
|
130
|
+
content: assistantContent,
|
|
131
|
+
timestamp
|
|
132
|
+
});
|
|
133
|
+
if (assistantContent.length > 50) {
|
|
134
|
+
recentMessages.push(assistantContent.slice(0, 500));
|
|
135
|
+
}
|
|
99
136
|
}
|
|
100
137
|
}
|
|
101
138
|
} catch {
|
|
@@ -108,11 +145,57 @@ function parseTranscript(transcriptPath) {
|
|
|
108
145
|
activeFiles: Array.from(activeFiles).slice(-20),
|
|
109
146
|
// Last 20 files
|
|
110
147
|
toolCallCount: toolCalls.length,
|
|
111
|
-
messageCount:
|
|
112
|
-
lastTools: toolCalls.slice(-10).map((t) => t.name)
|
|
148
|
+
messageCount: messages.length,
|
|
149
|
+
lastTools: toolCalls.slice(-10).map((t) => t.name),
|
|
113
150
|
// Last 10 tool names
|
|
151
|
+
messages,
|
|
152
|
+
startedAt
|
|
114
153
|
};
|
|
115
154
|
}
|
|
155
|
+
async function saveFullTranscript(sessionId, transcriptData, trigger) {
|
|
156
|
+
if (!API_KEY) {
|
|
157
|
+
return { success: false, message: "No API key configured" };
|
|
158
|
+
}
|
|
159
|
+
if (transcriptData.messages.length === 0) {
|
|
160
|
+
return { success: false, message: "No messages to save" };
|
|
161
|
+
}
|
|
162
|
+
const payload = {
|
|
163
|
+
session_id: sessionId,
|
|
164
|
+
messages: transcriptData.messages,
|
|
165
|
+
started_at: transcriptData.startedAt,
|
|
166
|
+
source_type: "pre_compact",
|
|
167
|
+
title: `Pre-compaction save (${trigger})`,
|
|
168
|
+
metadata: {
|
|
169
|
+
trigger,
|
|
170
|
+
active_files: transcriptData.activeFiles,
|
|
171
|
+
tool_call_count: transcriptData.toolCallCount
|
|
172
|
+
},
|
|
173
|
+
tags: ["pre_compaction", trigger]
|
|
174
|
+
};
|
|
175
|
+
if (WORKSPACE_ID) {
|
|
176
|
+
payload.workspace_id = WORKSPACE_ID;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const controller = new AbortController();
|
|
180
|
+
const timeoutId = setTimeout(() => controller.abort(), 1e4);
|
|
181
|
+
const response = await fetch(`${API_URL}/api/v1/transcripts`, {
|
|
182
|
+
method: "POST",
|
|
183
|
+
headers: {
|
|
184
|
+
"Content-Type": "application/json",
|
|
185
|
+
"X-API-Key": API_KEY
|
|
186
|
+
},
|
|
187
|
+
body: JSON.stringify(payload),
|
|
188
|
+
signal: controller.signal
|
|
189
|
+
});
|
|
190
|
+
clearTimeout(timeoutId);
|
|
191
|
+
if (response.ok) {
|
|
192
|
+
return { success: true, message: `Transcript saved (${transcriptData.messages.length} messages)` };
|
|
193
|
+
}
|
|
194
|
+
return { success: false, message: `API error: ${response.status}` };
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return { success: false, message: String(error) };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
116
199
|
async function saveSnapshot(sessionId, transcriptData, trigger) {
|
|
117
200
|
if (!API_KEY) {
|
|
118
201
|
return { success: false, message: "No API key configured" };
|
|
@@ -193,13 +276,19 @@ async function runPreCompactHook() {
|
|
|
193
276
|
}
|
|
194
277
|
let autoSaveStatus = "";
|
|
195
278
|
if (AUTO_SAVE && API_KEY) {
|
|
196
|
-
const
|
|
197
|
-
if (success) {
|
|
279
|
+
const transcriptResult = await saveFullTranscript(sessionId, transcriptData, trigger);
|
|
280
|
+
if (transcriptResult.success) {
|
|
198
281
|
autoSaveStatus = `
|
|
199
|
-
[ContextStream:
|
|
282
|
+
[ContextStream: ${transcriptResult.message}]`;
|
|
200
283
|
} else {
|
|
201
|
-
|
|
284
|
+
const { success, message } = await saveSnapshot(sessionId, transcriptData, trigger);
|
|
285
|
+
if (success) {
|
|
286
|
+
autoSaveStatus = `
|
|
287
|
+
[ContextStream: Auto-saved snapshot with ${transcriptData.activeFiles.length} active files (transcript save failed: ${transcriptResult.message})]`;
|
|
288
|
+
} else {
|
|
289
|
+
autoSaveStatus = `
|
|
202
290
|
[ContextStream: Auto-save failed - ${message}]`;
|
|
291
|
+
}
|
|
203
292
|
}
|
|
204
293
|
}
|
|
205
294
|
const filesList = transcriptData.activeFiles.slice(0, 5).join(", ") || "none detected";
|