@nex-ai/nex 0.1.33 → 0.1.35

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 (171) hide show
  1. package/dist/agent/loop.d.ts +3 -9
  2. package/dist/agent/loop.js +13 -29
  3. package/dist/agent/loop.js.map +1 -1
  4. package/dist/agent/queues.d.ts +0 -1
  5. package/dist/agent/queues.js +0 -3
  6. package/dist/agent/queues.js.map +1 -1
  7. package/dist/agent/templates.js +3 -3
  8. package/dist/agent/templates.js.map +1 -1
  9. package/dist/index.js +6 -19
  10. package/dist/index.js.map +1 -1
  11. package/dist/mcp/channel.d.ts +28 -0
  12. package/dist/mcp/channel.js +135 -0
  13. package/dist/mcp/channel.js.map +1 -0
  14. package/dist/mcp/client.d.ts +20 -0
  15. package/dist/mcp/client.js +130 -0
  16. package/dist/mcp/client.js.map +1 -0
  17. package/dist/mcp/config.d.ts +14 -0
  18. package/dist/mcp/config.js +33 -0
  19. package/dist/mcp/config.js.map +1 -0
  20. package/dist/mcp/context-files.d.ts +9 -0
  21. package/dist/mcp/context-files.js +90 -0
  22. package/dist/mcp/context-files.js.map +1 -0
  23. package/dist/mcp/file-manifest.d.ts +27 -0
  24. package/dist/mcp/file-manifest.js +64 -0
  25. package/dist/mcp/file-manifest.js.map +1 -0
  26. package/dist/mcp/file-scanner.d.ts +17 -0
  27. package/dist/mcp/file-scanner.js +77 -0
  28. package/dist/mcp/file-scanner.js.map +1 -0
  29. package/dist/mcp/index.d.ts +2 -0
  30. package/dist/mcp/index.js +51 -0
  31. package/dist/mcp/index.js.map +1 -0
  32. package/dist/mcp/rate-limiter.d.ts +14 -0
  33. package/dist/mcp/rate-limiter.js +60 -0
  34. package/dist/mcp/rate-limiter.js.map +1 -0
  35. package/dist/mcp/server.d.ts +6 -0
  36. package/dist/mcp/server.js +42 -0
  37. package/dist/mcp/server.js.map +1 -0
  38. package/dist/mcp/session-store.d.ts +16 -0
  39. package/dist/mcp/session-store.js +70 -0
  40. package/dist/mcp/session-store.js.map +1 -0
  41. package/dist/mcp/tools/context.d.ts +3 -0
  42. package/dist/mcp/tools/context.js +65 -0
  43. package/dist/mcp/tools/context.js.map +1 -0
  44. package/dist/mcp/tools/insights.d.ts +3 -0
  45. package/dist/mcp/tools/insights.js +24 -0
  46. package/dist/mcp/tools/insights.js.map +1 -0
  47. package/dist/mcp/tools/integrations.d.ts +3 -0
  48. package/dist/mcp/tools/integrations.js +27 -0
  49. package/dist/mcp/tools/integrations.js.map +1 -0
  50. package/dist/mcp/tools/lists.d.ts +3 -0
  51. package/dist/mcp/tools/lists.js +101 -0
  52. package/dist/mcp/tools/lists.js.map +1 -0
  53. package/dist/mcp/tools/notes.d.ts +3 -0
  54. package/dist/mcp/tools/notes.js +52 -0
  55. package/dist/mcp/tools/notes.js.map +1 -0
  56. package/dist/mcp/tools/records.d.ts +3 -0
  57. package/dist/mcp/tools/records.js +74 -0
  58. package/dist/mcp/tools/records.js.map +1 -0
  59. package/dist/mcp/tools/register.d.ts +3 -0
  60. package/dist/mcp/tools/register.js +30 -0
  61. package/dist/mcp/tools/register.js.map +1 -0
  62. package/dist/mcp/tools/relationships.d.ts +3 -0
  63. package/dist/mcp/tools/relationships.js +47 -0
  64. package/dist/mcp/tools/relationships.js.map +1 -0
  65. package/dist/mcp/tools/scan.d.ts +3 -0
  66. package/dist/mcp/tools/scan.js +37 -0
  67. package/dist/mcp/tools/scan.js.map +1 -0
  68. package/dist/mcp/tools/schema.d.ts +3 -0
  69. package/dist/mcp/tools/schema.js +108 -0
  70. package/dist/mcp/tools/schema.js.map +1 -0
  71. package/dist/mcp/tools/search.d.ts +3 -0
  72. package/dist/mcp/tools/search.js +8 -0
  73. package/dist/mcp/tools/search.js.map +1 -0
  74. package/dist/mcp/tools/tasks.d.ts +3 -0
  75. package/dist/mcp/tools/tasks.js +88 -0
  76. package/dist/mcp/tools/tasks.js.map +1 -0
  77. package/dist/plugin/auto-capture.js +106 -6
  78. package/dist/plugin/auto-capture.js.map +1 -1
  79. package/dist/plugin/auto-recall.js +79 -5
  80. package/dist/plugin/auto-recall.js.map +1 -1
  81. package/dist/plugin/auto-register.d.ts +1 -1
  82. package/dist/plugin/auto-register.js +8 -13
  83. package/dist/plugin/auto-register.js.map +1 -1
  84. package/dist/plugin/auto-scan.js +5 -0
  85. package/dist/plugin/auto-scan.js.map +1 -1
  86. package/dist/plugin/auto-session-start.d.ts +3 -0
  87. package/dist/plugin/auto-session-start.js +127 -8
  88. package/dist/plugin/auto-session-start.js.map +1 -1
  89. package/dist/plugin/config.d.ts +16 -7
  90. package/dist/plugin/config.js +20 -16
  91. package/dist/plugin/config.js.map +1 -1
  92. package/dist/plugin/context-format.d.ts +0 -4
  93. package/dist/plugin/context-format.js +0 -4
  94. package/dist/plugin/context-format.js.map +1 -1
  95. package/dist/plugin/file-manifest.d.ts +6 -0
  96. package/dist/plugin/file-manifest.js +16 -0
  97. package/dist/plugin/file-manifest.js.map +1 -1
  98. package/dist/plugin/nex-client.js +1 -1
  99. package/dist/plugin/nex-client.js.map +1 -1
  100. package/dist/plugin/recall-filter.d.ts +5 -14
  101. package/dist/plugin/recall-filter.js +44 -32
  102. package/dist/plugin/recall-filter.js.map +1 -1
  103. package/dist/plugin/shared.js +31 -22
  104. package/dist/plugin/shared.js.map +1 -1
  105. package/dist/tui/app.js +3 -3
  106. package/dist/tui/app.js.map +1 -1
  107. package/dist/tui/services/agent-service.d.ts +0 -6
  108. package/dist/tui/services/agent-service.js +5 -39
  109. package/dist/tui/services/agent-service.js.map +1 -1
  110. package/dist/tui/slash-commands.d.ts +0 -2
  111. package/dist/tui/slash-commands.js +7 -150
  112. package/dist/tui/slash-commands.js.map +1 -1
  113. package/dist/tui/views/stream.d.ts +3 -6
  114. package/dist/tui/views/stream.js +51 -241
  115. package/dist/tui/views/stream.js.map +1 -1
  116. package/package.json +6 -4
  117. package/plugin-commands/integrate.md +15 -10
  118. package/plugin-commands/recall.md +1 -1
  119. package/dist/agent/message-router.d.ts +0 -26
  120. package/dist/agent/message-router.js +0 -114
  121. package/dist/agent/message-router.js.map +0 -1
  122. package/dist/agent/orchestrate.d.ts +0 -26
  123. package/dist/agent/orchestrate.js +0 -87
  124. package/dist/agent/orchestrate.js.map +0 -1
  125. package/dist/agent/providers/claude-bridge.d.ts +0 -13
  126. package/dist/agent/providers/claude-bridge.js +0 -161
  127. package/dist/agent/providers/claude-bridge.js.map +0 -1
  128. package/dist/agent/providers/claude-code.d.ts +0 -27
  129. package/dist/agent/providers/claude-code.js +0 -164
  130. package/dist/agent/providers/claude-code.js.map +0 -1
  131. package/dist/agent/providers/claude-worker.d.ts +0 -6
  132. package/dist/agent/providers/claude-worker.js +0 -28
  133. package/dist/agent/providers/claude-worker.js.map +0 -1
  134. package/dist/agent/providers/gemini.d.ts +0 -12
  135. package/dist/agent/providers/gemini.js +0 -110
  136. package/dist/agent/providers/gemini.js.map +0 -1
  137. package/dist/agent/providers/types.d.ts +0 -5
  138. package/dist/agent/providers/types.js +0 -2
  139. package/dist/agent/providers/types.js.map +0 -1
  140. package/dist/agent/tick-manager.d.ts +0 -20
  141. package/dist/agent/tick-manager.js +0 -50
  142. package/dist/agent/tick-manager.js.map +0 -1
  143. package/dist/lib/claude-code-installer.d.ts +0 -8
  144. package/dist/lib/claude-code-installer.js +0 -76
  145. package/dist/lib/claude-code-installer.js.map +0 -1
  146. package/dist/lib/nex-mcp-config.d.ts +0 -21
  147. package/dist/lib/nex-mcp-config.js +0 -33
  148. package/dist/lib/nex-mcp-config.js.map +0 -1
  149. package/dist/tui/components/agent-roster.d.ts +0 -7
  150. package/dist/tui/components/agent-roster.js +0 -66
  151. package/dist/tui/components/agent-roster.js.map +0 -1
  152. package/plugin-commands/add-field.md +0 -12
  153. package/plugin-commands/artifact.md +0 -14
  154. package/plugin-commands/create-note.md +0 -10
  155. package/plugin-commands/create-object.md +0 -10
  156. package/plugin-commands/create-record.md +0 -11
  157. package/plugin-commands/create-task.md +0 -10
  158. package/plugin-commands/insights.md +0 -13
  159. package/plugin-commands/link-records.md +0 -10
  160. package/plugin-commands/list-members.md +0 -15
  161. package/plugin-commands/lists.md +0 -14
  162. package/plugin-commands/notes.md +0 -13
  163. package/plugin-commands/record.md +0 -12
  164. package/plugin-commands/relationships.md +0 -12
  165. package/plugin-commands/schema.md +0 -12
  166. package/plugin-commands/search.md +0 -12
  167. package/plugin-commands/tasks.md +0 -13
  168. package/plugin-commands/timeline.md +0 -12
  169. package/plugin-commands/update-field.md +0 -10
  170. package/plugin-commands/update-record.md +0 -11
  171. package/plugin-commands/upsert-record.md +0 -13
