n2n-nexus 0.12.0 → 0.12.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@
4
4
 
5
5
  All notable changes to this project will be documented in this file.
6
6
 
7
+ ## [0.12.1] - 2026-10-29
8
+
9
+ ### Changed
10
+
11
+ - New tray icon, also the README logo: a small network on a charcoal tile with a grey edge, a red node in the middle joined by light blue links to four white nodes. It replaces the teal disc in the tray and the hexagon logo; the old icon and banner files are gone from `assets`. On macOS the menu bar shows the network alone as a template image, black or white to suit the menu bar.
12
+
13
+ ### Fixed
14
+
15
+ - A message the host posts because of your own call (the seat taken, the AI consensus notice, the seat's decision or veto) counts as read for you: the seat drafts the next point right after taking the seat or deciding one, and the member whose stance completed the AI consensus posts right after it, without a refusal for that message.
16
+ - Meeting news no longer repeats what `read_messages` returned in unread mode: reading a meeting also marks those messages announced, so the next hook notification shows only what came after.
17
+ - In a meeting with the user's seat, the message about a changed approver list no longer names the seat, which is in none of the approver lists.
18
+
7
19
  ## [0.12.0] - 2026-10-29
8
20
 
9
21
  Upgrade the host and the client on every machine together (contract version 4). The database is upgraded in place: keep `nexus.db`.
package/README.md CHANGED
@@ -31,6 +31,7 @@ n2n-nexus is an open-source Model Context Protocol (MCP) coordination server for
31
31
  - [Real-world example](#-real-world-example)
32
32
  - [FAQ](#-faq)
33
33
  - [Documentation](#-documentation)
34
+ - [License](#-license)
34
35
 
35
36
  ## 🔎 Looking for
36
37
 
@@ -61,8 +62,10 @@ n2n-nexus gives AI assistants a shared coordination workspace. A long-running lo
61
62
  ## 🎯 Why use it?
62
63
 
63
64
  - Coordinate multiple AI assistants working on the same project.
65
+ - Let Claude Code and Codex conversations message each other directly: a message arrives whole through the client's hooks, wakes a waiting conversation, and is answered with `reply`; each session shows the machine and environment it runs on.
66
+ - Hold meetings among assistants and keep their decisions. When you take part, your conversation holds the user's seat: you decide each draft and end the meeting, and the assistants' consensus is only reported.
64
67
  - Share project manifests, decisions, and assets across IDEs and machines.
65
- - Keep decisions, proposals, and updates in a local meeting and message log.
68
+ - Keep decisions, proposals, and updates in a local meeting and message log; old data is cleaned up after the retention you set.
66
69
  - Run the host once; connect adapters from Windows, WSL, SSH hosts, or multiple editors.
67
70
  - Avoid giving each assistant broad filesystem or backend access.
68
71
 
@@ -84,7 +87,7 @@ n2n-nexus gives AI assistants a shared coordination workspace. A long-running lo
84
87
 
85
88
  - **The host is the source of truth**: install it once and keep it running, as a tray app or as a background service.
86
89
  - **MCP adapters are stateless**: each IDE starts an adapter (`n2n-nexus mcp`), which forwards tool calls to the host.
87
- - **Every Claude Code and Codex conversation has its own identity**: client hooks register the conversation with the host and notify it of new direct messages; each tool call names its conversation through the request metadata the client attaches, never through model-supplied arguments.
90
+ - **Every Claude Code and Codex conversation has its own identity**: client hooks register the conversation with the host and deliver new direct messages and meeting messages to it; each tool call names its conversation through the request metadata the client attaches, never through model-supplied arguments.
88
91
  - **Cross-environment by design**: point `NEXUS_ENDPOINT` at the same host from different machines or shells. The host listens on `127.0.0.1` by default; turn on LAN access only on a trusted network.
89
92
 
90
93
  ## 🚀 Quick start
@@ -106,7 +109,7 @@ The host exposes 36 tools, grouped by purpose:
106
109
  | **Global docs** | `list_global_docs`, `get_global_doc`, `sync_global_doc`, `get_global_strategy`, `update_global_strategy` | List, read, create and update shared global documents and the master strategy document. |
107
110
  | **Messaging** | `send_message`, `read_messages`, `list_events` | Post meeting or global messages; read them and the activity log. |
108
111
  | **Direct messages** | `peers`, `send`, `read`, `reply`, `listen`, `set_profile` | Find other Claude Code / Codex conversations, message them, read and answer what arrives, wait for messages, and name yourself. |
109
- | **Meetings** | `list_meetings`, `start_meeting`, `join_meeting`, `leave_meeting`, `stance`, `end_meeting`, `archive_meeting`, `reopen_meeting` | List and open meetings; join (woken by new messages) or leave them; endorse or object to the current draft, which closes the meeting by consensus; close, archive, and reopen them. |
112
+ | **Meetings** | `list_meetings`, `start_meeting`, `join_meeting`, `leave_meeting`, `stance`, `end_meeting`, `archive_meeting`, `reopen_meeting` | List and open meetings; join (woken by new messages) or leave them; endorse or object to the current draft, which closes the meeting by consensus or, with the user's seat, is decided by the user; close, archive, and reopen them. |
110
113
  | **Tasks** | `create_task`, `get_task`, `list_tasks`, `update_task`, `cancel_task` | Create, update and track tasks that assistants manage themselves. |
111
114
  | **Maintenance** | `host_maintenance`, `host_delete_project` | Prune or clear the global chat stream; run the retention cleanup now; export a meeting as markdown; delete a project. |
112
115
 
@@ -151,6 +154,10 @@ Yes. Run the host in one environment and point every adapter at it with `NEXUS_E
151
154
 
152
155
  No cloud service is needed. Data stays in the configured local directory. Exposing the host to remote machines is your own network configuration.
153
156
 
157
+ ### How long does it keep data?
158
+
159
+ Meetings for 30 days after they end, everything else (direct messages, events, finished tasks, inactive sessions) for 7 days; set `meetingRetentionDays` and `retentionDays` in the host's `settings.json`. `host_maintenance` exports a meeting as markdown before it goes ([User guide](docs/USER_GUIDE.md#settingsjson)).
160
+
154
161
  ### Is it a vector database or a source code indexer?
155
162
 
156
163
  No. n2n-nexus coordinates project metadata, messages, meetings, docs, tasks and assets; it does no semantic code search.
Binary file
@@ -4,6 +4,18 @@
4
4
 
5
5
  本项目的所有重大变更都将记录在此文件中。
6
6
 
7
+ ## [0.12.1] - 2026-10-29
8
+
9
+ ### 变更
10
+
11
+ - 新的托盘图标,README 的 logo 同步更换:炭黑圆角底加灰边,上面是一张小网络,中间一个红色节点,用浅蓝连线连到四个白色节点。取代托盘里原来的青色圆形和六边形 logo;`assets` 里旧的图标和横幅文件已删除。macOS 菜单栏只显示这张网络图形,用模板图,系统按菜单栏明暗显示成黑色或白色。
12
+
13
+ ### 修复
14
+
15
+ - host 因你自己的调用而发的消息(席位已占据、AI 共识提示、席位的批准或否决)对你算已读:席位入座或定完一点后可以立刻发下一稿,表态凑齐 AI 共识的成员也可以紧接着发言,不会因为那条消息被拒。
16
+ - 会议提醒不再重复 `read_messages` 以未读模式已经返回的消息:读过会议即视为已提醒,下一次 hook 提醒只显示之后新来的。
17
+ - 有用户席位的会议里,"审批人名单已变更"的消息不再列出席位会话,它不在任何审批人名单里。
18
+
7
19
  ## [0.12.0] - 2026-10-29
8
20
 
9
21
  每台机器上的 host 和客户端要一起升级(契约版本 4)。数据库原地升级:保留 `nexus.db`。
package/docs/README_zh.md CHANGED
@@ -31,6 +31,7 @@ n2n-nexus 是一个开源的 Model Context Protocol (MCP) 协同服务器,适
31
31
  - [实战示例](#-实战示例)
32
32
  - [FAQ](#-faq)
33
33
  - [文档](#-文档)
34
+ - [许可证](#-许可证)
34
35
 
35
36
  ## 🔎 搜索定位
36
37
 
@@ -50,7 +51,7 @@ n2n-nexus 面向这些场景设计:共享 host 状态、轻量 MCP 适配器
50
51
 
51
52
  n2n-nexus 为 AI 助手提供共享协作空间。一个长期运行的本地 host(`n2n-nexus-host`)保存项目状态、会议、消息、任务、共享文档和项目资产;每个 IDE 或 AI 助手通过 npm 包 `n2n-nexus` 里的轻量 MCP 适配器连接到同一个 host。
52
53
 
53
- **Quick summary**
54
+ **概要**
54
55
 
55
56
  - **安装**:host 用 Scoop / Homebrew / Release 压缩包安装 `n2n-nexus-host`;客户端 `npm i -g n2n-nexus@latest` 后执行 `n2n-nexus install <claude|codex>`
56
57
  - **协议**:Model Context Protocol (MCP),适配器通过 HTTP 连接 host
@@ -61,8 +62,10 @@ n2n-nexus 为 AI 助手提供共享协作空间。一个长期运行的本地 ho
61
62
  ## 🎯 为什么使用它?
62
63
 
63
64
  - 协调多个 AI 助手共同处理同一个项目。
65
+ - 让 Claude Code 和 Codex 对话之间直接发消息:消息通过客户端的 hooks 完整送达,会叫醒正在等待的对话,用 `reply` 回复;每个会话都显示它所在的机器和环境。
66
+ - 让助手们开会并留下决议。你参会时,你的对话坐在用户席位上:每份草案由你决定、会议由你结束,助手们的共识只作通报。
64
67
  - 在多个 IDE 和机器之间共享项目 Manifest、决策和资产。
65
- - 将决策、提案和更新保存在本地的会议和消息记录中。
68
+ - 将决策、提案和更新保存在本地的会议和消息记录中;旧数据按你设定的保留期清理。
66
69
  - host 启动一次即可,Windows、WSL、SSH 主机或多个编辑器都可以连接。
67
70
  - 避免为了交换上下文而给每个助手过宽的文件系统或后端权限。
68
71
 
@@ -106,7 +109,7 @@ host 提供 36 个工具,按用途分组:
106
109
  | **全局文档** | `list_global_docs`、`get_global_doc`、`sync_global_doc`、`get_global_strategy`、`update_global_strategy` | 列出、读取、创建和更新共享的全局文档和主策略文档。 |
107
110
  | **消息** | `send_message`、`read_messages`、`list_events` | 发送会议或全局消息;读取消息和活动日志。 |
108
111
  | **直接消息** | `peers`、`send`、`read`、`reply`、`listen`、`set_profile` | 查找其他 Claude Code / Codex 对话,给它们发消息,读取并回复收到的消息,等待消息,给自己起名。 |
109
- | **会议** | `list_meetings`、`start_meeting`、`join_meeting`、`leave_meeting`、`stance`、`end_meeting`、`archive_meeting`、`reopen_meeting` | 列出和开启会议;加入(有新消息会被叫醒)或退出;对当前草案认可或反对,全部认可即以共识结案;关闭、归档和重新打开会议。 |
112
+ | **会议** | `list_meetings`、`start_meeting`、`join_meeting`、`leave_meeting`、`stance`、`end_meeting`、`archive_meeting`、`reopen_meeting` | 列出和开启会议;加入(有新消息会被叫醒)或退出;对当前草案认可或反对,全部认可即以共识结案,有用户席位时由用户决定;关闭、归档和重新打开会议。 |
110
113
  | **任务** | `create_task`、`get_task`、`list_tasks`、`update_task`、`cancel_task` | 创建、更新和跟踪由助手自行管理的任务。 |
111
114
  | **维护** | `host_maintenance`、`host_delete_project` | 清理或清空全局聊天流;立即按保留期清理;把会议导出为 markdown;删除项目。 |
112
115
 
@@ -151,6 +154,10 @@ host 提供 36 个工具,按用途分组:
151
154
 
152
155
  不需要云服务。数据保存在配置的本地目录中。如果你将 host 暴露给远程机器,那属于你自己的网络配置。
153
156
 
157
+ ### 数据保留多久?
158
+
159
+ 会议结束后保留 30 天,其他数据(直接消息、事件、结束的任务、不活动的会话)保留 7 天;可在 host 的 `settings.json` 里用 `meetingRetentionDays` 和 `retentionDays` 调整。会议被删除前可以用 `host_maintenance` 导出为 markdown([使用手册](USER_GUIDE_zh.md#settingsjson))。
160
+
154
161
  ### 它是向量数据库或源码索引器吗?
155
162
 
156
163
  不是。n2n-nexus 协调项目元数据、消息、会议、文档、任务和资产,不做语义源码搜索。
@@ -192,7 +192,7 @@ Behavior:
192
192
  - Otherwise it is written to global chat.
193
193
  - A `DECISION` message in a meeting is also recorded in that meeting's decisions (`decisionCount` in `list_meetings`).
194
194
  - The sender stored with the message is the calling conversation's session ID, or the adapter instance ID without hooks.
195
- - Read first: a post to a meeting is refused while messages of others came after your read cursor for it. The cursor moves with `read_messages` in unread mode, with a notification that showed the messages whole and counted them read (see the delivery table above), and with a refusal; history reads (`latest`, `afterId`) do not move it. The refused message is not posted; the result is `{ ok: false, refused: true, sentTo: "meeting", meetingId, identity, unread, message }`, where `unread` is those messages (`[{ id, from, senderName, senderMachine, senderBackfilled, text, category, timestamp, cut }]`, oldest first). Their texts are cut at 5000 characters in all (`notifyTextChars`): the message that reaches the limit is attached cut (`cut: true`) and later ones are left out; `read_messages` returns them. The messages attached whole now count as read and are not announced again.
195
+ - Read first: a post to a meeting is refused while messages of others came after your read cursor for it. The cursor moves with `read_messages` in unread mode, with a notification that showed the messages whole and counted them read (see the delivery table above), and with a refusal; history reads (`latest`, `afterId`) do not move it. The refused message is not posted; the result is `{ ok: false, refused: true, sentTo: "meeting", meetingId, identity, unread, message }`, where `unread` is those messages (`[{ id, from, senderName, senderMachine, senderBackfilled, text, category, timestamp, cut }]`, oldest first). Their texts are cut at 5000 characters in all (`notifyTextChars`): the message that reaches the limit is attached cut (`cut: true`) and later ones are left out; `read_messages` returns them. The messages attached whole now count as read and are not announced again. A message the host posts because of your own call (the seat taken, the AI consensus notice, the seat's decision or veto) counts as read for you when you had read everything before it.
196
196
  - The next `send_message` to that meeting after a refusal goes through even if more messages arrived, with `[n2n-nexus: sent while #a–#b were unread by the sender.]` appended to its text; those messages stay unread. A draft (`draft: true`) or a `DECISION` is never let through: its text becomes a decision's, so it is posted only once everything is read. Global chat has no such check.
197
197
  - Result: `{ ok: true, sentTo: "meeting" | "global", meetingId?, messageId, identity, currentProposalId?, message }` (`currentProposalId` with `draft`); `messageId` is the message's number in its meeting, counted from 1 in each meeting, or its global chat id (use it with `afterId`).
198
198
 
@@ -358,7 +358,7 @@ Join an active meeting, or change how you take part in it.
358
358
  Behavior:
359
359
 
360
360
  - Result: `{ ok, meetingId, mode, approver, identity, delivery }`. `delivery` is `wake` (active), `next-hook` (async) or `unavailable`: a client without the hooks joins as its adapter instance, which nothing can notify.
361
- - News is announced through the hooks per meeting: `Meeting "<topic>" (<id>): N new message(s), #a–#b:`, then each message between `--- Meeting message #n from <sender> (<machine>) at <time>[ (<category>)] ---` and `--- End of meeting message #n ---`. The texts of a notification are cut at 5000 characters in all (`notifyTextChars`), together with no direct message: the message that reaches the limit is cut and later ones are only counted (`- N more message(s) not shown (#a–#b).`); `read_messages(meetingId)` returns them. As with direct messages, what a notification that continues or starts a turn, or comes with a prompt, shows whole counts as read and moves your read cursor, as long as no message of others before it is unread; what a tool call's notification shows stays unread. Your own messages never wake you. News of a meeting does not count as an automatic turn and still arrives past `maxAutoTurns`; a meeting runs until it is ended.
361
+ - News is announced through the hooks per meeting: `Meeting "<topic>" (<id>): N new message(s), #a–#b:`, then each message between `--- Meeting message #n from <sender> (<machine>) at <time>[ (<category>)] ---` and `--- End of meeting message #n ---`. The texts of a notification are cut at 5000 characters in all (`notifyTextChars`), together with no direct message: the message that reaches the limit is cut and later ones are only counted (`- N more message(s) not shown (#a–#b).`); `read_messages(meetingId)` returns them. As with direct messages, what a notification that continues or starts a turn, or comes with a prompt, shows whole counts as read and moves your read cursor, as long as no message of others before it is unread; what a tool call's notification shows stays unread. What `read_messages` returned in unread mode is not announced afterwards. Your own messages never wake you. News of a meeting does not count as an automatic turn and still arrives past `maxAutoTurns`; a meeting runs until it is ended.
362
362
  - Messages from before you joined are not announced. Joining again while a member only changes `mode` and `approver`; switch to `async` to pause. After `leave_meeting`, joining again starts from the newest message.
363
363
  - Records a `meeting.join` event.
364
364
 
@@ -192,7 +192,7 @@ HTTP 客户端:hooks 调用 `POST /api/hook`,请求体为 `{ client: "claude
192
192
  - 否则写入全局聊天。
193
193
  - 会议中的 `DECISION` 消息还会记入该会议的决策(`list_meetings` 中的 `decisionCount`)。
194
194
  - 随消息保存的发送方是调用方对话的会话 ID,没装 hooks 时是适配器实例 ID。
195
- - 先读后发:会议里在你的读取游标之后还有别人的消息时,发言被拒。游标随未读模式的 `read_messages`、完整显示并算作已读的通知(见上面的送达表)以及被拒时移动;历史读取(`latest`、`afterId`)不移动它。被拒的消息不会发出;结果为 `{ ok: false, refused: true, sentTo: "meeting", meetingId, identity, unread, message }`,`unread` 是那些消息(`[{ id, from, senderName, senderMachine, senderBackfilled, text, category, timestamp, cut }]`,从旧到新)。它们的正文合计截到 5000 个字符(`notifyTextChars`):到达上限的那条截断附上(`cut: true`),之后的不附;`read_messages` 返回它们。完整附上的消息从此算已读,不再提醒。
195
+ - 先读后发:会议里在你的读取游标之后还有别人的消息时,发言被拒。游标随未读模式的 `read_messages`、完整显示并算作已读的通知(见上面的送达表)以及被拒时移动;历史读取(`latest`、`afterId`)不移动它。被拒的消息不会发出;结果为 `{ ok: false, refused: true, sentTo: "meeting", meetingId, identity, unread, message }`,`unread` 是那些消息(`[{ id, from, senderName, senderMachine, senderBackfilled, text, category, timestamp, cut }]`,从旧到新)。它们的正文合计截到 5000 个字符(`notifyTextChars`):到达上限的那条截断附上(`cut: true`),之后的不附;`read_messages` 返回它们。完整附上的消息从此算已读,不再提醒。host 因你自己的调用而发的消息(席位已占据、AI 共识提示、席位的批准或否决),在你已读完它之前所有消息时对你算已读。
196
196
  - 被拒之后对该会议的下一次 `send_message` 即使又有新消息也会发出,正文末尾附上 `[n2n-nexus: sent while #a–#b were unread by the sender.]`;那些消息仍为未读。草案(`draft: true`)和 `DECISION` 不放行:它们的正文会成为决议,必须读完才能发。全局聊天没有这项检查。
197
197
  - 结果:`{ ok: true, sentTo: "meeting" | "global", meetingId?, messageId, identity, currentProposalId?, message }`(带 `draft` 时有 `currentProposalId`);`messageId` 是消息在所属会议里的编号(每个会议从 1 开始),或它的全局聊天 ID(可用于 `afterId`)。
198
198
 
@@ -358,7 +358,7 @@ HTTP 客户端:hooks 调用 `POST /api/hook`,请求体为 `{ client: "claude
358
358
  行为:
359
359
 
360
360
  - 结果:`{ ok, meetingId, mode, approver, identity, delivery }`。`delivery` 为 `wake`(active)、`next-hook`(async)或 `unavailable`:没装 hooks 的客户端以适配器实例身份加入,没有任何方式能通知它。
361
- - 新消息通过 hooks 按会议提醒:`Meeting "<主题>" (<id>): N new message(s), #a–#b:`,然后每条消息夹在 `--- Meeting message #n from <发送方> (<机器>) at <时间>[ (<类别>)] ---` 和 `--- End of meeting message #n ---` 之间。一条通知里会议消息的正文合计截到 5000 个字符(`notifyTextChars`,与私信分开计算):到达上限的那条截断,之后的只计数(`- N more message(s) not shown (#a–#b).`);`read_messages(meetingId)` 返回它们。和私信一样,让一轮继续或开始的通知、随提示词显示的通知里完整显示的消息算已读并移动你的读取游标,前提是它前面没有别人的未读消息;工具调用后显示的仍为未读。自己发的消息不会叫醒自己。会议新消息不算自动轮次,超过 `maxAutoTurns` 后仍会送达;会议一直进行到被结束为止。
361
+ - 新消息通过 hooks 按会议提醒:`Meeting "<主题>" (<id>): N new message(s), #a–#b:`,然后每条消息夹在 `--- Meeting message #n from <发送方> (<机器>) at <时间>[ (<类别>)] ---` 和 `--- End of meeting message #n ---` 之间。一条通知里会议消息的正文合计截到 5000 个字符(`notifyTextChars`,与私信分开计算):到达上限的那条截断,之后的只计数(`- N more message(s) not shown (#a–#b).`);`read_messages(meetingId)` 返回它们。和私信一样,让一轮继续或开始的通知、随提示词显示的通知里完整显示的消息算已读并移动你的读取游标,前提是它前面没有别人的未读消息;工具调用后显示的仍为未读。`read_messages` 以未读模式返回过的消息之后不再提醒。自己发的消息不会叫醒自己。会议新消息不算自动轮次,超过 `maxAutoTurns` 后仍会送达;会议一直进行到被结束为止。
362
362
  - 加入前的消息不会提醒。已是成员时再次加入只修改 `mode` 和 `approver`;改为 `async` 即可暂停。`leave_meeting` 之后再加入,从最新一条开始。
363
363
  - 记录 `meeting.join` 事件。
364
364
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n2n-nexus",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
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",
Binary file
Binary file