@qwickapps/qwickbrain-proxy 1.0.1 → 1.0.3
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/.claude/engineering/bugs/BUG-qwickbrain-proxy-cache-and-design.md +840 -0
- package/.github/workflows/publish.yml +13 -0
- package/CHANGELOG.md +54 -0
- package/dist/db/schema.d.ts +63 -6
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +17 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/lib/__tests__/cache-manager.test.js +146 -83
- package/dist/lib/__tests__/cache-manager.test.js.map +1 -1
- package/dist/lib/__tests__/proxy-server.test.js +16 -44
- package/dist/lib/__tests__/proxy-server.test.js.map +1 -1
- package/dist/lib/__tests__/sse-invalidation-listener.test.d.ts +2 -0
- package/dist/lib/__tests__/sse-invalidation-listener.test.d.ts.map +1 -0
- package/dist/lib/__tests__/sse-invalidation-listener.test.js +245 -0
- package/dist/lib/__tests__/sse-invalidation-listener.test.js.map +1 -0
- package/dist/lib/__tests__/write-queue-manager.test.d.ts +2 -0
- package/dist/lib/__tests__/write-queue-manager.test.d.ts.map +1 -0
- package/dist/lib/__tests__/write-queue-manager.test.js +291 -0
- package/dist/lib/__tests__/write-queue-manager.test.js.map +1 -0
- package/dist/lib/cache-manager.d.ts +35 -6
- package/dist/lib/cache-manager.d.ts.map +1 -1
- package/dist/lib/cache-manager.js +154 -41
- package/dist/lib/cache-manager.js.map +1 -1
- package/dist/lib/connection-manager.d.ts.map +1 -1
- package/dist/lib/connection-manager.js +4 -1
- package/dist/lib/connection-manager.js.map +1 -1
- package/dist/lib/proxy-server.d.ts +6 -0
- package/dist/lib/proxy-server.d.ts.map +1 -1
- package/dist/lib/proxy-server.js +182 -87
- package/dist/lib/proxy-server.js.map +1 -1
- package/dist/lib/qwickbrain-client.d.ts +4 -0
- package/dist/lib/qwickbrain-client.d.ts.map +1 -1
- package/dist/lib/qwickbrain-client.js +133 -0
- package/dist/lib/qwickbrain-client.js.map +1 -1
- package/dist/lib/sse-invalidation-listener.d.ts +27 -0
- package/dist/lib/sse-invalidation-listener.d.ts.map +1 -0
- package/dist/lib/sse-invalidation-listener.js +145 -0
- package/dist/lib/sse-invalidation-listener.js.map +1 -0
- package/dist/lib/tools.d.ts +21 -0
- package/dist/lib/tools.d.ts.map +1 -0
- package/dist/lib/tools.js +488 -0
- package/dist/lib/tools.js.map +1 -0
- package/dist/lib/write-queue-manager.d.ts +88 -0
- package/dist/lib/write-queue-manager.d.ts.map +1 -0
- package/dist/lib/write-queue-manager.js +191 -0
- package/dist/lib/write-queue-manager.js.map +1 -0
- package/dist/types/config.d.ts +7 -42
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +1 -6
- package/dist/types/config.js.map +1 -1
- package/drizzle/0002_lru_cache_migration.sql +94 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +6 -2
- package/scripts/rebuild-sqlite.sh +26 -0
- package/src/db/schema.ts +17 -2
- package/src/lib/__tests__/cache-manager.test.ts +180 -90
- package/src/lib/__tests__/proxy-server.test.ts +16 -51
- package/src/lib/__tests__/sse-invalidation-listener.test.ts +326 -0
- package/src/lib/__tests__/write-queue-manager.test.ts +383 -0
- package/src/lib/cache-manager.ts +198 -46
- package/src/lib/connection-manager.ts +4 -1
- package/src/lib/proxy-server.ts +222 -90
- package/src/lib/qwickbrain-client.ts +145 -1
- package/src/lib/sse-invalidation-listener.ts +171 -0
- package/src/lib/tools.ts +500 -0
- package/src/lib/write-queue-manager.ts +271 -0
- package/src/types/config.ts +1 -6
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { EventSource } from 'eventsource';
|
|
2
|
+
import type { CacheManager } from './cache-manager.js';
|
|
3
|
+
|
|
4
|
+
interface InvalidationEvent {
|
|
5
|
+
type: 'document' | 'memory';
|
|
6
|
+
docType?: string; // For document invalidation
|
|
7
|
+
name: string;
|
|
8
|
+
project?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class SSEInvalidationListener {
|
|
12
|
+
private eventSource: EventSource | null = null;
|
|
13
|
+
private reconnectTimeout: NodeJS.Timeout | null = null;
|
|
14
|
+
private reconnectDelay = 5000; // 5 seconds
|
|
15
|
+
private isActive = false;
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
private url: string,
|
|
19
|
+
private cacheManager: CacheManager,
|
|
20
|
+
private apiKey?: string
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Start listening for SSE invalidation events
|
|
25
|
+
*/
|
|
26
|
+
async start(): Promise<void> {
|
|
27
|
+
if (this.isActive) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.isActive = true;
|
|
32
|
+
this.connect();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private connect(): void {
|
|
36
|
+
if (!this.isActive) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// Build SSE endpoint URL
|
|
42
|
+
const sseUrl = new URL('/sse/cache-invalidation', this.url);
|
|
43
|
+
|
|
44
|
+
// Configure EventSource with auth header if needed
|
|
45
|
+
const eventSourceInitDict: any = {
|
|
46
|
+
headers: {},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (this.apiKey) {
|
|
50
|
+
eventSourceInitDict.headers['Authorization'] = `Bearer ${this.apiKey}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.eventSource = new EventSource(sseUrl.toString(), eventSourceInitDict);
|
|
54
|
+
|
|
55
|
+
this.eventSource.onopen = () => {
|
|
56
|
+
console.error('SSE invalidation listener connected');
|
|
57
|
+
// Clear reconnect timeout on successful connection
|
|
58
|
+
if (this.reconnectTimeout) {
|
|
59
|
+
clearTimeout(this.reconnectTimeout);
|
|
60
|
+
this.reconnectTimeout = null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
this.eventSource.onerror = (error: any) => {
|
|
65
|
+
console.error('SSE invalidation listener error:', error);
|
|
66
|
+
this.eventSource?.close();
|
|
67
|
+
this.eventSource = null;
|
|
68
|
+
|
|
69
|
+
// Schedule reconnection
|
|
70
|
+
if (this.isActive && !this.reconnectTimeout) {
|
|
71
|
+
console.error(`SSE reconnecting in ${this.reconnectDelay}ms...`);
|
|
72
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
73
|
+
this.reconnectTimeout = null;
|
|
74
|
+
this.connect();
|
|
75
|
+
}, this.reconnectDelay);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Listen for document invalidation events
|
|
80
|
+
this.eventSource.addEventListener('document:invalidate', (event: MessageEvent) => {
|
|
81
|
+
this.handleInvalidationEvent(event.data);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Listen for memory invalidation events
|
|
85
|
+
this.eventSource.addEventListener('memory:invalidate', (event: MessageEvent) => {
|
|
86
|
+
this.handleInvalidationEvent(event.data);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Listen for batch invalidation events (multiple items)
|
|
90
|
+
this.eventSource.addEventListener('cache:invalidate:batch', (event: MessageEvent) => {
|
|
91
|
+
this.handleBatchInvalidation(event.data);
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('Failed to connect SSE invalidation listener:', error);
|
|
95
|
+
// Schedule retry
|
|
96
|
+
if (this.isActive && !this.reconnectTimeout) {
|
|
97
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
98
|
+
this.reconnectTimeout = null;
|
|
99
|
+
this.connect();
|
|
100
|
+
}, this.reconnectDelay);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private async handleInvalidationEvent(data: string): Promise<void> {
|
|
106
|
+
try {
|
|
107
|
+
const event: InvalidationEvent = JSON.parse(data);
|
|
108
|
+
|
|
109
|
+
if (event.type === 'document') {
|
|
110
|
+
if (!event.docType) {
|
|
111
|
+
console.error('Invalid document invalidation event: missing docType');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await this.cacheManager.invalidateDocument(event.docType, event.name, event.project);
|
|
115
|
+
console.error(`Cache invalidated via SSE: ${event.docType}:${event.name}`);
|
|
116
|
+
} else if (event.type === 'memory') {
|
|
117
|
+
await this.cacheManager.invalidateMemory(event.name, event.project);
|
|
118
|
+
console.error(`Cache invalidated via SSE: memory:${event.name}`);
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('Failed to parse invalidation event:', error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private async handleBatchInvalidation(data: string): Promise<void> {
|
|
126
|
+
try {
|
|
127
|
+
const events: InvalidationEvent[] = JSON.parse(data);
|
|
128
|
+
|
|
129
|
+
// Process invalidations in parallel
|
|
130
|
+
await Promise.all(
|
|
131
|
+
events.map(async (event) => {
|
|
132
|
+
if (event.type === 'document' && event.docType) {
|
|
133
|
+
await this.cacheManager.invalidateDocument(event.docType, event.name, event.project);
|
|
134
|
+
} else if (event.type === 'memory') {
|
|
135
|
+
await this.cacheManager.invalidateMemory(event.name, event.project);
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
console.error(`Batch cache invalidation: ${events.length} items`);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('Failed to parse batch invalidation event:', error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Stop listening for SSE events
|
|
148
|
+
*/
|
|
149
|
+
stop(): void {
|
|
150
|
+
this.isActive = false;
|
|
151
|
+
|
|
152
|
+
if (this.reconnectTimeout) {
|
|
153
|
+
clearTimeout(this.reconnectTimeout);
|
|
154
|
+
this.reconnectTimeout = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (this.eventSource) {
|
|
158
|
+
this.eventSource.close();
|
|
159
|
+
this.eventSource = null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.error('SSE invalidation listener stopped');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check if listener is active
|
|
167
|
+
*/
|
|
168
|
+
isListening(): boolean {
|
|
169
|
+
return this.isActive && this.eventSource !== null && this.eventSource.readyState === EventSource.OPEN;
|
|
170
|
+
}
|
|
171
|
+
}
|
package/src/lib/tools.ts
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static tool definitions for QwickBrain MCP Proxy
|
|
3
|
+
*
|
|
4
|
+
* These tools are always exposed regardless of connection state.
|
|
5
|
+
* Non-cacheable tools return offline errors when QwickBrain is unavailable.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface ToolDefinition {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
inputSchema: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const QWICKBRAIN_TOOLS: ToolDefinition[] = [
|
|
15
|
+
// Code Analysis Tools
|
|
16
|
+
{
|
|
17
|
+
name: 'analyze_repository',
|
|
18
|
+
description: 'Analyze a repository and extract architecture-level information. Returns modules, files, languages, and import relationships. Use this for initial exploration of a codebase.',
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
path: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Absolute path to the repository root',
|
|
25
|
+
},
|
|
26
|
+
language: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Optional: filter by language (python, javascript, typescript, java, go)',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ['path'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'analyze_file',
|
|
36
|
+
description: 'Analyze a single source file and extract its structure. Returns functions, classes, methods, interfaces, and type aliases. Use this to understand the contents of a specific file.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
path: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'Absolute path to the source file',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ['path'],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'find_functions',
|
|
50
|
+
description: 'Find all functions in a file or repository matching a pattern. Returns function names, signatures, and locations.',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
path: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'Path to a file or repository',
|
|
57
|
+
},
|
|
58
|
+
pattern: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Optional: pattern to match function names (case-insensitive substring)',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
required: ['path'],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'find_classes',
|
|
68
|
+
description: 'Find all classes in a file or repository matching a pattern. Returns class names, bases, and locations.',
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
path: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
description: 'Path to a file or repository',
|
|
75
|
+
},
|
|
76
|
+
pattern: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
description: 'Optional: pattern to match class names (case-insensitive substring)',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ['path'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'get_imports',
|
|
86
|
+
description: 'Get all imports from a file or repository. Shows what modules and packages are imported and from where.',
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: 'object',
|
|
89
|
+
properties: {
|
|
90
|
+
path: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Path to a file or repository',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
required: ['path'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'search_codebase',
|
|
100
|
+
description: 'Semantic search across the indexed codebase. Uses natural language to find relevant functions, classes, and methods. Requires the codebase to be indexed first. Returns ranked results with similarity scores.',
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
query: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
description: 'Natural language search query. Examples: "function to parse JSON", "class that handles authentication", "async method for file upload"',
|
|
107
|
+
},
|
|
108
|
+
limit: {
|
|
109
|
+
type: 'integer',
|
|
110
|
+
description: 'Maximum results to return (default: 10, max: 20)',
|
|
111
|
+
default: 10,
|
|
112
|
+
},
|
|
113
|
+
min_score: {
|
|
114
|
+
type: 'number',
|
|
115
|
+
description: 'Minimum similarity score threshold (default: 0.5)',
|
|
116
|
+
default: 0.5,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ['query'],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'explain_function',
|
|
124
|
+
description: 'Get detailed explanation of a function or method. Analyzes implementation and provides insights.',
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
path: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
description: 'Path to the file containing the function',
|
|
131
|
+
},
|
|
132
|
+
function_name: {
|
|
133
|
+
type: 'string',
|
|
134
|
+
description: 'Name of the function to explain',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
required: ['path', 'function_name'],
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
// Repository Management Tools
|
|
142
|
+
{
|
|
143
|
+
name: 'add_repository',
|
|
144
|
+
description: 'Add a repository to the index for semantic search.',
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: {
|
|
148
|
+
path: {
|
|
149
|
+
type: 'string',
|
|
150
|
+
description: 'Absolute path to the repository root',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
required: ['path'],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: 'list_repositories',
|
|
158
|
+
description: 'List all indexed repositories.',
|
|
159
|
+
inputSchema: {
|
|
160
|
+
type: 'object',
|
|
161
|
+
properties: {},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'remove_repository',
|
|
166
|
+
description: 'Remove a repository from the index.',
|
|
167
|
+
inputSchema: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
path: {
|
|
171
|
+
type: 'string',
|
|
172
|
+
description: 'Path to the repository to remove',
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
required: ['path'],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'update_repository',
|
|
180
|
+
description: 'Update the index for a repository (re-index).',
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: 'object',
|
|
183
|
+
properties: {
|
|
184
|
+
path: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'Path to the repository to update',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
required: ['path'],
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// Document Management Tools (Cacheable)
|
|
194
|
+
{
|
|
195
|
+
name: 'create_document',
|
|
196
|
+
description: 'Create a new document.',
|
|
197
|
+
inputSchema: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
properties: {
|
|
200
|
+
name: {
|
|
201
|
+
type: 'string',
|
|
202
|
+
description: 'Document name',
|
|
203
|
+
},
|
|
204
|
+
doc_type: {
|
|
205
|
+
type: 'string',
|
|
206
|
+
description: 'Document type',
|
|
207
|
+
enum: ['adr', 'spike', 'frd', 'design', 'review', 'memory', 'workflow', 'rule'],
|
|
208
|
+
},
|
|
209
|
+
content: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
description: 'Document content (markdown)',
|
|
212
|
+
},
|
|
213
|
+
project: {
|
|
214
|
+
type: 'string',
|
|
215
|
+
description: 'Optional: Project scope',
|
|
216
|
+
},
|
|
217
|
+
metadata: {
|
|
218
|
+
type: 'object',
|
|
219
|
+
description: 'Optional: Additional metadata',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
required: ['name', 'doc_type', 'content'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: 'get_document',
|
|
227
|
+
description: 'Get a document by name, type, and optional project. Returns the full document content and metadata. CACHEABLE - works offline with cached data.',
|
|
228
|
+
inputSchema: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
name: {
|
|
232
|
+
type: 'string',
|
|
233
|
+
description: 'Document name',
|
|
234
|
+
},
|
|
235
|
+
doc_type: {
|
|
236
|
+
type: 'string',
|
|
237
|
+
description: 'Document type',
|
|
238
|
+
enum: ['adr', 'spike', 'frd', 'design', 'review', 'memory', 'workflow', 'rule'],
|
|
239
|
+
},
|
|
240
|
+
project: {
|
|
241
|
+
type: 'string',
|
|
242
|
+
description: 'Optional: Project scope (omit for global documents)',
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
required: ['name', 'doc_type'],
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: 'list_documents',
|
|
250
|
+
description: 'List documents with optional filters. Can filter by type and/or project.',
|
|
251
|
+
inputSchema: {
|
|
252
|
+
type: 'object',
|
|
253
|
+
properties: {
|
|
254
|
+
doc_type: {
|
|
255
|
+
type: 'string',
|
|
256
|
+
description: 'Optional: Filter by document type',
|
|
257
|
+
},
|
|
258
|
+
project: {
|
|
259
|
+
type: 'string',
|
|
260
|
+
description: 'Optional: Filter by project',
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'update_document',
|
|
267
|
+
description: 'Update an existing document.',
|
|
268
|
+
inputSchema: {
|
|
269
|
+
type: 'object',
|
|
270
|
+
properties: {
|
|
271
|
+
name: {
|
|
272
|
+
type: 'string',
|
|
273
|
+
description: 'Document name',
|
|
274
|
+
},
|
|
275
|
+
doc_type: {
|
|
276
|
+
type: 'string',
|
|
277
|
+
description: 'Document type',
|
|
278
|
+
},
|
|
279
|
+
content: {
|
|
280
|
+
type: 'string',
|
|
281
|
+
description: 'New document content',
|
|
282
|
+
},
|
|
283
|
+
project: {
|
|
284
|
+
type: 'string',
|
|
285
|
+
description: 'Optional: Project scope',
|
|
286
|
+
},
|
|
287
|
+
metadata: {
|
|
288
|
+
type: 'object',
|
|
289
|
+
description: 'Optional: Updated metadata',
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
required: ['name', 'doc_type', 'content'],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: 'delete_document',
|
|
297
|
+
description: 'Delete a document.',
|
|
298
|
+
inputSchema: {
|
|
299
|
+
type: 'object',
|
|
300
|
+
properties: {
|
|
301
|
+
name: {
|
|
302
|
+
type: 'string',
|
|
303
|
+
description: 'Document name',
|
|
304
|
+
},
|
|
305
|
+
doc_type: {
|
|
306
|
+
type: 'string',
|
|
307
|
+
description: 'Document type',
|
|
308
|
+
},
|
|
309
|
+
project: {
|
|
310
|
+
type: 'string',
|
|
311
|
+
description: 'Optional: Project scope',
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
required: ['name', 'doc_type'],
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: 'search_documents',
|
|
319
|
+
description: 'Search documents by content or metadata.',
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: 'object',
|
|
322
|
+
properties: {
|
|
323
|
+
query: {
|
|
324
|
+
type: 'string',
|
|
325
|
+
description: 'Search query',
|
|
326
|
+
},
|
|
327
|
+
doc_type: {
|
|
328
|
+
type: 'string',
|
|
329
|
+
description: 'Optional: Filter by document type',
|
|
330
|
+
},
|
|
331
|
+
project: {
|
|
332
|
+
type: 'string',
|
|
333
|
+
description: 'Optional: Filter by project',
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
required: ['query'],
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
// Workflow Tools (Cacheable)
|
|
341
|
+
{
|
|
342
|
+
name: 'get_workflow',
|
|
343
|
+
description: 'Get a workflow definition by name. CACHEABLE - works offline with cached data.',
|
|
344
|
+
inputSchema: {
|
|
345
|
+
type: 'object',
|
|
346
|
+
properties: {
|
|
347
|
+
name: {
|
|
348
|
+
type: 'string',
|
|
349
|
+
description: 'Workflow name',
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
required: ['name'],
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
name: 'list_workflows',
|
|
357
|
+
description: 'List all available workflows.',
|
|
358
|
+
inputSchema: {
|
|
359
|
+
type: 'object',
|
|
360
|
+
properties: {},
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: 'create_workflow',
|
|
365
|
+
description: 'Create a new workflow definition.',
|
|
366
|
+
inputSchema: {
|
|
367
|
+
type: 'object',
|
|
368
|
+
properties: {
|
|
369
|
+
name: {
|
|
370
|
+
type: 'string',
|
|
371
|
+
description: 'Workflow name',
|
|
372
|
+
},
|
|
373
|
+
content: {
|
|
374
|
+
type: 'string',
|
|
375
|
+
description: 'Workflow content (markdown)',
|
|
376
|
+
},
|
|
377
|
+
metadata: {
|
|
378
|
+
type: 'object',
|
|
379
|
+
description: 'Optional: Workflow metadata',
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
required: ['name', 'content'],
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: 'update_workflow',
|
|
387
|
+
description: 'Update an existing workflow.',
|
|
388
|
+
inputSchema: {
|
|
389
|
+
type: 'object',
|
|
390
|
+
properties: {
|
|
391
|
+
name: {
|
|
392
|
+
type: 'string',
|
|
393
|
+
description: 'Workflow name',
|
|
394
|
+
},
|
|
395
|
+
content: {
|
|
396
|
+
type: 'string',
|
|
397
|
+
description: 'Updated workflow content',
|
|
398
|
+
},
|
|
399
|
+
metadata: {
|
|
400
|
+
type: 'object',
|
|
401
|
+
description: 'Optional: Updated metadata',
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
required: ['name', 'content'],
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
// Memory Tools (Cacheable)
|
|
409
|
+
{
|
|
410
|
+
name: 'get_memory',
|
|
411
|
+
description: 'Get a memory/context document by name. CACHEABLE - works offline with cached data.',
|
|
412
|
+
inputSchema: {
|
|
413
|
+
type: 'object',
|
|
414
|
+
properties: {
|
|
415
|
+
name: {
|
|
416
|
+
type: 'string',
|
|
417
|
+
description: 'Memory name',
|
|
418
|
+
},
|
|
419
|
+
project: {
|
|
420
|
+
type: 'string',
|
|
421
|
+
description: 'Optional: Project scope',
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
required: ['name'],
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: 'set_memory',
|
|
429
|
+
description: 'Set or update a memory/context document.',
|
|
430
|
+
inputSchema: {
|
|
431
|
+
type: 'object',
|
|
432
|
+
properties: {
|
|
433
|
+
name: {
|
|
434
|
+
type: 'string',
|
|
435
|
+
description: 'Memory name',
|
|
436
|
+
},
|
|
437
|
+
content: {
|
|
438
|
+
type: 'string',
|
|
439
|
+
description: 'Memory content',
|
|
440
|
+
},
|
|
441
|
+
project: {
|
|
442
|
+
type: 'string',
|
|
443
|
+
description: 'Optional: Project scope',
|
|
444
|
+
},
|
|
445
|
+
metadata: {
|
|
446
|
+
type: 'object',
|
|
447
|
+
description: 'Optional: Memory metadata',
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
required: ['name', 'content'],
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: 'list_memories',
|
|
455
|
+
description: 'List all memories with optional project filter.',
|
|
456
|
+
inputSchema: {
|
|
457
|
+
type: 'object',
|
|
458
|
+
properties: {
|
|
459
|
+
project: {
|
|
460
|
+
type: 'string',
|
|
461
|
+
description: 'Optional: Filter by project',
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: 'search_memories',
|
|
468
|
+
description: 'Search memories by content.',
|
|
469
|
+
inputSchema: {
|
|
470
|
+
type: 'object',
|
|
471
|
+
properties: {
|
|
472
|
+
query: {
|
|
473
|
+
type: 'string',
|
|
474
|
+
description: 'Search query',
|
|
475
|
+
},
|
|
476
|
+
project: {
|
|
477
|
+
type: 'string',
|
|
478
|
+
description: 'Optional: Filter by project',
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
required: ['query'],
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
];
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Tools that are cacheable and work offline
|
|
488
|
+
*/
|
|
489
|
+
export const CACHEABLE_TOOLS = new Set([
|
|
490
|
+
'get_workflow',
|
|
491
|
+
'get_document',
|
|
492
|
+
'get_memory',
|
|
493
|
+
]);
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Tools that require active connection
|
|
497
|
+
*/
|
|
498
|
+
export function requiresConnection(toolName: string): boolean {
|
|
499
|
+
return !CACHEABLE_TOOLS.has(toolName);
|
|
500
|
+
}
|