@@ -0,0 +1,33 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join, dirname } from "node:path";
4
+ const CONFIG_PATH = join(homedir(), ".nex", "config.json");
5
+ export function loadConfig() {
6
+ try {
7
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
8
+ return JSON.parse(raw);
9
+ }
10
+ catch {
11
+ return {};
12
+ }
13
+ }
14
+ export function saveConfig(config) {
15
+ mkdirSync(dirname(CONFIG_PATH), { recursive: true });
16
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
17
+ }
18
+ export function loadApiKey() {
19
+ return process.env.NEX_API_KEY || loadConfig().api_key || undefined;
20
+ }
21
+ export function persistRegistration(data) {
22
+ const existing = loadConfig();
23
+ if (typeof data.api_key === "string")
24
+ existing.api_key = data.api_key;
25
+ if (typeof data.workspace_id === "string" || typeof data.workspace_id === "number") {
26
+ existing.workspace_id = String(data.workspace_id);
27
+ }
28
+ if (typeof data.workspace_slug === "string")
29
+ existing.workspace_slug = data.workspace_slug;
30
+ saveConfig(existing);
31
+ }
32
+ export { CONFIG_PATH };
33
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/mcp/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAW3D,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,UAAU,EAAE,CAAC,OAAO,IAAI,SAAS,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAA6B;IAC/D,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;QAAE,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IACtE,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QACnF,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ;QAAE,QAAQ,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;IAC3F,UAAU,CAAC,QAAQ,CAAC,CAAC;AACvB,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { NexApiClient } from "./client.js";
2
+ import type { RateLimiter } from "./rate-limiter.js";
3
+ export interface ContextFilesResult {
4
+ ingested: number;
5
+ skipped: number;
6
+ errors: number;
7
+ files: string[];
8
+ }
9
+ export declare function ingestContextFiles(client: NexApiClient, rateLimiter: RateLimiter, cwd: string): Promise<ContextFilesResult>;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Ingests Claude Code context files (CLAUDE.md + memory files) into Nex.
3
+ *
4
+ * Reads from both global and project-level locations:
5
+ * - ~/.claude/CLAUDE.md (global instructions)
6
+ * - {cwd}/CLAUDE.md (project instructions)
7
+ * - ~/.claude/projects/{project-key}/memory/*.md (memory files)
8
+ *
9
+ * Uses the file manifest for change detection — unchanged files are skipped.
10
+ */
11
+ import { existsSync, readdirSync, statSync, readFileSync } from "node:fs";
12
+ import { join, extname, basename } from "node:path";
13
+ import { homedir } from "node:os";
14
+ import { readManifest, writeManifest, isChanged, markIngested } from "./file-manifest.js";
15
+ const CLAUDE_DIR = join(homedir(), ".claude");
16
+ const INGEST_TIMEOUT_MS = 10_000;
17
+ const MAX_FILE_SIZE = 100_000;
18
+ function projectKey(cwd) {
19
+ return cwd.replace(/\//g, "-");
20
+ }
21
+ function collectContextFiles(cwd) {
22
+ const files = [];
23
+ const key = projectKey(cwd);
24
+ const globalClaude = join(CLAUDE_DIR, "CLAUDE.md");
25
+ if (existsSync(globalClaude)) {
26
+ files.push({ path: globalClaude, contextTag: "claude-md:global" });
27
+ }
28
+ const projectClaude = join(cwd, "CLAUDE.md");
29
+ if (existsSync(projectClaude)) {
30
+ files.push({ path: projectClaude, contextTag: "claude-md:project" });
31
+ }
32
+ const memoryDir = join(CLAUDE_DIR, "projects", key, "memory");
33
+ if (existsSync(memoryDir)) {
34
+ try {
35
+ const entries = readdirSync(memoryDir, { withFileTypes: true });
36
+ for (const entry of entries) {
37
+ if (!entry.isFile())
38
+ continue;
39
+ if (extname(entry.name).toLowerCase() !== ".md")
40
+ continue;
41
+ const fullPath = join(memoryDir, entry.name);
42
+ const name = basename(entry.name, ".md");
43
+ files.push({ path: fullPath, contextTag: `claude-memory:${name}` });
44
+ }
45
+ }
46
+ catch {
47
+ // memoryDir unreadable — skip
48
+ }
49
+ }
50
+ return files;
51
+ }
52
+ export async function ingestContextFiles(client, rateLimiter, cwd) {
53
+ const result = { ingested: 0, skipped: 0, errors: 0, files: [] };
54
+ const manifest = readManifest();
55
+ const candidates = collectContextFiles(cwd);
56
+ let dirty = false;
57
+ for (const { path, contextTag } of candidates) {
58
+ try {
59
+ const stat = statSync(path);
60
+ if (!isChanged(path, stat, manifest)) {
61
+ result.skipped++;
62
+ continue;
63
+ }
64
+ if (!rateLimiter.canProceed()) {
65
+ process.stderr.write("[nex-context-files] Rate limited — stopping context file ingest\n");
66
+ result.skipped += candidates.length - result.ingested - result.skipped - result.errors;
67
+ break;
68
+ }
69
+ let content = readFileSync(path, "utf-8");
70
+ if (content.length > MAX_FILE_SIZE) {
71
+ content = content.slice(0, MAX_FILE_SIZE) + "\n[...truncated]";
72
+ }
73
+ await client.post("/v1/context/text", { content, context: contextTag });
74
+ rateLimiter.recordRequest();
75
+ markIngested(path, stat, contextTag, manifest);
76
+ result.ingested++;
77
+ result.files.push(contextTag);
78
+ dirty = true;
79
+ }
80
+ catch (err) {
81
+ process.stderr.write(`[nex-context-files] Failed to ingest ${contextTag}: ${err instanceof Error ? err.message : String(err)}\n`);
82
+ result.errors++;
83
+ }
84
+ }
85
+ if (dirty) {
86
+ writeManifest(manifest);
87
+ }
88
+ return result;
89
+ }
90
+ //# sourceMappingURL=context-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-files.js","sourceRoot":"","sources":["../../src/mcp/context-files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Persistent file manifest — tracks which files have been ingested
3
+ * using mtime + size as change detection.
4
+ *
5
+ * Stored at ~/.nex/file-scan-manifest.json.
6
+ */
7
+ import { type Stats } from "node:fs";
8
+ export interface FileManifestEntry {
9
+ mtime: number;
10
+ size: number;
11
+ ingestedAt: number;
12
+ context: string;
13
+ }
14
+ export interface FileManifest {
15
+ version: 1;
16
+ lastScanAt?: number;
17
+ files: Record<string, FileManifestEntry>;
18
+ }
19
+ export declare function readManifest(): FileManifest;
20
+ export declare function writeManifest(manifest: FileManifest): void;
21
+ export declare function isChanged(path: string, stat: Stats, manifest: FileManifest): boolean;
22
+ export declare function markIngested(path: string, stat: Stats, context: string, manifest: FileManifest): void;
23
+ /**
24
+ * Record that a full scan completed at this moment.
25
+ */
26
+ export declare function markScanned(manifest: FileManifest): void;
27
+ export declare function isScanFresh(manifest: FileManifest, windowMs?: number): boolean;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Persistent file manifest — tracks which files have been ingested
3
+ * using mtime + size as change detection.
4
+ *
5
+ * Stored at ~/.nex/file-scan-manifest.json.
6
+ */
7
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { homedir } from "node:os";
10
+ const DATA_DIR = join(homedir(), ".nex");
11
+ const MANIFEST_PATH = join(DATA_DIR, "file-scan-manifest.json");
12
+ export function readManifest() {
13
+ try {
14
+ const raw = readFileSync(MANIFEST_PATH, "utf-8");
15
+ const data = JSON.parse(raw);
16
+ if (data && data.version === 1 && data.files) {
17
+ return data;
18
+ }
19
+ return { version: 1, files: {} };
20
+ }
21
+ catch {
22
+ return { version: 1, files: {} };
23
+ }
24
+ }
25
+ export function writeManifest(manifest) {
26
+ try {
27
+ mkdirSync(DATA_DIR, { recursive: true });
28
+ writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2), "utf-8");
29
+ }
30
+ catch {
31
+ // Best-effort — if we can't write, next scan re-ingests
32
+ }
33
+ }
34
+ export function isChanged(path, stat, manifest) {
35
+ const entry = manifest.files[path];
36
+ if (!entry)
37
+ return true;
38
+ return entry.mtime !== stat.mtimeMs || entry.size !== stat.size;
39
+ }
40
+ export function markIngested(path, stat, context, manifest) {
41
+ manifest.files[path] = {
42
+ mtime: stat.mtimeMs,
43
+ size: stat.size,
44
+ ingestedAt: Date.now(),
45
+ context,
46
+ };
47
+ }
48
+ /**
49
+ * Record that a full scan completed at this moment.
50
+ */
51
+ export function markScanned(manifest) {
52
+ manifest.lastScanAt = Date.now();
53
+ }
54
+ /**
55
+ * Check if a scan completed recently (within the given window).
56
+ * Default window: 1 hour.
57
+ */
58
+ const DEFAULT_SCAN_FRESHNESS_MS = 60 * 60 * 1000; // 1 hour
59
+ export function isScanFresh(manifest, windowMs = DEFAULT_SCAN_FRESHNESS_MS) {
60
+ if (!manifest.lastScanAt)
61
+ return false;
62
+ return Date.now() - manifest.lastScanAt < windowMs;
63
+ }
64
+ //# sourceMappingURL=file-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-manifest.js","sourceRoot":"","sources":["../../src/mcp/file-manifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAc,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AACzC,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,yBAAyB,CAAC,CAAC;AAehE,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAsB;IAClD,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAW,EAAE,QAAsB;IACzE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,IAAW,EAAE,OAAe,EAAE,QAAsB;IAC7F,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;QACrB,KAAK,EAAE,IAAI,CAAC,OAAO;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;QACtB,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAsB;IAChD,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAE3D,MAAM,UAAU,WAAW,CAAC,QAAsB,EAAE,QAAQ,GAAG,yBAAyB;IACtF,IAAI,CAAC,QAAQ,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC;AACrD,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { NexApiClient } from "./client.js";
2
+ import type { RateLimiter } from "./rate-limiter.js";
3
+ export interface ScanConfig {
4
+ enabled: boolean;
5
+ extensions: string[];
6
+ maxFileSize: number;
7
+ maxFilesPerScan: number;
8
+ scanDepth: number;
9
+ ignoreDirs: string[];
10
+ }
11
+ export interface ScanResult {
12
+ scanned: number;
13
+ ingested: number;
14
+ skipped: number;
15
+ errors: number;
16
+ }
17
+ export declare function scanAndIngest(client: NexApiClient, rateLimiter: RateLimiter, cwd: string, config: ScanConfig): Promise<ScanResult>;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Core file scanner — walks project directories, detects changed files,
3
+ * and ingests them into Nex via the developer API.
4
+ */
5
+ import { readdirSync, statSync, readFileSync } from "node:fs";
6
+ import { join, relative, extname } from "node:path";
7
+ import { readManifest, writeManifest, isChanged, markIngested } from "./file-manifest.js";
8
+ function walkDir(dir, cwd, config, depth, results) {
9
+ if (depth > config.scanDepth)
10
+ return;
11
+ let entries;
12
+ try {
13
+ entries = readdirSync(dir, { withFileTypes: true });
14
+ }
15
+ catch {
16
+ return;
17
+ }
18
+ for (const entry of entries) {
19
+ const fullPath = join(dir, entry.name);
20
+ if (entry.isDirectory()) {
21
+ if (config.ignoreDirs.includes(entry.name))
22
+ continue;
23
+ walkDir(fullPath, cwd, config, depth + 1, results);
24
+ }
25
+ else if (entry.isFile()) {
26
+ const ext = extname(entry.name).toLowerCase();
27
+ if (!config.extensions.includes(ext))
28
+ continue;
29
+ try {
30
+ const stat = statSync(fullPath);
31
+ results.push({ absolutePath: fullPath, relativePath: relative(cwd, fullPath), stat });
32
+ }
33
+ catch {
34
+ // stat failed — skip
35
+ }
36
+ }
37
+ }
38
+ }
39
+ export async function scanAndIngest(client, rateLimiter, cwd, config) {
40
+ const result = { scanned: 0, ingested: 0, skipped: 0, errors: 0 };
41
+ if (!config.enabled)
42
+ return result;
43
+ const manifest = readManifest();
44
+ const candidates = [];
45
+ walkDir(cwd, cwd, config, 0, candidates);
46
+ result.scanned = candidates.length;
47
+ const changed = candidates
48
+ .filter((f) => isChanged(f.absolutePath, f.stat, manifest))
49
+ .sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
50
+ .slice(0, config.maxFilesPerScan);
51
+ result.skipped = candidates.length - changed.length;
52
+ for (const file of changed) {
53
+ if (!rateLimiter.canProceed()) {
54
+ process.stderr.write(`[nex-scan] Rate limited — stopping after ${result.ingested} files\n`);
55
+ result.skipped += changed.length - result.ingested - result.errors;
56
+ break;
57
+ }
58
+ try {
59
+ let content = readFileSync(file.absolutePath, "utf-8");
60
+ if (content.length > config.maxFileSize) {
61
+ content = content.slice(0, config.maxFileSize) + "\n[...truncated]";
62
+ }
63
+ const context = `file-scan:${file.relativePath}`;
64
+ await client.post("/v1/context/text", { content, context });
65
+ rateLimiter.recordRequest();
66
+ markIngested(file.absolutePath, file.stat, context, manifest);
67
+ result.ingested++;
68
+ }
69
+ catch (err) {
70
+ process.stderr.write(`[nex-scan] Failed to ingest ${file.relativePath}: ${err instanceof Error ? err.message : String(err)}\n`);
71
+ result.errors++;
72
+ }
73
+ }
74
+ writeManifest(manifest);
75
+ return result;
76
+ }
77
+ //# sourceMappingURL=file-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-scanner.js","sourceRoot":"","sources":["../../src/mcp/file-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { createServer } from "./server.js";
5
+ import { createServer as createHttpServer } from "node:http";
6
+ import { loadApiKey } from "./config.js";
7
+ import { startChannel } from "./channel.js";
8
+ const apiKey = loadApiKey();
9
+ if (!apiKey) {
10
+ console.error("No API key found (checked NEX_API_KEY env and ~/.nex/config.json). Starting in registration-only mode. Use the 'register' tool to create an account and get an API key. Once registered, all context, search, and scan tools become available.");
11
+ }
12
+ const transport = process.env.MCP_TRANSPORT ?? "stdio";
13
+ async function main() {
14
+ const { server, client } = createServer(apiKey);
15
+ if (transport === "http") {
16
+ const port = parseInt(process.env.MCP_PORT ?? "3001", 10);
17
+ const httpTransport = new StreamableHTTPServerTransport({
18
+ sessionIdGenerator: undefined,
19
+ });
20
+ const httpServer = createHttpServer(async (req, res) => {
21
+ const url = new URL(req.url ?? "/", `http://localhost:${port}`);
22
+ if (url.pathname === "/mcp") {
23
+ await httpTransport.handleRequest(req, res);
24
+ }
25
+ else if (url.pathname === "/health") {
26
+ res.writeHead(200, { "Content-Type": "application/json" });
27
+ res.end(JSON.stringify({ status: "ok" }));
28
+ }
29
+ else {
30
+ res.writeHead(404);
31
+ res.end("Not found");
32
+ }
33
+ });
34
+ await server.connect(httpTransport);
35
+ startChannel(server.server, client);
36
+ httpServer.listen(port, () => {
37
+ console.error(`Nex MCP server running on http://localhost:${port}/mcp`);
38
+ });
39
+ }
40
+ else {
41
+ const stdioTransport = new StdioServerTransport();
42
+ await server.connect(stdioTransport);
43
+ startChannel(server.server, client);
44
+ console.error("Nex MCP server running on stdio");
45
+ }
46
+ }
47
+ main().catch((err) => {
48
+ console.error("Fatal error:", err);
49
+ process.exit(1);
50
+ });
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,KAAK,CAAC,gPAAgP,CAAC,CAAC;AAClQ,CAAC;AAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC;AAEvD,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAEhD,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;QAE1D,MAAM,aAAa,GAAG,IAAI,6BAA6B,CAAC;YACtD,kBAAkB,EAAE,SAAS;SAC9B,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YACrD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;gBAC5B,MAAM,aAAa,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC9C,CAAC;iBAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACtC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC5C,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACvB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACpC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YAC3B,OAAO,CAAC,KAAK,CAAC,8CAA8C,IAAI,MAAM,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,cAAc,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAClD,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACrC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface RateLimiterConfig {
2
+ maxRequests: number;
3
+ windowMs: number;
4
+ dataDir: string;
5
+ }
6
+ export declare class RateLimiter {
7
+ private config;
8
+ private filePath;
9
+ constructor(config?: Partial<RateLimiterConfig>);
10
+ private readTimestamps;
11
+ private writeTimestamps;
12
+ canProceed(): boolean;
13
+ recordRequest(): void;
14
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * File-based sliding window rate limiter.
3
+ * Designed for Nex /text endpoint (10 req/min).
4
+ *
5
+ * Persists timestamps to a JSON file so rate limits are respected
6
+ * across invocations.
7
+ */
8
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { homedir } from "node:os";
11
+ const DEFAULTS = {
12
+ maxRequests: 10,
13
+ windowMs: 60_000,
14
+ dataDir: join(homedir(), ".nex"),
15
+ };
16
+ export class RateLimiter {
17
+ config;
18
+ filePath;
19
+ constructor(config) {
20
+ this.config = { ...DEFAULTS, ...config };
21
+ this.filePath = join(this.config.dataDir, "rate-limiter.json");
22
+ mkdirSync(this.config.dataDir, { recursive: true });
23
+ }
24
+ readTimestamps() {
25
+ try {
26
+ const raw = readFileSync(this.filePath, "utf-8");
27
+ const data = JSON.parse(raw);
28
+ if (Array.isArray(data))
29
+ return data;
30
+ return [];
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ }
36
+ writeTimestamps(timestamps) {
37
+ try {
38
+ writeFileSync(this.filePath, JSON.stringify(timestamps), "utf-8");
39
+ }
40
+ catch {
41
+ // Best-effort
42
+ }
43
+ }
44
+ canProceed() {
45
+ const now = Date.now();
46
+ const timestamps = this.readTimestamps().filter((t) => now - t < this.config.windowMs);
47
+ if (timestamps.length >= this.config.maxRequests) {
48
+ this.writeTimestamps(timestamps);
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ recordRequest() {
54
+ const now = Date.now();
55
+ const timestamps = this.readTimestamps().filter((t) => now - t < this.config.windowMs);
56
+ timestamps.push(now);
57
+ this.writeTimestamps(timestamps);
58
+ }
59
+ }
60
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/mcp/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQlC,MAAM,QAAQ,GAAsB;IAClC,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,OAAO,WAAW;IACd,MAAM,CAAoB;IAC1B,QAAQ,CAAS;IAEzB,YAAY,MAAmC;QAC7C,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QAC/D,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;YACrC,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,eAAe,CAAC,UAAoB;QAC1C,IAAI,CAAC;YACH,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IAED,UAAU;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvF,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;YACjC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,aAAa;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvF,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NexApiClient } from "./client.js";
3
+ export declare function createServer(apiKey?: string): {
4
+ server: McpServer;
5
+ client: NexApiClient;
6
+ };
@@ -0,0 +1,42 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NexApiClient } from "./client.js";
3
+ import { registerContextTools } from "./tools/context.js";
4
+ import { registerSearchTools } from "./tools/search.js";
5
+ import { registerSchemaTools } from "./tools/schema.js";
6
+ import { registerRecordTools } from "./tools/records.js";
7
+ import { registerRelationshipTools } from "./tools/relationships.js";
8
+ import { registerListTools } from "./tools/lists.js";
9
+ import { registerTaskTools } from "./tools/tasks.js";
10
+ import { registerNoteTools } from "./tools/notes.js";
11
+ import { registerInsightTools } from "./tools/insights.js";
12
+ import { registerRegistrationTools } from "./tools/register.js";
13
+ import { registerScanTools } from "./tools/scan.js";
14
+ import { registerIntegrationTools } from "./tools/integrations.js";
15
+ export function createServer(apiKey) {
16
+ const server = new McpServer({ name: "nex", version: "0.1.0" }, {
17
+ capabilities: {
18
+ experimental: { "claude/channel": {} },
19
+ },
20
+ instructions: 'Events from the nex channel arrive as <channel source="nex" type="...">. ' +
21
+ "They contain daily digest summaries (type=daily_digest) and proactive " +
22
+ "notifications (type=proactive_notification) about important context " +
23
+ "changes — deals, meetings, relationships, tasks. These are one-way " +
24
+ "informational: acknowledge them naturally and incorporate into your " +
25
+ "awareness. No reply expected.",
26
+ });
27
+ const client = new NexApiClient(apiKey);
28
+ registerRegistrationTools(server, client);
29
+ registerContextTools(server, client);
30
+ registerSearchTools(server, client);
31
+ registerSchemaTools(server, client);
32
+ registerRecordTools(server, client);
33
+ registerRelationshipTools(server, client);
34
+ registerListTools(server, client);
35
+ registerTaskTools(server, client);
36
+ registerNoteTools(server, client);
37
+ registerInsightTools(server, client);
38
+ registerScanTools(server, client);
39
+ registerIntegrationTools(server, client);
40
+ return { server, client };
41
+ }
42
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,MAAM,UAAU,YAAY,CAAC,MAAe;IAI1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EACjC;QACE,YAAY,EAAE;YACZ,YAAY,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE;SACvC;QACD,YAAY,EACV,2EAA2E;YAC3E,wEAAwE;YACxE,sEAAsE;YACtE,qEAAqE;YACrE,sEAAsE;YACtE,+BAA+B;KAClC,CACF,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IAExC,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface SessionStoreConfig {
2
+ maxSize: number;
3
+ dataDir: string;
4
+ }
5
+ export declare class SessionStore {
6
+ private filePath;
7
+ private maxSize;
8
+ constructor(config?: Partial<SessionStoreConfig>);
9
+ private readStore;
10
+ private writeStore;
11
+ get(sessionKey: string): string | undefined;
12
+ set(sessionKey: string, nexSessionId: string): void;
13
+ delete(sessionKey: string): boolean;
14
+ get size(): number;
15
+ clear(): void;
16
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * File-based session store for MCP session ID mapping.
3
+ * Persists session mappings to ~/.nex/mcp-sessions.json.
4
+ */
5
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { homedir } from "node:os";
8
+ const DEFAULT_MAX = 100;
9
+ const DEFAULT_DATA_DIR = join(homedir(), ".nex");
10
+ export class SessionStore {
11
+ filePath;
12
+ maxSize;
13
+ constructor(config) {
14
+ const dataDir = config?.dataDir ?? DEFAULT_DATA_DIR;
15
+ this.maxSize = config?.maxSize ?? DEFAULT_MAX;
16
+ this.filePath = join(dataDir, "mcp-sessions.json");
17
+ mkdirSync(dataDir, { recursive: true });
18
+ }
19
+ readStore() {
20
+ try {
21
+ const raw = readFileSync(this.filePath, "utf-8");
22
+ const data = JSON.parse(raw);
23
+ if (data && typeof data === "object" && !Array.isArray(data)) {
24
+ return data;
25
+ }
26
+ return {};
27
+ }
28
+ catch {
29
+ return {};
30
+ }
31
+ }
32
+ writeStore(store) {
33
+ try {
34
+ writeFileSync(this.filePath, JSON.stringify(store), "utf-8");
35
+ }
36
+ catch {
37
+ // Best-effort
38
+ }
39
+ }
40
+ get(sessionKey) {
41
+ const store = this.readStore();
42
+ return store[sessionKey];
43
+ }
44
+ set(sessionKey, nexSessionId) {
45
+ const store = this.readStore();
46
+ store[sessionKey] = nexSessionId;
47
+ const keys = Object.keys(store);
48
+ while (keys.length > this.maxSize) {
49
+ const oldest = keys.shift();
50
+ delete store[oldest];
51
+ }
52
+ this.writeStore(store);
53
+ }
54
+ delete(sessionKey) {
55
+ const store = this.readStore();
56
+ if (sessionKey in store) {
57
+ delete store[sessionKey];
58
+ this.writeStore(store);
59
+ return true;
60
+ }
61
+ return false;
62
+ }
63
+ get size() {
64
+ return Object.keys(this.readStore()).length;
65
+ }
66
+ clear() {
67
+ this.writeStore({});
68
+ }
69
+ }
70
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/mcp/session-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAOlC,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,OAAO,YAAY;IACf,QAAQ,CAAS;IACjB,OAAO,CAAS;IAExB,YAAY,MAAoC;QAC9C,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,gBAAgB,CAAC;QACpD,IAAI,CAAC,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,WAAW,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QACnD,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAEO,SAAS;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7D,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,KAA6B;QAC9C,IAAI,CAAC;YACH,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IAED,GAAG,CAAC,UAAkB;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC;IAED,GAAG,CAAC,UAAkB,EAAE,YAAoB;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/B,KAAK,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAG,CAAC;YAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,UAAkB;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/B,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC;YACzB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,IAAI;QACN,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;IAC9C,CAAC;IAED,KAAK;QACH,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NexApiClient } from "../client.js";
3
+ export declare function registerContextTools(server: McpServer, client: NexApiClient): void;