n2n-nexus 0.4.2 → 0.7.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +77 -117
  3. package/assets/n2n-nexus-banner.jpg +0 -0
  4. package/assets/n2n-nexus-icon.png +0 -0
  5. package/assets/n2n-nexus-logo.png +0 -0
  6. package/build/client/nexus-client.js +44 -21
  7. package/build/config/cli.js +0 -3
  8. package/build/config/index.js +0 -10
  9. package/build/constants.js +7 -11
  10. package/build/daemon/index.js +35 -19
  11. package/build/daemon/rate-limit.js +62 -0
  12. package/build/daemon/server.js +422 -545
  13. package/build/daemon/tool-outputs.js +177 -0
  14. package/build/daemon/tools.js +321 -0
  15. package/build/index.js +1 -1
  16. package/build/server/instance-id.js +19 -0
  17. package/build/server/nexus.js +243 -47
  18. package/build/storage/direct-messages.js +89 -0
  19. package/build/storage/docs.js +14 -7
  20. package/build/storage/events.js +31 -0
  21. package/build/storage/fs-utils.js +42 -0
  22. package/build/storage/global-messages.js +44 -0
  23. package/build/storage/index.js +47 -41
  24. package/build/storage/migrations.js +86 -0
  25. package/build/storage/paths.js +0 -3
  26. package/build/storage/projects.js +4 -5
  27. package/build/storage/registry.js +67 -25
  28. package/build/storage/sessions.js +77 -0
  29. package/build/storage/sqlite-meeting.js +35 -23
  30. package/build/storage/sqlite.js +73 -24
  31. package/build/storage/tasks.js +29 -103
  32. package/build/types.js +1 -1
  33. package/docs/ARCHITECTURE.md +36 -25
  34. package/docs/ARCHITECTURE_zh.md +37 -26
  35. package/docs/ASSISTANT_GUIDE.md +77 -65
  36. package/docs/README_zh.md +34 -19
  37. package/llms.txt +12 -2
  38. package/package.json +24 -14
  39. package/build/storage/logs.js +0 -60
  40. package/build/storage/meetings.js +0 -276
  41. package/build/storage/store.js +0 -153
@@ -1,120 +1,132 @@
1
1
  # Nexus Assistant Guide
2
2
 
3
- 你现在是 **n2ns Nexus** 协作网络的一员。Nexus 由一个独立运行的 **daemon** 提供所有能力——你所使用的工具均由 daemon 定义和执行,MCP 只是透明的转发层。
3
+ You are now part of the **n2ns Nexus** coordination network. All capabilities are provided by a standalone **daemon** — every tool you use is defined and executed by the daemon. The MCP adapter is a transparent forwarding layer only.
4
4
 
5
- > **前提**:在使用任何工具之前,确认 daemon 已启动(`n2n-nexus daemon --port 5688`),你的 MCP 已连接(工具列表非空即为已连接)。
5
+ > **Prerequisite**: Before calling any tool, confirm that the daemon is running (`n2n-nexus daemon --port 5688`) and that your MCP is connected (a non-empty tool list means you are connected).
6
6
 
7
7
  ---
8
8
 
9
- ## 🚦 核心原则:先发现,再操作
9
+ ## Core principle: discover first, then act
10
10
 
11
- ### 1. 了解系统全局状态
11
+ ### 1. Understand the global system state
12
12
 
13
- 在任何任务开始前,先用以下工具了解环境:
13
+ Before starting any task, use these tools to orient yourself:
14
14
 
15
15
  ```
16
- get_global_topology() → 获取所有项目的摘要列表 + 依赖统计
17
- get_global_topology(projectId) → 获取特定项目的详细依赖子图
18
- search_projects(query) → 按名称或描述搜索项目
19
- read_messages(count) → 获取你尚未读取的消息(增量,自动游标)
16
+ get_global_topology() → summary list of all projects + dependency stats
17
+ get_global_topology(projectId) → detailed dependency sub-graph for one project
18
+ search_projects(query) → search projects by name or description
19
+ get_project(projectId) → full manifest + internal docs of one project
20
+ read_messages(count) → fetch messages you have not yet read (incremental, auto-cursor)
20
21
  ```
21
22
 
22
- ### 2. 声明工作上下文
23
+ ### 2. Project IDs
23
24
 
