@a13xu/lucid 1.12.0 → 1.13.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/build/index.js CHANGED
@@ -21,6 +21,7 @@ import { handleGetContext, GetContextSchema, handleGetRecent, GetRecentSchema, }
21
21
  import { handleReward, RewardSchema, handlePenalize, PenalizeSchema, handleShowRewards, ShowRewardsSchema, } from "./tools/reward.js";
22
22
  import { handleGetCodingRules, handleCheckCodeQuality, CheckCodeQualitySchema, } from "./tools/coding-guard.js";
23
23
  import { handlePlanCreate, PlanCreateSchema, handlePlanList, PlanListSchema, handlePlanGet, PlanGetSchema, handlePlanUpdateTask, PlanUpdateTaskSchema, } from "./tools/plan.js";
24
+ import { UpdateLucidSchema, handleUpdateLucid, checkForUpdatesOnStartup, getCurrentVersion, } from "./tools/updater.js";
24
25
  import { GenerateComponentSchema, handleGenerateComponent, ScaffoldPageSchema, handleScaffoldPage, SeoMetaSchema, handleSeoMeta, AccessibilityAuditSchema, handleAccessibilityAudit, ApiClientSchema, handleApiClient, TestGeneratorSchema, handleTestGenerator, ResponsiveLayoutSchema, handleResponsiveLayout, SecurityScanSchema, handleSecurityScan, DesignTokensSchema, handleDesignTokens, PerfHintsSchema, handlePerfHints, } from "./tools/webdev/index.js";
25
26
  // ---------------------------------------------------------------------------
26
27
  // Init DB
@@ -54,7 +55,7 @@ else {
54
55
  // ---------------------------------------------------------------------------
55
56
  // MCP Server
56
57
  // ---------------------------------------------------------------------------
57
- const server = new Server({ name: "lucid", version: "1.12.0" }, { capabilities: { tools: {} } });
58
+ const server = new Server({ name: "lucid", version: "1.13.0" }, { capabilities: { tools: {} } });
58
59
  // ---------------------------------------------------------------------------
59
60
  // Tool definitions
60
61
  // ---------------------------------------------------------------------------
@@ -393,6 +394,23 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
393
394
  required: ["task_id", "status"],
394
395
  },
395
396
  },
397
+ // ── Updater ──────────────────────────────────────────────────────────────
398
+ {
399
+ name: "update_lucid",
400
+ description: "Check for a newer version of Lucid on npm and update automatically. " +
401
+ "For global npm installs: runs npm install -g @a13xu/lucid@latest. " +
402
+ "For local source installs: shows git pull + npm run build instructions. " +
403
+ "After updating, restart Claude Code to load the new version.",
404
+ inputSchema: {
405
+ type: "object",
406
+ properties: {
407
+ force: {
408
+ type: "boolean",
409
+ description: "Force reinstall even if already on latest version (default false)",
410
+ },
411
+ },
412
+ },
413
+ },
396
414
  // ── Web Dev Skills ───────────────────────────────────────────────────────
