@aexol/spectral 0.9.16 → 0.9.19
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/dist/memory/compaction.d.ts +1 -1
- package/dist/memory/compaction.js +3 -3
- package/dist/memory/deterministic-pruner.d.ts +65 -0
- package/dist/memory/deterministic-pruner.d.ts.map +1 -0
- package/dist/memory/deterministic-pruner.js +333 -0
- package/dist/memory/hooks/compaction-hook.d.ts.map +1 -1
- package/dist/memory/hooks/compaction-hook.js +158 -132
- package/dist/memory/prompts.d.ts.map +1 -1
- package/dist/memory/prompts.js +9 -0
- package/dist/memory/unified-compaction.d.ts +59 -0
- package/dist/memory/unified-compaction.d.ts.map +1 -0
- package/dist/memory/unified-compaction.js +332 -0
- package/dist/relay/dispatcher.d.ts +1 -1
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +13 -1
- package/dist/server/handlers/projects.d.ts +8 -0
- package/dist/server/handlers/projects.d.ts.map +1 -1
- package/dist/server/handlers/projects.js +6 -0
- package/dist/server/storage.d.ts +11 -0
- package/dist/server/storage.d.ts.map +1 -1
- package/dist/server/storage.js +20 -0
- package/package.json +1 -1
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Compaction — single LLM call replacing both:
|
|
3
|
+
* 1. Core spectral generateSummary() (narrative conversation summary)
|
|
4
|
+
* 2. Sync catch-up observer (observation extraction from gap entries)
|
|
5
|
+
*
|
|
6
|
+
* Uses a text-based delimited output format (compatible with any model
|
|
7
|
+
* without requiring native structured-output support):
|
|
8
|
+
*
|
|
9
|
+
* ===NARRATIVE===
|
|
10
|
+
* ## Goal
|
|
11
|
+
* ...
|
|
12
|
+
*
|
|
13
|
+
* ===OBSERVATIONS===
|
|
14
|
+
* [YYYY-MM-DD HH:MM] [relevance] Content line
|
|
15
|
+
* ...
|
|
16
|
+
*/
|
|
17
|
+
import { completeSimple } from "../sdk/ai/index.js";
|
|
18
|
+
import { extractFileOpsFromMessage, computeFileLists, createFileOps, formatFileOperations, } from "../sdk/coding-agent/core/compaction/utils.js";
|
|
19
|
+
import { hashId } from "./ids.js";
|
|
20
|
+
import { nowTimestamp, truncateRecordContent } from "./serialize.js";
|
|
21
|
+
import { debugLog } from "./debug-log.js";
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Section Delimiters
|
|
24
|
+
// ============================================================================
|
|
25
|
+
const NARRATIVE_SECTION = "===NARRATIVE===";
|
|
26
|
+
const OBSERVATIONS_SECTION = "===OBSERVATIONS===";
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Prompt Templates
|
|
29
|
+
// ============================================================================
|
|
30
|
+
const UNIFIED_SYSTEM_PROMPT = `You are a context compression agent. Your task has TWO complementary outputs that MUST be produced together in a single response.
|
|
31
|
+
|
|
32
|
+
TASK A — NARRATIVE SUMMARY: Create a structured checkpoint of the conversation progress. This is what another LLM reads to understand where the work stands.
|
|
33
|
+
|
|
34
|
+
TASK B — FACTUAL MEMORY: Extract timestamped observations (single-line facts with relevance tags). These records are the assistant's ONLY memory of this conversation after the raw messages fall out of context.
|
|
35
|
+
|
|
36
|
+
Do NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured result using the EXACT format specified.`;
|
|
37
|
+
function buildUnifiedPrompt(conversationText, previousSummary, customInstructions, currentTime) {
|
|
38
|
+
let prompt = `<conversation>\n${conversationText}\n</conversation>\n\n`;
|
|
39
|
+
if (previousSummary) {
|
|
40
|
+
prompt += `<previous-summary>\n${previousSummary}\n</previous-summary>\n\n`;
|
|
41
|
+
}
|
|
42
|
+
prompt += `Current local time: ${currentTime}\n\n`;
|
|
43
|
+
prompt += `Output your response in TWO sections delimited by the exact markers shown below.
|
|
44
|
+
|
|
45
|
+
SECTION A — ${NARRATIVE_SECTION}
|
|
46
|
+
|
|
47
|
+
Produce a structured context checkpoint summary using this EXACT format:
|
|
48
|
+
|
|
49
|
+
## Goal
|
|
50
|
+
[What is the user trying to accomplish? Can be multiple items. If updating a previous summary, preserve existing goals and add new ones.]
|
|
51
|
+
|
|
52
|
+
## Constraints & Preferences
|
|
53
|
+
- [Any constraints, preferences, or requirements mentioned by user]
|
|
54
|
+
- [Or "(none)" if none were mentioned]
|
|
55
|
+
[When updating: preserve existing constraints, add new ones.]
|
|
56
|
+
|
|
57
|
+
## Progress
|
|
58
|
+
### Done
|
|
59
|
+
- [x] [Completed tasks/changes. Preserve previously completed items, add newly completed ones.]
|
|
60
|
+
|
|
61
|
+
### In Progress
|
|
62
|
+
- [ ] [Current work. Update based on progress.]
|
|
63
|
+
|
|
64
|
+
### Blocked
|
|
65
|
+
- [Issues preventing progress, if any. Remove blockers that have been resolved.]
|
|
66
|
+
|
|
67
|
+
## Key Decisions
|
|
68
|
+
- **[Decision]**: [Brief rationale]
|
|
69
|
+
[Preserve all previous decisions, add new ones.]
|
|
70
|
+
|
|
71
|
+
## Next Steps
|
|
72
|
+
1. [Ordered list of what should happen next. Update based on current state.]
|
|
73
|
+
|
|
74
|
+
## Critical Context
|
|
75
|
+
- [Any data, examples, or references needed to continue]
|
|
76
|
+
- [Or "(none)" if not applicable]
|
|
77
|
+
|
|
78
|
+
Keep each section concise. Preserve exact file paths, function names, and error messages.
|
|
79
|
+
${customInstructions ? `\nAdditional focus for the narrative: ${customInstructions}` : ""}
|
|
80
|
+
|
|
81
|
+
SECTION B — ${OBSERVATIONS_SECTION}
|
|
82
|
+
|
|
83
|
+
Extract NEW timestamped facts from the conversation. Each observation must be on its own line in this exact format:
|
|
84
|
+
|
|
85
|
+
[YYYY-MM-DD HH:MM] [relevance] Single-line plain prose fact. No markdown, no bullets.
|
|
86
|
+
|
|
87
|
+
Do NOT restate facts already captured in the <previous-summary>. Skip routine, low-information events (tool-call acks, status updates).
|
|
88
|
+
|
|
89
|
+
OBSERVATION CONTENT RULES:
|
|
90
|
+
- Single line of plain prose. No markdown, no bullets, no code fences, no XML/HTML tags, no emojis.
|
|
91
|
+
- Preserve user assertions exactly. When the user STATES something about themselves, their project, or their environment, capture it as an assertion. When the user ASKS something, capture it as a question.
|
|
92
|
+
- Use precise action verbs (completed, resolved, implemented, chose, configured etc.).
|
|
93
|
+
- Mark concrete completions explicitly: "completed: implemented X at path/to/file.ts; user confirmed tests pass."
|
|
94
|
+
- Split compound statements into separate observations (one fact per line).
|
|
95
|
+
- Group repeated similar tool calls into a single observation.
|
|
96
|
+
- Preserve exact file paths, function names, line numbers, error messages (verbatim), package names, identifiers.
|
|
97
|
+
- Use the timestamp from the closest conversation message. Fall back to the current local time if no message timestamp applies.
|
|
98
|
+
|
|
99
|
+
RELEVANCE LEVELS (pick one per observation):
|
|
100
|
+
- critical: user identity, role, persistent preferences, explicit corrections, concrete completions that future runs MUST NOT redo.
|
|
101
|
+
- high: non-trivial technical decisions, architectural direction, unresolved blockers, key constraints.
|
|
102
|
+
- medium: task-level context that helps within the current work. Default when unsure between medium and high.
|
|
103
|
+
- low: routine tool-call acks, repetitive status updates, trivially re-derivable content. Skip these unless they carry unique detail.
|
|
104
|
+
|
|
105
|
+
Do NOT default everything to "high" or "critical". Most observations should be "medium". Use "low" only for truly routine items.
|
|
106
|
+
|
|
107
|
+
Focus areas for observations:
|
|
108
|
+
- User identity, preferences, constraints, corrections.
|
|
109
|
+
- Project goals, architectural decisions, rationale.
|
|
110
|
+
- File paths and line numbers of changes.
|
|
111
|
+
- Error messages (verbatim).
|
|
112
|
+
- Completed work that should not be redone.
|
|
113
|
+
- Named identifiers (package names, function/variable names, ticket IDs, commit SHAs).`;
|
|
114
|
+
return prompt;
|
|
115
|
+
}
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Conversation Serialization
|
|
118
|
+
// ============================================================================
|
|
119
|
+
const TOOL_RESULT_MAX_CHARS = 2000;
|
|
120
|
+
const VISION_DESCRIPTION_PREFIX = "[Image description from ";
|
|
121
|
+
function stripVisionBlocks(text) {
|
|
122
|
+
if (!text.includes(VISION_DESCRIPTION_PREFIX))
|
|
123
|
+
return text;
|
|
124
|
+
const lines = text.split("\n");
|
|
125
|
+
const kept = [];
|
|
126
|
+
let skipping = false;
|
|
127
|
+
for (const line of lines) {
|
|
128
|
+
if (!skipping && line.startsWith(VISION_DESCRIPTION_PREFIX)) {
|
|
129
|
+
skipping = true;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (skipping) {
|
|
133
|
+
if (line === "]") {
|
|
134
|
+
skipping = false;
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
kept.push(line);
|
|
139
|
+
}
|
|
140
|
+
return kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
141
|
+
}
|
|
142
|
+
function serializeMessagesForUnified(messages) {
|
|
143
|
+
const parts = [];
|
|
144
|
+
for (const msg of messages) {
|
|
145
|
+
if (msg.role === "user") {
|
|
146
|
+
const content = typeof msg.content === "string"
|
|
147
|
+
? msg.content
|
|
148
|
+
: Array.isArray(msg.content)
|
|
149
|
+
? msg.content.filter((c) => c.type === "text").map(c => c.text).join("")
|
|
150
|
+
: "";
|
|
151
|
+
const cleaned = stripVisionBlocks(content);
|
|
152
|
+
if (cleaned)
|
|
153
|
+
parts.push(`[User]: ${cleaned}`);
|
|
154
|
+
}
|
|
155
|
+
else if (msg.role === "assistant" && "content" in msg && Array.isArray(msg.content)) {
|
|
156
|
+
const textParts = [];
|
|
157
|
+
const toolParts = [];
|
|
158
|
+
for (const block of msg.content) {
|
|
159
|
+
if (block.type === "text" && "text" in block) {
|
|
160
|
+
textParts.push(block.text);
|
|
161
|
+
}
|
|
162
|
+
else if (block.type === "toolCall" && "name" in block) {
|
|
163
|
+
const args = block.arguments;
|
|
164
|
+
const argsStr = Object.keys(args).sort().map(k => `${k}=${JSON.stringify(args[k])}`).join(", ");
|
|
165
|
+
toolParts.push(`${block.name}(${argsStr})`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const combined = [...textParts, ...(toolParts.length ? [`[Tools: ${toolParts.join("; ")}]`] : [])];
|
|
169
|
+
if (combined.length)
|
|
170
|
+
parts.push(`[Assistant]: ${combined.join("\n")}`);
|
|
171
|
+
}
|
|
172
|
+
else if (msg.role === "toolResult") {
|
|
173
|
+
const text = Array.isArray(msg.content)
|
|
174
|
+
? msg.content.filter((c) => c.type === "text").map(c => c.text).join("")
|
|
175
|
+
: typeof msg.content === "string" ? msg.content : "";
|
|
176
|
+
if (text) {
|
|
177
|
+
const truncated = text.length > TOOL_RESULT_MAX_CHARS
|
|
178
|
+
? `${text.slice(0, TOOL_RESULT_MAX_CHARS)}\n[...truncated]`
|
|
179
|
+
: text;
|
|
180
|
+
parts.push(`[Tool result]: ${truncated}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (msg.role === "compactionSummary" && "summary" in msg) {
|
|
184
|
+
parts.push(`[Previous compaction summary]: ${msg.summary}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return parts.join("\n\n");
|
|
188
|
+
}
|
|
189
|
+
// ============================================================================
|
|
190
|
+
// Output Parsing
|
|
191
|
+
// ============================================================================
|
|
192
|
+
const OBSERVATION_LINE_RE = /^\[(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})\]\s*\[(low|medium|high|critical)\]\s*(.+)$/i;
|
|
193
|
+
function parseObservations(text) {
|
|
194
|
+
const results = [];
|
|
195
|
+
const lines = text.split("\n");
|
|
196
|
+
for (const line of lines) {
|
|
197
|
+
const trimmed = line.trim();
|
|
198
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed === OBSERVATIONS_SECTION)
|
|
199
|
+
continue;
|
|
200
|
+
const match = trimmed.match(OBSERVATION_LINE_RE);
|
|
201
|
+
if (match) {
|
|
202
|
+
results.push({
|
|
203
|
+
timestamp: match[1],
|
|
204
|
+
relevance: match[2].toLowerCase(),
|
|
205
|
+
content: match[3].trim(),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return results;
|
|
210
|
+
}
|
|
211
|
+
function normalizeObservation(raw) {
|
|
212
|
+
const content = truncateRecordContent(raw.content);
|
|
213
|
+
if (!content)
|
|
214
|
+
return undefined;
|
|
215
|
+
const validRelevance = ["low", "medium", "high", "critical"];
|
|
216
|
+
const relevance = validRelevance.includes(raw.relevance)
|
|
217
|
+
? raw.relevance
|
|
218
|
+
: "medium";
|
|
219
|
+
return {
|
|
220
|
+
id: hashId(content),
|
|
221
|
+
content,
|
|
222
|
+
timestamp: raw.timestamp,
|
|
223
|
+
relevance,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Generate a unified compaction result: narrative summary + observations
|
|
228
|
+
* in a single LLM call. Uses delimited text output for broad model compatibility.
|
|
229
|
+
*/
|
|
230
|
+
export async function generateUnifiedCompaction(input) {
|
|
231
|
+
const { messagesToSummarize, gapChunk, model, apiKey, headers, signal, previousSummary, customInstructions, thinkingLevel, reserveTokens, } = input;
|
|
232
|
+
const maxTokens = Math.min(Math.floor(0.8 * reserveTokens), model.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY);
|
|
233
|
+
// Build conversation text
|
|
234
|
+
const parts = [];
|
|
235
|
+
const coreText = serializeMessagesForUnified(messagesToSummarize);
|
|
236
|
+
if (coreText)
|
|
237
|
+
parts.push(coreText);
|
|
238
|
+
if (gapChunk?.trim()) {
|
|
239
|
+
parts.push(`\n--- Gap entries (unobserved raw conversation) ---\n${gapChunk}`);
|
|
240
|
+
}
|
|
241
|
+
const conversationText = parts.join("\n\n");
|
|
242
|
+
const currentTime = nowTimestamp();
|
|
243
|
+
const userPrompt = buildUnifiedPrompt(conversationText, previousSummary, customInstructions, currentTime);
|
|
244
|
+
const promptMessages = [
|
|
245
|
+
{
|
|
246
|
+
role: "user",
|
|
247
|
+
content: [{ type: "text", text: userPrompt }],
|
|
248
|
+
timestamp: Date.now(),
|
|
249
|
+
},
|
|
250
|
+
];
|
|
251
|
+
const options = { maxTokens, signal, apiKey, headers };
|
|
252
|
+
if (model.reasoning && thinkingLevel && thinkingLevel !== "off") {
|
|
253
|
+
options.reasoning = thinkingLevel;
|
|
254
|
+
}
|
|
255
|
+
debugLog("unified_compaction.start", {
|
|
256
|
+
messageCount: messagesToSummarize.length,
|
|
257
|
+
hasGap: !!gapChunk?.trim(),
|
|
258
|
+
conversationLength: conversationText.length,
|
|
259
|
+
});
|
|
260
|
+
const response = await completeSimple(model, { systemPrompt: UNIFIED_SYSTEM_PROMPT, messages: promptMessages }, options);
|
|
261
|
+
if (response.stopReason === "error") {
|
|
262
|
+
throw new Error(`Unified compaction failed: ${response.errorMessage || "Unknown error"}`);
|
|
263
|
+
}
|
|
264
|
+
if (response.stopReason === "aborted") {
|
|
265
|
+
throw new Error("Unified compaction aborted");
|
|
266
|
+
}
|
|
267
|
+
const fullText = response.content
|
|
268
|
+
.filter((c) => c.type === "text")
|
|
269
|
+
.map((c) => c.text)
|
|
270
|
+
.join("\n");
|
|
271
|
+
// Parse the two sections
|
|
272
|
+
const narrativeIdx = fullText.indexOf(NARRATIVE_SECTION);
|
|
273
|
+
const obsIdx = fullText.indexOf(OBSERVATIONS_SECTION);
|
|
274
|
+
let narrativeSummary;
|
|
275
|
+
let rawObservationsText;
|
|
276
|
+
if (narrativeIdx >= 0 && obsIdx >= 0) {
|
|
277
|
+
// Both sections present
|
|
278
|
+
if (narrativeIdx < obsIdx) {
|
|
279
|
+
narrativeSummary = fullText.slice(narrativeIdx + NARRATIVE_SECTION.length, obsIdx).trim();
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
narrativeSummary = fullText.slice(narrativeIdx + NARRATIVE_SECTION.length).trim();
|
|
283
|
+
}
|
|
284
|
+
rawObservationsText = fullText.slice(obsIdx + OBSERVATIONS_SECTION.length).trim();
|
|
285
|
+
}
|
|
286
|
+
else if (narrativeIdx >= 0) {
|
|
287
|
+
// Only narrative
|
|
288
|
+
narrativeSummary = fullText.slice(narrativeIdx + NARRATIVE_SECTION.length).trim();
|
|
289
|
+
rawObservationsText = "";
|
|
290
|
+
}
|
|
291
|
+
else if (obsIdx >= 0) {
|
|
292
|
+
// Only observations (unusual but handle gracefully)
|
|
293
|
+
narrativeSummary = fullText.slice(0, obsIdx).trim();
|
|
294
|
+
rawObservationsText = fullText.slice(obsIdx + OBSERVATIONS_SECTION.length).trim();
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
// No delimiters found — treat entire output as narrative
|
|
298
|
+
debugLog("unified_compaction.no_delimiters", { textLength: fullText.length });
|
|
299
|
+
narrativeSummary = fullText;
|
|
300
|
+
rawObservationsText = "";
|
|
301
|
+
}
|
|
302
|
+
// Parse observations
|
|
303
|
+
const rawObservations = parseObservations(rawObservationsText);
|
|
304
|
+
const observations = [];
|
|
305
|
+
const seen = new Set();
|
|
306
|
+
for (const raw of rawObservations) {
|
|
307
|
+
const normalized = normalizeObservation(raw);
|
|
308
|
+
if (normalized && !seen.has(normalized.id)) {
|
|
309
|
+
seen.add(normalized.id);
|
|
310
|
+
observations.push(normalized);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Compute file operations
|
|
314
|
+
const fileOps = createFileOps();
|
|
315
|
+
for (const msg of messagesToSummarize) {
|
|
316
|
+
extractFileOpsFromMessage(msg, fileOps);
|
|
317
|
+
}
|
|
318
|
+
const { readFiles, modifiedFiles } = computeFileLists(fileOps);
|
|
319
|
+
// Append file operations to narrative
|
|
320
|
+
const fullNarrativeSummary = narrativeSummary + formatFileOperations(readFiles, modifiedFiles);
|
|
321
|
+
debugLog("unified_compaction.result", {
|
|
322
|
+
narrativeLength: fullNarrativeSummary.length,
|
|
323
|
+
observationCount: observations.length,
|
|
324
|
+
rawObservationLines: rawObservations.length,
|
|
325
|
+
});
|
|
326
|
+
return {
|
|
327
|
+
narrativeSummary: fullNarrativeSummary,
|
|
328
|
+
observations,
|
|
329
|
+
readFiles,
|
|
330
|
+
modifiedFiles,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
@@ -48,7 +48,7 @@ import type { RelayClient } from "./client.js";
|
|
|
48
48
|
* `id` is populated when the route had an `:id` placeholder.
|
|
49
49
|
*/
|
|
50
50
|
interface RouteMatch {
|
|
51
|
-
route: "list_projects" | "create_project" | "update_project" | "delete_project" | "bind_studio" | "list_project_sessions" | "create_session" | "get_session" | "update_session" | "delete_session" | "get_session_memory" | "get_session_memory_details" | "compact_session" | "remember_and_delete_session" | "fork_session" | "list_path_autocomplete" | "pick_directory" | "search_project_files" | "enqueue_prompt" | "get_prompt_queue" | "remove_prompt" | "clear_prompt_queue" | "list_mcp_status" | "get_settings" | "put_settings";
|
|
51
|
+
route: "list_projects" | "create_project" | "update_project" | "delete_project" | "bind_studio" | "get_project_observations" | "list_project_sessions" | "create_session" | "get_session" | "update_session" | "delete_session" | "get_session_memory" | "get_session_memory_details" | "compact_session" | "remember_and_delete_session" | "fork_session" | "list_path_autocomplete" | "pick_directory" | "search_project_files" | "enqueue_prompt" | "get_prompt_queue" | "remove_prompt" | "clear_prompt_queue" | "list_mcp_status" | "get_settings" | "put_settings";
|
|
52
52
|
id?: string;
|
|
53
53
|
/** Parsed query params, if the path carried a `?...` suffix. */
|
|
54
54
|
query?: URLSearchParams;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"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"}
|
package/dist/relay/dispatcher.js
CHANGED
|
@@ -44,7 +44,7 @@ import { handleListMcpStatus } from "../server/handlers/mcp-status.js";
|
|
|
44
44
|
import { handlePathAutocomplete } from "../server/handlers/paths-autocomplete.js";
|
|
45
45
|
import { handlePickDirectory } from "../server/handlers/paths-pick-directory.js";
|
|
46
46
|
import { handleSearchProjectFiles } from "../server/handlers/files-search.js";
|
|
47
|
-
import { handleBindStudioProject, handleCreateProject, handleDeleteProject, handleListProjects, handleListSessionsByProject, handleUpdateProject, } from "../server/handlers/projects.js";
|
|
47
|
+
import { handleBindStudioProject, handleCreateProject, handleDeleteProject, handleGetProjectObservations, handleListProjects, handleListSessionsByProject, handleUpdateProject, } from "../server/handlers/projects.js";
|
|
48
48
|
import { handleCompactSession, handleCreateSession, handleDeleteSession, handleForkSession, handleRememberAndDeleteSession, handleGetSessionDetail, handleGetSessionMemoryDetails, handleGetSessionMemoryStatus, handleUpdateSession, } from "../server/handlers/sessions.js";
|
|
49
49
|
import { handleClearPromptQueue, handleEnqueuePrompt, handleGetPromptQueue, handleRemovePrompt, } from "../server/handlers/queue.js";
|
|
50
50
|
import { handleGetSettings, handlePutSettings, } from "../server/handlers/settings.js";
|
|
@@ -118,6 +118,14 @@ export function matchRoute(method, path) {
|
|
|
118
118
|
return { route: "bind_studio", id };
|
|
119
119
|
return null;
|
|
120
120
|
}
|
|
121
|
+
// /api/projects/:id/observations
|
|
122
|
+
const projectObsMatch = /^\/api\/projects\/([^/]+)\/observations$/.exec(cleanPath);
|
|
123
|
+
if (projectObsMatch) {
|
|
124
|
+
const id = decodeURIComponent(projectObsMatch[1]);
|
|
125
|
+
if (method === "GET")
|
|
126
|
+
return { route: "get_project_observations", id };
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
121
129
|
// /api/projects/:id and /api/projects/:id/sessions
|
|
122
130
|
const projectMatch = /^\/api\/projects\/([^/]+)(\/sessions)?$/.exec(cleanPath);
|
|
123
131
|
if (projectMatch) {
|
|
@@ -330,6 +338,10 @@ async function dispatchRoute(match, body, deps) {
|
|
|
330
338
|
});
|
|
331
339
|
return result;
|
|
332
340
|
}
|
|
341
|
+
case "get_project_observations": {
|
|
342
|
+
const limitVal = Number(match.query?.get("limit") ?? 30);
|
|
343
|
+
return handleGetProjectObservations(store, id, Math.max(1, Math.min(100, limitVal || 30)));
|
|
344
|
+
}
|
|
333
345
|
case "list_project_sessions": {
|
|
334
346
|
const activeIds = manager.getActiveTurnSessionIds();
|
|
335
347
|
const sessions = handleListSessionsByProject(store, id);
|
|
@@ -21,6 +21,14 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { SessionStore } from "../storage.js";
|
|
23
23
|
import type { WireProject, WireSessionSummary } from "../wire.js";
|
|
24
|
+
export interface WireProjectObservation {
|
|
25
|
+
id: string;
|
|
26
|
+
content: string;
|
|
27
|
+
relevance: string;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
sessionId: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function handleGetProjectObservations(store: SessionStore, id: string, limit?: number): WireProjectObservation[];
|
|
24
32
|
export interface CreateProjectInputRaw {
|
|
25
33
|
name?: unknown;
|
|
26
34
|
path?: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIlE,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAErE;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAYb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAI7E;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAwBb;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,mBAAmB,CAMrB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAoC3B;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,kBAAkB,EAAE,CAItB"}
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIlE,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,KAAK,SAAK,GACT,sBAAsB,EAAE,CAI1B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAErE;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAYb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAI7E;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAwBb;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,mBAAmB,CAMrB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAoC3B;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,kBAAkB,EAAE,CAItB"}
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
import { validateProjectPath } from "../paths.js";
|
|
23
23
|
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
24
24
|
import { writeStudioBindingAt } from "../../studio-binding.js";
|
|
25
|
+
export function handleGetProjectObservations(store, id, limit = 30) {
|
|
26
|
+
const project = store.getProject(id);
|
|
27
|
+
if (!project)
|
|
28
|
+
throw new NotFoundError("Project not found");
|
|
29
|
+
return store.getRecentProjectObservations(id, limit);
|
|
30
|
+
}
|
|
25
31
|
export function handleListProjects(store) {
|
|
26
32
|
return store.listProjects();
|
|
27
33
|
}
|
package/dist/server/storage.d.ts
CHANGED
|
@@ -261,6 +261,17 @@ export declare class SessionStore {
|
|
|
261
261
|
createdAt: number;
|
|
262
262
|
sessionId: string;
|
|
263
263
|
} | null;
|
|
264
|
+
/**
|
|
265
|
+
* Retrieve the most recent N project observations for a given project.
|
|
266
|
+
* Returns observations sorted by created_at DESC, newest first.
|
|
267
|
+
*/
|
|
268
|
+
getRecentProjectObservations(projectId: string, limit?: number): Array<{
|
|
269
|
+
id: string;
|
|
270
|
+
content: string;
|
|
271
|
+
relevance: string;
|
|
272
|
+
createdAt: number;
|
|
273
|
+
sessionId: string;
|
|
274
|
+
}>;
|
|
264
275
|
/**
|
|
265
276
|
* Look up a project by its absolute filesystem path.
|
|
266
277
|
* Returns null when no project has been registered for the given path.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/server/storage.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/server/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAUH,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC;AAExC,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,sBAAsB,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA2MD,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAgBD,qBAAa,YAAY;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,gBAAgB,CAA2C;IACnE,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,iBAAiB,CAA4D;IACrF,OAAO,CAAC,iBAAiB,CAAoD;IAC7E,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,yBAAyB,CAAiD;IAClF,OAAO,CAAC,2BAA2B,CAA4C;IAG/E,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,iBAAiB,CAA4D;IACrF,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,iBAAiB,CAEvB;IACF,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,2BAA2B,CAA4B;IAC/D,OAAO,CAAC,2BAA2B,CAAoC;IACvE,OAAO,CAAC,gBAAgB,CAAoC;IAC5D,OAAO,CAAC,iBAAiB,CAA4C;IACrE,OAAO,CAAC,oBAAoB,CAAiD;IAC7E,OAAO,CAAC,4BAA4B,CAAsD;IAC1F,OAAO,CAAC,+BAA+B,CAA4D;IACnG,OAAO,CAAC,+BAA+B,CAA4B;IAEnE,OAAO,CAAC,mBAAmB,CAAyD;IACpF,OAAO,CAAC,mBAAmB,CAA2C;IACtE,OAAO,CAAC,6BAA6B,CAAiE;IACtG,OAAO,CAAC,6BAA6B,CAA2C;IAEhF,OAAO,CAAC,wBAAwB,CAA2C;IAC3E,OAAO,CAAC,wBAAwB,CAAuE;IAEvG,OAAO,CAAC,oBAAoB,CAAoE;IAChG,OAAO,CAAC,oBAAoB,CAA2D;IACvF,OAAO,CAAC,qBAAqB,CAA2D;IACxF,OAAO,CAAC,mBAAmB,CAA4C;IAGvE,OAAO,CAAC,iBAAiB,CAA4D;IACrF,OAAO,CAAC,kBAAkB,CAAsC;IAChE,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,qBAAqB,CAA4B;IACzD,OAAO,CAAC,kBAAkB,CAA4C;IAGtE,OAAO,CAAC,2BAA2B,CAEjC;IACF,OAAO,CAAC,0BAA0B,CAGhC;IACF,OAAO,CAAC,kCAAkC,CAAoC;IAC9E,OAAO,CAAC,mCAAmC,CAA4B;IACvE,OAAO,CAAC,+BAA+B,CAA4B;gBAEvD,IAAI,EAAE,MAAM;IA8RxB,8DAA8D;IAC9D,UAAU,IAAI,MAAM,EAAE;IAWtB,YAAY,IAAI,WAAW,EAAE;IAc7B,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,WAAW;IAgBrD,iCAAiC;IACjC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAgB1C;;;;OAIG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,WAAW,GAAG,IAAI;IAYxE;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE;IAMrE,4DAA4D;IAC5D,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAe9D,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,kBAAkB;IAyB5D,iCAAiC;IACjC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAoBhD,oEAAoE;IACpE,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAK9C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE;IAc/C;;;OAGG;IACH,kEAAkE;IAClE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAY/B,mDAAmD;IACnD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAYhD,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,GAAG,aAAa;IAwBxE;;;;;;;OAOG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IASpE;;;;OAIG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAiBnE,+DAA+D;IAC/D,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IASlC,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI;IAqBzE,2BAA2B,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,IAAI,CAAC,qBAAqB,EAAE,WAAW,GAAG,WAAW,CAAC,GAC/D,IAAI;IAWP,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQpD;;;;;;;OAOG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKjD;;;;;;OAMG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIhE;;;;OAIG;IACH,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAK3D;;;;OAIG;IACH,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQzE;;;;;OAKG;IACH,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,kBAAkB;IAoDrB;;;OAGG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKtD;;;OAGG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ/C;;;OAGG;IACH,yBAAyB,CACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EACvE,SAAS,EAAE,MAAM,GAChB,IAAI;IAUP;;OAEG;IACH,yBAAyB,CACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,SAAK,GACT,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAWtF;;OAEG;IACH,yBAAyB,CACvB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAYlG;;;OAGG;IACH,4BAA4B,CAC1B,SAAS,EAAE,MAAM,EACjB,KAAK,SAAK,GACT,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAmBlG;;;OAGG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAS3C,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI;IAgBrD,sBAAsB,CAAC,KAAK,EAAE;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,OAAO,CAAC;KACxB,GAAG,iBAAiB,EAAE;IA2CvB,+BAA+B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIlD,iCAAiC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQvD;;;OAGG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ;IAW3D;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAYjD;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE;IAI7C;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAUrD;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIzC,KAAK,IAAI,IAAI;CAKd;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAkB/D"}
|
package/dist/server/storage.js
CHANGED
|
@@ -834,6 +834,26 @@ export class SessionStore {
|
|
|
834
834
|
sessionId: row.session_id,
|
|
835
835
|
};
|
|
836
836
|
}
|
|
837
|
+
/**
|
|
838
|
+
* Retrieve the most recent N project observations for a given project.
|
|
839
|
+
* Returns observations sorted by created_at DESC, newest first.
|
|
840
|
+
*/
|
|
841
|
+
getRecentProjectObservations(projectId, limit = 30) {
|
|
842
|
+
const rows = this.db
|
|
843
|
+
.prepare(`SELECT id, project_id, session_id, content, relevance, created_at
|
|
844
|
+
FROM project_observations
|
|
845
|
+
WHERE project_id = ?
|
|
846
|
+
ORDER BY created_at DESC
|
|
847
|
+
LIMIT ?`)
|
|
848
|
+
.all(projectId, limit);
|
|
849
|
+
return rows.map((r) => ({
|
|
850
|
+
id: r.id,
|
|
851
|
+
content: r.content,
|
|
852
|
+
relevance: r.relevance,
|
|
853
|
+
createdAt: r.created_at,
|
|
854
|
+
sessionId: r.session_id,
|
|
855
|
+
}));
|
|
856
|
+
}
|
|
837
857
|
/**
|
|
838
858
|
* Look up a project by its absolute filesystem path.
|
|
839
859
|
* Returns null when no project has been registered for the given path.
|