@a13xu/lucid 1.16.1 → 1.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/compression/semantic.js +5 -1
- package/build/guardian/checklist.d.ts +2 -1
- package/build/guardian/checklist.js +20 -1
- package/build/guardian/coding-rules.d.ts +2 -1
- package/build/guardian/coding-rules.js +20 -1
- package/build/index.js +491 -742
- package/build/tools/plan.js +2 -2
- package/package.json +3 -1
- package/skills/lucid-audit/SKILL.md +11 -0
- package/skills/lucid-context/SKILL.md +9 -0
- package/skills/lucid-plan/SKILL.md +9 -0
- package/skills/lucid-security/SKILL.md +9 -0
- package/skills/lucid-start/SKILL.md +9 -0
- package/skills/lucid-webdev/SKILL.md +14 -0
package/build/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
4
|
import { z } from "zod";
|
|
6
5
|
import { initDatabase, prepareStatements } from "./database.js";
|
|
7
6
|
import { guardRequest, guardOutput, configureGuard } from "./security/guard.js";
|
|
@@ -136,13 +135,12 @@ const stmts = prepareStatements(db);
|
|
|
136
135
|
// ---------------------------------------------------------------------------
|
|
137
136
|
const _appCfg = loadConfig();
|
|
138
137
|
configureGuard(_appCfg.security ?? {});
|
|
139
|
-
// Register Qdrant host in SSRF allowlist if configured
|
|
140
138
|
const _qdrantUrl = process.env["QDRANT_URL"] ?? _appCfg.qdrant?.url;
|
|
141
139
|
if (_qdrantUrl) {
|
|
142
140
|
try {
|
|
143
141
|
allowHost(_qdrantUrl);
|
|
144
142
|
}
|
|
145
|
-
catch { /* ignore
|
|
143
|
+
catch { /* ignore */ }
|
|
146
144
|
}
|
|
147
145
|
const _embeddingUrl = process.env["EMBEDDING_URL"] ?? _appCfg.qdrant?.embeddingUrl;
|
|
148
146
|
if (_embeddingUrl) {
|
|
@@ -152,755 +150,506 @@ if (_embeddingUrl) {
|
|
|
152
150
|
catch { /* ignore */ }
|
|
153
151
|
}
|
|
154
152
|
else {
|
|
155
|
-
// Default embedding endpoint
|
|
156
153
|
allowHost("https://api.openai.com");
|
|
157
154
|
}
|
|
158
155
|
// ---------------------------------------------------------------------------
|
|
159
|
-
// MCP Server
|
|
160
|
-
// ---------------------------------------------------------------------------
|
|
161
|
-
const server = new Server({ name: "lucid", version: "1.13.0" }, { capabilities: { tools: {} } });
|
|
162
|
-
// ---------------------------------------------------------------------------
|
|
163
|
-
// Tool definitions
|
|
164
|
-
// ---------------------------------------------------------------------------
|
|
165
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
166
|
-
tools: [
|
|
167
|
-
// ── Memory ──────────────────────────────────────────────────────────────
|
|
168
|
-
{
|
|
169
|
-
name: "remember",
|
|
170
|
-
description: "Store a fact, decision, or observation about an entity in the knowledge graph.",
|
|
171
|
-
inputSchema: {
|
|
172
|
-
type: "object",
|
|
173
|
-
properties: {
|
|
174
|
-
entity: { type: "string", description: "Entity name (project, person, concept, tool)" },
|
|
175
|
-
entityType: {
|
|
176
|
-
type: "string",
|
|
177
|
-
enum: ["person", "project", "decision", "pattern", "tool", "config", "bug", "convention"],
|
|
178
|
-
},
|
|
179
|
-
observation: { type: "string", description: "The fact to remember" },
|
|
180
|
-
},
|
|
181
|
-
required: ["entity", "entityType", "observation"],
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
name: "relate",
|
|
186
|
-
description: "Create a directed relationship between two entities in the knowledge graph.",
|
|
187
|
-
inputSchema: {
|
|
188
|
-
type: "object",
|
|
189
|
-
properties: {
|
|
190
|
-
from: { type: "string", description: "Source entity name" },
|
|
191
|
-
to: { type: "string", description: "Target entity name" },
|
|
192
|
-
relationType: {
|
|
193
|
-
type: "string",
|
|
194
|
-
enum: ["uses", "depends_on", "created_by", "part_of", "replaced_by", "conflicts_with", "tested_by"],
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
required: ["from", "to", "relationType"],
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
name: "recall",
|
|
202
|
-
description: "Search memory using full-text search. Fast, indexed, supports partial matches and stemming.",
|
|
203
|
-
inputSchema: {
|
|
204
|
-
type: "object",
|
|
205
|
-
properties: {
|
|
206
|
-
query: { type: "string", description: "Search terms" },
|
|
207
|
-
},
|
|
208
|
-
required: ["query"],
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
name: "recall_all",
|
|
213
|
-
description: "Get the entire knowledge graph with statistics.",
|
|
214
|
-
inputSchema: { type: "object", properties: {} },
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
name: "forget",
|
|
218
|
-
description: "Remove an entity and all its relations from memory.",
|
|
219
|
-
inputSchema: {
|
|
220
|
-
type: "object",
|
|
221
|
-
properties: {
|
|
222
|
-
entity: { type: "string", description: "Entity name to remove" },
|
|
223
|
-
},
|
|
224
|
-
required: ["entity"],
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
name: "memory_stats",
|
|
229
|
-
description: "Get memory usage statistics.",
|
|
230
|
-
inputSchema: { type: "object", properties: {} },
|
|
231
|
-
},
|
|
232
|
-
// ── Init / Indexing ──────────────────────────────────────────────────────
|
|
233
|
-
{
|
|
234
|
-
name: "init_project",
|
|
235
|
-
description: "Scan and index a project directory into the knowledge graph. " +
|
|
236
|
-
"Reads CLAUDE.md (directives, conventions), package.json / pyproject.toml (dependencies, scripts), " +
|
|
237
|
-
"README.md (description), .mcp.json (MCP servers), logic-guardian.yaml (drift patterns), " +
|
|
238
|
-
"and source files (exported functions/classes). " +
|
|
239
|
-
"Call this once when starting work on a project to bootstrap memory with project context.",
|
|
240
|
-
inputSchema: {
|
|
241
|
-
type: "object",
|
|
242
|
-
properties: {
|
|
243
|
-
directory: {
|
|
244
|
-
type: "string",
|
|
245
|
-
description: "Absolute path to the project root. Defaults to current working directory.",
|
|
246
|
-
},
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
name: "sync_file",
|
|
252
|
-
description: "Index or re-index a single source file after it was written or modified. " +
|
|
253
|
-
"Extracts exports, description, and open TODOs, then updates the knowledge graph. " +
|
|
254
|
-
"IMPORTANT: call this automatically after every Write or Edit tool call.",
|
|
255
|
-
inputSchema: {
|
|
256
|
-
type: "object",
|
|
257
|
-
properties: {
|
|
258
|
-
path: { type: "string", description: "Absolute or relative path to the modified file." },
|
|
259
|
-
},
|
|
260
|
-
required: ["path"],
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
name: "sync_project",
|
|
265
|
-
description: "Re-index the entire project directory incrementally. " +
|
|
266
|
-
"Use this when multiple files have changed (e.g. after a refactor or git pull).",
|
|
267
|
-
inputSchema: {
|
|
268
|
-
type: "object",
|
|
269
|
-
properties: {
|
|
270
|
-
directory: {
|
|
271
|
-
type: "string",
|
|
272
|
-
description: "Project root directory. Defaults to current working directory.",
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
name: "grep_code",
|
|
279
|
-
description: "Search indexed source files using a regex pattern. " +
|
|
280
|
-
"Decompresses stored binary content and returns only matching lines with context. " +
|
|
281
|
-
"Token-efficient: returns ~20-50 tokens instead of full file contents. " +
|
|
282
|
-
"Useful for finding function calls, variable usages, import patterns.",
|
|
283
|
-
inputSchema: {
|
|
284
|
-
type: "object",
|
|
285
|
-
properties: {
|
|
286
|
-
pattern: { type: "string", description: "Regex pattern to search for." },
|
|
287
|
-
language: { type: "string", enum: ["python", "javascript", "typescript", "vue", "generic"], description: "Filter by language." },
|
|
288
|
-
context: { type: "number", description: "Lines of context before/after each match (0-10, default 2)." },
|
|
289
|
-
},
|
|
290
|
-
required: ["pattern"],
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
// ── Context & Token Optimization ─────────────────────────────────────────
|
|
294
|
-
{
|
|
295
|
-
name: "get_context",
|
|
296
|
-
description: "Retrieve the minimal relevant context for a task or query. " +
|
|
297
|
-
"Uses TF-IDF scoring (or Qdrant vector search if configured) to rank files by relevance, " +
|
|
298
|
-
"applies recency boost for recently modified files, and returns skeletons (signatures only) " +
|
|
299
|
-
"for large files to stay within the token budget. " +
|
|
300
|
-
"Configure limits in lucid.config.json. Set QDRANT_URL env var for vector search.",
|
|
301
|
-
inputSchema: {
|
|
302
|
-
type: "object",
|
|
303
|
-
properties: {
|
|
304
|
-
query: { type: "string", description: "What you are working on or searching for" },
|
|
305
|
-
maxTokens: { type: "number", description: "Total token budget (default 4000)" },
|
|
306
|
-
dirs: { type: "array", items: { type: "string" }, description: "Whitelist directories (e.g. [\"src\", \"backend\"])" },
|
|
307
|
-
recentOnly: { type: "boolean", description: "Only files modified within recentWindowHours" },
|
|
308
|
-
recentHours: { type: "number", description: "Override recent window (hours)" },
|
|
309
|
-
skeletonOnly: { type: "boolean", description: "Always show skeleton (signatures only)" },
|
|
310
|
-
topK: { type: "number", description: "Max files to consider (default 10)" },
|
|
311
|
-
},
|
|
312
|
-
required: ["query"],
|
|
313
|
-
},
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
name: "get_recent",
|
|
317
|
-
description: "Return files modified recently with line-level diffs. " +
|
|
318
|
-
"Shows what changed in each file since the previous sync. " +
|
|
319
|
-
"Useful for catching up after a git pull or resuming a session.",
|
|
320
|
-
inputSchema: {
|
|
321
|
-
type: "object",
|
|
322
|
-
properties: {
|
|
323
|
-
hours: { type: "number", description: "Look back N hours (default 24)" },
|
|
324
|
-
withDiffs: { type: "boolean", description: "Include line diffs (default true)" },
|
|
325
|
-
},
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
// ── Smart Context + Model Advisor ─────────────────────────────────────────
|
|
329
|
-
{
|
|
330
|
-
name: "smart_context",
|
|
331
|
-
description: "Combined: knowledge graph (recall) + code files (get_context) in one call. " +
|
|
332
|
-
"Use instead of calling recall() + get_context() separately. " +
|
|
333
|
-
"task_type adjusts token budget: simple=2000, moderate=6000, complex=12000. " +
|
|
334
|
-
"Logs an experience so reward()/penalize() work after this call.",
|
|
335
|
-
inputSchema: {
|
|
336
|
-
type: "object",
|
|
337
|
-
properties: {
|
|
338
|
-
query: { type: "string", description: "What you are working on" },
|
|
339
|
-
task_type: {
|
|
340
|
-
type: "string",
|
|
341
|
-
enum: ["simple", "moderate", "complex"],
|
|
342
|
-
description: "Token budget: simple=2000, moderate=6000 (default), complex=12000",
|
|
343
|
-
},
|
|
344
|
-
dirs: {
|
|
345
|
-
type: "array",
|
|
346
|
-
items: { type: "string" },
|
|
347
|
-
description: "Whitelist directories (e.g. [\"src\", \"backend\"])",
|
|
348
|
-
},
|
|
349
|
-
},
|
|
350
|
-
required: ["query"],
|
|
351
|
-
},
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
name: "suggest_model",
|
|
355
|
-
description: "Classify task complexity → recommend Claude model. " +
|
|
356
|
-
"Returns { model, model_id, reasoning, context_budget }. " +
|
|
357
|
-
"Call at the start of any workflow. Simple lookups → Haiku; everything else → Sonnet (default).",
|
|
358
|
-
inputSchema: {
|
|
359
|
-
type: "object",
|
|
360
|
-
properties: {
|
|
361
|
-
task_description: {
|
|
362
|
-
type: "string",
|
|
363
|
-
description: "Natural language description of the task you are about to perform",
|
|
364
|
-
},
|
|
365
|
-
},
|
|
366
|
-
required: ["task_description"],
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
name: "compress_text",
|
|
371
|
-
description: "Compress text using LLMLingua-2 semantic compression (microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank). " +
|
|
372
|
-
"Identifies and drops semantically unimportant tokens while preserving meaning. " +
|
|
373
|
-
"Model downloads ~700MB on first use and is cached in ~/.lucid/models/. " +
|
|
374
|
-
"Returns compressed text with stats (original/compressed length, ratio, tokens saved).",
|
|
375
|
-
inputSchema: {
|
|
376
|
-
type: "object",
|
|
377
|
-
properties: {
|
|
378
|
-
text: { type: "string", description: "Text to compress" },
|
|
379
|
-
ratio: {
|
|
380
|
-
type: "number",
|
|
381
|
-
description: "Target compression ratio: 0.3 = keep 30%, 0.5 = keep 50% (default: 0.5)",
|
|
382
|
-
},
|
|
383
|
-
min_length: {
|
|
384
|
-
type: "number",
|
|
385
|
-
description: "Skip compression for texts shorter than this in chars (default: 300)",
|
|
386
|
-
},
|
|
387
|
-
},
|
|
388
|
-
required: ["text"],
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
// ── Reward System ────────────────────────────────────────────────────────
|
|
392
|
-
{
|
|
393
|
-
name: "reward",
|
|
394
|
-
description: "Signal that the last get_context() result was helpful (+1 reward). " +
|
|
395
|
-
"The files returned in that context will be ranked higher in future similar queries. " +
|
|
396
|
-
"Call this after a get_context() result led to a correct fix or useful code.",
|
|
397
|
-
inputSchema: {
|
|
398
|
-
type: "object",
|
|
399
|
-
properties: {
|
|
400
|
-
note: { type: "string", description: "Optional note about what worked (stored for future reference)" },
|
|
401
|
-
},
|
|
402
|
-
},
|
|
403
|
-
},
|
|
404
|
-
{
|
|
405
|
-
name: "penalize",
|
|
406
|
-
description: "Signal that the last get_context() result was unhelpful (-1 reward). " +
|
|
407
|
-
"The files returned in that context will be ranked lower in future similar queries. " +
|
|
408
|
-
"Call this after a get_context() result missed important files or was irrelevant.",
|
|
409
|
-
inputSchema: {
|
|
410
|
-
type: "object",
|
|
411
|
-
properties: {
|
|
412
|
-
note: { type: "string", description: "Optional note about what was missing or wrong" },
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
name: "show_rewards",
|
|
418
|
-
description: "Show the top rewarded experiences and most rewarded files. " +
|
|
419
|
-
"Rewards decay exponentially (half-life ~14 days). " +
|
|
420
|
-
"Use this to understand which context queries and files have been most valuable.",
|
|
421
|
-
inputSchema: {
|
|
422
|
-
type: "object",
|
|
423
|
-
properties: {
|
|
424
|
-
query: { type: "string", description: "Filter experiences by query text (optional)" },
|
|
425
|
-
topK: { type: "number", description: "Number of top results to show (default 10)" },
|
|
426
|
-
},
|
|
427
|
-
},
|
|
428
|
-
},
|
|
429
|
-
// ── Logic Guardian ───────────────────────────────────────────────────────
|
|
430
|
-
{
|
|
431
|
-
name: "validate_file",
|
|
432
|
-
description: "Run Logic Guardian validation on a source file. Detects LLM drift patterns: " +
|
|
433
|
-
"logic inversions, null propagation, type confusion, copy-paste drift, silent exceptions, and more. " +
|
|
434
|
-
"Supports Python, JavaScript, TypeScript. Use after writing or modifying any code.",
|
|
435
|
-
inputSchema: {
|
|
436
|
-
type: "object",
|
|
437
|
-
properties: {
|
|
438
|
-
path: { type: "string", description: "Absolute or relative path to the file to validate." },
|
|
439
|
-
},
|
|
440
|
-
required: ["path"],
|
|
441
|
-
},
|
|
442
|
-
},
|
|
443
|
-
{
|
|
444
|
-
name: "check_drift",
|
|
445
|
-
description: "Analyze a code snippet for LLM drift patterns without saving to disk. " +
|
|
446
|
-
"Use this to validate code before writing it to a file.",
|
|
447
|
-
inputSchema: {
|
|
448
|
-
type: "object",
|
|
449
|
-
properties: {
|
|
450
|
-
code: { type: "string", description: "The code snippet to analyze." },
|
|
451
|
-
language: {
|
|
452
|
-
type: "string",
|
|
453
|
-
enum: ["python", "javascript", "typescript", "generic"],
|
|
454
|
-
description: "Programming language. Defaults to 'generic'.",
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
required: ["code"],
|
|
458
|
-
},
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
name: "get_checklist",
|
|
462
|
-
description: "Get the full Logic Guardian validation checklist (5 passes). " +
|
|
463
|
-
"Call this before marking any implementation task as done.",
|
|
464
|
-
inputSchema: { type: "object", properties: {} },
|
|
465
|
-
},
|
|
466
|
-
// ── Coding Guard ─────────────────────────────────────────────────────────
|
|
467
|
-
{
|
|
468
|
-
name: "coding_rules",
|
|
469
|
-
description: "Get the 25 Golden Rules coding checklist. Covers clarity, naming, single responsibility, " +
|
|
470
|
-
"error handling, frontend component size/reuse/props, singleton rules, library selection, " +
|
|
471
|
-
"and architecture separation. Review before marking any task done.",
|
|
472
|
-
inputSchema: { type: "object", properties: {} },
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
name: "check_code_quality",
|
|
476
|
-
description: "Analyze a file or code snippet against the 25 Golden Rules. " +
|
|
477
|
-
"Detects: file/function size violations, vague naming, deep nesting, dead code, and — " +
|
|
478
|
-
"for React/Vue component files — inline styles, prop explosion, fetch-in-component, " +
|
|
479
|
-
"direct DOM access, mixed styling systems. " +
|
|
480
|
-
"Complements validate_file (which checks logic correctness).",
|
|
481
|
-
inputSchema: {
|
|
482
|
-
type: "object",
|
|
483
|
-
properties: {
|
|
484
|
-
path: { type: "string", description: "Absolute or relative path to the file to analyze." },
|
|
485
|
-
code: { type: "string", description: "Code snippet to analyze inline." },
|
|
486
|
-
language: {
|
|
487
|
-
type: "string",
|
|
488
|
-
enum: ["python", "javascript", "typescript", "vue", "generic"],
|
|
489
|
-
description: "Language hint. Auto-detected from file extension if path is provided.",
|
|
490
|
-
},
|
|
491
|
-
},
|
|
492
|
-
},
|
|
493
|
-
},
|
|
494
|
-
// ── Planning ─────────────────────────────────────────────────────────────
|
|
495
|
-
{
|
|
496
|
-
name: "plan_create",
|
|
497
|
-
description: "Create a plan with user story, ordered tasks, and test criteria. " +
|
|
498
|
-
"Call BEFORE writing any code to establish intent and acceptance criteria.",
|
|
499
|
-
inputSchema: {
|
|
500
|
-
type: "object",
|
|
501
|
-
properties: {
|
|
502
|
-
title: { type: "string", description: "Short plan title." },
|
|
503
|
-
description: { type: "string", description: "What this plan accomplishes." },
|
|
504
|
-
user_story: { type: "string", description: "As a [user], I want [goal], so that [benefit]." },
|
|
505
|
-
tasks: {
|
|
506
|
-
type: "array",
|
|
507
|
-
description: "Ordered list of implementation tasks (1–20).",
|
|
508
|
-
items: {
|
|
509
|
-
type: "object",
|
|
510
|
-
properties: {
|
|
511
|
-
title: { type: "string" },
|
|
512
|
-
description: { type: "string" },
|
|
513
|
-
test_criteria: { type: "string", description: "How to verify this task is done." },
|
|
514
|
-
},
|
|
515
|
-
required: ["title", "description", "test_criteria"],
|
|
516
|
-
},
|
|
517
|
-
minItems: 1,
|
|
518
|
-
maxItems: 20,
|
|
519
|
-
},
|
|
520
|
-
},
|
|
521
|
-
required: ["title", "description", "user_story", "tasks"],
|
|
522
|
-
},
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
name: "plan_list",
|
|
526
|
-
description: "List plans with progress summary. Defaults to active plans.",
|
|
527
|
-
inputSchema: {
|
|
528
|
-
type: "object",
|
|
529
|
-
properties: {
|
|
530
|
-
status: {
|
|
531
|
-
type: "string",
|
|
532
|
-
enum: ["active", "completed", "abandoned", "all"],
|
|
533
|
-
description: "Filter by plan status (default: active).",
|
|
534
|
-
},
|
|
535
|
-
},
|
|
536
|
-
},
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
name: "plan_get",
|
|
540
|
-
description: "Get full plan details: tasks, test criteria, status, and notes.",
|
|
541
|
-
inputSchema: {
|
|
542
|
-
type: "object",
|
|
543
|
-
properties: {
|
|
544
|
-
plan_id: { type: "number", description: "Plan ID from plan_create or plan_list." },
|
|
545
|
-
},
|
|
546
|
-
required: ["plan_id"],
|
|
547
|
-
},
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
name: "plan_update_task",
|
|
551
|
-
description: "Update a task status. Auto-completes the plan when all tasks are done. " +
|
|
552
|
-
"Statuses: pending → in_progress → done (or blocked).",
|
|
553
|
-
inputSchema: {
|
|
554
|
-
type: "object",
|
|
555
|
-
properties: {
|
|
556
|
-
task_id: { type: "number", description: "Task ID from plan_get." },
|
|
557
|
-
status: { type: "string", enum: ["pending", "in_progress", "done", "blocked"] },
|
|
558
|
-
note: { type: "string", description: "Optional note appended to task history." },
|
|
559
|
-
},
|
|
560
|
-
required: ["task_id", "status"],
|
|
561
|
-
},
|
|
562
|
-
},
|
|
563
|
-
// ── Updater ──────────────────────────────────────────────────────────────
|
|
564
|
-
{
|
|
565
|
-
name: "update_lucid",
|
|
566
|
-
description: "Check for a newer version of Lucid on npm and update automatically. " +
|
|
567
|
-
"For global npm installs: runs npm install -g @a13xu/lucid@latest. " +
|
|
568
|
-
"For local source installs: shows git pull + npm run build instructions. " +
|
|
569
|
-
"After updating, restart Claude Code to load the new version.",
|
|
570
|
-
inputSchema: {
|
|
571
|
-
type: "object",
|
|
572
|
-
properties: {
|
|
573
|
-
force: {
|
|
574
|
-
type: "boolean",
|
|
575
|
-
description: "Force reinstall even if already on latest version (default false)",
|
|
576
|
-
},
|
|
577
|
-
},
|
|
578
|
-
},
|
|
579
|
-
},
|
|
580
|
-
// ── Web Dev Skills ───────────────────────────────────────────────────────
|
|
581
|
-
{
|
|
582
|
-
name: "generate_component",
|
|
583
|
-
description: "Generate a complete component scaffold from a natural language description. " +
|
|
584
|
-
"Supports React (TSX/JSX) and Vue/Nuxt (Composition API + <script setup>). " +
|
|
585
|
-
"Styling options: Tailwind CSS, CSS Modules, or none.",
|
|
586
|
-
inputSchema: {
|
|
587
|
-
type: "object",
|
|
588
|
-
properties: {
|
|
589
|
-
description: { type: "string", description: "Natural language description of the component" },
|
|
590
|
-
framework: { type: "string", enum: ["react", "vue", "nuxt"], description: "Target framework" },
|
|
591
|
-
styling: { type: "string", enum: ["tailwind", "css-modules", "none"], description: "Styling approach" },
|
|
592
|
-
typescript: { type: "boolean", description: "Whether to use TypeScript" },
|
|
593
|
-
},
|
|
594
|
-
required: ["description", "framework", "styling", "typescript"],
|
|
595
|
-
},
|
|
596
|
-
},
|
|
597
|
-
{
|
|
598
|
-
name: "scaffold_page",
|
|
599
|
-
description: "Generate a full page scaffold with layout, SEO head meta, and placeholder sections. " +
|
|
600
|
-
"Supports Nuxt (useHead), Next.js (Metadata API), and plain Vue.",
|
|
601
|
-
inputSchema: {
|
|
602
|
-
type: "object",
|
|
603
|
-
properties: {
|
|
604
|
-
page_name: { type: "string", description: "Page name (e.g. About, Dashboard)" },
|
|
605
|
-
framework: { type: "string", enum: ["nuxt", "next", "vue"], description: "Target framework" },
|
|
606
|
-
sections: { type: "array", items: { type: "string" }, description: "Section names (e.g. hero, features, footer)" },
|
|
607
|
-
seo_title: { type: "string", description: "Optional SEO title" },
|
|
608
|
-
},
|
|
609
|
-
required: ["page_name", "framework", "sections"],
|
|
610
|
-
},
|
|
611
|
-
},
|
|
612
|
-
{
|
|
613
|
-
name: "seo_meta",
|
|
614
|
-
description: "Generate complete SEO metadata for a page: HTML meta tags, Open Graph, Twitter Card, " +
|
|
615
|
-
"and JSON-LD structured data (Article, Product, WebSite, or WebPage).",
|
|
616
|
-
inputSchema: {
|
|
617
|
-
type: "object",
|
|
618
|
-
properties: {
|
|
619
|
-
title: { type: "string", description: "Page title" },
|
|
620
|
-
description: { type: "string", description: "Meta description (≤160 chars recommended)" },
|
|
621
|
-
keywords: { type: "array", items: { type: "string" }, description: "SEO keywords" },
|
|
622
|
-
page_type: { type: "string", enum: ["article", "product", "landing", "home"], description: "Page type for JSON-LD" },
|
|
623
|
-
url: { type: "string", description: "Canonical page URL" },
|
|
624
|
-
image_url: { type: "string", description: "OG/Twitter image URL" },
|
|
625
|
-
},
|
|
626
|
-
required: ["title", "description", "keywords", "page_type"],
|
|
627
|
-
},
|
|
628
|
-
},
|
|
629
|
-
{
|
|
630
|
-
name: "accessibility_audit",
|
|
631
|
-
description: "Audit HTML, JSX, or Vue template snippets for WCAG accessibility violations. " +
|
|
632
|
-
"Checks: missing alt text, unlabeled inputs, empty buttons/links, positive tabindex, " +
|
|
633
|
-
"non-interactive click handlers, open-in-new-tab links, and more. " +
|
|
634
|
-
"Returns severity (critical/warning/info), WCAG criterion, and corrected code.",
|
|
635
|
-
inputSchema: {
|
|
636
|
-
type: "object",
|
|
637
|
-
properties: {
|
|
638
|
-
code: { type: "string", description: "HTML, JSX, or Vue snippet to audit" },
|
|
639
|
-
wcag_level: { type: "string", enum: ["A", "AA", "AAA"], description: "WCAG conformance level" },
|
|
640
|
-
framework: { type: "string", enum: ["html", "jsx", "vue"], description: "Code framework" },
|
|
641
|
-
},
|
|
642
|
-
required: ["code", "wcag_level", "framework"],
|
|
643
|
-
},
|
|
644
|
-
},
|
|
645
|
-
{
|
|
646
|
-
name: "api_client",
|
|
647
|
-
description: "Generate a typed TypeScript async function for a REST API endpoint. " +
|
|
648
|
-
"Includes full types, error handling (throws on non-2xx), and a usage example. " +
|
|
649
|
-
"Auth strategies: Bearer token, cookie, API key, or none.",
|
|
650
|
-
inputSchema: {
|
|
651
|
-
type: "object",
|
|
652
|
-
properties: {
|
|
653
|
-
endpoint: { type: "string", description: "API endpoint path (e.g. /users/:id)" },
|
|
654
|
-
method: { type: "string", enum: ["GET", "POST", "PUT", "PATCH", "DELETE"] },
|
|
655
|
-
request_schema: { type: "string", description: "TypeScript type for request body" },
|
|
656
|
-
response_schema: { type: "string", description: "TypeScript type for response" },
|
|
657
|
-
auth: { type: "string", enum: ["bearer", "cookie", "apikey", "none"] },
|
|
658
|
-
base_url_var: { type: "string", description: "Env var name for base URL (e.g. NEXT_PUBLIC_API_URL)" },
|
|
659
|
-
},
|
|
660
|
-
required: ["endpoint", "method", "auth"],
|
|
661
|
-
},
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
name: "test_generator",
|
|
665
|
-
description: "Generate a complete test file for a function, component, or API handler. " +
|
|
666
|
-
"Covers: happy path, edge cases (empty/null/boundary), error path, and mock setup. " +
|
|
667
|
-
"Frameworks: Vitest, Jest, or Playwright (e2e). " +
|
|
668
|
-
"Component testing: Vue Test Utils or React Testing Library.",
|
|
669
|
-
inputSchema: {
|
|
670
|
-
type: "object",
|
|
671
|
-
properties: {
|
|
672
|
-
code: { type: "string", description: "Source code to generate tests for" },
|
|
673
|
-
test_framework: { type: "string", enum: ["vitest", "jest", "playwright"] },
|
|
674
|
-
test_type: { type: "string", enum: ["unit", "integration", "e2e"] },
|
|
675
|
-
component_framework: { type: "string", enum: ["vue", "react", "none"] },
|
|
676
|
-
},
|
|
677
|
-
required: ["code", "test_framework", "test_type"],
|
|
678
|
-
},
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
name: "responsive_layout",
|
|
682
|
-
description: "Generate a responsive mobile-first layout from a wireframe description. " +
|
|
683
|
-
"Outputs: Tailwind CSS utility classes, CSS Grid with named areas, or Flexbox with media queries. " +
|
|
684
|
-
"Container types: full-width, centered max-width, or sidebar layout.",
|
|
685
|
-
inputSchema: {
|
|
686
|
-
type: "object",
|
|
687
|
-
properties: {
|
|
688
|
-
description: { type: "string", description: "Wireframe description (e.g. 'sidebar + main + right panel')" },
|
|
689
|
-
framework: { type: "string", enum: ["tailwind", "css-grid", "flexbox"] },
|
|
690
|
-
breakpoints: { type: "array", items: { type: "string" }, description: "Breakpoint names (e.g. ['mobile', 'tablet', 'desktop'])" },
|
|
691
|
-
container: { type: "string", enum: ["full", "centered", "sidebar"] },
|
|
692
|
-
},
|
|
693
|
-
required: ["description", "framework", "breakpoints"],
|
|
694
|
-
},
|
|
695
|
-
},
|
|
696
|
-
{
|
|
697
|
-
name: "security_scan",
|
|
698
|
-
description: "Scan JavaScript/TypeScript/HTML/Vue code for common web security vulnerabilities. " +
|
|
699
|
-
"Detects: XSS (innerHTML, v-html, dangerouslySetInnerHTML), code injection (eval, new Function), " +
|
|
700
|
-
"SQL injection, hardcoded secrets, open redirects, prototype pollution, path traversal, " +
|
|
701
|
-
"render-blocking scripts, and insecure CORS. Context-aware: frontend vs backend vs API rules. " +
|
|
702
|
-
"Complements validate_file (logic drift) — this focuses on web security patterns.",
|
|
703
|
-
inputSchema: {
|
|
704
|
-
type: "object",
|
|
705
|
-
properties: {
|
|
706
|
-
code: { type: "string", description: "Code snippet to scan" },
|
|
707
|
-
language: { type: "string", enum: ["javascript", "typescript", "html", "vue"] },
|
|
708
|
-
context: { type: "string", enum: ["frontend", "backend", "api"] },
|
|
709
|
-
},
|
|
710
|
-
required: ["code", "language", "context"],
|
|
711
|
-
},
|
|
712
|
-
},
|
|
713
|
-
{
|
|
714
|
-
name: "design_tokens",
|
|
715
|
-
description: "Generate a complete design system token set from a brand color and mood. " +
|
|
716
|
-
"Produces: 11-step color scales (50–950), neutral scale, semantic color aliases, " +
|
|
717
|
-
"typography scale, spacing, border-radius, and shadow tokens. " +
|
|
718
|
-
"Output formats: CSS custom properties, Tailwind config, or JSON.",
|
|
719
|
-
inputSchema: {
|
|
720
|
-
type: "object",
|
|
721
|
-
properties: {
|
|
722
|
-
brand_name: { type: "string", description: "Brand or project name" },
|
|
723
|
-
primary_color: { type: "string", description: "Primary color as hex (#3B82F6) or name (blue)" },
|
|
724
|
-
mood: { type: "string", enum: ["minimal", "bold", "playful", "corporate"] },
|
|
725
|
-
output_format: { type: "string", enum: ["css-variables", "tailwind-config", "json"] },
|
|
726
|
-
},
|
|
727
|
-
required: ["brand_name", "primary_color", "mood", "output_format"],
|
|
728
|
-
},
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
name: "perf_hints",
|
|
732
|
-
description: "Analyze a component or page file for Core Web Vitals (CWV) and web performance issues. " +
|
|
733
|
-
"Detects: missing LCP image priority, images without dimensions (CLS), render-blocking scripts, " +
|
|
734
|
-
"fetch-in-render (TTFB), heavy click handlers (INP), missing useMemo/computed, " +
|
|
735
|
-
"whole-library imports, and inline style objects. Issues ranked by CWV metric impact.",
|
|
736
|
-
inputSchema: {
|
|
737
|
-
type: "object",
|
|
738
|
-
properties: {
|
|
739
|
-
code: { type: "string", description: "Component or page source code to analyze" },
|
|
740
|
-
framework: { type: "string", enum: ["react", "vue", "nuxt", "vanilla"] },
|
|
741
|
-
context: { type: "string", enum: ["component", "page", "layout"] },
|
|
742
|
-
},
|
|
743
|
-
required: ["code", "framework", "context"],
|
|
744
|
-
},
|
|
745
|
-
},
|
|
746
|
-
],
|
|
747
|
-
}));
|
|
748
|
-
// ---------------------------------------------------------------------------
|
|
749
|
-
// Tool handlers
|
|
156
|
+
// MCP Server (high-level McpServer API, SDK 1.27+)
|
|
750
157
|
// ---------------------------------------------------------------------------
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
break;
|
|
801
|
-
// Smart Context + Model Advisor
|
|
802
|
-
case "smart_context":
|
|
803
|
-
text = await handleSmartContext(stmts, SmartContextSchema.parse(args));
|
|
804
|
-
break;
|
|
805
|
-
case "suggest_model":
|
|
806
|
-
text = handleSuggestModel(SuggestModelSchema.parse(args));
|
|
807
|
-
break;
|
|
808
|
-
case "compress_text":
|
|
809
|
-
text = await handleCompressText(CompressTextSchema.parse(args));
|
|
810
|
-
break;
|
|
811
|
-
// Reward System
|
|
812
|
-
case "reward":
|
|
813
|
-
text = handleReward(stmts, RewardSchema.parse(args));
|
|
814
|
-
break;
|
|
815
|
-
case "penalize":
|
|
816
|
-
text = handlePenalize(stmts, PenalizeSchema.parse(args));
|
|
817
|
-
break;
|
|
818
|
-
case "show_rewards":
|
|
819
|
-
text = handleShowRewards(stmts, ShowRewardsSchema.parse(args));
|
|
820
|
-
break;
|
|
821
|
-
// Logic Guardian
|
|
822
|
-
case "validate_file":
|
|
823
|
-
text = handleValidateFile(ValidateFileSchema.parse(args));
|
|
824
|
-
break;
|
|
825
|
-
case "check_drift":
|
|
826
|
-
text = handleCheckDrift(CheckDriftSchema.parse(args));
|
|
827
|
-
break;
|
|
828
|
-
case "get_checklist":
|
|
829
|
-
text = handleGetChecklist();
|
|
830
|
-
break;
|
|
831
|
-
// Coding Guard
|
|
832
|
-
case "coding_rules":
|
|
833
|
-
text = handleGetCodingRules();
|
|
834
|
-
break;
|
|
835
|
-
case "check_code_quality":
|
|
836
|
-
text = handleCheckCodeQuality(CheckCodeQualitySchema.parse(args));
|
|
837
|
-
break;
|
|
838
|
-
// Planning
|
|
839
|
-
case "plan_create":
|
|
840
|
-
text = handlePlanCreate(db, stmts, PlanCreateSchema.parse(args));
|
|
841
|
-
break;
|
|
842
|
-
case "plan_list":
|
|
843
|
-
text = handlePlanList(stmts, PlanListSchema.parse(args));
|
|
844
|
-
break;
|
|
845
|
-
case "plan_get":
|
|
846
|
-
text = handlePlanGet(stmts, PlanGetSchema.parse(args));
|
|
847
|
-
break;
|
|
848
|
-
case "plan_update_task":
|
|
849
|
-
text = handlePlanUpdateTask(stmts, PlanUpdateTaskSchema.parse(args));
|
|
850
|
-
break;
|
|
851
|
-
// Updater
|
|
852
|
-
case "update_lucid":
|
|
853
|
-
text = await handleUpdateLucid(UpdateLucidSchema.parse(args));
|
|
854
|
-
break;
|
|
855
|
-
// Web Dev Skills
|
|
856
|
-
case "generate_component":
|
|
857
|
-
text = handleGenerateComponent(GenerateComponentSchema.parse(args));
|
|
858
|
-
break;
|
|
859
|
-
case "scaffold_page":
|
|
860
|
-
text = handleScaffoldPage(ScaffoldPageSchema.parse(args));
|
|
861
|
-
break;
|
|
862
|
-
case "seo_meta":
|
|
863
|
-
text = handleSeoMeta(SeoMetaSchema.parse(args));
|
|
864
|
-
break;
|
|
865
|
-
case "accessibility_audit":
|
|
866
|
-
text = handleAccessibilityAudit(AccessibilityAuditSchema.parse(args));
|
|
867
|
-
break;
|
|
868
|
-
case "api_client":
|
|
869
|
-
text = handleApiClient(ApiClientSchema.parse(args));
|
|
870
|
-
break;
|
|
871
|
-
case "test_generator":
|
|
872
|
-
text = handleTestGenerator(TestGeneratorSchema.parse(args));
|
|
873
|
-
break;
|
|
874
|
-
case "responsive_layout":
|
|
875
|
-
text = handleResponsiveLayout(ResponsiveLayoutSchema.parse(args));
|
|
876
|
-
break;
|
|
877
|
-
case "security_scan":
|
|
878
|
-
text = handleSecurityScan(SecurityScanSchema.parse(args));
|
|
879
|
-
break;
|
|
880
|
-
case "design_tokens":
|
|
881
|
-
text = handleDesignTokens(DesignTokensSchema.parse(args));
|
|
882
|
-
break;
|
|
883
|
-
case "perf_hints":
|
|
884
|
-
text = handlePerfHints(PerfHintsSchema.parse(args));
|
|
885
|
-
break;
|
|
886
|
-
default:
|
|
887
|
-
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
158
|
+
const SERVER_VERSION = getCurrentVersion();
|
|
159
|
+
const server = new McpServer({ name: "lucid", version: SERVER_VERSION }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
|
|
160
|
+
function tx(name, handler) {
|
|
161
|
+
return async (args) => {
|
|
162
|
+
const guard = guardRequest(name, args);
|
|
163
|
+
if (guard.blocked) {
|
|
164
|
+
return {
|
|
165
|
+
content: [{ type: "text", text: guard.reason ?? "Request blocked by security guard" }],
|
|
166
|
+
isError: true,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const out = await handler(args);
|
|
171
|
+
if (typeof out === "string") {
|
|
172
|
+
return { content: [{ type: "text", text: guardOutput(name, out) }] };
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
content: [{ type: "text", text: guardOutput(name, out.text) }],
|
|
176
|
+
structuredContent: out.structured,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
const msg = err instanceof z.ZodError
|
|
181
|
+
? `Validation error: ${err.errors.map((e) => e.message).join(", ")}`
|
|
182
|
+
: err instanceof Error ? err.message : String(err);
|
|
183
|
+
return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// Helpers that produce both text + structured output for tools whose handlers
|
|
188
|
+
// already return JSON. Avoids touching downstream handler files.
|
|
189
|
+
const memoryStatsRich = () => {
|
|
190
|
+
const text = memoryStats(db, stmts);
|
|
191
|
+
return { text, structured: JSON.parse(text) };
|
|
192
|
+
};
|
|
193
|
+
const recallAllRich = () => {
|
|
194
|
+
const text = recallAll(db, stmts);
|
|
195
|
+
return { text, structured: JSON.parse(text) };
|
|
196
|
+
};
|
|
197
|
+
const recallRich = (args) => {
|
|
198
|
+
const text = recall(stmts, args);
|
|
199
|
+
// recall returns either "No results..." text or JSON array.
|
|
200
|
+
const trimmed = text.trim();
|
|
201
|
+
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
|
|
202
|
+
try {
|
|
203
|
+
return { text, structured: { entities: JSON.parse(text) } };
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return text;
|
|
888
207
|
}
|
|
889
|
-
// Security: scan output for sensitive data leakage
|
|
890
|
-
return { content: [{ type: "text", text: guardOutput(name, text) }] };
|
|
891
|
-
}
|
|
892
|
-
catch (err) {
|
|
893
|
-
const message = err instanceof z.ZodError
|
|
894
|
-
? `Validation error: ${err.errors.map((e) => e.message).join(", ")}`
|
|
895
|
-
: err instanceof Error ? err.message : String(err);
|
|
896
|
-
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
897
208
|
}
|
|
209
|
+
return text;
|
|
210
|
+
};
|
|
211
|
+
// Output schemas (Zod raw shapes) for structured-content tools
|
|
212
|
+
const memoryStatsOutputShape = {
|
|
213
|
+
entity_count: z.number().int(),
|
|
214
|
+
relation_count: z.number().int(),
|
|
215
|
+
observation_count: z.number().int(),
|
|
216
|
+
db_size_bytes: z.number().int(),
|
|
217
|
+
db_size_kb: z.number().int(),
|
|
218
|
+
wal_mode: z.boolean(),
|
|
219
|
+
fts5_enabled: z.boolean(),
|
|
220
|
+
};
|
|
221
|
+
const entityShape = {
|
|
222
|
+
id: z.number().int(),
|
|
223
|
+
name: z.string(),
|
|
224
|
+
type: z.string(),
|
|
225
|
+
observations: z.array(z.string()),
|
|
226
|
+
created_at: z.number(),
|
|
227
|
+
updated_at: z.number(),
|
|
228
|
+
relations: z.array(z.object({
|
|
229
|
+
from: z.string(), to: z.string(), type: z.string(),
|
|
230
|
+
})),
|
|
231
|
+
};
|
|
232
|
+
const recallAllOutputShape = {
|
|
233
|
+
stats: z.object(memoryStatsOutputShape),
|
|
234
|
+
entities: z.array(z.object(entityShape)),
|
|
235
|
+
};
|
|
236
|
+
const recallOutputShape = {
|
|
237
|
+
entities: z.array(z.object(entityShape)),
|
|
238
|
+
};
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// Tools — Memory
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
server.registerTool("remember", {
|
|
243
|
+
title: "Remember",
|
|
244
|
+
description: "Store a fact, decision, or observation about an entity in the knowledge graph.",
|
|
245
|
+
inputSchema: RememberSchema.shape,
|
|
246
|
+
}, tx("remember", (args) => remember(stmts, args)));
|
|
247
|
+
server.registerTool("relate", {
|
|
248
|
+
title: "Relate",
|
|
249
|
+
description: "Create a directed relationship between two entities in the knowledge graph.",
|
|
250
|
+
inputSchema: RelateSchema.shape,
|
|
251
|
+
}, tx("relate", (args) => relate(stmts, args)));
|
|
252
|
+
server.registerTool("recall", {
|
|
253
|
+
title: "Recall",
|
|
254
|
+
description: "Search memory using full-text search. Fast, indexed, supports partial matches and stemming.",
|
|
255
|
+
inputSchema: RecallSchema.shape,
|
|
256
|
+
outputSchema: recallOutputShape,
|
|
257
|
+
}, tx("recall", (args) => recallRich(args)));
|
|
258
|
+
server.registerTool("recall_all", {
|
|
259
|
+
title: "Recall All",
|
|
260
|
+
description: "Get the entire knowledge graph with statistics.",
|
|
261
|
+
outputSchema: recallAllOutputShape,
|
|
262
|
+
}, tx("recall_all", () => recallAllRich()));
|
|
263
|
+
server.registerTool("forget", {
|
|
264
|
+
title: "Forget",
|
|
265
|
+
description: "Remove an entity and all its relations from memory.",
|
|
266
|
+
inputSchema: ForgetSchema.shape,
|
|
267
|
+
}, tx("forget", (args) => forget(stmts, args)));
|
|
268
|
+
server.registerTool("memory_stats", {
|
|
269
|
+
title: "Memory Stats",
|
|
270
|
+
description: "Get memory usage statistics.",
|
|
271
|
+
outputSchema: memoryStatsOutputShape,
|
|
272
|
+
}, tx("memory_stats", () => memoryStatsRich()));
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
// Tools — Init / Indexing
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
server.registerTool("init_project", {
|
|
277
|
+
title: "Init Project",
|
|
278
|
+
description: "Scan and index a project directory into the knowledge graph. " +
|
|
279
|
+
"Reads CLAUDE.md, package.json/pyproject.toml, README.md, .mcp.json, logic-guardian.yaml, " +
|
|
280
|
+
"and source files (exported functions/classes). Call once when starting work on a project.",
|
|
281
|
+
inputSchema: InitProjectSchema.shape,
|
|
282
|
+
}, tx("init_project", async (args) => handleInitProject(stmts, args)));
|
|
283
|
+
server.registerTool("sync_file", {
|
|
284
|
+
title: "Sync File",
|
|
285
|
+
description: "Index or re-index a single source file after it was written or modified. " +
|
|
286
|
+
"IMPORTANT: call this automatically after every Write or Edit tool call.",
|
|
287
|
+
inputSchema: SyncFileSchema.shape,
|
|
288
|
+
}, tx("sync_file", (args) => handleSyncFile(stmts, args)));
|
|
289
|
+
server.registerTool("sync_project", {
|
|
290
|
+
title: "Sync Project",
|
|
291
|
+
description: "Re-index the entire project directory incrementally (after refactor or git pull).",
|
|
292
|
+
inputSchema: SyncProjectSchema.shape,
|
|
293
|
+
}, tx("sync_project", (args) => handleSyncProject(stmts, args)));
|
|
294
|
+
server.registerTool("grep_code", {
|
|
295
|
+
title: "Grep Code",
|
|
296
|
+
description: "Search indexed source files using a regex pattern. Decompresses stored content and returns " +
|
|
297
|
+
"only matching lines with context. Token-efficient (~20-50 tokens vs full file).",
|
|
298
|
+
inputSchema: GrepCodeSchema.shape,
|
|
299
|
+
}, tx("grep_code", (args) => handleGrepCode(stmts, args)));
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
// Tools — Context & Token Optimization
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
server.registerTool("get_context", {
|
|
304
|
+
title: "Get Context",
|
|
305
|
+
description: "Retrieve the minimal relevant context for a task or query. TF-IDF (or Qdrant) ranking " +
|
|
306
|
+
"+ recency boost + skeleton pruning to stay within token budget.",
|
|
307
|
+
inputSchema: GetContextSchema.shape,
|
|
308
|
+
}, tx("get_context", async (args) => handleGetContext(stmts, args)));
|
|
309
|
+
server.registerTool("get_recent", {
|
|
310
|
+
title: "Get Recent",
|
|
311
|
+
description: "Return files modified recently with line-level diffs. Useful after a git pull or session resume.",
|
|
312
|
+
inputSchema: GetRecentSchema.shape,
|
|
313
|
+
}, tx("get_recent", (args) => handleGetRecent(stmts, args)));
|
|
314
|
+
server.registerTool("smart_context", {
|
|
315
|
+
title: "Smart Context",
|
|
316
|
+
description: "Combined: knowledge graph (recall) + code files (get_context) in one call. " +
|
|
317
|
+
"task_type adjusts token budget: simple=2000, moderate=6000, complex=12000.",
|
|
318
|
+
inputSchema: SmartContextSchema.shape,
|
|
319
|
+
}, tx("smart_context", async (args) => handleSmartContext(stmts, args)));
|
|
320
|
+
server.registerTool("suggest_model", {
|
|
321
|
+
title: "Suggest Model",
|
|
322
|
+
description: "Classify task complexity → recommend Claude model. Returns { model, model_id, reasoning, context_budget }. " +
|
|
323
|
+
"Call at the start of any workflow.",
|
|
324
|
+
inputSchema: SuggestModelSchema.shape,
|
|
325
|
+
}, tx("suggest_model", (args) => handleSuggestModel(args)));
|
|
326
|
+
server.registerTool("compress_text", {
|
|
327
|
+
title: "Compress Text",
|
|
328
|
+
description: "Compress text using LLMLingua-2 semantic compression. Model downloads ~700MB on first use " +
|
|
329
|
+
"(cached in ~/.lucid/models/). Returns compressed text with stats.",
|
|
330
|
+
inputSchema: CompressTextSchema.shape,
|
|
331
|
+
}, tx("compress_text", async (args) => handleCompressText(args)));
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
// Tools — Reward System
|
|
334
|
+
// ---------------------------------------------------------------------------
|
|
335
|
+
server.registerTool("reward", {
|
|
336
|
+
title: "Reward",
|
|
337
|
+
description: "Signal that the last get_context() result was helpful (+1 reward). " +
|
|
338
|
+
"Files in that context will be ranked higher in future similar queries.",
|
|
339
|
+
inputSchema: RewardSchema.shape,
|
|
340
|
+
}, tx("reward", (args) => handleReward(stmts, args)));
|
|
341
|
+
server.registerTool("penalize", {
|
|
342
|
+
title: "Penalize",
|
|
343
|
+
description: "Signal that the last get_context() result was unhelpful (-1 reward). " +
|
|
344
|
+
"Files in that context will be ranked lower in future similar queries.",
|
|
345
|
+
inputSchema: PenalizeSchema.shape,
|
|
346
|
+
}, tx("penalize", (args) => handlePenalize(stmts, args)));
|
|
347
|
+
server.registerTool("show_rewards", {
|
|
348
|
+
title: "Show Rewards",
|
|
349
|
+
description: "Show the top rewarded experiences and most rewarded files. " +
|
|
350
|
+
"Rewards decay exponentially (half-life ~14 days).",
|
|
351
|
+
inputSchema: ShowRewardsSchema.shape,
|
|
352
|
+
}, tx("show_rewards", (args) => handleShowRewards(stmts, args)));
|
|
353
|
+
// ---------------------------------------------------------------------------
|
|
354
|
+
// Tools — Logic Guardian
|
|
355
|
+
// ---------------------------------------------------------------------------
|
|
356
|
+
server.registerTool("validate_file", {
|
|
357
|
+
title: "Validate File",
|
|
358
|
+
description: "Run Logic Guardian validation on a source file. Detects LLM drift: logic inversions, " +
|
|
359
|
+
"null propagation, type confusion, copy-paste drift, silent exceptions. Python/JS/TS.",
|
|
360
|
+
inputSchema: ValidateFileSchema.shape,
|
|
361
|
+
}, tx("validate_file", (args) => handleValidateFile(args)));
|
|
362
|
+
server.registerTool("check_drift", {
|
|
363
|
+
title: "Check Drift",
|
|
364
|
+
description: "Analyze a code snippet for LLM drift patterns without saving to disk.",
|
|
365
|
+
inputSchema: CheckDriftSchema.shape,
|
|
366
|
+
}, tx("check_drift", (args) => handleCheckDrift(args)));
|
|
367
|
+
server.registerTool("get_checklist", {
|
|
368
|
+
title: "Get Checklist",
|
|
369
|
+
description: "Get the full Logic Guardian validation checklist (5 passes).",
|
|
370
|
+
}, tx("get_checklist", () => handleGetChecklist()));
|
|
371
|
+
// ---------------------------------------------------------------------------
|
|
372
|
+
// Tools — Coding Guard
|
|
373
|
+
// ---------------------------------------------------------------------------
|
|
374
|
+
server.registerTool("coding_rules", {
|
|
375
|
+
title: "Coding Rules",
|
|
376
|
+
description: "Get the 25 Golden Rules coding checklist. Covers clarity, naming, single responsibility, " +
|
|
377
|
+
"frontend rules, library selection, architecture separation.",
|
|
378
|
+
}, tx("coding_rules", () => handleGetCodingRules()));
|
|
379
|
+
// CheckCodeQualitySchema uses .refine(); pass the raw shape to MCP and re-parse
|
|
380
|
+
// inside the handler so the refinement runs.
|
|
381
|
+
const checkCodeQualityShape = {
|
|
382
|
+
path: z.string().optional().describe("Absolute or relative path to the file to analyze."),
|
|
383
|
+
code: z.string().optional().describe("Code snippet to analyze inline."),
|
|
384
|
+
language: z.enum(["python", "javascript", "typescript", "vue", "generic"]).optional()
|
|
385
|
+
.describe("Language hint. Auto-detected from file extension if path is provided."),
|
|
386
|
+
};
|
|
387
|
+
server.registerTool("check_code_quality", {
|
|
388
|
+
title: "Check Code Quality",
|
|
389
|
+
description: "Analyze a file or snippet against the 25 Golden Rules. Detects size violations, vague naming, " +
|
|
390
|
+
"deep nesting, dead code, inline styles, prop explosion, fetch-in-component.",
|
|
391
|
+
inputSchema: checkCodeQualityShape,
|
|
392
|
+
}, tx("check_code_quality", (args) => handleCheckCodeQuality(CheckCodeQualitySchema.parse(args))));
|
|
393
|
+
// ---------------------------------------------------------------------------
|
|
394
|
+
// Tools — Planning
|
|
395
|
+
// ---------------------------------------------------------------------------
|
|
396
|
+
server.registerTool("plan_create", {
|
|
397
|
+
title: "Plan Create",
|
|
398
|
+
description: "Create a plan with user story, ordered tasks, and test criteria. " +
|
|
399
|
+
"Call BEFORE writing any code to establish intent and acceptance criteria.",
|
|
400
|
+
inputSchema: PlanCreateSchema.shape,
|
|
401
|
+
}, tx("plan_create", (args) => handlePlanCreate(db, stmts, args)));
|
|
402
|
+
server.registerTool("plan_list", {
|
|
403
|
+
title: "Plan List",
|
|
404
|
+
description: "List plans with progress summary. Defaults to active plans.",
|
|
405
|
+
inputSchema: PlanListSchema.shape,
|
|
406
|
+
}, tx("plan_list", (args) => handlePlanList(stmts, args)));
|
|
407
|
+
server.registerTool("plan_get", {
|
|
408
|
+
title: "Plan Get",
|
|
409
|
+
description: "Get full plan details: tasks, test criteria, status, and notes.",
|
|
410
|
+
inputSchema: PlanGetSchema.shape,
|
|
411
|
+
}, tx("plan_get", (args) => handlePlanGet(stmts, args)));
|
|
412
|
+
server.registerTool("plan_update_task", {
|
|
413
|
+
title: "Plan Update Task",
|
|
414
|
+
description: "Update a task status. Auto-completes the plan when all tasks are done. " +
|
|
415
|
+
"Statuses: pending → in_progress → done (or blocked).",
|
|
416
|
+
inputSchema: PlanUpdateTaskSchema.shape,
|
|
417
|
+
}, tx("plan_update_task", (args) => handlePlanUpdateTask(stmts, args)));
|
|
418
|
+
// ---------------------------------------------------------------------------
|
|
419
|
+
// Tools — Updater
|
|
420
|
+
// ---------------------------------------------------------------------------
|
|
421
|
+
server.registerTool("update_lucid", {
|
|
422
|
+
title: "Update Lucid",
|
|
423
|
+
description: "Check for a newer version of Lucid on npm and update automatically. " +
|
|
424
|
+
"Restart Claude Code after updating.",
|
|
425
|
+
inputSchema: UpdateLucidSchema.shape,
|
|
426
|
+
}, tx("update_lucid", async (args) => handleUpdateLucid(args)));
|
|
427
|
+
// ---------------------------------------------------------------------------
|
|
428
|
+
// Tools — Web Dev Skills
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
server.registerTool("generate_component", {
|
|
431
|
+
title: "Generate Component",
|
|
432
|
+
description: "Generate a complete component scaffold from a description. React (TSX/JSX) or Vue/Nuxt. " +
|
|
433
|
+
"Styling: Tailwind, CSS Modules, or none.",
|
|
434
|
+
inputSchema: GenerateComponentSchema.shape,
|
|
435
|
+
}, tx("generate_component", (args) => handleGenerateComponent(args)));
|
|
436
|
+
server.registerTool("scaffold_page", {
|
|
437
|
+
title: "Scaffold Page",
|
|
438
|
+
description: "Generate a full page scaffold with layout, SEO head meta, and placeholder sections. " +
|
|
439
|
+
"Nuxt (useHead), Next.js (Metadata API), or plain Vue.",
|
|
440
|
+
inputSchema: ScaffoldPageSchema.shape,
|
|
441
|
+
}, tx("scaffold_page", (args) => handleScaffoldPage(args)));
|
|
442
|
+
server.registerTool("seo_meta", {
|
|
443
|
+
title: "SEO Meta",
|
|
444
|
+
description: "Generate complete SEO metadata: HTML meta tags, Open Graph, Twitter Card, JSON-LD " +
|
|
445
|
+
"(Article, Product, WebSite, WebPage).",
|
|
446
|
+
inputSchema: SeoMetaSchema.shape,
|
|
447
|
+
}, tx("seo_meta", (args) => handleSeoMeta(args)));
|
|
448
|
+
server.registerTool("accessibility_audit", {
|
|
449
|
+
title: "Accessibility Audit",
|
|
450
|
+
description: "Audit HTML/JSX/Vue snippets for WCAG violations. Checks: alt text, labels, empty buttons, " +
|
|
451
|
+
"tabindex, click handlers, target=_blank. Returns severity + WCAG criterion + corrected code.",
|
|
452
|
+
inputSchema: AccessibilityAuditSchema.shape,
|
|
453
|
+
}, tx("accessibility_audit", (args) => handleAccessibilityAudit(args)));
|
|
454
|
+
server.registerTool("api_client", {
|
|
455
|
+
title: "API Client",
|
|
456
|
+
description: "Generate a typed TypeScript async function for a REST endpoint. Includes types, " +
|
|
457
|
+
"error handling (throws on non-2xx), usage example. Auth: bearer/cookie/apikey/none.",
|
|
458
|
+
inputSchema: ApiClientSchema.shape,
|
|
459
|
+
}, tx("api_client", (args) => handleApiClient(args)));
|
|
460
|
+
server.registerTool("test_generator", {
|
|
461
|
+
title: "Test Generator",
|
|
462
|
+
description: "Generate a complete test file. Covers happy path, edge cases, error path, mock setup. " +
|
|
463
|
+
"Frameworks: Vitest, Jest, Playwright. Component: Vue Test Utils or React Testing Library.",
|
|
464
|
+
inputSchema: TestGeneratorSchema.shape,
|
|
465
|
+
}, tx("test_generator", (args) => handleTestGenerator(args)));
|
|
466
|
+
server.registerTool("responsive_layout", {
|
|
467
|
+
title: "Responsive Layout",
|
|
468
|
+
description: "Generate a responsive mobile-first layout from a wireframe description. " +
|
|
469
|
+
"Tailwind utility classes, CSS Grid (named areas), or Flexbox + media queries.",
|
|
470
|
+
inputSchema: ResponsiveLayoutSchema.shape,
|
|
471
|
+
}, tx("responsive_layout", (args) => handleResponsiveLayout(args)));
|
|
472
|
+
server.registerTool("security_scan", {
|
|
473
|
+
title: "Security Scan",
|
|
474
|
+
description: "Scan JS/TS/HTML/Vue for web security vulns: XSS, code injection, SQL injection, " +
|
|
475
|
+
"hardcoded secrets, open redirects, prototype pollution, path traversal, insecure CORS. " +
|
|
476
|
+
"Context-aware (frontend/backend/api).",
|
|
477
|
+
inputSchema: SecurityScanSchema.shape,
|
|
478
|
+
}, tx("security_scan", (args) => handleSecurityScan(args)));
|
|
479
|
+
server.registerTool("design_tokens", {
|
|
480
|
+
title: "Design Tokens",
|
|
481
|
+
description: "Generate a complete design system token set from a brand color and mood. " +
|
|
482
|
+
"11-step color scales, neutrals, semantic aliases, type/spacing/radius/shadow tokens. " +
|
|
483
|
+
"Output: CSS vars, Tailwind config, or JSON.",
|
|
484
|
+
inputSchema: DesignTokensSchema.shape,
|
|
485
|
+
}, tx("design_tokens", (args) => handleDesignTokens(args)));
|
|
486
|
+
server.registerTool("perf_hints", {
|
|
487
|
+
title: "Perf Hints",
|
|
488
|
+
description: "Analyze a component or page for Core Web Vitals issues. Detects LCP image priority, " +
|
|
489
|
+
"CLS dimensions, render-blocking scripts, fetch-in-render, INP, missing memoization, " +
|
|
490
|
+
"whole-library imports. Issues ranked by CWV metric impact.",
|
|
491
|
+
inputSchema: PerfHintsSchema.shape,
|
|
492
|
+
}, tx("perf_hints", (args) => handlePerfHints(args)));
|
|
493
|
+
// ---------------------------------------------------------------------------
|
|
494
|
+
// Resources — read-only knowledge graph + config snapshots
|
|
495
|
+
// ---------------------------------------------------------------------------
|
|
496
|
+
server.registerResource("memory-stats", "lucid://memory/stats", {
|
|
497
|
+
title: "Memory Stats",
|
|
498
|
+
description: "Current memory usage: entity/relation/observation counts and DB size.",
|
|
499
|
+
mimeType: "application/json",
|
|
500
|
+
}, async (uri) => ({
|
|
501
|
+
contents: [{ uri: uri.href, mimeType: "application/json", text: memoryStats(db, stmts) }],
|
|
502
|
+
}));
|
|
503
|
+
server.registerResource("memory-graph", "lucid://memory/graph", {
|
|
504
|
+
title: "Memory Graph",
|
|
505
|
+
description: "Full knowledge graph snapshot: all entities, relations, and observations.",
|
|
506
|
+
mimeType: "application/json",
|
|
507
|
+
}, async (uri) => ({
|
|
508
|
+
contents: [{ uri: uri.href, mimeType: "application/json", text: recallAll(db, stmts) }],
|
|
509
|
+
}));
|
|
510
|
+
server.registerResource("memory-recent", new ResourceTemplate("lucid://memory/recent/{hours}", { list: undefined }), {
|
|
511
|
+
title: "Recent Activity",
|
|
512
|
+
description: "Files modified in the last {hours} hours, with line-level diffs.",
|
|
513
|
+
mimeType: "text/markdown",
|
|
514
|
+
}, async (uri, vars) => {
|
|
515
|
+
const hours = Number(vars["hours"]);
|
|
516
|
+
const safeHours = Number.isFinite(hours) && hours > 0 ? Math.min(hours, 720) : 24;
|
|
517
|
+
const text = handleGetRecent(stmts, { hours: safeHours, withDiffs: true });
|
|
518
|
+
return { contents: [{ uri: uri.href, mimeType: "text/markdown", text }] };
|
|
519
|
+
});
|
|
520
|
+
server.registerResource("plan-list", "lucid://plan/list", {
|
|
521
|
+
title: "Active Plans",
|
|
522
|
+
description: "All active development plans with progress summary.",
|
|
523
|
+
mimeType: "text/markdown",
|
|
524
|
+
}, async (uri) => ({
|
|
525
|
+
contents: [{
|
|
526
|
+
uri: uri.href,
|
|
527
|
+
mimeType: "text/markdown",
|
|
528
|
+
text: handlePlanList(stmts, { status: "active" }),
|
|
529
|
+
}],
|
|
530
|
+
}));
|
|
531
|
+
server.registerResource("checklist", "lucid://guardian/checklist", {
|
|
532
|
+
title: "Logic Guardian Checklist",
|
|
533
|
+
description: "Full 5-pass validation checklist Claude must run before completing any task.",
|
|
534
|
+
mimeType: "text/markdown",
|
|
535
|
+
}, async (uri) => ({
|
|
536
|
+
contents: [{ uri: uri.href, mimeType: "text/markdown", text: handleGetChecklist() }],
|
|
537
|
+
}));
|
|
538
|
+
server.registerResource("coding-rules", "lucid://guardian/coding-rules", {
|
|
539
|
+
title: "25 Golden Rules",
|
|
540
|
+
description: "Coding-quality checklist: clarity, naming, single responsibility, frontend rules.",
|
|
541
|
+
mimeType: "text/markdown",
|
|
542
|
+
}, async (uri) => ({
|
|
543
|
+
contents: [{ uri: uri.href, mimeType: "text/markdown", text: handleGetCodingRules() }],
|
|
544
|
+
}));
|
|
545
|
+
server.registerResource("config", "lucid://config", {
|
|
546
|
+
title: "Lucid Configuration",
|
|
547
|
+
description: "Effective configuration (lucid.config.json + env overrides).",
|
|
548
|
+
mimeType: "application/json",
|
|
549
|
+
}, async (uri) => ({
|
|
550
|
+
contents: [{
|
|
551
|
+
uri: uri.href,
|
|
552
|
+
mimeType: "application/json",
|
|
553
|
+
text: JSON.stringify({
|
|
554
|
+
version: SERVER_VERSION,
|
|
555
|
+
config: _appCfg,
|
|
556
|
+
env: {
|
|
557
|
+
MEMORY_DB_PATH: process.env["MEMORY_DB_PATH"] ?? null,
|
|
558
|
+
QDRANT_URL: _qdrantUrl ?? null,
|
|
559
|
+
EMBEDDING_URL: _embeddingUrl ?? null,
|
|
560
|
+
},
|
|
561
|
+
}, null, 2),
|
|
562
|
+
}],
|
|
563
|
+
}));
|
|
564
|
+
// ---------------------------------------------------------------------------
|
|
565
|
+
// Prompts — reusable workflows the user can invoke as slash commands
|
|
566
|
+
// ---------------------------------------------------------------------------
|
|
567
|
+
server.registerPrompt("validate-changes", {
|
|
568
|
+
title: "Validate recent changes",
|
|
569
|
+
description: "Run the Logic Guardian 5-pass validation across files modified in the last N hours.",
|
|
570
|
+
argsSchema: { hours: z.string().optional() },
|
|
571
|
+
}, ({ hours }) => {
|
|
572
|
+
const h = hours ? Number(hours) : 24;
|
|
573
|
+
return {
|
|
574
|
+
messages: [{
|
|
575
|
+
role: "user",
|
|
576
|
+
content: {
|
|
577
|
+
type: "text",
|
|
578
|
+
text: `Run Logic Guardian validation on every file modified in the last ${h} hours.\n\n` +
|
|
579
|
+
`Steps:\n` +
|
|
580
|
+
`1. Call \`get_recent\` with hours=${h} to list changed files.\n` +
|
|
581
|
+
`2. For EACH file, call \`validate_file(path)\` and \`check_code_quality(path)\`.\n` +
|
|
582
|
+
`3. Apply the 5-pass checklist from \`get_checklist\`.\n` +
|
|
583
|
+
`4. Report: per-file findings + a single summary table (file × pass × issue count).\n` +
|
|
584
|
+
`5. Stop and ask before fixing anything — report only.`,
|
|
585
|
+
},
|
|
586
|
+
}],
|
|
587
|
+
};
|
|
588
|
+
});
|
|
589
|
+
server.registerPrompt("audit-file", {
|
|
590
|
+
title: "Audit a single file",
|
|
591
|
+
description: "Run the full Lucid audit pipeline (validate + drift + coding rules + security) on one file.",
|
|
592
|
+
argsSchema: { path: z.string() },
|
|
593
|
+
}, ({ path }) => ({
|
|
594
|
+
messages: [{
|
|
595
|
+
role: "user",
|
|
596
|
+
content: {
|
|
597
|
+
type: "text",
|
|
598
|
+
text: `Audit \`${path}\` with the full Lucid pipeline:\n\n` +
|
|
599
|
+
`1. \`validate_file(path="${path}")\` — Logic Guardian drift detection.\n` +
|
|
600
|
+
`2. \`check_code_quality(path="${path}")\` — 25 Golden Rules.\n` +
|
|
601
|
+
`3. Read the file content, then \`security_scan(code, language, context)\` if it's web code.\n` +
|
|
602
|
+
`4. Apply the 5-pass checklist (\`get_checklist\`).\n` +
|
|
603
|
+
`5. Report findings grouped by severity (high/medium/low). Do not fix yet.`,
|
|
604
|
+
},
|
|
605
|
+
}],
|
|
606
|
+
}));
|
|
607
|
+
server.registerPrompt("plan-feature", {
|
|
608
|
+
title: "Plan a new feature",
|
|
609
|
+
description: "Scaffold a Lucid plan from a feature description with tasks and test criteria.",
|
|
610
|
+
argsSchema: { feature: z.string() },
|
|
611
|
+
}, ({ feature }) => ({
|
|
612
|
+
messages: [{
|
|
613
|
+
role: "user",
|
|
614
|
+
content: {
|
|
615
|
+
type: "text",
|
|
616
|
+
text: `Create a Lucid plan for this feature:\n\n"${feature}"\n\n` +
|
|
617
|
+
`Steps:\n` +
|
|
618
|
+
`1. Call \`smart_context(query="${feature}", task_type="moderate")\` to gather relevant files.\n` +
|
|
619
|
+
`2. Draft a user story: "As a [user], I want [goal], so that [benefit]."\n` +
|
|
620
|
+
`3. Break into 3–8 tasks. EACH task needs explicit \`test_criteria\` (how to verify done).\n` +
|
|
621
|
+
`4. Call \`plan_create({title, description, user_story, tasks})\`.\n` +
|
|
622
|
+
`5. Show the plan ID and the task list.`,
|
|
623
|
+
},
|
|
624
|
+
}],
|
|
625
|
+
}));
|
|
626
|
+
server.registerPrompt("security-review", {
|
|
627
|
+
title: "Security review of recent changes",
|
|
628
|
+
description: "Scan recently changed web code for XSS, injection, secrets, SSRF, and OWASP Top 10 patterns.",
|
|
629
|
+
argsSchema: { hours: z.string().optional() },
|
|
630
|
+
}, ({ hours }) => {
|
|
631
|
+
const h = hours ? Number(hours) : 24;
|
|
632
|
+
return {
|
|
633
|
+
messages: [{
|
|
634
|
+
role: "user",
|
|
635
|
+
content: {
|
|
636
|
+
type: "text",
|
|
637
|
+
text: `Security review of files changed in the last ${h} hours.\n\n` +
|
|
638
|
+
`1. Call \`get_recent\` with hours=${h}.\n` +
|
|
639
|
+
`2. Filter to JS/TS/HTML/Vue files only.\n` +
|
|
640
|
+
`3. For each, read content and call \`security_scan(code, language, context)\` ` +
|
|
641
|
+
`with context inferred from the path (frontend/backend/api).\n` +
|
|
642
|
+
`4. Report findings as a table: file × vuln class × severity × line.\n` +
|
|
643
|
+
`5. Recommend fixes only after the report is complete.`,
|
|
644
|
+
},
|
|
645
|
+
}],
|
|
646
|
+
};
|
|
898
647
|
});
|
|
899
648
|
// ---------------------------------------------------------------------------
|
|
900
649
|
// Start
|
|
901
650
|
// ---------------------------------------------------------------------------
|
|
902
651
|
const transport = new StdioServerTransport();
|
|
903
652
|
await server.connect(transport);
|
|
904
|
-
console.error(`[lucid] Server v${
|
|
653
|
+
console.error(`[lucid] Server v${SERVER_VERSION} started on stdio (tools + resources + prompts).`);
|
|
905
654
|
// Non-blocking — logs to stderr if update is available
|
|
906
655
|
checkForUpdatesOnStartup().catch(() => { });
|