kratos-mcp 1.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/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/host-middleware-v2.d.ts +3 -0
- package/dist/host-middleware-v2.d.ts.map +1 -0
- package/dist/host-middleware-v2.js +471 -0
- package/dist/host-middleware-v2.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +939 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-server/concept-store-enhanced.d.ts +88 -0
- package/dist/memory-server/concept-store-enhanced.d.ts.map +1 -0
- package/dist/memory-server/concept-store-enhanced.js +392 -0
- package/dist/memory-server/concept-store-enhanced.js.map +1 -0
- package/dist/memory-server/concept-store.d.ts +58 -0
- package/dist/memory-server/concept-store.d.ts.map +1 -0
- package/dist/memory-server/concept-store.js +329 -0
- package/dist/memory-server/concept-store.js.map +1 -0
- package/dist/memory-server/context-broker.d.ts +63 -0
- package/dist/memory-server/context-broker.d.ts.map +1 -0
- package/dist/memory-server/context-broker.js +340 -0
- package/dist/memory-server/context-broker.js.map +1 -0
- package/dist/memory-server/database.d.ts +61 -0
- package/dist/memory-server/database.d.ts.map +1 -0
- package/dist/memory-server/database.js +309 -0
- package/dist/memory-server/database.js.map +1 -0
- package/dist/modules/prd/index.d.ts +47 -0
- package/dist/modules/prd/index.d.ts.map +1 -0
- package/dist/modules/prd/index.js +220 -0
- package/dist/modules/prd/index.js.map +1 -0
- package/dist/modules/prompt/index.d.ts +47 -0
- package/dist/modules/prompt/index.d.ts.map +1 -0
- package/dist/modules/prompt/index.js +313 -0
- package/dist/modules/prompt/index.js.map +1 -0
- package/dist/project-manager.d.ts +69 -0
- package/dist/project-manager.d.ts.map +1 -0
- package/dist/project-manager.js +207 -0
- package/dist/project-manager.js.map +1 -0
- package/dist/security/data-retention.d.ts +104 -0
- package/dist/security/data-retention.d.ts.map +1 -0
- package/dist/security/data-retention.js +444 -0
- package/dist/security/data-retention.js.map +1 -0
- package/dist/security/encryption.d.ts +48 -0
- package/dist/security/encryption.d.ts.map +1 -0
- package/dist/security/encryption.js +131 -0
- package/dist/security/encryption.js.map +1 -0
- package/dist/security/pii-detector.d.ts +61 -0
- package/dist/security/pii-detector.d.ts.map +1 -0
- package/dist/security/pii-detector.js +220 -0
- package/dist/security/pii-detector.js.map +1 -0
- package/dist/tools/ci-hooks.d.ts +48 -0
- package/dist/tools/ci-hooks.d.ts.map +1 -0
- package/dist/tools/ci-hooks.js +452 -0
- package/dist/tools/ci-hooks.js.map +1 -0
- package/dist/tools/migrate-to-sqlite.d.ts +32 -0
- package/dist/tools/migrate-to-sqlite.d.ts.map +1 -0
- package/dist/tools/migrate-to-sqlite.js +341 -0
- package/dist/tools/migrate-to-sqlite.js.map +1 -0
- package/dist/types/index.d.ts +151 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +33 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mcp-logger.d.ts +14 -0
- package/dist/utils/mcp-logger.d.ts.map +1 -0
- package/dist/utils/mcp-logger.js +40 -0
- package/dist/utils/mcp-logger.js.map +1 -0
- package/package.json +88 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,939 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { MemoryDatabase } from './memory-server/database.js';
|
|
7
|
+
import { ConceptStore } from './memory-server/concept-store.js';
|
|
8
|
+
import { ContextBroker } from './memory-server/context-broker.js';
|
|
9
|
+
// Evidence Guard removed - was flaky and not useful
|
|
10
|
+
import { PRDManager } from './modules/prd/index.js';
|
|
11
|
+
import { PromptManager } from './modules/prompt/index.js';
|
|
12
|
+
import { ProjectManager } from './project-manager.js';
|
|
13
|
+
import { MCPLogger as Logger } from './utils/mcp-logger.js';
|
|
14
|
+
import { EncryptionManager } from './security/encryption.js';
|
|
15
|
+
import { PIIDetector } from './security/pii-detector.js';
|
|
16
|
+
import { DataRetentionManager } from './security/data-retention.js';
|
|
17
|
+
const logger = new Logger('Kratos');
|
|
18
|
+
class KratosProtocolServer {
|
|
19
|
+
server;
|
|
20
|
+
projectManager;
|
|
21
|
+
memoryDb = null;
|
|
22
|
+
conceptStore = null;
|
|
23
|
+
contextBroker = null;
|
|
24
|
+
// Evidence Guard removed - was flaky and not delivering value
|
|
25
|
+
prdManager;
|
|
26
|
+
promptManager;
|
|
27
|
+
// Security components
|
|
28
|
+
encryption = null;
|
|
29
|
+
piiDetector;
|
|
30
|
+
dataRetention = null;
|
|
31
|
+
constructor() {
|
|
32
|
+
this.server = new Server({
|
|
33
|
+
name: 'kratos-protocol',
|
|
34
|
+
version: '4.0.0',
|
|
35
|
+
}, {
|
|
36
|
+
capabilities: {
|
|
37
|
+
tools: {},
|
|
38
|
+
resources: {},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
this.projectManager = new ProjectManager();
|
|
42
|
+
this.prdManager = new PRDManager();
|
|
43
|
+
this.promptManager = new PromptManager();
|
|
44
|
+
this.piiDetector = new PIIDetector();
|
|
45
|
+
this.setupHandlers();
|
|
46
|
+
}
|
|
47
|
+
ensureInitialized() {
|
|
48
|
+
if (!this.memoryDb || !this.conceptStore || !this.contextBroker) {
|
|
49
|
+
throw new Error('Project not initialized. Please wait for initialization to complete.');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async initializeProject() {
|
|
53
|
+
try {
|
|
54
|
+
// AUTO-DETECT project from current directory
|
|
55
|
+
// No more manual project ID needed!
|
|
56
|
+
const workingDir = process.env.KRATOS_PROJECT_ROOT || process.cwd();
|
|
57
|
+
const project = await this.projectManager.detectProject(workingDir);
|
|
58
|
+
logger.info(`Auto-detected project: ${project.name} at ${project.root}`);
|
|
59
|
+
// Initialize components with ISOLATED project
|
|
60
|
+
this.memoryDb = new MemoryDatabase(project.root, project.id);
|
|
61
|
+
this.conceptStore = ConceptStore.getInstance(project.id);
|
|
62
|
+
this.contextBroker = new ContextBroker(project.root, project.id);
|
|
63
|
+
// Initialize security components
|
|
64
|
+
this.encryption = new EncryptionManager(project.root, project.id);
|
|
65
|
+
this.dataRetention = new DataRetentionManager(project.root, project.id);
|
|
66
|
+
logger.info(chalk.green(`ā
Project initialized: ${project.name}`));
|
|
67
|
+
logger.info(chalk.blue(`š Project root: ${project.root}`));
|
|
68
|
+
logger.info(chalk.yellow(`š Isolated data: ~/.kratos/projects/${project.id}/`));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
logger.error('Failed to initialize project:', error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
setupHandlers() {
|
|
75
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
76
|
+
tools: [
|
|
77
|
+
// Memory Management (per-project)
|
|
78
|
+
{
|
|
79
|
+
name: 'memory_save',
|
|
80
|
+
description: 'Save a memory document to the active project',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
summary: { type: 'string', description: 'Short, 1-2 line summary' },
|
|
85
|
+
text: { type: 'string', description: 'Full memory content' },
|
|
86
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags for categorization' },
|
|
87
|
+
paths: { type: 'array', items: { type: 'string' }, description: 'File/directory paths (globs)' },
|
|
88
|
+
importance: { type: 'integer', minimum: 1, maximum: 5, description: 'Importance level' },
|
|
89
|
+
ttl: { type: 'integer', description: 'Time to live in seconds' },
|
|
90
|
+
},
|
|
91
|
+
required: ['summary', 'text'],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'memory_search',
|
|
96
|
+
description: 'Search memory documents in the active project',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
q: { type: 'string', description: 'Search query' },
|
|
101
|
+
k: { type: 'integer', description: 'Max results to return' },
|
|
102
|
+
require_path_match: { type: 'boolean', description: 'Require path matching' },
|
|
103
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
|
|
104
|
+
include_expired: { type: 'boolean', description: 'Include expired memories' },
|
|
105
|
+
},
|
|
106
|
+
required: ['q'],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'memory_get_recent',
|
|
111
|
+
description: 'Get recent memories from active project',
|
|
112
|
+
inputSchema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {
|
|
115
|
+
k: { type: 'integer', description: 'Max results' },
|
|
116
|
+
path_prefix: { type: 'string', description: 'Filter by path prefix' },
|
|
117
|
+
include_expired: { type: 'boolean', description: 'Include expired memories' },
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'memory_forget',
|
|
123
|
+
description: 'Delete a memory by ID',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
id: { type: 'string', description: 'Memory ID to delete' },
|
|
128
|
+
},
|
|
129
|
+
required: ['id'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'memory_link',
|
|
134
|
+
description: 'Link a global concept to the current project',
|
|
135
|
+
inputSchema: {
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: {
|
|
138
|
+
concept_id: { type: 'string', description: 'Global concept ID to link' },
|
|
139
|
+
local_tags: { type: 'array', items: { type: 'string' }, description: 'Additional local tags' },
|
|
140
|
+
},
|
|
141
|
+
required: ['concept_id'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
// Global Concept Store
|
|
145
|
+
{
|
|
146
|
+
name: 'concept_search',
|
|
147
|
+
description: 'Search global concept store',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {
|
|
151
|
+
q: { type: 'string', description: 'Search query' },
|
|
152
|
+
k: { type: 'integer', description: 'Max results' },
|
|
153
|
+
allowlist: { type: 'array', items: { type: 'string' }, description: 'Concept ID allowlist' },
|
|
154
|
+
},
|
|
155
|
+
required: ['q'],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: 'concept_get',
|
|
160
|
+
description: 'Get a specific concept by ID',
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: 'object',
|
|
163
|
+
properties: {
|
|
164
|
+
id: { type: 'string', description: 'Concept ID' },
|
|
165
|
+
},
|
|
166
|
+
required: ['id'],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'concept_save',
|
|
171
|
+
description: 'Save a concept to global store',
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
id: { type: 'string', description: 'Optional concept ID' },
|
|
176
|
+
title: { type: 'string', description: 'Concept title' },
|
|
177
|
+
body: { type: 'string', description: 'Concept body (600-900 chars recommended)' },
|
|
178
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Concept tags' },
|
|
179
|
+
importance: { type: 'integer', minimum: 1, maximum: 5, description: 'Importance level' },
|
|
180
|
+
},
|
|
181
|
+
required: ['title', 'body'],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'concept_allowlist',
|
|
186
|
+
description: 'Manage project concept allowlist',
|
|
187
|
+
inputSchema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
add: { type: 'array', items: { type: 'string' }, description: 'Concept IDs to add' },
|
|
191
|
+
remove: { type: 'array', items: { type: 'string' }, description: 'Concept IDs to remove' },
|
|
192
|
+
list: { type: 'boolean', description: 'List current allowlist' },
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
// Context Management
|
|
197
|
+
{
|
|
198
|
+
name: 'context_preview',
|
|
199
|
+
description: 'Preview context injection for current task',
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: 'object',
|
|
202
|
+
properties: {
|
|
203
|
+
open_files: { type: 'array', items: { type: 'string' }, description: 'Currently open files' },
|
|
204
|
+
task: { type: 'string', description: 'Current task description' },
|
|
205
|
+
budget_bytes: { type: 'integer', description: 'Maximum context size in bytes' },
|
|
206
|
+
top_k: { type: 'integer', description: 'Maximum number of injections' },
|
|
207
|
+
mode: { type: 'string', enum: ['hard', 'soft', 'smart'], description: 'Injection mode' },
|
|
208
|
+
},
|
|
209
|
+
required: ['task'],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'context_rules_get',
|
|
214
|
+
description: 'Get current context injection rules',
|
|
215
|
+
inputSchema: {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'context_rules_set',
|
|
222
|
+
description: 'Update context injection rules',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
maxMemoryAge: { type: 'integer', description: 'Max memory age in milliseconds' },
|
|
227
|
+
minImportance: { type: 'integer', description: 'Minimum importance threshold' },
|
|
228
|
+
pathBoostMultiplier: { type: 'number', description: 'Path matching boost multiplier' },
|
|
229
|
+
conceptImportanceThreshold: { type: 'integer', description: 'Concept importance threshold' },
|
|
230
|
+
dedupeThreshold: { type: 'number', description: 'Deduplication threshold' },
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
// PRD Management (Pillar 1)
|
|
235
|
+
{
|
|
236
|
+
name: 'prd_fetch',
|
|
237
|
+
description: 'Fetch PRD content for feature or path',
|
|
238
|
+
inputSchema: {
|
|
239
|
+
type: 'object',
|
|
240
|
+
properties: {
|
|
241
|
+
feature: { type: 'string', description: 'Feature name' },
|
|
242
|
+
path: { type: 'string', description: 'File path' },
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: 'prd_update',
|
|
248
|
+
description: 'Update PRD content',
|
|
249
|
+
inputSchema: {
|
|
250
|
+
type: 'object',
|
|
251
|
+
properties: {
|
|
252
|
+
feature: { type: 'string', description: 'Feature name' },
|
|
253
|
+
content: { type: 'string', description: 'Updated content' },
|
|
254
|
+
section: { type: 'string', description: 'PRD section to update' },
|
|
255
|
+
},
|
|
256
|
+
required: ['feature', 'content'],
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
// Prompt Engineering (Pillar 2)
|
|
260
|
+
{
|
|
261
|
+
name: 'prompt_build',
|
|
262
|
+
description: 'Build a structured prompt using best practices',
|
|
263
|
+
inputSchema: {
|
|
264
|
+
type: 'object',
|
|
265
|
+
properties: {
|
|
266
|
+
role: { type: 'string', description: 'AI role/persona' },
|
|
267
|
+
goal: { type: 'string', description: 'Task goal' },
|
|
268
|
+
scope: { type: 'string', description: 'Task scope' },
|
|
269
|
+
files: { type: 'array', items: { type: 'string' }, description: 'Relevant files' },
|
|
270
|
+
plan: { type: 'string', description: 'Execution plan' },
|
|
271
|
+
verify: { type: 'string', description: 'Verification criteria' },
|
|
272
|
+
memory_refs: { type: 'array', items: { type: 'string' }, description: 'Memory references to include' },
|
|
273
|
+
},
|
|
274
|
+
required: ['goal'],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
// Security Tools
|
|
278
|
+
{
|
|
279
|
+
name: 'security_scan',
|
|
280
|
+
description: 'Scan text for PII and secrets',
|
|
281
|
+
inputSchema: {
|
|
282
|
+
type: 'object',
|
|
283
|
+
properties: {
|
|
284
|
+
text: { type: 'string', description: 'Text to scan' },
|
|
285
|
+
redact: { type: 'boolean', description: 'Return redacted version' },
|
|
286
|
+
},
|
|
287
|
+
required: ['text'],
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: 'security_encrypt',
|
|
292
|
+
description: 'Encrypt sensitive data for storage',
|
|
293
|
+
inputSchema: {
|
|
294
|
+
type: 'object',
|
|
295
|
+
properties: {
|
|
296
|
+
data: { type: 'object', description: 'Data to encrypt' },
|
|
297
|
+
},
|
|
298
|
+
required: ['data'],
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'security_rbac_check',
|
|
303
|
+
description: 'Check user access permission',
|
|
304
|
+
inputSchema: {
|
|
305
|
+
type: 'object',
|
|
306
|
+
properties: {
|
|
307
|
+
user_id: { type: 'string', description: 'User ID' },
|
|
308
|
+
action: { type: 'string', enum: ['read', 'write', 'search', 'delete', 'admin'], description: 'Action to check' },
|
|
309
|
+
resource: { type: 'string', description: 'Optional resource identifier' },
|
|
310
|
+
},
|
|
311
|
+
required: ['user_id', 'action'],
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: 'security_rbac_grant',
|
|
316
|
+
description: 'Grant user permission to project',
|
|
317
|
+
inputSchema: {
|
|
318
|
+
type: 'object',
|
|
319
|
+
properties: {
|
|
320
|
+
user_id: { type: 'string', description: 'User ID' },
|
|
321
|
+
permissions: { type: 'array', items: { type: 'string' }, description: 'Permissions to grant' },
|
|
322
|
+
},
|
|
323
|
+
required: ['user_id', 'permissions'],
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
name: 'security_retention_apply',
|
|
328
|
+
description: 'Apply retention policy to memory',
|
|
329
|
+
inputSchema: {
|
|
330
|
+
type: 'object',
|
|
331
|
+
properties: {
|
|
332
|
+
memory_id: { type: 'string', description: 'Memory ID' },
|
|
333
|
+
policy: { type: 'string', enum: ['default', 'temporary', 'important', 'permanent'], description: 'Retention policy' },
|
|
334
|
+
},
|
|
335
|
+
required: ['memory_id', 'policy'],
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: 'security_gdpr_delete',
|
|
340
|
+
description: 'Delete data (GDPR right to erasure)',
|
|
341
|
+
inputSchema: {
|
|
342
|
+
type: 'object',
|
|
343
|
+
properties: {
|
|
344
|
+
target_type: { type: 'string', enum: ['memory', 'project', 'user'], description: 'Type of data to delete' },
|
|
345
|
+
target_id: { type: 'string', description: 'ID of target to delete' },
|
|
346
|
+
user_id: { type: 'string', description: 'User requesting deletion' },
|
|
347
|
+
reason: { type: 'string', description: 'Reason for deletion' },
|
|
348
|
+
},
|
|
349
|
+
required: ['target_type', 'target_id', 'user_id', 'reason'],
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: 'security_gdpr_export',
|
|
354
|
+
description: 'Export user data (GDPR compliance)',
|
|
355
|
+
inputSchema: {
|
|
356
|
+
type: 'object',
|
|
357
|
+
properties: {
|
|
358
|
+
user_id: { type: 'string', description: 'User ID to export data for' },
|
|
359
|
+
},
|
|
360
|
+
required: ['user_id'],
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
// Project Management
|
|
364
|
+
{
|
|
365
|
+
name: 'project_switch',
|
|
366
|
+
description: 'Switch to a different project',
|
|
367
|
+
inputSchema: {
|
|
368
|
+
type: 'object',
|
|
369
|
+
properties: {
|
|
370
|
+
project_path: { type: 'string', description: 'Path to project directory' },
|
|
371
|
+
},
|
|
372
|
+
required: ['project_path'],
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: 'project_list',
|
|
377
|
+
description: 'List all known projects',
|
|
378
|
+
inputSchema: {
|
|
379
|
+
type: 'object',
|
|
380
|
+
properties: {},
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: 'project_current',
|
|
385
|
+
description: 'Get current active project',
|
|
386
|
+
inputSchema: {
|
|
387
|
+
type: 'object',
|
|
388
|
+
properties: {},
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
// System Management
|
|
392
|
+
{
|
|
393
|
+
name: 'system_status',
|
|
394
|
+
description: 'Get system status and statistics',
|
|
395
|
+
inputSchema: {
|
|
396
|
+
type: 'object',
|
|
397
|
+
properties: {},
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
name: 'system_migrate',
|
|
402
|
+
description: 'Migrate from legacy JSON format to SQLite',
|
|
403
|
+
inputSchema: {
|
|
404
|
+
type: 'object',
|
|
405
|
+
properties: {
|
|
406
|
+
dry_run: { type: 'boolean', description: 'Perform dry run without changes' },
|
|
407
|
+
create_backup: { type: 'boolean', description: 'Create backup before migration' },
|
|
408
|
+
extract_concepts: { type: 'boolean', description: 'Extract concepts during migration' },
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
}));
|
|
414
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
415
|
+
const { name, arguments: args } = request.params;
|
|
416
|
+
// Ensure project is initialized for project-specific operations
|
|
417
|
+
if (name.startsWith('memory_') || name.startsWith('context_') || name.startsWith('prd_')) {
|
|
418
|
+
const project = this.projectManager.getCurrentProject();
|
|
419
|
+
if (!project) {
|
|
420
|
+
await this.initializeProject();
|
|
421
|
+
if (!this.projectManager.getCurrentProject()) {
|
|
422
|
+
return {
|
|
423
|
+
content: [{
|
|
424
|
+
type: 'text',
|
|
425
|
+
text: 'Error: No active project. Set KRATOS_ACTIVE_PROJECT environment variable.'
|
|
426
|
+
}]
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
switch (name) {
|
|
433
|
+
// Memory operations
|
|
434
|
+
case 'memory_save':
|
|
435
|
+
const saveResult = this.memoryDb.save(args);
|
|
436
|
+
return {
|
|
437
|
+
content: [{
|
|
438
|
+
type: 'text',
|
|
439
|
+
text: JSON.stringify(saveResult, null, 2)
|
|
440
|
+
}]
|
|
441
|
+
};
|
|
442
|
+
case 'memory_search':
|
|
443
|
+
const searchResults = this.memoryDb.search(args);
|
|
444
|
+
return {
|
|
445
|
+
content: [{
|
|
446
|
+
type: 'text',
|
|
447
|
+
text: JSON.stringify({
|
|
448
|
+
count: searchResults.length,
|
|
449
|
+
results: searchResults.map(r => ({
|
|
450
|
+
id: r.memory.id,
|
|
451
|
+
summary: r.memory.summary,
|
|
452
|
+
text: r.memory.text.substring(0, 200) + '...',
|
|
453
|
+
score: r.score,
|
|
454
|
+
tags: r.memory.tags,
|
|
455
|
+
paths: r.memory.paths,
|
|
456
|
+
importance: r.memory.importance,
|
|
457
|
+
created_at: r.memory.created_at,
|
|
458
|
+
snippet: r.snippet
|
|
459
|
+
}))
|
|
460
|
+
}, null, 2)
|
|
461
|
+
}]
|
|
462
|
+
};
|
|
463
|
+
case 'memory_get_recent':
|
|
464
|
+
const recentResults = this.memoryDb.getRecent(args);
|
|
465
|
+
return {
|
|
466
|
+
content: [{
|
|
467
|
+
type: 'text',
|
|
468
|
+
text: JSON.stringify({
|
|
469
|
+
count: recentResults.length,
|
|
470
|
+
memories: recentResults.map(m => ({
|
|
471
|
+
id: m.id,
|
|
472
|
+
summary: m.summary,
|
|
473
|
+
tags: m.tags,
|
|
474
|
+
paths: m.paths,
|
|
475
|
+
importance: m.importance,
|
|
476
|
+
created_at: m.created_at
|
|
477
|
+
}))
|
|
478
|
+
}, null, 2)
|
|
479
|
+
}]
|
|
480
|
+
};
|
|
481
|
+
case 'memory_forget':
|
|
482
|
+
const forgetResult = this.memoryDb.forget(args?.id);
|
|
483
|
+
return {
|
|
484
|
+
content: [{
|
|
485
|
+
type: 'text',
|
|
486
|
+
text: JSON.stringify(forgetResult, null, 2)
|
|
487
|
+
}]
|
|
488
|
+
};
|
|
489
|
+
case 'memory_link':
|
|
490
|
+
this.ensureInitialized();
|
|
491
|
+
const concept = this.conceptStore.get(args?.concept_id);
|
|
492
|
+
if (!concept) {
|
|
493
|
+
throw new Error(`Concept not found: ${args?.concept_id}`);
|
|
494
|
+
}
|
|
495
|
+
const linkedMemory = this.memoryDb.save({
|
|
496
|
+
summary: `Linked: ${concept.title}`,
|
|
497
|
+
text: concept.body,
|
|
498
|
+
tags: [...concept.tags, ...(args?.local_tags || []), 'linked-concept'],
|
|
499
|
+
importance: concept.importance
|
|
500
|
+
});
|
|
501
|
+
return {
|
|
502
|
+
content: [{
|
|
503
|
+
type: 'text',
|
|
504
|
+
text: JSON.stringify({ ...linkedMemory, concept_id: concept.id }, null, 2)
|
|
505
|
+
}]
|
|
506
|
+
};
|
|
507
|
+
// Concept operations
|
|
508
|
+
case 'concept_search':
|
|
509
|
+
if (!this.conceptStore) {
|
|
510
|
+
throw new McpError(ErrorCode.InternalError, 'Concept store not initialized');
|
|
511
|
+
}
|
|
512
|
+
// Handle empty query or missing query by returning all concepts
|
|
513
|
+
const searchQuery = args?.q || '*';
|
|
514
|
+
const conceptSearchResults = this.conceptStore.search({
|
|
515
|
+
q: searchQuery.trim() || '*', // Default to wildcard if empty
|
|
516
|
+
k: args?.k || 10,
|
|
517
|
+
allowlist: args?.allowlist,
|
|
518
|
+
projectId: undefined // Don't filter by project to show all global concepts
|
|
519
|
+
});
|
|
520
|
+
// If no results and query wasn't wildcard, try wildcard as fallback
|
|
521
|
+
let finalConceptResults = conceptSearchResults;
|
|
522
|
+
if (conceptSearchResults.length === 0 && searchQuery !== '*') {
|
|
523
|
+
finalConceptResults = this.conceptStore.search({
|
|
524
|
+
q: '*',
|
|
525
|
+
k: args?.k || 10,
|
|
526
|
+
allowlist: args?.allowlist
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
content: [{
|
|
531
|
+
type: 'text',
|
|
532
|
+
text: JSON.stringify({
|
|
533
|
+
query: searchQuery,
|
|
534
|
+
count: finalConceptResults.length,
|
|
535
|
+
concepts: finalConceptResults.map(c => ({
|
|
536
|
+
id: c.concept.id,
|
|
537
|
+
title: c.concept.title,
|
|
538
|
+
body: c.concept.body.substring(0, 200) + '...',
|
|
539
|
+
tags: c.concept.tags,
|
|
540
|
+
importance: c.concept.importance,
|
|
541
|
+
score: c.score
|
|
542
|
+
})),
|
|
543
|
+
note: finalConceptResults.length === 0 ?
|
|
544
|
+
'No concepts found. Concepts need to be created first with concept_save.' :
|
|
545
|
+
searchQuery === '*' ?
|
|
546
|
+
'Showing all available global concepts' :
|
|
547
|
+
`Found ${finalConceptResults.length} concepts matching "${searchQuery}"`
|
|
548
|
+
}, null, 2)
|
|
549
|
+
}]
|
|
550
|
+
};
|
|
551
|
+
case 'concept_get':
|
|
552
|
+
if (!this.conceptStore) {
|
|
553
|
+
throw new McpError(ErrorCode.InternalError, 'Concept store not initialized');
|
|
554
|
+
}
|
|
555
|
+
const conceptResult = this.conceptStore.get(args?.id);
|
|
556
|
+
return {
|
|
557
|
+
content: [{
|
|
558
|
+
type: 'text',
|
|
559
|
+
text: JSON.stringify(conceptResult, null, 2)
|
|
560
|
+
}]
|
|
561
|
+
};
|
|
562
|
+
case 'concept_save':
|
|
563
|
+
if (!this.conceptStore) {
|
|
564
|
+
throw new McpError(ErrorCode.InternalError, 'Concept store not initialized');
|
|
565
|
+
}
|
|
566
|
+
const conceptSaveResult = this.conceptStore.save(args);
|
|
567
|
+
return {
|
|
568
|
+
content: [{
|
|
569
|
+
type: 'text',
|
|
570
|
+
text: JSON.stringify(conceptSaveResult, null, 2)
|
|
571
|
+
}]
|
|
572
|
+
};
|
|
573
|
+
case 'concept_allowlist':
|
|
574
|
+
if (!this.conceptStore) {
|
|
575
|
+
throw new Error('Concept store not initialized');
|
|
576
|
+
}
|
|
577
|
+
const currentProj = this.projectManager.getCurrentProject();
|
|
578
|
+
const allowlistResult = this.conceptStore.updateAllowlist({
|
|
579
|
+
projectId: currentProj?.id || 'global',
|
|
580
|
+
...args
|
|
581
|
+
});
|
|
582
|
+
return {
|
|
583
|
+
content: [{
|
|
584
|
+
type: 'text',
|
|
585
|
+
text: JSON.stringify(allowlistResult, null, 2)
|
|
586
|
+
}]
|
|
587
|
+
};
|
|
588
|
+
// Evidence Guard operations
|
|
589
|
+
// Context operations
|
|
590
|
+
case 'context_preview':
|
|
591
|
+
const preview = await this.contextBroker.preview(args);
|
|
592
|
+
return {
|
|
593
|
+
content: [{
|
|
594
|
+
type: 'text',
|
|
595
|
+
text: JSON.stringify(preview, null, 2)
|
|
596
|
+
}]
|
|
597
|
+
};
|
|
598
|
+
case 'context_rules_get':
|
|
599
|
+
const rules = this.contextBroker.getRules();
|
|
600
|
+
return {
|
|
601
|
+
content: [{
|
|
602
|
+
type: 'text',
|
|
603
|
+
text: JSON.stringify(rules, null, 2)
|
|
604
|
+
}]
|
|
605
|
+
};
|
|
606
|
+
case 'context_rules_set':
|
|
607
|
+
this.contextBroker.setRules(args);
|
|
608
|
+
return {
|
|
609
|
+
content: [{
|
|
610
|
+
type: 'text',
|
|
611
|
+
text: 'Context rules updated successfully'
|
|
612
|
+
}]
|
|
613
|
+
};
|
|
614
|
+
// PRD operations
|
|
615
|
+
case 'prd_fetch':
|
|
616
|
+
const prdResult = await this.prdManager.getPRD(args?.feature || args?.path);
|
|
617
|
+
return {
|
|
618
|
+
content: [{
|
|
619
|
+
type: 'text',
|
|
620
|
+
text: JSON.stringify(prdResult, null, 2)
|
|
621
|
+
}]
|
|
622
|
+
};
|
|
623
|
+
case 'prd_update':
|
|
624
|
+
const updateResult = await this.prdManager.updatePRD(args?.section, args?.content);
|
|
625
|
+
return {
|
|
626
|
+
content: [{
|
|
627
|
+
type: 'text',
|
|
628
|
+
text: JSON.stringify(updateResult, null, 2)
|
|
629
|
+
}]
|
|
630
|
+
};
|
|
631
|
+
// Prompt operations
|
|
632
|
+
case 'prompt_build':
|
|
633
|
+
const promptArgs = {
|
|
634
|
+
task: args?.goal,
|
|
635
|
+
role: args?.role,
|
|
636
|
+
stack: args?.files,
|
|
637
|
+
fileContext: args?.files,
|
|
638
|
+
templateId: args?.templateId
|
|
639
|
+
};
|
|
640
|
+
const promptResult = await this.promptManager.generatePrompt(promptArgs);
|
|
641
|
+
return {
|
|
642
|
+
content: [{
|
|
643
|
+
type: 'text',
|
|
644
|
+
text: JSON.stringify(promptResult, null, 2)
|
|
645
|
+
}]
|
|
646
|
+
};
|
|
647
|
+
// Security operations
|
|
648
|
+
case 'security_scan':
|
|
649
|
+
const scanResult = this.piiDetector.detect(args?.text);
|
|
650
|
+
if (args?.redact) {
|
|
651
|
+
return {
|
|
652
|
+
content: [{
|
|
653
|
+
type: 'text',
|
|
654
|
+
text: JSON.stringify({
|
|
655
|
+
hasPII: scanResult.hasPII,
|
|
656
|
+
hasSecrets: scanResult.hasSecrets,
|
|
657
|
+
redactedText: scanResult.redactedText,
|
|
658
|
+
findings: scanResult.findings
|
|
659
|
+
}, null, 2)
|
|
660
|
+
}]
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
const scanReport = this.piiDetector.scan(args?.text);
|
|
664
|
+
return {
|
|
665
|
+
content: [{
|
|
666
|
+
type: 'text',
|
|
667
|
+
text: JSON.stringify(scanReport, null, 2)
|
|
668
|
+
}]
|
|
669
|
+
};
|
|
670
|
+
case 'security_encrypt':
|
|
671
|
+
if (!this.encryption) {
|
|
672
|
+
throw new Error('Encryption not initialized. Initialize project first.');
|
|
673
|
+
}
|
|
674
|
+
const encrypted = this.encryption.encryptJSON(args?.data);
|
|
675
|
+
return {
|
|
676
|
+
content: [{
|
|
677
|
+
type: 'text',
|
|
678
|
+
text: JSON.stringify({ encrypted, projectId: this.projectManager.getCurrentProject()?.id }, null, 2)
|
|
679
|
+
}]
|
|
680
|
+
};
|
|
681
|
+
case 'security_retention_apply':
|
|
682
|
+
if (!this.dataRetention) {
|
|
683
|
+
throw new Error('Data retention not initialized. Initialize project first.');
|
|
684
|
+
}
|
|
685
|
+
this.dataRetention.applyPolicy(args?.memory_id, args?.policy);
|
|
686
|
+
return {
|
|
687
|
+
content: [{
|
|
688
|
+
type: 'text',
|
|
689
|
+
text: `Applied ${args?.policy} retention policy to memory ${args?.memory_id}`
|
|
690
|
+
}]
|
|
691
|
+
};
|
|
692
|
+
case 'security_gdpr_delete':
|
|
693
|
+
if (!this.dataRetention) {
|
|
694
|
+
throw new Error('Data retention not initialized. Initialize project first.');
|
|
695
|
+
}
|
|
696
|
+
await this.dataRetention.deleteData({
|
|
697
|
+
targetType: args?.target_type,
|
|
698
|
+
targetId: args?.target_id,
|
|
699
|
+
userId: args?.user_id,
|
|
700
|
+
reason: args?.reason
|
|
701
|
+
});
|
|
702
|
+
return {
|
|
703
|
+
content: [{
|
|
704
|
+
type: 'text',
|
|
705
|
+
text: `Deleted ${args?.target_type} ${args?.target_id} per GDPR request`
|
|
706
|
+
}]
|
|
707
|
+
};
|
|
708
|
+
case 'security_gdpr_export':
|
|
709
|
+
if (!this.dataRetention) {
|
|
710
|
+
throw new Error('Data retention not initialized. Initialize project first.');
|
|
711
|
+
}
|
|
712
|
+
const exportData = await this.dataRetention.exportUserData(args?.user_id);
|
|
713
|
+
return {
|
|
714
|
+
content: [{
|
|
715
|
+
type: 'text',
|
|
716
|
+
text: exportData
|
|
717
|
+
}]
|
|
718
|
+
};
|
|
719
|
+
// Project Management
|
|
720
|
+
case 'project_switch':
|
|
721
|
+
const newProject = await this.projectManager.switchProject(args?.project_path);
|
|
722
|
+
// Re-initialize components for new project
|
|
723
|
+
this.memoryDb = new MemoryDatabase(newProject.root, newProject.id);
|
|
724
|
+
this.conceptStore = ConceptStore.getInstance(newProject.id);
|
|
725
|
+
this.contextBroker = new ContextBroker(newProject.root, newProject.id);
|
|
726
|
+
return {
|
|
727
|
+
content: [{
|
|
728
|
+
type: 'text',
|
|
729
|
+
text: `ā
Switched to project: ${newProject.name}\nRoot: ${newProject.root}\nIsolated data: ~/.kratos/projects/${newProject.id}/`
|
|
730
|
+
}]
|
|
731
|
+
};
|
|
732
|
+
case 'project_list':
|
|
733
|
+
const projects = this.projectManager.listProjects();
|
|
734
|
+
return {
|
|
735
|
+
content: [{
|
|
736
|
+
type: 'text',
|
|
737
|
+
text: JSON.stringify(projects.map(p => ({
|
|
738
|
+
name: p.name,
|
|
739
|
+
root: p.root,
|
|
740
|
+
lastAccessed: p.lastAccessed,
|
|
741
|
+
id: p.id
|
|
742
|
+
})), null, 2)
|
|
743
|
+
}]
|
|
744
|
+
};
|
|
745
|
+
case 'project_current':
|
|
746
|
+
const current = this.projectManager.getCurrentProject();
|
|
747
|
+
return {
|
|
748
|
+
content: [{
|
|
749
|
+
type: 'text',
|
|
750
|
+
text: current ?
|
|
751
|
+
`Current project: ${current.name}\nRoot: ${current.root}\nID: ${current.id}` :
|
|
752
|
+
'No active project'
|
|
753
|
+
}]
|
|
754
|
+
};
|
|
755
|
+
// System operations
|
|
756
|
+
case 'system_status':
|
|
757
|
+
const status = await this.getSystemStatus();
|
|
758
|
+
return {
|
|
759
|
+
content: [{
|
|
760
|
+
type: 'text',
|
|
761
|
+
text: JSON.stringify(status, null, 2)
|
|
762
|
+
}]
|
|
763
|
+
};
|
|
764
|
+
case 'system_migrate':
|
|
765
|
+
// Import migration tool
|
|
766
|
+
const { KratosMigrationTool } = await import('./tools/migrate-to-sqlite.js');
|
|
767
|
+
const migrationTool = new KratosMigrationTool();
|
|
768
|
+
const migrationResult = await migrationTool.migrateProject(this.projectManager.getCurrentProject()?.root || process.cwd(), args);
|
|
769
|
+
return {
|
|
770
|
+
content: [{
|
|
771
|
+
type: 'text',
|
|
772
|
+
text: JSON.stringify(migrationResult, null, 2)
|
|
773
|
+
}]
|
|
774
|
+
};
|
|
775
|
+
default:
|
|
776
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
catch (error) {
|
|
780
|
+
logger.error(`Tool error (${name}):`, error);
|
|
781
|
+
return {
|
|
782
|
+
content: [{
|
|
783
|
+
type: 'text',
|
|
784
|
+
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
785
|
+
}]
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
// Resource handlers
|
|
790
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
791
|
+
const resources = [
|
|
792
|
+
{
|
|
793
|
+
uri: 'kratos://system/status',
|
|
794
|
+
name: 'System Status',
|
|
795
|
+
description: 'Current system status and statistics',
|
|
796
|
+
mimeType: 'application/json',
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
uri: 'kratos://concepts/all',
|
|
800
|
+
name: 'All Concepts',
|
|
801
|
+
description: 'Global concept store contents',
|
|
802
|
+
mimeType: 'application/json',
|
|
803
|
+
}
|
|
804
|
+
];
|
|
805
|
+
const currentProject = this.projectManager.getCurrentProject();
|
|
806
|
+
if (currentProject) {
|
|
807
|
+
resources.push({
|
|
808
|
+
uri: `kratos://project/${currentProject.id}/memories`,
|
|
809
|
+
name: 'Project Memories',
|
|
810
|
+
description: `All memories for project ${currentProject.name}`,
|
|
811
|
+
mimeType: 'application/json',
|
|
812
|
+
}, {
|
|
813
|
+
uri: `kratos://project/${currentProject.id}/prd`,
|
|
814
|
+
name: 'Project PRD',
|
|
815
|
+
description: `PRD for project ${currentProject.name}`,
|
|
816
|
+
mimeType: 'application/json',
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
return { resources };
|
|
820
|
+
});
|
|
821
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
822
|
+
const { uri } = request.params;
|
|
823
|
+
try {
|
|
824
|
+
if (uri === 'kratos://system/status') {
|
|
825
|
+
const status = await this.getSystemStatus();
|
|
826
|
+
return {
|
|
827
|
+
contents: [{
|
|
828
|
+
uri,
|
|
829
|
+
mimeType: 'application/json',
|
|
830
|
+
text: JSON.stringify(status, null, 2)
|
|
831
|
+
}]
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
if (uri === 'kratos://concepts/all') {
|
|
835
|
+
if (!this.conceptStore) {
|
|
836
|
+
throw new McpError(ErrorCode.InternalError, 'Concept store not initialized');
|
|
837
|
+
}
|
|
838
|
+
const concepts = this.conceptStore.search({ q: '*', k: 100 });
|
|
839
|
+
return {
|
|
840
|
+
contents: [{
|
|
841
|
+
uri,
|
|
842
|
+
mimeType: 'application/json',
|
|
843
|
+
text: JSON.stringify(concepts, null, 2)
|
|
844
|
+
}]
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
if (uri.includes('/memories')) {
|
|
848
|
+
const memories = this.memoryDb.search({ q: '*', k: 100 });
|
|
849
|
+
return {
|
|
850
|
+
contents: [{
|
|
851
|
+
uri,
|
|
852
|
+
mimeType: 'application/json',
|
|
853
|
+
text: JSON.stringify(memories, null, 2)
|
|
854
|
+
}]
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
858
|
+
}
|
|
859
|
+
catch (error) {
|
|
860
|
+
logger.error(`Resource error: ${error}`);
|
|
861
|
+
throw error;
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
async getSystemStatus() {
|
|
866
|
+
const status = {
|
|
867
|
+
version: '4.0.0',
|
|
868
|
+
timestamp: new Date().toISOString(),
|
|
869
|
+
activeProject: this.projectManager.getCurrentProject(),
|
|
870
|
+
components: {
|
|
871
|
+
memoryDb: !!this.memoryDb,
|
|
872
|
+
conceptStore: !!this.conceptStore,
|
|
873
|
+
contextBroker: !!this.contextBroker,
|
|
874
|
+
prdManager: !!this.prdManager,
|
|
875
|
+
promptManager: !!this.promptManager,
|
|
876
|
+
encryption: !!this.encryption,
|
|
877
|
+
dataRetention: !!this.dataRetention,
|
|
878
|
+
},
|
|
879
|
+
security: {
|
|
880
|
+
encryption: this.encryption ? 'AES-256-GCM' : 'disabled',
|
|
881
|
+
piiDetection: 'enabled',
|
|
882
|
+
dataRetention: this.dataRetention ? 'enabled' : 'disabled',
|
|
883
|
+
},
|
|
884
|
+
environment: {
|
|
885
|
+
nodeVersion: process.version,
|
|
886
|
+
platform: process.platform,
|
|
887
|
+
cwd: process.cwd(),
|
|
888
|
+
kratosProjectRoot: process.env.KRATOS_PROJECT_ROOT,
|
|
889
|
+
kratosActiveProject: process.env.KRATOS_ACTIVE_PROJECT,
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
if (this.memoryDb) {
|
|
893
|
+
const recentMemories = this.memoryDb.getRecent({ k: 5 });
|
|
894
|
+
status.stats = {
|
|
895
|
+
recentMemoryCount: recentMemories.length,
|
|
896
|
+
lastMemoryCreated: recentMemories[0]?.created_at || null,
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
if (this.dataRetention) {
|
|
900
|
+
status.retentionStats = this.dataRetention.getStats();
|
|
901
|
+
}
|
|
902
|
+
return status;
|
|
903
|
+
}
|
|
904
|
+
async run() {
|
|
905
|
+
const transport = new StdioServerTransport();
|
|
906
|
+
await this.server.connect(transport);
|
|
907
|
+
logger.info(chalk.green('š± Kratos Protocol - Production Edition'));
|
|
908
|
+
logger.info(chalk.blue('⨠SQLite + FTS5 | Concepts | Budget Control | Leak Protection'));
|
|
909
|
+
// Initialize project if available
|
|
910
|
+
await this.initializeProject();
|
|
911
|
+
const activeProject = this.projectManager.getCurrentProject();
|
|
912
|
+
if (activeProject) {
|
|
913
|
+
logger.info(chalk.yellow(`š Active: ${activeProject.name} (${activeProject.id})`));
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
logger.info(chalk.gray('š No active project - set KRATOS_ACTIVE_PROJECT to enable all features'));
|
|
917
|
+
}
|
|
918
|
+
// Graceful shutdown
|
|
919
|
+
process.on('SIGINT', () => {
|
|
920
|
+
logger.info(chalk.yellow('\nš Shutting down...'));
|
|
921
|
+
this.memoryDb?.close();
|
|
922
|
+
this.contextBroker?.close();
|
|
923
|
+
this.conceptStore?.close();
|
|
924
|
+
this.dataRetention?.close();
|
|
925
|
+
process.exit(0);
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
// Export for testing
|
|
930
|
+
export { KratosProtocolServer };
|
|
931
|
+
// Run server if this is the main module
|
|
932
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
933
|
+
const server = new KratosProtocolServer();
|
|
934
|
+
server.run().catch((error) => {
|
|
935
|
+
logger.error('Failed to start server:', error);
|
|
936
|
+
process.exit(1);
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
//# sourceMappingURL=index.js.map
|