fossel 1.0.1 → 1.0.8

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.
Files changed (5) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +108 -13
  3. package/dist/cli.js +1020 -0
  4. package/dist/index.js +469 -60
  5. package/package.json +5 -3
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { homedir } from "os";
5
- import { join } from "path";
5
+ import { join, resolve } from "path";
6
+ import { fileURLToPath } from "url";
6
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
9
 
@@ -10,6 +11,106 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
10
11
  import Database from "better-sqlite3";
11
12
  import { mkdirSync } from "fs";
12
13
  import { dirname } from "path";
14
+
15
+ // src/db/migrate.ts
16
+ function hasColumn(db, tableName, columnName) {
17
+ const columns = db.prepare(`PRAGMA table_info(${tableName})`).all();
18
+ return columns.some((column) => column.name === columnName);
19
+ }
20
+ var migrations = [
21
+ {
22
+ name: "001_init_memories_schema",
23
+ apply: (db) => {
24
+ db.exec(`
25
+ CREATE TABLE IF NOT EXISTS memories (
26
+ id TEXT PRIMARY KEY,
27
+ repo TEXT NOT NULL,
28
+ type TEXT NOT NULL CHECK (type IN ('convention', 'bug_fix', 'reviewer_pattern', 'decision', 'issue', 'general')),
29
+ note TEXT NOT NULL,
30
+ tags TEXT NOT NULL DEFAULT '[]',
31
+ created_at INTEGER NOT NULL
32
+ );
33
+
34
+ CREATE INDEX IF NOT EXISTS idx_memories_repo ON memories (repo);
35
+ CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories (created_at DESC);
36
+
37
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
38
+ repo,
39
+ note,
40
+ content = 'memories',
41
+ content_rowid = 'rowid'
42
+ );
43
+
44
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
45
+ INSERT INTO memories_fts(rowid, repo, note) VALUES (new.rowid, new.repo, new.note);
46
+ END;
47
+
48
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
49
+ INSERT INTO memories_fts(memories_fts, rowid, repo, note) VALUES ('delete', old.rowid, old.repo, old.note);
50
+ END;
51
+
52
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
53
+ INSERT INTO memories_fts(memories_fts, rowid, repo, note) VALUES ('delete', old.rowid, old.repo, old.note);
54
+ INSERT INTO memories_fts(rowid, repo, note) VALUES (new.rowid, new.repo, new.note);
55
+ END;
56
+ `);
57
+ }
58
+ },
59
+ {
60
+ name: "002_add_memories_updated_at",
61
+ apply: (db) => {
62
+ if (!hasColumn(db, "memories", "updated_at")) {
63
+ db.exec(`
64
+ ALTER TABLE memories
65
+ ADD COLUMN updated_at INTEGER NOT NULL DEFAULT 0;
66
+ `);
67
+ db.exec(`
68
+ UPDATE memories
69
+ SET updated_at = created_at
70
+ WHERE updated_at = 0;
71
+ `);
72
+ }
73
+ }
74
+ },
75
+ {
76
+ name: "003_add_memories_pinned",
77
+ apply: (db) => {
78
+ if (!hasColumn(db, "memories", "pinned")) {
79
+ db.exec(`
80
+ ALTER TABLE memories
81
+ ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0;
82
+ `);
83
+ }
84
+ }
85
+ }
86
+ ];
87
+ function runMigrations(db) {
88
+ db.exec(`
89
+ CREATE TABLE IF NOT EXISTS migrations (
90
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
91
+ name TEXT NOT NULL UNIQUE,
92
+ applied_at INTEGER NOT NULL
93
+ );
94
+ `);
95
+ const appliedRows = db.prepare("SELECT name FROM migrations").all();
96
+ const applied = new Set(appliedRows.map((row) => row.name));
97
+ const insertMigration = db.prepare(`
98
+ INSERT INTO migrations (name, applied_at)
99
+ VALUES (?, ?)
100
+ `);
101
+ for (const migration of migrations) {
102
+ if (applied.has(migration.name)) {
103
+ continue;
104
+ }
105
+ const applyTx = db.transaction(() => {
106
+ migration.apply(db);
107
+ insertMigration.run(migration.name, Math.floor(Date.now() / 1e3));
108
+ });
109
+ applyTx();
110
+ }
111
+ }
112
+
113
+ // src/db/client.ts
13
114
  var MEMORY_TYPES = [
14
115
  "convention",
15
116
  "bug_fix",
@@ -19,40 +120,6 @@ var MEMORY_TYPES = [
19
120
  "general"
20
121
  ];
21
122
  var dbInstance = null;
22
- var SCHEMA_SQL = `
23
- CREATE TABLE IF NOT EXISTS memories (
24
- id TEXT PRIMARY KEY,
25
- repo TEXT NOT NULL,
26
- type TEXT NOT NULL CHECK (type IN ('convention', 'bug_fix', 'reviewer_pattern', 'decision', 'issue', 'general')),
27
- note TEXT NOT NULL,
28
- tags TEXT NOT NULL DEFAULT '[]',
29
- created_at INTEGER NOT NULL,
30
- updated_at INTEGER NOT NULL
31
- );
32
-
33
- CREATE INDEX IF NOT EXISTS idx_memories_repo ON memories (repo);
34
- CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories (created_at DESC);
35
-
36
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
37
- repo,
38
- note,
39
- content = 'memories',
40
- content_rowid = 'rowid'
41
- );
42
-
43
- CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
44
- INSERT INTO memories_fts(rowid, repo, note) VALUES (new.rowid, new.repo, new.note);
45
- END;
46
-
47
- CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
48
- INSERT INTO memories_fts(memories_fts, rowid, repo, note) VALUES ('delete', old.rowid, old.repo, old.note);
49
- END;
50
-
51
- CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
52
- INSERT INTO memories_fts(memories_fts, rowid, repo, note) VALUES ('delete', old.rowid, old.repo, old.note);
53
- INSERT INTO memories_fts(rowid, repo, note) VALUES (new.rowid, new.repo, new.note);
54
- END;
55
- `;
56
123
  function initDb(dbPath) {
57
124
  if (dbInstance) {
58
125
  return dbInstance;
@@ -61,7 +128,7 @@ function initDb(dbPath) {
61
128
  const db = new Database(dbPath);
62
129
  db.pragma("journal_mode = WAL");
63
130
  db.pragma("foreign_keys = ON");
64
- db.exec(SCHEMA_SQL);
131
+ runMigrations(db);
65
132
  dbInstance = db;
66
133
  return db;
67
134
  }
@@ -156,10 +223,10 @@ function registerGetRepoContextTool(server) {
156
223
  const db = getDb();
157
224
  const rows = db.prepare(
158
225
  `
159
- SELECT id, repo, type, note, tags, created_at, updated_at
226
+ SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
160
227
  FROM memories
161
228
  WHERE repo = ?
162
- ORDER BY updated_at DESC
229
+ ORDER BY pinned DESC, updated_at DESC
163
230
  LIMIT ?
164
231
  `
165
232
  ).all(repo, limit);
@@ -177,7 +244,8 @@ function registerGetRepoContextTool(server) {
177
244
  for (const memory of rows) {
178
245
  const tags = parseTags(memory.tags);
179
246
  const tagSuffix = tags.length > 0 ? ` [tags: ${tags.join(", ")}]` : "";
180
- const item = `- (${memory.id}) ${memory.note}${tagSuffix}`;
247
+ const pinPrefix = memory.pinned ? "\u{1F4CC} Pinned " : "";
248
+ const item = `- (${memory.row_id} | legacy: ${memory.id}) ${pinPrefix}${memory.note}${tagSuffix}`;
181
249
  const existing = grouped.get(memory.type) ?? [];
182
250
  existing.push(item);
183
251
  grouped.set(memory.type, existing);
@@ -218,12 +286,127 @@ ${sections.join("\n\n")}`
218
286
  );
219
287
  }
220
288
 
221
- // src/tools/search.ts
289
+ // src/tools/pin.ts
222
290
  import { z as z3 } from "zod";
291
+ var pinInputSchema = {
292
+ id: z3.number().int().positive()
293
+ };
294
+ function setPinnedState(memoryId, pinned) {
295
+ const db = getDb();
296
+ const now = Math.floor(Date.now() / 1e3);
297
+ const updateResult = db.prepare(
298
+ `
299
+ UPDATE memories
300
+ SET pinned = ?, updated_at = ?
301
+ WHERE rowid = ?
302
+ `
303
+ ).run(pinned, now, memoryId);
304
+ if (updateResult.changes === 0) {
305
+ return null;
306
+ }
307
+ return db.prepare(
308
+ `
309
+ SELECT rowid AS row_id, note, pinned
310
+ FROM memories
311
+ WHERE rowid = ?
312
+ `
313
+ ).get(memoryId);
314
+ }
315
+ function registerPinMemoryTool(server) {
316
+ server.registerTool(
317
+ "pin_memory",
318
+ {
319
+ description: "Pin a memory to keep it at the top of repository context.",
320
+ inputSchema: pinInputSchema
321
+ },
322
+ async ({ id }) => {
323
+ try {
324
+ const memory = setPinnedState(id, 1);
325
+ if (!memory) {
326
+ return {
327
+ isError: true,
328
+ content: [
329
+ {
330
+ type: "text",
331
+ text: `Memory ${id} not found.`
332
+ }
333
+ ]
334
+ };
335
+ }
336
+ return {
337
+ content: [
338
+ {
339
+ type: "text",
340
+ text: `Pinned memory ${memory.row_id}: ${memory.note}`
341
+ }
342
+ ]
343
+ };
344
+ } catch (error) {
345
+ const message = error instanceof Error ? error.message : "Unknown error while pinning memory.";
346
+ return {
347
+ isError: true,
348
+ content: [
349
+ {
350
+ type: "text",
351
+ text: `Failed to pin memory: ${message}`
352
+ }
353
+ ]
354
+ };
355
+ }
356
+ }
357
+ );
358
+ }
359
+ function registerUnpinMemoryTool(server) {
360
+ server.registerTool(
361
+ "unpin_memory",
362
+ {
363
+ description: "Unpin a previously pinned memory.",
364
+ inputSchema: pinInputSchema
365
+ },
366
+ async ({ id }) => {
367
+ try {
368
+ const memory = setPinnedState(id, 0);
369
+ if (!memory) {
370
+ return {
371
+ isError: true,
372
+ content: [
373
+ {
374
+ type: "text",
375
+ text: `Memory ${id} not found.`
376
+ }
377
+ ]
378
+ };
379
+ }
380
+ return {
381
+ content: [
382
+ {
383
+ type: "text",
384
+ text: `Unpinned memory ${memory.row_id}.`
385
+ }
386
+ ]
387
+ };
388
+ } catch (error) {
389
+ const message = error instanceof Error ? error.message : "Unknown error while unpinning memory.";
390
+ return {
391
+ isError: true,
392
+ content: [
393
+ {
394
+ type: "text",
395
+ text: `Failed to unpin memory: ${message}`
396
+ }
397
+ ]
398
+ };
399
+ }
400
+ }
401
+ );
402
+ }
403
+
404
+ // src/tools/search.ts
405
+ import { z as z4 } from "zod";
223
406
  var searchMemoryInputSchema = {
224
- query: z3.string().trim().min(1, "query is required"),
225
- repo: z3.string().trim().min(1).optional(),
226
- limit: z3.number().int().positive().max(50).default(5)
407
+ query: z4.string().trim().min(1, "query is required"),
408
+ repo: z4.string().trim().min(1).optional(),
409
+ limit: z4.number().int().positive().max(50).default(5)
227
410
  };
228
411
  function normalizeFtsQuery(query) {
229
412
  const terms = query.trim().split(/\s+/).map((term) => term.replaceAll('"', '""')).filter(Boolean);
@@ -253,7 +436,7 @@ function registerSearchMemoryTool(server) {
253
436
  const ftsQuery = normalizeFtsQuery(query);
254
437
  const rows = repo ? db.prepare(
255
438
  `
256
- SELECT m.id, m.repo, m.type, m.note, m.tags, m.created_at, m.updated_at, bm25(memories_fts) AS rank
439
+ SELECT m.rowid AS row_id, m.id, m.repo, m.type, m.note, m.tags, m.created_at, m.updated_at, m.pinned, bm25(memories_fts) AS rank
257
440
  FROM memories_fts
258
441
  JOIN memories AS m ON m.rowid = memories_fts.rowid
259
442
  WHERE memories_fts MATCH ? AND m.repo = ?
@@ -262,7 +445,7 @@ function registerSearchMemoryTool(server) {
262
445
  `
263
446
  ).all(ftsQuery, repo, limit) : db.prepare(
264
447
  `
265
- SELECT m.id, m.repo, m.type, m.note, m.tags, m.created_at, m.updated_at, bm25(memories_fts) AS rank
448
+ SELECT m.rowid AS row_id, m.id, m.repo, m.type, m.note, m.tags, m.created_at, m.updated_at, m.pinned, bm25(memories_fts) AS rank
266
449
  FROM memories_fts
267
450
  JOIN memories AS m ON m.rowid = memories_fts.rowid
268
451
  WHERE memories_fts MATCH ?
@@ -283,8 +466,9 @@ function registerSearchMemoryTool(server) {
283
466
  const formatted = rows.map((row, index) => {
284
467
  const tags = parseTags2(row.tags);
285
468
  const tagsText = tags.length > 0 ? ` | tags: ${tags.join(", ")}` : "";
286
- return `${index + 1}. [${row.repo}] ${row.type} (${row.id})
287
- ${row.note}${tagsText}`;
469
+ const pinPrefix = row.pinned ? "\u{1F4CC} Pinned " : "";
470
+ return `${index + 1}. [${row.repo}] ${row.type} (${row.row_id} | legacy: ${row.id})
471
+ ${pinPrefix}${row.note}${tagsText}`;
288
472
  }).join("\n\n");
289
473
  return {
290
474
  content: [
@@ -314,12 +498,12 @@ ${formatted}`
314
498
 
315
499
  // src/tools/store.ts
316
500
  import { nanoid } from "nanoid";
317
- import { z as z4 } from "zod";
501
+ import { z as z5 } from "zod";
318
502
  var storeContextInputSchema = {
319
- repo: z4.string().trim().min(1, "repo is required"),
320
- type: z4.enum(MEMORY_TYPES),
321
- note: z4.string().trim().min(1, "note is required"),
322
- tags: z4.array(z4.string().trim().min(1)).optional()
503
+ repo: z5.string().trim().min(1, "repo is required"),
504
+ type: z5.enum(MEMORY_TYPES),
505
+ note: z5.string().trim().min(1, "note is required"),
506
+ tags: z5.array(z5.string().trim().min(1)).optional()
323
507
  };
324
508
  function registerStoreContextTool(server) {
325
509
  server.registerTool(
@@ -342,11 +526,18 @@ function registerStoreContextTool(server) {
342
526
  VALUES (?, ?, ?, ?, ?, ?, ?)
343
527
  `
344
528
  ).run(id, repo, type, note, JSON.stringify(normalizedTags), now, now);
529
+ const stored = db.prepare(
530
+ `
531
+ SELECT rowid AS row_id, id
532
+ FROM memories
533
+ WHERE id = ?
534
+ `
535
+ ).get(id);
345
536
  return {
346
537
  content: [
347
538
  {
348
539
  type: "text",
349
- text: `Stored memory ${id} for ${repo} (${type}).`
540
+ text: `Stored memory ${id} (numeric id: ${stored?.row_id ?? "unknown"}) for ${repo} (${type}).`
350
541
  }
351
542
  ]
352
543
  };
@@ -366,9 +557,215 @@ function registerStoreContextTool(server) {
366
557
  );
367
558
  }
368
559
 
560
+ // src/tools/summarize.ts
561
+ import { z as z6 } from "zod";
562
+ var summarizeRepoContextInputSchema = {
563
+ repo: z6.string().trim().min(1, "repo is required")
564
+ };
565
+ var sectionTitleByType = {
566
+ convention: "Conventions",
567
+ bug_fix: "Bug Fixes",
568
+ reviewer_pattern: "Reviewer Patterns",
569
+ decision: "Decisions",
570
+ issue: "Issues",
571
+ general: "General"
572
+ };
573
+ function registerSummarizeRepoContextTool(server) {
574
+ server.registerTool(
575
+ "summarize_repo_context",
576
+ {
577
+ description: "Generate a structured markdown summary of all memories for a repository.",
578
+ inputSchema: summarizeRepoContextInputSchema
579
+ },
580
+ async ({ repo }) => {
581
+ try {
582
+ const db = getDb();
583
+ const rows = db.prepare(
584
+ `
585
+ SELECT rowid AS row_id, type, note, pinned
586
+ FROM memories
587
+ WHERE repo = ?
588
+ ORDER BY pinned DESC, updated_at DESC
589
+ `
590
+ ).all(repo);
591
+ if (rows.length === 0) {
592
+ return {
593
+ content: [
594
+ {
595
+ type: "text",
596
+ text: `Fossel Context Summary: ${repo}
597
+
598
+ No memories found.`
599
+ }
600
+ ]
601
+ };
602
+ }
603
+ const pinnedLines = rows.filter((row) => row.pinned === 1).map((row) => `- (${row.row_id}) ${row.note}`);
604
+ const sections = [`Fossel Context Summary: ${repo}`];
605
+ if (pinnedLines.length > 0) {
606
+ sections.push(`\u{1F4CC} Pinned
607
+ ${pinnedLines.join("\n")}`);
608
+ }
609
+ for (const type of MEMORY_TYPES) {
610
+ const entries = rows.filter((row) => row.type === type).map((row) => `- (${row.row_id}) ${row.note}`);
611
+ if (entries.length === 0) {
612
+ continue;
613
+ }
614
+ sections.push(`${sectionTitleByType[type]}
615
+ ${entries.join("\n")}`);
616
+ }
617
+ return {
618
+ content: [
619
+ {
620
+ type: "text",
621
+ text: sections.join("\n\n")
622
+ }
623
+ ]
624
+ };
625
+ } catch (error) {
626
+ const message = error instanceof Error ? error.message : "Unknown error while summarizing repository context.";
627
+ return {
628
+ isError: true,
629
+ content: [
630
+ {
631
+ type: "text",
632
+ text: `Failed to summarize repository context: ${message}`
633
+ }
634
+ ]
635
+ };
636
+ }
637
+ }
638
+ );
639
+ }
640
+
641
+ // src/tools/update.ts
642
+ import { z as z7 } from "zod";
643
+ var updateMemoryInputSchema = {
644
+ id: z7.number().int().positive(),
645
+ content: z7.string().trim().min(1).optional(),
646
+ memory_type: z7.enum(MEMORY_TYPES).optional()
647
+ };
648
+ function parseTags3(raw) {
649
+ try {
650
+ const parsed = JSON.parse(raw);
651
+ return Array.isArray(parsed) ? parsed.filter((value) => typeof value === "string") : [];
652
+ } catch {
653
+ return [];
654
+ }
655
+ }
656
+ function formatMemory(memory) {
657
+ const tags = parseTags3(memory.tags);
658
+ const tagsLine = tags.length > 0 ? tags.join(", ") : "(none)";
659
+ return [
660
+ `Memory ${memory.row_id} updated successfully.`,
661
+ `id: ${memory.row_id}`,
662
+ `legacy_id: ${memory.id}`,
663
+ `repo: ${memory.repo}`,
664
+ `memory_type: ${memory.type}`,
665
+ `content: ${memory.note}`,
666
+ `tags: ${tagsLine}`,
667
+ `pinned: ${memory.pinned === 1 ? "true" : "false"}`,
668
+ `created_at: ${memory.created_at}`,
669
+ `updated_at: ${memory.updated_at}`
670
+ ].join("\n");
671
+ }
672
+ function registerUpdateMemoryTool(server) {
673
+ server.registerTool(
674
+ "update_memory",
675
+ {
676
+ description: "Update an existing memory by numeric id with partial fields.",
677
+ inputSchema: updateMemoryInputSchema
678
+ },
679
+ async ({ id, content, memory_type }) => {
680
+ try {
681
+ if (!content && !memory_type) {
682
+ return {
683
+ isError: true,
684
+ content: [
685
+ {
686
+ type: "text",
687
+ text: "Provide at least one field to update: content or memory_type."
688
+ }
689
+ ]
690
+ };
691
+ }
692
+ const db = getDb();
693
+ const existing = db.prepare(
694
+ `
695
+ SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
696
+ FROM memories
697
+ WHERE rowid = ?
698
+ `
699
+ ).get(id);
700
+ if (!existing) {
701
+ return {
702
+ isError: true,
703
+ content: [
704
+ {
705
+ type: "text",
706
+ text: `Memory ${id} not found.`
707
+ }
708
+ ]
709
+ };
710
+ }
711
+ const now = Math.floor(Date.now() / 1e3);
712
+ const nextType = memory_type ?? existing.type;
713
+ const nextNote = content ?? existing.note;
714
+ db.prepare(
715
+ `
716
+ UPDATE memories
717
+ SET type = ?, note = ?, updated_at = ?
718
+ WHERE rowid = ?
719
+ `
720
+ ).run(nextType, nextNote, now, id);
721
+ const updated = db.prepare(
722
+ `
723
+ SELECT rowid AS row_id, id, repo, type, note, tags, created_at, updated_at, pinned
724
+ FROM memories
725
+ WHERE rowid = ?
726
+ `
727
+ ).get(id);
728
+ if (!updated) {
729
+ return {
730
+ isError: true,
731
+ content: [
732
+ {
733
+ type: "text",
734
+ text: `Memory ${id} could not be loaded after update.`
735
+ }
736
+ ]
737
+ };
738
+ }
739
+ return {
740
+ content: [
741
+ {
742
+ type: "text",
743
+ text: formatMemory(updated)
744
+ }
745
+ ]
746
+ };
747
+ } catch (error) {
748
+ const message = error instanceof Error ? error.message : "Unknown error while updating memory.";
749
+ return {
750
+ isError: true,
751
+ content: [
752
+ {
753
+ type: "text",
754
+ text: `Failed to update memory: ${message}`
755
+ }
756
+ ]
757
+ };
758
+ }
759
+ }
760
+ );
761
+ }
762
+
369
763
  // src/index.ts
370
- async function main() {
371
- const dbPath = process.env.FOSSYL_DB_PATH?.trim() || join(homedir(), ".fossyl", "memory.db");
764
+ function resolveDbPath() {
765
+ return process.env.FOSSEL_DB_PATH?.trim() || join(homedir(), ".fossel", "memory.db");
766
+ }
767
+ async function startServer() {
768
+ const dbPath = resolveDbPath();
372
769
  initDb(dbPath);
373
770
  const server = new McpServer({
374
771
  name: "fossel",
@@ -378,11 +775,23 @@ async function main() {
378
775
  registerGetRepoContextTool(server);
379
776
  registerSearchMemoryTool(server);
380
777
  registerDeleteMemoryTool(server);
778
+ registerUpdateMemoryTool(server);
779
+ registerPinMemoryTool(server);
780
+ registerUnpinMemoryTool(server);
781
+ registerSummarizeRepoContextTool(server);
381
782
  const transport = new StdioServerTransport();
382
783
  await server.connect(transport);
383
784
  }
384
- main().catch((error) => {
385
- const message = error instanceof Error ? error.message : String(error);
386
- console.error(`Fossyl server failed to start: ${message}`);
387
- process.exit(1);
388
- });
785
+ var entryPath = process.argv[1];
786
+ var currentPath = fileURLToPath(import.meta.url);
787
+ if (entryPath && currentPath === resolve(entryPath)) {
788
+ startServer().catch((error) => {
789
+ const message = error instanceof Error ? error.message : String(error);
790
+ console.error(`Fossel server failed to start: ${message}`);
791
+ process.exit(1);
792
+ });
793
+ }
794
+ export {
795
+ resolveDbPath,
796
+ startServer
797
+ };
package/package.json CHANGED
@@ -1,19 +1,21 @@
1
1
  {
2
2
  "name": "fossel",
3
- "version": "1.0.1",
3
+ "version": "1.0.8",
4
4
  "description": "Local MCP memory server for open-source contributors",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
8
8
  ],
9
9
  "bin": {
10
- "fossel": "dist/index.js"
10
+ "fossel": "dist/cli.js"
11
11
  },
12
12
  "scripts": {
13
13
  "build": "tsup",
14
14
  "dev": "tsx src/index.ts",
15
15
  "start": "node dist/index.js",
16
- "smoke": "tsx scripts/smoke.ts"
16
+ "smoke": "tsx scripts/smoke.ts",
17
+ "typecheck": "tsc --noEmit",
18
+ "ci": "npm run typecheck && npm run build && npm run smoke"
17
19
  },
18
20
  "dependencies": {
19
21
  "@modelcontextprotocol/sdk": "latest",