24
- 在写入任何项目数据前,必须先声明活跃项目:
25
+ Project operations need no implicit project context: every project tool takes the `projectId` it acts on.
26
+ Project IDs must follow `[prefix]_[name]` format, for example: `web_my-site`, `api_user-auth`, `mcp_nexus`.
27
+
28
+ ### 3. Write project data
25
29
 
26
30
  ```
27
- register_session_context(projectId) → 绑定当前会话到指定项目
31
+ sync_project_assets(manifest, internalDocs) → sync full project data
32
+ update_project(projectId, patch) → partial update of manifest fields
33
+ rename_project(oldId, newId) → rename and cascade-update all references
34
+ upload_project_asset(projectId, fileName, base64Content) → upload a binary file to the project store
28
35
  ```
29
36
 
30
- 项目 ID 格式必须为 `[prefix]_[name]`,例如:`web_datafrog.io`、`api_user-auth`、`mcp_nexus`。
37
+ All write tools run synchronously and return their result directly.
31
38
 
32
- ### 3. 项目数据写入
39
+ ### Direct conversations
33
40
 
34
- ```
35
- sync_project_assets(manifest, internalDocs) → [ASYNC] 同步项目全量数据,返回 taskId
36
- update_project(projectId, patch) → 部分更新 Manifest 字段
37
- rename_project(oldId, newId) → [ASYNC] 重命名并级联更新所有引用
38
- upload_project_asset(fileName, base64Content) → 上传二进制文件到项目库
39
- ```
41
+ 1. Call `list_sessions` to find the exact destination `sessionId`; use `update_session` to set your name and project association.
42
+ 2. Send `send_message({ to: sessionId, message: "Please review this change" })`. Inspect `status`: accepted means stored, refused means rejected.
43
+ 3. The recipient calls `read_inbox`, then `acknowledge_message({ messageId })` to confirm receipt or passes `outcome: "refused"` to decline.
44
+ 4. Reply with `send_message({ to: original.from, replyTo: original.messageId, message: "Review result..." })`. The sender can query `get_message({ messageId })` for the original receipt.
40
45
 