397
415
  {
398
416
  name: "generate_component",
@@ -654,6 +672,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
654
672
  case "plan_update_task":
655
673
  text = handlePlanUpdateTask(stmts, PlanUpdateTaskSchema.parse(args));
656
674
  break;
675
+ // Updater
676
+ case "update_lucid":
677
+ text = await handleUpdateLucid(UpdateLucidSchema.parse(args));
678
+ break;
657
679
  // Web Dev Skills
658
680
  case "generate_component":
659
681
  text = handleGenerateComponent(GenerateComponentSchema.parse(args));
@@ -703,4 +725,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
703
725
  // ---------------------------------------------------------------------------
704
726
  const transport = new StdioServerTransport();
705
727
  await server.connect(transport);
706
- console.error("[lucid] Server started on stdio.");
728
+ console.error(`[lucid] Server v${getCurrentVersion()} started on stdio.`);
729
+ // Non-blocking — logs to stderr if update is available
730
+ checkForUpdatesOnStartup().catch(() => { });
@@ -29,6 +29,7 @@ export const InitProjectSchema = z.object({
29
29
  projectName: z.string().optional(),
30
30
  });
31
31
  const LUCID_MARKER = "Lucid: call sync_file";
32
+ const LUCID_UPDATE_MARKER = "lucid-update-check";
32
33
  const LUCID_HOOK = {
33
34
  matcher: "Write|Edit|NotebookEdit",
34
35
  hooks: [
@@ -38,7 +39,27 @@ const LUCID_HOOK = {
38
39
  },
39
40
  ],
40
41
  };
41
- function installHook(dir) {
42
+ // SessionStart hook: checks npm registry and notifies if update is available.
43
+ // Uses only Node.js built-in https module — no external dependencies required.
44
+ const LUCID_UPDATE_HOOK = {
45
+ hooks: [
46
+ {
47
+ type: "command",
48
+ command: `node -e "const h=require('https');` +
49
+ `h.get('https://registry.npmjs.org/@a13xu/lucid/latest',` +
50
+ `function(r){var d='';r.on('data',function(c){d+=c});` +
51
+ `r.on('end',function(){` +
52
+ `try{var v=JSON.parse(d).version;` +
53
+ `var s=require('child_process').execSync(` +
54
+ `'npm list -g @a13xu/lucid --depth=0 2>/dev/null',{encoding:'utf8'});` +
55
+ `var m=s.match(/lucid@([\\d.]+)/);` +
56
+ `if(m&&m[1]&&v!==m[1])` +
57
+ `console.log('[Lucid] Update available: v'+m[1]+' → v'+v+'. Call update_lucid().')}` +
58
+ `catch(e){}})}).on('error',function(){})" 2>/dev/null || true`,
59
+ },
60
+ ],
61
+ };
62
+ function installHooks(dir) {
42
63
  const claudeDir = join(dir, ".claude");
43
64
  const settingsPath = join(claudeDir, "settings.json");
44
65
  let settings = {};
@@ -51,20 +72,34 @@ function installHook(dir) {
51
72
  }
52
73
  }
53
74
  const hooks = (settings["hooks"] ?? {});
75
+ let changed = false;
76
+ // ── PostToolUse: sync_file reminder ──────────────────────────────────────
54
77
  const postToolUse = hooks["PostToolUse"] ?? [];
55
- // Detectează atât formatul vechi cât și cel nou
56
- const alreadyInstalled = postToolUse.some((h) => {
78
+ const syncAlreadyInstalled = postToolUse.some((h) => {
57
79
  const cmd = h.command ?? h.hooks?.[0]?.command ?? "";
58
80
  return cmd.includes(LUCID_MARKER);
59
81
  });
60
- if (alreadyInstalled) {
82
+ if (!syncAlreadyInstalled) {
83
+ hooks["PostToolUse"] = [...postToolUse, LUCID_HOOK];
84
+ changed = true;
85
+ }
86
+ // ── SessionStart: version check ───────────────────────────────────────────
87
+ const sessionStart = hooks["SessionStart"] ?? [];
88
+ const updateAlreadyInstalled = sessionStart.some((h) => {
89
+ const cmd = h.command ?? h.hooks?.[0]?.command ?? "";
90
+ return cmd.includes(LUCID_UPDATE_MARKER);
91
+ });
92
+ if (!updateAlreadyInstalled) {
93
+ hooks["SessionStart"] = [...sessionStart, LUCID_UPDATE_HOOK];
94
+ changed = true;
95
+ }
96
+ if (!changed) {
61
97
  return { installed: false, reason: "already installed" };
62
98
  }
63
- hooks["PostToolUse"] = [...postToolUse, LUCID_HOOK];
64
99
  settings["hooks"] = hooks;
65
100
  mkdirSync(claudeDir, { recursive: true });
66
101
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
67
- return { installed: true, reason: "hook added to .claude/settings.json" };
102
+ return { installed: true, reason: "hooks added to .claude/settings.json" };
68
103
  }
69
104
  // ---------------------------------------------------------------------------
70
105
  // Adaugă instrucțiune în CLAUDE.md
@@ -111,13 +146,14 @@ export async function handleInitProject(stmts, input) {
111
146
  }
112
147
  // ── Hook PostToolUse ──────────────────────────────────────────────────────
113
148
  lines.push(``);
114
- const hookResult = installHook(dir);
149
+ const hookResult = installHooks(dir);
115
150
  if (hookResult.installed) {
116
- lines.push(`🔗 Claude Code hook installed (.claude/settings.json)`);
117
- lines.push(` After every Write/Edit, you will see a reminder to call sync_file().`);
151
+ lines.push(`🔗 Claude Code hooks installed (.claude/settings.json)`);
152
+ lines.push(` PostToolUse: reminder to call sync_file() after every Write/Edit`);
153
+ lines.push(` SessionStart: auto-check for Lucid updates on session start`);
118
154
  }
119
155
  else {
120
- lines.push(`🔗 Hook: ${hookResult.reason}`);
156
+ lines.push(`🔗 Hooks: ${hookResult.reason}`);
121
157
  }
122
158
  // ── Skills ────────────────────────────────────────────────────────────────
123
159
  const skillsResult = installSkills(dir);
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export declare function getCurrentVersion(): string;
3
+ export declare function checkForUpdatesOnStartup(): Promise<void>;
4
+ export declare const UpdateLucidSchema: z.ZodObject<{
5
+ force: z.ZodOptional<z.ZodBoolean>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ force?: boolean | undefined;
8
+ }, {
9
+ force?: boolean | undefined;
10
+ }>;
11
+ export declare function handleUpdateLucid(args: z.infer<typeof UpdateLucidSchema>): Promise<string>;
@@ -0,0 +1,133 @@
1
+ import { z } from "zod";
2
+ import { join } from "path";
3
+ import { readFileSync, existsSync } from "fs";
4
+ import { fileURLToPath } from "url";
5
+ import { execSync } from "child_process";
6
+ // ---------------------------------------------------------------------------
7
+ // Package root resolution
8
+ // ---------------------------------------------------------------------------
9
+ // build/tools/updater.js → ../../ = package root
10
+ const PACKAGE_ROOT = join(fileURLToPath(new URL(".", import.meta.url)), "../..");
11
+ export function getCurrentVersion() {
12
+ try {
13
+ const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"));
14
+ return pkg.version ?? "unknown";
15
+ }
16
+ catch {
17
+ return "unknown";
18
+ }
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // npm registry check
22
+ // ---------------------------------------------------------------------------
23
+ async function fetchLatestVersion() {
24
+ try {
25
+ const res = await fetch("https://registry.npmjs.org/@a13xu/lucid/latest", { signal: AbortSignal.timeout(5000) });
26
+ if (!res.ok)
27
+ return null;
28
+ const data = (await res.json());
29
+ return data.version ?? null;
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ function compareVersions(a, b) {
36
+ const pa = a.split(".").map(Number);
37
+ const pb = b.split(".").map(Number);
38
+ for (let i = 0; i < 3; i++) {
39
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
40
+ if (diff !== 0)
41
+ return diff;
42
+ }
43
+ return 0;
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // Install method detection
47
+ // ---------------------------------------------------------------------------
48
+ function detectInstallMethod() {
49
+ // If the package root is inside node_modules, it's npm-installed
50
+ if (PACKAGE_ROOT.includes("node_modules")) {
51
+ return "global-npm";
52
+ }
53
+ // Check if there's a .git folder — local source checkout
54
+ if (existsSync(join(PACKAGE_ROOT, ".git"))) {
55
+ return "local-source";
56
+ }
57
+ return "global-npm";
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Startup check (non-blocking — call from index.ts without await)
61
+ // ---------------------------------------------------------------------------
62
+ export async function checkForUpdatesOnStartup() {
63
+ const current = getCurrentVersion();
64
+ const latest = await fetchLatestVersion();
65
+ if (latest && compareVersions(latest, current) > 0) {
66
+ console.error(`[lucid] ⬆️ Update available: v${current} → v${latest}. ` +
67
+ `Call update_lucid() to update, or: npm install -g @a13xu/lucid@latest`);
68
+ }
69
+ }
70
+ // ---------------------------------------------------------------------------
71
+ // Schema & handler
72
+ // ---------------------------------------------------------------------------
73
+ export const UpdateLucidSchema = z.object({
74
+ force: z
75
+ .boolean()
76
+ .optional()
77
+ .describe("Force reinstall even if already on latest version"),
78
+ });
79
+ // Example call:
80
+ // handleUpdateLucid({ force: false })
81
+ export async function handleUpdateLucid(args) {
82
+ const current = getCurrentVersion();
83
+ const lines = [`🔍 Checking for updates... (current: v${current})`];
84
+ const latest = await fetchLatestVersion();
85
+ if (!latest) {
86
+ return lines.concat("❌ Could not reach npm registry. Check your internet connection.").join("\n");
87
+ }
88
+ lines.push(`📦 Latest on npm: v${latest}`);
89
+ const upToDate = compareVersions(latest, current) <= 0;
90
+ if (upToDate && !args.force) {
91
+ lines.push(`✅ Lucid is up to date.`);
92
+ return lines.join("\n");
93
+ }
94
+ if (upToDate && args.force) {
95
+ lines.push(`⚠️ Already on v${latest}, reinstalling (force=true)...`);
96
+ }
97
+ else {
98
+ lines.push(`🔄 Updating v${current} → v${latest}...`);
99
+ }
100
+ const method = detectInstallMethod();
101
+ if (method === "local-source") {
102
+ lines.push(``);
103
+ lines.push(`📁 Local source installation detected (${PACKAGE_ROOT}).`);
104
+ lines.push(`Run these commands to update:`);
105
+ lines.push(` cd "${PACKAGE_ROOT}"`);
106
+ lines.push(` git pull`);
107
+ lines.push(` npm run build`);
108
+ lines.push(`Then restart Claude Code.`);
109
+ return lines.join("\n");
110
+ }
111
+ // Global npm install
112
+ try {
113
+ lines.push(`Running: npm install -g @a13xu/lucid@${latest}`);
114
+ execSync(`npm install -g @a13xu/lucid@${latest}`, {
115
+ timeout: 120_000,
116
+ stdio: "pipe",
117
+ });
118
+ lines.push(`✅ Updated to v${latest}`);
119
+ lines.push(``);
120
+ lines.push(`⚠️ Restart Claude Code to load the new version:`);
121
+ lines.push(` • VS Code: Cmd/Ctrl+Shift+P → "Restart Claude Code"`);
122
+ lines.push(` • CLI: exit and re-run \`claude\``);
123
+ }
124
+ catch (err) {
125
+ const msg = err instanceof Error ? err.message : String(err);
126
+ lines.push(`❌ Auto-update failed: ${msg}`);
127
+ lines.push(` Run manually: npm install -g @a13xu/lucid@${latest}`);
128
+ if (process.platform !== "win32") {
129
+ lines.push(` Or with sudo: sudo npm install -g @a13xu/lucid@${latest}`);
130
+ }
131
+ }
132
+ return lines.join("\n");
133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a13xu/lucid",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Token-efficient memory, code indexing, and validation for Claude Code agents — SQLite + FTS5, TF-IDF + Qdrant retrieval, AST skeleton pruning, diff-aware context, Logic Guardian drift detection",
5
5
  "type": "module",
6
6
  "bin": {