41
- 异步操作返回 `taskId`,通过 `get_task(taskId)` 轮询进度(`progress` 0.0→1.0)。
46
+ Unconfirmed fetched messages can appear again; use their IDs to recognize retries. Acknowledgement does not mean work is complete. The inbox is pull-only: there is no automatic model wakeup. Connection restarts create new session IDs; discover the destination again. See [receipt and session contracts](TOOLS_REFERENCE.md#session-directory-and-direct-inboxes).
42
47
 
43
- ### 4. 消息与协作
48
+ ### 4. Messages and collaboration
44
49
 
45
50
  ```
46
- send_message(message, category?) → 发消息到活跃会议或全局聊天
47
- read_messages(count?, meetingId?) → 读取你的未读消息(增量)
48
- update_global_strategy(content) → 覆盖写入主战略文档
49
- sync_global_doc(docId, title, content) → 创建/更新跨项目共享文档
51
+ send_message(message, category?, meetingId?) → post to meetingId, else the active meeting, else global chat
52
+ read_messages(count?, meetingId?) → read your unread messages (incremental)
53
+ list_events(limit?, action?) → structured activity log (project.sync, meeting.end, ...)
54
+ get_global_strategy() → read the master strategy document
55
+ update_global_strategy(content) → overwrite the master strategy document
56
+ list_global_docs() → list cross-project shared documents
57
+ get_global_doc(docId) → read a shared document
58
+ sync_global_doc(docId, title, content) → create or update a cross-project shared document
50
59
  ```
51
60
 
52
- 消息分类(`category`):
53
- - `CHAT` — 普通讨论(默认)
54
- - `PROPOSAL` — 提案
55
- - `DECISION` — 决策/共识
56
- - `UPDATE` — 进度更新
57
- - `MEETING_START` — 系统用,无需手动设置
61
+ Message categories (`category`):
62
+
63
+ - `CHAT` — general discussion (default)
64
+ - `PROPOSAL` — a proposal for others to review
65
+ - `DECISION` — a locked consensus or decision
66
+ - `UPDATE` — a progress update
67
+ - `MEETING_START` — set by the system; do not set manually
58
68
 
59
- ### 5. 战术会议
69
+ ### 5. Tactical meetings
60
70
 
61
71
  ```
62
- start_meeting(topic) → 开启新会议,返回 meetingId
63
- send_message("...", "PROPOSAL") → 在会议中发言
64
- send_message("...", "DECISION") → 记录决策
65
- end_meeting(meetingId?, summary?) → 关闭并锁定会议
66
- archive_meeting(meetingId) → 存档(只读)
67
- reopen_meeting(meetingId) → 重新开启
72
+ list_meetings(status?, limit?) → list meetings with status, participants, counts, summary
73
+ start_meeting(topic) → open a meeting, returns meetingId
74
+ send_message("...", "PROPOSAL") → post a proposal inside the meeting
75
+ send_message("...", "DECISION") → record a decision
76
+ end_meeting(meetingId?, summary?) → close and lock the meeting
77
+ archive_meeting(meetingId) → move to archive (read-only)
78
+ reopen_meeting(meetingId) → reactivate a closed or archived meeting
68
79
  ```
69
80
 
70
- ### 6. 后台任务管理
81
+ ### 6. Task tracking
71
82
 
72
83
  ```
73
- create_task(source_meeting_id?, metadata?) → 创建任务,返回 taskId
74
- get_task(taskId) → 查询状态和进度
75
- list_tasks(status?) → 列出所有任务
76
- cancel_task(taskId) → 取消任务
84
+ create_task(source_meeting_id?, metadata?) → create a task you manage yourself, returns taskId
85
+ get_task(taskId) → query status and progress
86
+ list_tasks(status?) → list all tasks
87
+ cancel_task(taskId) → cancel a pending or running task
77
88
  ```
78
89
 
79
- ### 7. 维护工具
90
+ ### 7. Maintenance
80
91
 
81
92
  ```
82
- host_maintenance(action, count) → prune 最旧 N 条日志 / clear 全部
83
- host_delete_project(projectId) → [ASYNC] 永久删除项目(不可逆)
93
+ host_maintenance(action, count) → prune the oldest N global messages / clear all
94
+ host_delete_project(projectId) → permanently delete a project (irreversible)
84
95
  ```
85
96
 
86
97
  ---
87
98
 
88
- ## 📋 典型工作流
99
+ ## Typical workflows
100
+
101
+ ### First connection to the system
89
102
 
90
- ### 首次接入系统
91
103
  ```
92
- 1. get_global_topology() ← 了解有哪些项目
93
- 2. read_messages(20) ← 了解最近的讨论
94
- 3. register_session_context(id) ← 声明我在哪个项目工作
104
+ 1. get_global_topology() ← learn what projects exist
105
+ 2. read_messages(20) ← catch up on recent discussion
106
+ 3. get_project(projectId) ← read the manifest and docs of the project you work on
95
107
  ```
96
108
 
97
- ### 同步项目数据
109
+ ### Sync project data
110
+
98
111
  ```
99
- 1. register_session_context(projectId)
100
- 2. sync_project_assets(manifest, internalDocs) ← 返回 taskId
101
- 3. get_task(taskId) ← 轮询直到 completed
112
+ 1. sync_project_assets(manifest, internalDocs) ← returns { ok, projectId }
102
113
  ```
103
114
 
104
- ### 发起协作讨论
115
+ ### Start a collaborative discussion
116
+
105
117
  ```
106
118
  1. start_meeting("Topic")
107
- 2. send_message("我的提案...", "PROPOSAL")
108
- 3. read_messages() ← 读取其他实例的回复
109
- 4. send_message("已达成共识", "DECISION")
119
+ 2. send_message("My proposal...", "PROPOSAL")
120
+ 3. read_messages() ← read replies from other instances
121
+ 4. send_message("Consensus reached", "DECISION")
110
122
  5. end_meeting(meetingId, "summary")
111
123
  ```
112
124
 
113
125
  ---
114
126
 
115
- ## ⚠️ 注意事项
127
+ ## Notes
116
128
 
117
- - `read_messages` 是**增量的**:每次调用只返回自上次读取后的新消息,游标由 daemon 自动管理,不需要传 `afterId`。
118
- - 异步操作(`sync_project_assets`、`rename_project`、`host_delete_project`)立即返回 `taskId`,不阻塞。如需等待完成,轮询 `get_task`。
119
- - 项目 ID 一旦被其他项目引用(`relations`),重命名会自动级联更新所有引用,不需要手动处理。
120
- - daemon 重启后,你的 MCP 会自动重连并恢复工具列表,无需重启 IDE。
129
+ - `read_messages` is **incremental**: each call returns only messages received since the last read. The cursor is managed automatically by the daemon — do not pass `afterId`.
130
+ - Write tools (`sync_project_assets`, `update_project`, `rename_project`, `host_delete_project`) complete before they return; there is nothing to poll.
131
+ - When a project ID is referenced by other projects via `relations`, renaming it automatically cascades to all references — no manual cleanup needed.
132
+ - After a daemon restart, your MCP reconnects automatically and restores the tool list. You do not need to restart the IDE.
package/docs/README_zh.md CHANGED
@@ -31,18 +31,18 @@ n2n-nexus 是一个开源的 Model Context Protocol (MCP) 协同服务器,适
31
31
  - AI 助手项目注册表
32
32
  - 编码 agent 会议和任务协同
33
33
 
34
- n2n-nexus 面向这些场景设计:共享 daemon 状态、无状态 MCP 适配器、项目感知协作、本地存储和跨环境 IDE 工作流。
34
+ n2n-nexus 面向这些场景设计:共享 daemon 状态、轻量 MCP 适配器、项目感知协作、本地存储和跨环境 IDE 工作流。
35
35
 
36
36
  ## n2n-nexus 是什么?
37
37
 
38
38
  n2n-nexus 为 AI 助手提供共享协作空间。不同助手不再只依赖自己的聊天上下文,而是可以通过 MCP 读取和更新同一个本地 daemon 中的项目状态。
39
39
 
40
- **TL;DR**
40
+ **Quick summary**
41
41
 
42
42
  - **安装**:`npx n2n-nexus daemon --port 5688`
43
43
  - **协议**:Model Context Protocol (MCP),适配器通过 HTTP 连接 daemon
44
44
  - **存储**:默认在 `~/.n2n-nexus` 下使用本地文件和 SQLite
45
- - **适合**:多助手编码会话、项目交接、共享决策、会议记录、异步任务、项目 Manifest
45
+ - **适合**:多助手编码会话、项目交接、共享决策、会议记录、任务跟踪、项目 Manifest
46
46
  - **不适合**:云端团队聊天、公开项目管理 SaaS、源码索引、向量搜索或远程数据库托管
47
47
 
48
48
  ## 为什么使用它?
@@ -66,15 +66,17 @@ n2n-nexus 为 AI 助手提供共享协作空间。不同助手不再只依赖自
66
66
  ▼ ▼ ▼
67
67
  MCP-A MCP-B MCP-C
68
68
  (Win) (WSL) (SSH/VM)
69
- 每个 IDE 一个无状态适配器
69
+ 每条 MCP 连接一个轻量适配器
70
70
  ```
71
71
 
72
72
  - **Daemon 是唯一数据源**:启动一次并保持运行。
73
- - **MCP 适配器无状态**:每个 IDE 通过 `npx` 启动适配器,然后把工具调用转发给 daemon。
73
+ - **MCP 适配器只维护连接身份**:每个 IDE 通过 `npx` 启动适配器,然后把工具调用转发给 daemon;会话目录和收件箱保存在 daemon。
74
74
  - **跨环境协作**:通过 `NEXUS_ENDPOINT` 让不同机器或 shell 指向同一个 daemon。daemon 默认只监听本机;只有在可信网络中才使用 `--host 0.0.0.0`。
75
75
 
76
76
  ## 快速开始
77
77
 
78
+ 运行环境要求 Node.js 22.x 中的 22.14.0 或更高版本,或 Node.js 23.6.0 及以上版本。
79
+
78
80
  ### 1. 启动 daemon
79
81
 
80
82
  ```bash
@@ -110,43 +112,50 @@ npx n2n-nexus daemon --port 5688
110
112
 
111
113
  ## 工具集
112
114
 
113
- ### 会话和上下文
114
-
115
- - `register_session_context`:声明当前活跃项目 ID。
116
-
117
115
  ### 项目资产管理
118
116
 
119
117
  - `sync_project_assets`:提交项目 Manifest 和内部文档。
120
118
  - `update_project`:局部更新项目 Manifest。
121
119
  - `rename_project`:重命名项目 ID 并更新关联关系。
122
- - `upload_project_asset`:上传二进制或文本资产。
120
+ - `upload_project_asset`:向指定项目上传二进制或文本资产。
123
121
  - `search_projects`:搜索项目注册表。
124
122
  - `get_global_topology`:查看项目拓扑和依赖关系。
123
+ - `get_project`:读取项目完整 Manifest 和内部文档。
125
124
 
126
125
  ### 消息和协作
127
126
 
128
- - `send_message`:发送会议消息或全局消息。
129
- - `read_messages`:增量读取未读消息。
127
+ - `send_message`:向精确会话 ID 发送定向消息,也保留会议消息和全局消息。
128
+ - `list_sessions` / `update_session`:发现连接,设置自己的名称、项目关联和接收策略。
129
+ - `read_inbox` / `acknowledge_message`:取回个人消息并明确确认或拒绝。
130
+ - `get_message`:查询自己发送或接收的消息状态和回复关联。
131
+ - `read_messages`:增量读取未读消息(全局或指定会议)。
132
+ - `list_events`:读取结构化活动日志(项目同步、重命名、会议结束等)。
133
+ - `get_global_strategy`:读取主策略文档。
130
134
  - `update_global_strategy`:更新主策略文档。
135
+ - `list_global_docs`:列出共享文档。
136
+ - `get_global_doc`:读取共享文档。
131
137
  - `sync_global_doc`:创建或更新共享文档。
132
138
 
139
+ 每条 MCP 连接有独立会话 ID;多个聊天若共用连接,仍视为一个会话。在线仅表示近期心跳,消息采用主动拉取,不自动唤醒模型。已存储、已取回、已确认和已回复是不同状态,确认收件不等于任务完成。使用流程见[助手指南](ASSISTANT_GUIDE_zh.md),精确契约见[工具参考](TOOLS_REFERENCE.md#session-directory-and-direct-inboxes)。
140
+
133
141
  ### 会议管理
134
142
 
143
+ - `list_meetings`:列出会议(状态、参与者、消息与决策数、摘要)。
135
144
  - `start_meeting`:开启会议会话。
136
145
  - `end_meeting`:关闭并锁定会议。
137
146
  - `archive_meeting`:归档已关闭会议。
138
147
  - `reopen_meeting`:重新打开已关闭或已归档会议。
139
148
 
140
- ### 异步任务管理
149
+ ### 任务管理
141
150
 
142
- - `create_task`:创建后台任务。
151
+ - `create_task`:创建由助手自行管理的任务。
143
152
  - `get_task`:查询任务状态和结果。
144
153
  - `list_tasks`:按状态列出任务。
145
154
  - `cancel_task`:取消等待中或运行中的任务。
146
155
 
147
156
  ### 维护
148
157
 
149
- - `host_maintenance`:清理或清空系统日志。
158
+ - `host_maintenance`:清理或清空全局聊天流。
150
159
  - `host_delete_project`:删除项目和资产。
151
160
 
152
161
  ## 数据存储
@@ -209,7 +218,11 @@ NEXUS_ENDPOINT=http://127.0.0.1:5688 n2n-nexus mcp
209
218
  | `NEXUS_ENDPOINT` | MCP 适配器连接的 daemon 地址 | `http://127.0.0.1:5688` |
210
219
  | `NEXUS_ROOT` | daemon 存储根目录 | `~/.n2n-nexus` |
211
220
  | `NEXUS_HOST` | daemon 监听地址 | `127.0.0.1` |
212
- | `NEXUS_INSTANCE_ID` | 覆盖 MCP 实例 ID | 自动生成 |
221
+ | `NEXUS_DAEMON_PORT` | daemon 端口(`--port` 优先) | `5688` |
222
+ | `NEXUS_RATE_LIMIT` | 每个实例每秒工具调用数,每个客户端地址为其 5 倍;`0` 关闭限流 | `20` |
223
+ | `NEXUS_RATE_BURST` | 每个实例可一次性突发的调用数(最小为 1) | `60` |
224
+ | `NEXUS_ALLOWED_HOSTS` | `Host` 头额外允许的域名,逗号分隔(IP、`localhost`、`host.docker.internal` 始终允许) | 空 |
225
+ | `NEXUS_INSTANCE_ID` | 覆盖 MCP 实例 ID(未读游标、会议权限都以它为键) | `mcp-<主机名>-<工作目录哈希>-<IDE 名>` |
213
226
 
214
227
  ## 安全和治理说明
215
228
 
@@ -226,10 +239,12 @@ NEXUS_ENDPOINT=http://127.0.0.1:5688 n2n-nexus mcp
226
239
  | 文件 | 说明 |
227
240
  | --- | --- |
228
241
  | [会议纪要](./MEETING_MINUTES_2025-12-29.md) | 结构化决策和测试记录 |
229
- | [讨论日志](./discussion_2025-12-29_en.md) | 可读的讨论记录 |
242
+ | [讨论日志](./discussion_2025-12-29.md) | 可读的讨论记录 |
230
243
 
231
244
  ## 本地开发
232
245
 
246
+ 开发请使用 Node.js 24,与 CI 和 lint 工具链保持一致。
247
+
233
248
  ```bash
234
249
  git clone https://github.com/n2ns/n2n-nexus.git
235
250
  cd n2n-nexus
@@ -272,7 +287,7 @@ NEXUS_ENDPOINT=http://127.0.0.1:5688 node build/index.js mcp
272
287
  ## 相关文档
273
288
 
274
289
  - [架构文档](./ARCHITECTURE_zh.md)
275
- - [AI 助手指南](./ASSISTANT_GUIDE.md)
290
+ - [AI 助手指南](./ASSISTANT_GUIDE_zh.md)
276
291
  - [英文 README](../README.md)
277
292
  - [llms.txt](../llms.txt)
278
293
 
@@ -282,4 +297,4 @@ NEXUS_ENDPOINT=http://127.0.0.1:5688 node build/index.js mcp
282
297
 
283
298
  ---
284
299
 
285
- Built by N2NS Lab, short for Next-to-Native Systems Lab, Datafrog's open-source lab for practical AI developer tools.
300
+ Built by N2NS Lab, Datafrog's open-source lab for practical AI developer tools.
package/llms.txt CHANGED
@@ -1,6 +1,16 @@
1
1
  # n2n-nexus
2
2
 
3
- n2n-nexus is a local-first Model Context Protocol (MCP) coordination hub from N2NS Lab for multi-AI assistant collaboration. It uses a long-running local daemon as the source of truth and stateless MCP adapters for IDEs and AI coding assistants.
3
+ n2n-nexus is a local-first Model Context Protocol (MCP) coordination hub from N2NS Lab for multi-AI assistant collaboration. It uses a long-running local daemon as the source of truth and lightweight MCP adapters for IDEs and AI coding assistants. Each MCP connection has a discoverable session identity and a pull-based direct inbox with explicit receipts and reply links; messages do not automatically wake models.
4
+
5
+ ## Search intent coverage
6
+
7
+ - multi-agent MCP coordination
8
+ - multi-AI assistant collaboration
9
+ - local MCP coordination hub
10
+ - shared project context for AI coding agents
11
+ - cross-IDE MCP collaboration server
12
+ - local-first project registry for AI assistants
13
+ - meeting and task coordination for coding agents
4
14
 
5
15
  ## Core positioning
6
16
 
@@ -43,4 +53,4 @@ Default storage root is `~/.n2n-nexus`, containing global docs, project manifest
43
53
 
44
54
  ## Brand
45
55
 
46
- Built by N2NS Lab, short for Next-to-Native Systems Lab, Datafrog's open-source lab for practical AI developer tools.
56
+ Built by N2NS Lab, Datafrog's open-source lab for practical AI developer tools.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n2n-nexus",
3
- "version": "0.4.2",
3
+ "version": "0.7.0",
4
4
  "description": "Local-first MCP coordination hub from N2NS Lab for multi-AI assistant collaboration.",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "build",
12
+ "assets",
12
13
  "README.md",
13
14
  "llms.txt",
14
15
  "CHANGELOG.md",
@@ -49,6 +50,10 @@
49
50
  "ai-developer-tools"
50
51
  ],
51
52
  "author": "N2NS Lab",
53
+ "funding": {
54
+ "type": "github",
55
+ "url": "https://github.com/sponsors/n2ns"
56
+ },
52
57
  "license": "Apache-2.0",
53
58
  "repository": {
54
59
  "type": "git",
@@ -59,32 +64,37 @@
59
64
  "url": "https://github.com/n2ns/n2n-nexus/issues"
60
65
  },
61
66
  "engines": {
62
- "node": ">=18.0.0"
67
+ "node": "^22.14.0 || >=23.6.0"
63
68
  },
64
69
  "scripts": {
65
- "build": "tsc",
70
+ "build": "node -e \"fs.rmSync('build', { recursive: true, force: true })\" && tsc",
66
71
  "start": "node build/index.js",
67
72
  "daemon": "node build/index.js daemon",
68
73
  "dev": "tsc -w",
69
74
  "test": "vitest run",
75
+ "audit": "npm audit",
76
+ "audit:prod": "npm audit --omit=dev",
77
+ "pack:dry-run": "npm pack --dry-run",
78
+ "check": "npm run lint && npm test && npm run build && npm run audit && npm run pack:dry-run",
70
79
  "test:publish": "npm run build && npm test && npm pack --dry-run",
71
80
  "test:integration": "vitest run tests/daemon_projects.test.ts tests/daemon_messages.test.ts tests/message_cursor.test.ts",
72
- "lint": "eslint src/**",
73
- "prepublishOnly": "npm run build && npm test"
81
+ "lint": "eslint src tests",
82
+ "prepublishOnly": "npm run check"
74
83
  },
75
84
  "dependencies": {
76
- "@modelcontextprotocol/sdk": "^1.29.0",
77
- "better-sqlite3": "^12.10.1",
78
- "zod": "^4.4.3"
85
+ "@modelcontextprotocol/server": "^2.3.1",
86
+ "better-sqlite3": "^13.0.3",
87
+ "zod": "^4.6.7"
79
88
  },
80
89
  "devDependencies": {
81
90
  "@eslint/js": "^10.0.1",
82
- "@types/better-sqlite3": "^7.6.13",
83
- "@types/node": "^25.9.3",
84
- "eslint": "^10.5.0",
85
- "lefthook": "^2.1.9",
91
+ "@modelcontextprotocol/client": "^2.3.1",
92
+ "@types/better-sqlite3": "^9.6.0",
93
+ "@types/node": "^26.6.5",
94
+ "eslint": "^10.13.0",
95
+ "lefthook": "^2.2.2",
86
96
  "typescript": "^6.0.3",
87
- "typescript-eslint": "^8.61.0",
88
- "vitest": "^4.1.8"
97
+ "typescript-eslint": "^8.72.0",
98
+ "vitest": "^5.0.5"
89
99
  }
90
100
  }
@@ -1,60 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import { NexusPaths } from "./paths.js";
3
- export class LogStorage {
4
- static async ensureLogFile() {
5
- try {
6
- await fs.access(NexusPaths.globalDiscussion);
7
- }
8
- catch {
9
- await fs.writeFile(NexusPaths.globalDiscussion, "[]", "utf-8");
10
- }
11
- }
12
- static async addLog(from, text, category) {
13
- await this.ensureLogFile();
14
- const logs = await this.getLogs();
15
- const payload = {
16
- timestamp: new Date().toISOString(),
17
- from,
18
- text,
19
- category: this.normalizeCategory(category)
20
- };
21
- logs.push(payload);
22
- await fs.writeFile(NexusPaths.globalDiscussion, JSON.stringify(logs, null, 2), "utf-8");
23
- }
24
- static normalizeCategory(category) {
25
- if (!category)
26
- return undefined;
27
- const allowed = ["MEETING_START", "PROPOSAL", "DECISION", "UPDATE", "CHAT", "message", "SYSTEM"];
28
- return allowed.includes(category) ? category : "UPDATE";
29
- }
30
- static async getLogs(limit = 10) {
31
- await this.ensureLogFile();
32
- const rows = await this.readRawLogs();
33
- if (limit <= 0)
34
- return rows;
35
- return rows.slice(-limit);
36
- }
37
- static async pruneLogs(count) {
38
- const current = await this.readRawLogs();
39
- if (count <= 0)
40
- return;
41
- if (current.length <= count)
42
- return;
43
- const remaining = current.slice(count);
44
- await fs.writeFile(NexusPaths.globalDiscussion, JSON.stringify(remaining, null, 2), "utf-8");
45
- }
46
- static async clearLogs() {
47
- await fs.writeFile(NexusPaths.globalDiscussion, "[]", "utf-8");
48
- }
49
- static async readRawLogs() {
50
- await this.ensureLogFile();
51
- try {
52
- const raw = await fs.readFile(NexusPaths.globalDiscussion, "utf-8");
53
- const parsed = JSON.parse(raw);
54
- return Array.isArray(parsed) ? parsed : [];
55
- }
56
- catch {
57
- return [];
58
- }
59
- }
60
- }