@datafrog-io/n2n-nexus 0.1.7 โ 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -16
- package/README_zh.md +179 -0
- package/build/index.js +38 -22
- package/build/resources/index.js +60 -11
- package/build/storage/index.js +9 -35
- package/build/storage/meetings.js +275 -0
- package/build/storage/sqlite-meeting.js +281 -0
- package/build/storage/sqlite.js +132 -0
- package/build/storage/store.js +146 -0
- package/build/storage/tasks.js +204 -0
- package/build/tools/handlers.js +459 -152
- package/build/tools/index.js +12 -1
- package/build/tools/schemas.js +275 -0
- package/build/utils/async-mutex.js +36 -0
- package/build/utils/auth.js +11 -0
- package/build/utils/error.js +15 -0
- package/docs/ASSISTANT_GUIDE.md +56 -0
- package/docs/CHANGELOG.md +170 -0
- package/docs/CHANGELOG_zh.md +170 -0
- package/docs/MEETING_MINUTES_2025-12-29.md +160 -0
- package/docs/discussion_2025-12-29_en.json +330 -0
- package/docs/discussion_2025-12-29_en.md +717 -0
- package/package.json +14 -9
- package/build/tools/definitions.js +0 -228
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# n2ns Nexus ๐
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@datafrog-io/n2n-nexus)
|
|
4
|
-
[](https://www.npmjs.com/package/@datafrog-io/n2n-nexus)
|
|
5
|
+
[](https://modelcontextprotocol.io)
|
|
5
6
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
7
|
[](https://github.com/n2ns/n2n-nexus)
|
|
7
8
|
|
|
8
9
|
**n2ns Nexus** is a "Local Digital Asset Hub" designed for multi-AI assistant collaboration. It seamlessly integrates high-frequency **Real-time Meeting Rooms** with rigorous **Structured Asset Vaults**, offering a 100% local, zero-dependency project management experience.
|
|
9
10
|
|
|
10
|
-
> **Works with:** VS Code ยท Cursor ยท Windsurf ยท Zed ยท JetBrains ยท Theia ยท Google Antigravity
|
|
11
|
+
> **Works with:** Claude Code ยท Claude Desktop ยท VS Code ยท Cursor ยท Windsurf ยท Zed ยท JetBrains ยท Theia ยท Google Antigravity
|
|
11
12
|
|
|
12
13
|
## ๐๏ธ Architecture
|
|
13
14
|
|
|
@@ -78,31 +79,48 @@ To ensure clarity and prevent collisions in the flat local namespace, all Projec
|
|
|
78
79
|
- `mcp://nexus/session`: View current identity, role (Moderator/Regular), and active project.
|
|
79
80
|
|
|
80
81
|
### B. Project Asset Management
|
|
81
|
-
- `sync_project_assets`: **[Core]** Submit full Project Manifest and Internal Docs.
|
|
82
|
+
- `sync_project_assets`: **[Core/ASYNC]** Submit full Project Manifest and Internal Docs. Returns `taskId`.
|
|
82
83
|
- **Manifest**: Includes ID, Tech Stack, **Relations**, Repo URL, Local Path, API Spec, etc.
|
|
83
84
|
- **Schema v2.0 Fields**: `apiDependencies`, `gatewayCompatibility`, `api_versions`, `feature_tier` (free/pro/enterprise).
|
|
84
85
|
- `update_project`: Partially update Manifest fields (e.g., endpoints or description only).
|
|
85
|
-
- `rename_project`: Rename Project ID with automatic cascading updates to all dependency references.
|
|
86
|
+
- `rename_project`: **[ASYNC]** Rename Project ID with automatic cascading updates to all dependency references. Returns `taskId`.
|
|
86
87
|
- `upload_project_asset`: Upload binary/text files (Base64) to the project vault.
|
|
87
|
-
-
|
|
88
|
+
- **Read Operations**: Use Resources (e.g., `mcp://nexus/projects/{id}/manifest`) for all read-only access.
|
|
88
89
|
|
|
89
90
|
### C. Global Collaboration
|
|
90
|
-
- `
|
|
91
|
+
- `send_message`: Post a message to the team (Auto-routes to active meeting).
|
|
92
|
+
- `read_messages`: Retrieve latest logs from active meeting or global registry.
|
|
91
93
|
- `update_global_strategy`: Update the core strategic blueprint (`# Master Plan`).
|
|
92
94
|
- `get_global_topology`: Retrieve the network-wide project dependency graph.
|
|
93
|
-
- `sync_global_doc
|
|
94
|
-
|
|
95
|
-
### D.
|
|
95
|
+
- `sync_global_doc`: Create or update a shared cross-project document.
|
|
96
|
+
|
|
97
|
+
### D. Meeting Management
|
|
98
|
+
- `start_meeting`: Start a new tactical session for focused collaboration.
|
|
99
|
+
- `reopen_meeting`: Reactivate a `closed` or `archived` session to continue discussion.
|
|
100
|
+
- `end_meeting`: Conclude a meeting, lock history (**Moderator only**).
|
|
101
|
+
- `archive_meeting`: Move closed meetings to cold storage (**Moderator only**).
|
|
102
|
+
|
|
103
|
+
### E. Task Management (Phase 2 - ASYNC)
|
|
104
|
+
- `create_task`: Create a new background task. Link to meeting for traceability.
|
|
105
|
+
- `get_task`: Poll status, progress (0.0-1.0), and results of a task.
|
|
106
|
+
- `list_tasks`: Query all tasks with status filtering.
|
|
107
|
+
- `update_task`: Update progress or result (typically for workers).
|
|
108
|
+
- `cancel_task`: Cancel a pending or running task.
|
|
109
|
+
|
|
110
|
+
### F. Admin (Moderator Only)
|
|
96
111
|
- `moderator_maintenance`: Prune or clear system logs.
|
|
112
|
+
- `moderator_delete_project`: Completely remove a project and its assets.
|
|
97
113
|
|
|
98
114
|
## ๐ Resources (URI)
|
|
99
115
|
|
|
100
|
-
- `mcp://chat/global`: Real-time conversation history.
|
|
101
|
-
- `mcp://hub/registry`: Global project registry overview.
|
|
102
|
-
- `mcp://docs/global-strategy`: Strategic blueprint.
|
|
103
|
-
- `mcp://nexus/session`: Current session status.
|
|
104
|
-
- `mcp://
|
|
105
|
-
- `mcp://
|
|
116
|
+
- `mcp://nexus/chat/global`: Real-time conversation history.
|
|
117
|
+
- `mcp://nexus/hub/registry`: Global project registry overview.
|
|
118
|
+
- `mcp://nexus/docs/global-strategy`: Strategic blueprint.
|
|
119
|
+
- `mcp://nexus/session`: Current session status and identity.
|
|
120
|
+
- `mcp://nexus/status`: System operational status and storage mode.
|
|
121
|
+
- `mcp://nexus/active-meeting`: Real-time transcript of the current active meeting.
|
|
122
|
+
- `mcp://nexus/projects/{id}/manifest`: Full metadata for a specific project.
|
|
123
|
+
- `mcp://nexus/projects/{id}/internal-docs`: Internal technical docs for a specific project.
|
|
106
124
|
|
|
107
125
|
## ๐ Quick Start
|
|
108
126
|
|
|
@@ -171,8 +189,8 @@ The following files demonstrate a real orchestration session where **4 AI agents
|
|
|
171
189
|
|
|
172
190
|
| File | Description |
|
|
173
191
|
|------|-------------|
|
|
174
|
-
| [๐ Discussion Log (Markdown)](docs/discussion_2025-12-29_en.md) | Human-readable meeting transcript with formatting |
|
|
175
192
|
| [๐ Meeting Minutes](docs/MEETING_MINUTES_2025-12-29.md) | Structured summary of decisions, action items, and test results |
|
|
193
|
+
| [๐ Discussion Log (Markdown)](docs/discussion_2025-12-29_en.md) | Human-readable meeting transcript with formatting |
|
|
176
194
|
| [๐ฆ Discussion Log (JSON)](docs/discussion_2025-12-29_en.json) | Raw meeting room data for programmatic access |
|
|
177
195
|
|
|
178
196
|
**Highlights from this session**:
|
package/README_zh.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# n2ns Nexus ๐
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@datafrog-io/n2n-nexus)
|
|
4
|
+
[](https://www.npmjs.com/package/@datafrog-io/n2n-nexus)
|
|
5
|
+
[](https://modelcontextprotocol.io)
|
|
6
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
7
|
+
[](https://github.com/n2ns/n2n-nexus)
|
|
8
|
+
|
|
9
|
+
**n2ns Nexus** ๆฏไธไธชไธไธบๅค AI ๅฉๆๅๅ่ฎพ่ฎก็โๆฌๅฐๆฐๅญๅ่ตไบงไธญๅฟโใๅฎๅฐ้ซ้ข็**ๅฎๆถไผ่ฎฎๅฎค**ไธไธฅ่ฐจ็**็ปๆๅ่ตไบงๅบ**ๅฎ็พ่ๅ๏ผๆไพ 100% ๆฌๅฐๅใ้ถๅค้จไพ่ต็้กน็ฎ็ฎก็ไฝ้ชใ
|
|
10
|
+
|
|
11
|
+
> **ๆฏๆ็ IDE๏ผ** Claude Code ยท Claude Desktop ยท VS Code ยท Cursor ยท Windsurf ยท Zed ยท JetBrains ยท Theia ยท Google Antigravity
|
|
12
|
+
|
|
13
|
+
## ๐๏ธ ็ณป็ปๆถๆ (Architecture)
|
|
14
|
+
|
|
15
|
+
1. **Nexus Room (่ฎจ่ฎบๅบ)**: ๆๆ IDE ๅฉๆ็็ปไธๅ
ฌๅ้ข้๏ผ็จไบ่ทจ้กน็ฎๅ่ฐใ
|
|
16
|
+
2. **Asset Vault (ๅฝๆกฃๅบ)**:
|
|
17
|
+
- **Manifest**: ๆฏไธช้กน็ฎ็ๆๆฏ็ป่ใ่ฎก่ดนใๆๆๅ
ณ็ณปใAPI ่ง่ใ
|
|
18
|
+
- **Internal Docs**: ๆฏไธช้กน็ฎ็่ฏฆ็ปๆๆฏๅฎๆฝๆนๆกใ
|
|
19
|
+
- **Assets**: ๆฌๅฐ็ฉ็็ด ๆๅญๅจ๏ผLogo/UI ๆชๅพ็ญ๏ผใ
|
|
20
|
+
3. **Global Knowledge (ๅ
จๅฑ็ฅ่ฏๅบ)**:
|
|
21
|
+
- **Master Strategy**: ้กถๅฑๆ็ฅๆป็บฒใ
|
|
22
|
+
- **Global Docs**: ่ทจ้กน็ฎ็้็จๆๆกฃ๏ผๅฆ็ผ็ ่ง่ใ่ทฏ็บฟๅพ๏ผใ
|
|
23
|
+
4. **Topology Engine**: ่ชๅจๅๆ้กน็ฎ้ด็ไพ่ตๅ
ณ็ณปๅพ่ฐฑใ
|
|
24
|
+
|
|
25
|
+
## ๏ฟฝ ๆฐๆฎๆไน
ๅ (Data Persistence)
|
|
26
|
+
|
|
27
|
+
Nexus ๅฐๆๆๆฐๆฎๅญๅจๅจๆฌๅฐๆไปถ็ณป็ปไธญ๏ผ้ป่ฎค่ทฏๅพๅฏ้
็ฝฎ๏ผ๏ผๅฎๅ
จๆๆงๆฐๆฎไธปๆใ
|
|
28
|
+
|
|
29
|
+
**็ฎๅฝ็ปๆ็คบไพ**:
|
|
30
|
+
```text
|
|
31
|
+
Nexus_Storage/
|
|
32
|
+
โโโ global/
|
|
33
|
+
โ โโโ blueprint.md # Master Strategy
|
|
34
|
+
โ โโโ discussion.json # Chat History
|
|
35
|
+
โ โโโ docs_index.json # Global Docs Metadata
|
|
36
|
+
โ โโโ docs/ # Global Markdown Docs
|
|
37
|
+
โ โโโ coding-standards.md
|
|
38
|
+
โ โโโ deployment-flow.md
|
|
39
|
+
โโโ projects/
|
|
40
|
+
โ โโโ my-app/
|
|
41
|
+
โ โ โโโ manifest.json # Project Metadata
|
|
42
|
+
โ โ โโโ internal_blueprint.md
|
|
43
|
+
โ โ โโโ assets/ # Binary Assets
|
|
44
|
+
โ โโโ ...
|
|
45
|
+
โโโ registry.json # Global Project Index
|
|
46
|
+
โโโ archives/ # (Reserved for backups)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**่ชๆไฟฎๅค (Self-healing)**: ๆ ธๅฟๆฐๆฎๆไปถ๏ผๅฆ `registry.json`, `discussion.json`๏ผๅ
ทๅค่ชๅจๆฃๆตไธไฟฎๅคๆบๅถใๅฆๆๆไปถๆๅๆๆๅคไธขๅคฑ๏ผ็ณป็ปไผ่ชๅจ้ๅปบๅๅง็ถๆ๏ผ็กฎไฟๆๅกไธไธญๆญใ
|
|
50
|
+
|
|
51
|
+
## ๏ฟฝ๐ ๏ธ ๅทฅๅ
ท้ (Toolset)
|
|
52
|
+
|
|
53
|
+
### A. ไผ่ฏไธไธไธๆ (Session)
|
|
54
|
+
- `register_session_context`: ๅฃฐๆๅฝๅ IDE ๅทฅไฝ็้กน็ฎ ID๏ผ่งฃ้ๅๆ้ใ
|
|
55
|
+
- `mcp://nexus/session`: ๆฅ็ๅฝๅ่บซไปฝใ่ง่ฒ๏ผModerator/Regular๏ผๅๆดปๅจ้กน็ฎใ
|
|
56
|
+
|
|
57
|
+
### B. ้กน็ฎ่ตไบง็ฎก็ (Project Assets)
|
|
58
|
+
- `sync_project_assets`: **[ๆ ธๅฟ/ๅผๆญฅ]** ๆไบคๅฎๆด็้กน็ฎ Manifest ๅๅ
้จๆๆฏๆๆกฃใ่ฟๅ `taskId`ใ
|
|
59
|
+
- **Manifest**: ๅ
ๅซ IDใๆๆฏๆ ใ**ไพ่ตๅ
ณ็ณป (Relations)**ใไปๅบๅฐๅใๆฌๅฐ่ทฏๅพใAPI Spec ็ญใ
|
|
60
|
+
- `update_project`: ้จๅๆดๆฐ Manifest ๅญๆฎต๏ผๅฆไป
ๆดๆฐ endpoints ๆ description๏ผใ
|
|
61
|
+
- `rename_project`: **[ๅผๆญฅ]** ้ๅฝๅ้กน็ฎ ID๏ผ่ชๅจ็บง่ๆดๆฐๆๆ็ธๅ
ณ้กน็ฎ็ไพ่ตๅผ็จใ่ฟๅ `taskId`ใ
|
|
62
|
+
- `upload_project_asset`: ไธไผ ไบ่ฟๅถ/ๆๆฌๆไปถ๏ผBase64๏ผๅฐ้กน็ฎๅบใ
|
|
63
|
+
- **่ฏปๅๆไฝ**: ๅ
จ้จ่ฝฌไธบ่ตๆบ่ฎฟ้ฎๆจกๅผ (ไพๅฆ๏ผ`mcp://nexus/projects/${id}/manifest`)ใ
|
|
64
|
+
|
|
65
|
+
### C. ๅ
จๅฑๅไฝ (Global Collaboration)
|
|
66
|
+
- `send_message`: ๅ้ๆถๆฏ๏ผๅฆๆๆๆดป่ทไผ่ฎฎ๏ผๅฐ่ชๅจ่ทฏ็ฑ่ณไผ่ฎฎ๏ผใ
|
|
67
|
+
- `read_messages`: ่ฏปๅๅข้ๆถๆฏ๏ผ่ชๅจ้ๅๆดป่ทไผ่ฎฎๆๅ
จๅฑๆฅๅฟ๏ผใ
|
|
68
|
+
- `update_global_strategy`: ๆดๆฐๆ ธๅฟๆ็ฅ่ๅพ๏ผ`# Master Plan`๏ผใ
|
|
69
|
+
- `get_global_topology`: ่ทๅๅ
จ็ฝ้กน็ฎไพ่ตๆๆๅพใ
|
|
70
|
+
- `sync_global_doc`: ๅๅปบๆๆดๆฐๅ
จๅฑๅ
ฑไบซๆๆกฃใ
|
|
71
|
+
|
|
72
|
+
### D. ไผ่ฎฎ็ฎก็ (Tactical Meetings)
|
|
73
|
+
- `start_meeting`: ๅผๅฏๆฐ็ๆๆฏ่ฎจ่ฎบไผ่ฎฎใ
|
|
74
|
+
- `reopen_meeting`: ้ๆฐๅผๅฏๅทฒโๅ
ณ้ญโๆโๅฝๆกฃโ็ไผ่ฎฎใ
|
|
75
|
+
- `end_meeting`: ็ปๆไผ่ฎฎ๏ผ้ๅฎๅๅฒ่ฎฐๅฝ (**ไป
้็ฎก็ๅ Moderator**)ใ
|
|
76
|
+
- `archive_meeting`: ๅฐๅทฒ็ปๆ็ไผ่ฎฎ็งป่ณๅญๆกฃ (**ไป
้็ฎก็ๅ Moderator**)ใ
|
|
77
|
+
|
|
78
|
+
### E. ไปปๅก็ฎก็ (Phase 2 - ๅผๆญฅ)
|
|
79
|
+
- `create_task`: ๅๅปบๆฐ็ๅๅฐไปปๅกใๅ
ณ่ไผ่ฎฎไปฅๅฎ็ฐๆบฏๆบใ
|
|
80
|
+
- `get_task`: ่ฝฎ่ฏขไปปๅก็ถๆใ่ฟๅบฆ (0.0-1.0) ๅ็ปๆใ
|
|
81
|
+
- `list_tasks`: ๆฅ่ฏขๆๆไปปๅก๏ผๆฏๆ็ถๆ่ฟๆปคใ
|
|
82
|
+
- `update_task`: ๆดๆฐไปปๅก่ฟๅบฆๆ็ปๆ๏ผ้ๅธธไพ Worker ่ฐ็จ๏ผใ
|
|
83
|
+
- `cancel_task`: ๅๆถๅพ
ๅค็ๆ่ฟ่กไธญ็ไปปๅกใ
|
|
84
|
+
|
|
85
|
+
### F. ็ฎก็ๅๅทฅๅ
ท (ไป
้ Moderator)
|
|
86
|
+
- `moderator_maintenance`: ๆธ
็ๆไฟฎๅช็ณป็ปๆฅๅฟใ
|
|
87
|
+
- `moderator_delete_project`: ๅฝปๅบๅ ้ค้กน็ฎๅๅ
ถๆๆ่ตไบงใ
|
|
88
|
+
|
|
89
|
+
## ๐ ่ตๆบ URI (Resources)
|
|
90
|
+
|
|
91
|
+
- `mcp://nexus/chat/global`: ๅฎๆถๅฏน่ฏๆตๅๅฒใ
|
|
92
|
+
- `mcp://nexus/hub/registry`: ๅ
จๅฑ้กน็ฎๆณจๅ่กจๆฆ่งใ
|
|
93
|
+
- `mcp://nexus/docs/global-strategy`: ๆ็ฅๆป้ขๆๆกฃใ
|
|
94
|
+
- `mcp://nexus/session`: ๅฝๅไผ่ฏ็ถๆๆ ่ฏใ
|
|
95
|
+
- `mcp://nexus/status`: ็ณป็ป่ฟ่ก็ถๆไธๅญๅจๆจกๅผใ
|
|
96
|
+
- `mcp://nexus/active-meeting`: ๅฝๅๆดป่ทไผ่ฎฎๅฎๅฝใ
|
|
97
|
+
- `mcp://nexus/projects/{id}/manifest`: ็นๅฎ้กน็ฎ็ๅฎๆดๅ
ๆฐๆฎใ
|
|
98
|
+
- `mcp://nexus/projects/{id}/internal-docs`: ็นๅฎ้กน็ฎ็ๅ
้จๆๆฏๆๆกฃใ
|
|
99
|
+
|
|
100
|
+
## ๐ ๅฟซ้ๅฏๅจ
|
|
101
|
+
|
|
102
|
+
### MCP ้
็ฝฎ๏ผๆจ่๏ผ
|
|
103
|
+
|
|
104
|
+
ๅจไฝ ็ MCP ้
็ฝฎๆไปถไธญ๏ผๅฆ `claude_desktop_config.json` ๆ Cursor MCP ่ฎพ็ฝฎ๏ผๆทปๅ ๏ผ
|
|
105
|
+
|
|
106
|
+
#### ไธปๆ่
๏ผ็ฎก็ๅ AI๏ผ
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"n2n-nexus": {
|
|
111
|
+
"command": "npx",
|
|
112
|
+
"args": [
|
|
113
|
+
"-y",
|
|
114
|
+
"@datafrog-io/n2n-nexus",
|
|
115
|
+
"--id", "Master-AI",
|
|
116
|
+
"--moderator",
|
|
117
|
+
"--root", "D:/DevSpace/Nexus_Storage"
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### ๆฎ้ AI
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"mcpServers": {
|
|
128
|
+
"n2n-nexus": {
|
|
129
|
+
"command": "npx",
|
|
130
|
+
"args": [
|
|
131
|
+
"-y",
|
|
132
|
+
"@datafrog-io/n2n-nexus",
|
|
133
|
+
"--id", "Assistant-AI",
|
|
134
|
+
"--root", "D:/DevSpace/Nexus_Storage"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### ๅฝไปค่กๅๆฐ
|
|
142
|
+
| ๅๆฐ | ่ฏดๆ | ้ป่ฎคๅผ |
|
|
143
|
+
|------|------|--------|
|
|
144
|
+
| `--id` | ๅฝๅ AI ๅฉๆ็ๅฎไพๆ ่ฏ็ฌฆ | `Assistant` |
|
|
145
|
+
| `--moderator` | ๆไบๆญคๅฎไพ็ฎก็ๅๆ้ | `false` |
|
|
146
|
+
| `--root` | ๆฌๅฐๆฐๆฎๅญๅจ่ทฏๅพ | `./storage` |
|
|
147
|
+
|
|
148
|
+
> **ๆณจๆ๏ผ** ไป
ๅธฆๆ `--moderator` ๆ ๅฟ็ๅฎไพๅฏไฝฟ็จ็ฎก็ๅๅทฅๅ
ท๏ผๅฆ `moderator_maintenance` ๅ `moderator_delete_project`๏ผใ
|
|
149
|
+
|
|
150
|
+
### ๆฌๅฐๅผๅ
|
|
151
|
+
```bash
|
|
152
|
+
git clone https://github.com/n2ns/n2n-nexus.git
|
|
153
|
+
cd n2n-nexus
|
|
154
|
+
npm install
|
|
155
|
+
npm run build
|
|
156
|
+
npm start -- --id Master-AI --root ./my-storage
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## ๐ ๅฎๆๆกไพ๏ผๅค AI ๅๅ
|
|
162
|
+
ไปฅไธๆไปถๅฑ็คบไบไธไธช็ๅฎ็็ผๆไผ่ฏ๏ผ**4 ไธช AI ๅฉๆ** (Claude, ChatGPT, Gemini, Augment) ๅๅ่ฎพ่ฎกๅนถๅฎ็ฐไบ่บซไปฝ้ช่ฏ็ณป็ปๅ Edge-Sync ๅ่ฎฎ๏ผ
|
|
163
|
+
|
|
164
|
+
| ๆไปถ | ่ฏดๆ |
|
|
165
|
+
|------|-------------|
|
|
166
|
+
| [๐ ไผ่ฎฎ็บช่ฆ](docs/MEETING_MINUTES_2025-12-29.md) | ๅณ็ญใ่กๅจ้กนๅๆต่ฏ็ปๆ็็ปๆๅๆ่ฆ |
|
|
167
|
+
| [๐ ่ฎจ่ฎบๆฅๅฟ (Markdown)](docs/discussion_2025-12-29_en.md) | ๅ
ๅซๆ ผๅผๅ็ๅฏ่ฏปไผ่ฎฎ่ฎฐๅฝ |
|
|
168
|
+
| [๐ฆ ่ฎจ่ฎบๆฅๅฟ (JSON)](docs/discussion_2025-12-29_en.json) | ็จไบ็จๅบๅ่ฎฟ้ฎ็ๅๅงไผ่ฎฎๅฎคๆฐๆฎ |
|
|
169
|
+
|
|
170
|
+
**ๆฌๆฌกไผ่ฏไบฎ็น**๏ผ
|
|
171
|
+
- ๐ ่ทจ 4 ไธช้กน็ฎ็ OAuth ้ช่ฏ้พ่ฐ่ฏ
|
|
172
|
+
- ๐ ๅธฆๆ RSA ็ญพๅๅๅจๆๆงๅถ็ Edge-Sync ๅ่ฎฎ v1.1.1 ่ฎพ่ฎก
|
|
173
|
+
- โ
ๆๆ้ๆๆต่ฏ้่ฟ๏ผGateway, Backbone, Hub, Nexus Core๏ผ
|
|
174
|
+
- ๐๏ธ ๅธฆๆ `apiDependencies` ่ฟฝ่ธช็ Manifest Schema v2.0
|
|
175
|
+
|
|
176
|
+
> *่ฟๅฐฑๆฏ AI ๅ็ๅผๅ็ๅไฝๆนๅผใ*
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
ยฉ 2025 datafrog.io. Built for Local-Only AI Workflows.
|
package/build/index.js
CHANGED
|
@@ -2,10 +2,17 @@
|
|
|
2
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
5
8
|
import { CONFIG } from "./config.js";
|
|
6
9
|
import { StorageManager } from "./storage/index.js";
|
|
7
10
|
import { TOOL_DEFINITIONS, handleToolCall } from "./tools/index.js";
|
|
8
11
|
import { listResources, getResourceContent } from "./resources/index.js";
|
|
12
|
+
import { sanitizeErrorMessage } from "./utils/error.js";
|
|
13
|
+
import { checkModeratorPermission } from "./utils/auth.js";
|
|
14
|
+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
15
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
9
16
|
/**
|
|
10
17
|
* n2ns Nexus: Unified Project Asset & Collaboration Hub
|
|
11
18
|
*
|
|
@@ -15,26 +22,9 @@ class NexusServer {
|
|
|
15
22
|
server;
|
|
16
23
|
currentProject = null;
|
|
17
24
|
constructor() {
|
|
18
|
-
this.server = new Server({ name: "n2n-nexus", version:
|
|
25
|
+
this.server = new Server({ name: "n2n-nexus", version: pkg.version }, { capabilities: { resources: {}, tools: {}, prompts: {} } });
|
|
19
26
|
this.setupHandlers();
|
|
20
27
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Validates moderator permissions for admin tools.
|
|
23
|
-
*/
|
|
24
|
-
checkModerator(toolName) {
|
|
25
|
-
if (!CONFIG.isModerator) {
|
|
26
|
-
throw new McpError(ErrorCode.InvalidRequest, `Forbidden: ${toolName} requires Moderator rights.`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Strips internal file paths from error messages to prevent path exposure to AI.
|
|
31
|
-
*/
|
|
32
|
-
sanitizeErrorMessage(msg) {
|
|
33
|
-
let sanitized = msg.replace(/[A-Za-z]:\\[^\s:]+/g, "[internal-path]");
|
|
34
|
-
sanitized = sanitized.replace(/\/[^\s:]+\/[^\s:]*/g, "[internal-path]");
|
|
35
|
-
sanitized = sanitized.replace(/\.\.[\\/][^\s]*/g, "[internal-path]");
|
|
36
|
-
return sanitized;
|
|
37
|
-
}
|
|
38
28
|
setupHandlers() {
|
|
39
29
|
// --- Resource Listing ---
|
|
40
30
|
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
@@ -43,7 +33,7 @@ class NexusServer {
|
|
|
43
33
|
}
|
|
44
34
|
catch (error) {
|
|
45
35
|
const msg = error instanceof Error ? error.message : String(error);
|
|
46
|
-
throw new McpError(ErrorCode.InternalError, `Nexus Registry Error: ${
|
|
36
|
+
throw new McpError(ErrorCode.InternalError, `Nexus Registry Error: ${sanitizeErrorMessage(msg)}`);
|
|
47
37
|
}
|
|
48
38
|
});
|
|
49
39
|
// --- Resource Reading ---
|
|
@@ -61,7 +51,7 @@ class NexusServer {
|
|
|
61
51
|
if (error instanceof McpError)
|
|
62
52
|
throw error;
|
|
63
53
|
const msg = error instanceof Error ? error.message : String(error);
|
|
64
|
-
throw new McpError(ErrorCode.InternalError, `Nexus Resource Error: ${
|
|
54
|
+
throw new McpError(ErrorCode.InternalError, `Nexus Resource Error: ${sanitizeErrorMessage(msg)}`);
|
|
65
55
|
}
|
|
66
56
|
});
|
|
67
57
|
// --- Tool Listing ---
|
|
@@ -73,7 +63,7 @@ class NexusServer {
|
|
|
73
63
|
const { name, arguments: toolArgs } = request.params;
|
|
74
64
|
try {
|
|
75
65
|
if (name.startsWith("moderator_"))
|
|
76
|
-
|
|
66
|
+
checkModeratorPermission(name);
|
|
77
67
|
const result = await handleToolCall(name, toolArgs, {
|
|
78
68
|
currentProject: this.currentProject,
|
|
79
69
|
setCurrentProject: (id) => { this.currentProject = id; },
|
|
@@ -89,7 +79,7 @@ class NexusServer {
|
|
|
89
79
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
90
80
|
return {
|
|
91
81
|
isError: true,
|
|
92
|
-
content: [{ type: "text", text: `Nexus Error: ${
|
|
82
|
+
content: [{ type: "text", text: `Nexus Error: ${sanitizeErrorMessage(errorMessage)}` }]
|
|
93
83
|
};
|
|
94
84
|
}
|
|
95
85
|
});
|
|
@@ -137,8 +127,34 @@ class NexusServer {
|
|
|
137
127
|
});
|
|
138
128
|
}
|
|
139
129
|
async run() {
|
|
130
|
+
// Handle graceful shutdown
|
|
131
|
+
const shutdown = async (signal) => {
|
|
132
|
+
console.error(`\n[Nexus] Received ${signal}. Shutting down...`);
|
|
133
|
+
try {
|
|
134
|
+
// Post-departure log
|
|
135
|
+
const msg = `Nexus Session Terminated (IDE Closed).`;
|
|
136
|
+
await StorageManager.addGlobalLog(`SYSTEM:${CONFIG.instanceId}`, msg, "UPDATE");
|
|
137
|
+
console.error(`[Nexus:${CONFIG.instanceId}] Goodbye!`);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Ignore if storage is already cleaned up
|
|
141
|
+
}
|
|
142
|
+
process.exit(0);
|
|
143
|
+
};
|
|
144
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
145
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
140
146
|
const transport = new StdioServerTransport();
|
|
141
147
|
await this.server.connect(transport);
|
|
148
|
+
// Announce presence
|
|
149
|
+
try {
|
|
150
|
+
await StorageManager.init();
|
|
151
|
+
const onlineMsg = `Nexus Session Active (IDE Opened). Role: ${CONFIG.isModerator ? "Moderator" : "Regular"}`;
|
|
152
|
+
await StorageManager.addGlobalLog(`SYSTEM:${CONFIG.instanceId}`, onlineMsg, "UPDATE");
|
|
153
|
+
console.error(`[Nexus:${CONFIG.instanceId}] ${onlineMsg}`);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
console.error("[Nexus] Failed to post online message:", e);
|
|
157
|
+
}
|
|
142
158
|
}
|
|
143
159
|
}
|
|
144
160
|
const server = new NexusServer();
|
package/build/resources/index.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { promises as fs } from "fs";
|
|
2
2
|
import { CONFIG } from "../config.js";
|
|
3
3
|
import { StorageManager } from "../storage/index.js";
|
|
4
|
+
import { UnifiedMeetingStore } from "../storage/store.js";
|
|
4
5
|
/**
|
|
5
6
|
* Resource content providers for MCP ReadResourceRequestSchema
|
|
6
7
|
*/
|
|
7
8
|
export async function getResourceContent(uri, currentProject) {
|
|
8
9
|
await StorageManager.init();
|
|
9
|
-
if (uri === "mcp://chat/global") {
|
|
10
|
+
if (uri === "mcp://nexus/chat/global") {
|
|
10
11
|
const text = await fs.readFile(StorageManager.globalDiscussion, "utf-8");
|
|
11
12
|
return { mimeType: "application/json", text };
|
|
12
13
|
}
|
|
13
|
-
if (uri === "mcp://hub/registry") {
|
|
14
|
+
if (uri === "mcp://nexus/hub/registry") {
|
|
14
15
|
const text = await fs.readFile(StorageManager.registryFile, "utf-8");
|
|
15
16
|
return { mimeType: "application/json", text };
|
|
16
17
|
}
|
|
17
|
-
if (uri === "mcp://docs/global-strategy") {
|
|
18
|
+
if (uri === "mcp://nexus/docs/global-strategy") {
|
|
18
19
|
const text = await fs.readFile(StorageManager.globalBlueprint, "utf-8");
|
|
19
20
|
return { mimeType: "text/markdown", text };
|
|
20
21
|
}
|
|
@@ -27,16 +28,58 @@ export async function getResourceContent(uri, currentProject) {
|
|
|
27
28
|
};
|
|
28
29
|
return { mimeType: "application/json", text: JSON.stringify(info, null, 2) };
|
|
29
30
|
}
|
|
31
|
+
if (uri === "mcp://nexus/status") {
|
|
32
|
+
const state = await UnifiedMeetingStore.getState();
|
|
33
|
+
const storageInfo = await UnifiedMeetingStore.getStorageInfo();
|
|
34
|
+
const status = {
|
|
35
|
+
status: "online",
|
|
36
|
+
version: "0.2.0",
|
|
37
|
+
...storageInfo,
|
|
38
|
+
active_meetings_count: state.activeMeetings.length,
|
|
39
|
+
default_meeting: state.defaultMeetingId
|
|
40
|
+
};
|
|
41
|
+
return { mimeType: "application/json", text: JSON.stringify(status, null, 2) };
|
|
42
|
+
}
|
|
43
|
+
if (uri === "mcp://nexus/active-meeting") {
|
|
44
|
+
const active = await UnifiedMeetingStore.getActiveMeeting();
|
|
45
|
+
if (active)
|
|
46
|
+
return { mimeType: "application/json", text: JSON.stringify(active, null, 2) };
|
|
47
|
+
return { mimeType: "application/json", text: JSON.stringify({ message: "No active meeting" }, null, 2) };
|
|
48
|
+
}
|
|
49
|
+
if (uri === "mcp://nexus/meetings/list") {
|
|
50
|
+
const meetings = await UnifiedMeetingStore.listMeetings();
|
|
51
|
+
return { mimeType: "application/json", text: JSON.stringify(meetings, null, 2) };
|
|
52
|
+
}
|
|
53
|
+
if (uri === "mcp://nexus/docs/list") {
|
|
54
|
+
const docs = await StorageManager.listGlobalDocs();
|
|
55
|
+
return { mimeType: "application/json", text: JSON.stringify(docs, null, 2) };
|
|
56
|
+
}
|
|
57
|
+
if (uri.startsWith("mcp://nexus/meetings/")) {
|
|
58
|
+
const meetingId = uri.substring("mcp://nexus/meetings/".length);
|
|
59
|
+
const mtg = await UnifiedMeetingStore.getMeeting(meetingId);
|
|
60
|
+
if (mtg)
|
|
61
|
+
return { mimeType: "application/json", text: JSON.stringify(mtg, null, 2) };
|
|
62
|
+
}
|
|
63
|
+
if (uri.startsWith("mcp://nexus/docs/")) {
|
|
64
|
+
const docId = uri.substring("mcp://nexus/docs/".length);
|
|
65
|
+
if (docId === "global-strategy") {
|
|
66
|
+
const text = await fs.readFile(StorageManager.globalBlueprint, "utf-8");
|
|
67
|
+
return { mimeType: "text/markdown", text };
|
|
68
|
+
}
|
|
69
|
+
const text = await StorageManager.getGlobalDoc(docId);
|
|
70
|
+
if (text)
|
|
71
|
+
return { mimeType: "text/markdown", text };
|
|
72
|
+
}
|
|
30
73
|
// Dynamic Project Resources (Handles Namespaces)
|
|
31
|
-
if (uri.startsWith("mcp://
|
|
74
|
+
if (uri.startsWith("mcp://nexus/projects/")) {
|
|
32
75
|
if (uri.endsWith("/manifest")) {
|
|
33
|
-
const id = uri.substring("mcp://
|
|
76
|
+
const id = uri.substring("mcp://nexus/projects/".length, uri.lastIndexOf("/manifest"));
|
|
34
77
|
const manifest = await StorageManager.getProjectManifest(id);
|
|
35
78
|
if (manifest)
|
|
36
79
|
return { mimeType: "application/json", text: JSON.stringify(manifest, null, 2) };
|
|
37
80
|
}
|
|
38
81
|
if (uri.endsWith("/internal-docs")) {
|
|
39
|
-
const id = uri.substring("mcp://
|
|
82
|
+
const id = uri.substring("mcp://nexus/projects/".length, uri.lastIndexOf("/internal-docs"));
|
|
40
83
|
const text = await StorageManager.getProjectDocs(id);
|
|
41
84
|
if (text)
|
|
42
85
|
return { mimeType: "text/markdown", text };
|
|
@@ -52,10 +95,14 @@ export async function listResources() {
|
|
|
52
95
|
const projectIds = Object.keys(registry.projects);
|
|
53
96
|
return {
|
|
54
97
|
resources: [
|
|
55
|
-
{ uri: "mcp://chat/global", name: "Global Collaboration History", description: "Real-time discussion stream." },
|
|
56
|
-
{ uri: "mcp://hub/registry", name: "Global Project Registry", description: "Consolidated index of all local projects." },
|
|
57
|
-
{ uri: "mcp://docs/
|
|
98
|
+
{ uri: "mcp://nexus/chat/global", name: "Global Collaboration History", description: "Real-time discussion stream." },
|
|
99
|
+
{ uri: "mcp://nexus/hub/registry", name: "Global Project Registry", description: "Consolidated index of all local projects." },
|
|
100
|
+
{ uri: "mcp://nexus/docs/list", name: "Global Documentation Index", description: "List of all shared cross-project documents." },
|
|
101
|
+
{ uri: "mcp://nexus/docs/global-strategy", name: "Master Strategy Blueprint", description: "Top-level cross-project coordination document." },
|
|
102
|
+
{ uri: "mcp://nexus/meetings/list", name: "Meeting Registry", description: "Consolidated list of active and closed meetings." },
|
|
58
103
|
{ uri: "mcp://nexus/session", name: "Current Session Info", description: "Your identity and role in this Nexus instance." },
|
|
104
|
+
{ uri: "mcp://nexus/status", name: "System Status & Storage Mode", description: "Backend storage mode (sqlite/json) and active meeting counts." },
|
|
105
|
+
{ uri: "mcp://nexus/active-meeting", name: "Current Active Meeting", description: "Full transcript and participants of the current default meeting." },
|
|
59
106
|
...projectIds.map(id => {
|
|
60
107
|
const prefix = id.split("_")[0];
|
|
61
108
|
const typeLabel = {
|
|
@@ -65,14 +112,16 @@ export async function listResources() {
|
|
|
65
112
|
lib: "๐ฆ Library", bot: "๐ค Bot", infra: "โ๏ธ Infra", doc: "๐ Docs"
|
|
66
113
|
}[prefix] || "๐ Project";
|
|
67
114
|
return {
|
|
68
|
-
uri: `mcp://
|
|
115
|
+
uri: `mcp://nexus/projects/${id}/manifest`,
|
|
69
116
|
name: `${typeLabel}: ${id}`,
|
|
70
117
|
description: `Structured metadata (Tech stack, relations) for ${id}`
|
|
71
118
|
};
|
|
72
119
|
})
|
|
73
120
|
],
|
|
74
121
|
resourceTemplates: [
|
|
75
|
-
{ uriTemplate: "mcp://
|
|
122
|
+
{ uriTemplate: "mcp://nexus/projects/{projectId}/internal-docs", name: "Internal Project Docs", description: "Markdown-based detailed implementation plans." },
|
|
123
|
+
{ uriTemplate: "mcp://nexus/docs/{docId}", name: "Specific Global Doc", description: "Read a specific document from the global index." },
|
|
124
|
+
{ uriTemplate: "mcp://nexus/meetings/{meetingId}", name: "Meeting Insights", description: "Full transcript and decisions for a specific meeting." }
|
|
76
125
|
]
|
|
77
126
|
};
|
|
78
127
|
}
|
package/build/storage/index.js
CHANGED
|
@@ -1,41 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { CONFIG } from "../config.js";
|
|
4
|
-
|
|
5
|
-
* Simple mutex lock for preventing concurrent file writes.
|
|
6
|
-
* Ensures that only one write operation can happen at a time.
|
|
7
|
-
*/
|
|
8
|
-
class AsyncMutex {
|
|
9
|
-
locked = false;
|
|
10
|
-
queue = [];
|
|
11
|
-
async acquire() {
|
|
12
|
-
if (!this.locked) {
|
|
13
|
-
this.locked = true;
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
return new Promise((resolve) => {
|
|
17
|
-
this.queue.push(resolve);
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
release() {
|
|
21
|
-
if (this.queue.length > 0) {
|
|
22
|
-
const next = this.queue.shift();
|
|
23
|
-
next?.();
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
this.locked = false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async withLock(fn) {
|
|
30
|
-
await this.acquire();
|
|
31
|
-
try {
|
|
32
|
-
return await fn();
|
|
33
|
-
}
|
|
34
|
-
finally {
|
|
35
|
-
this.release();
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
4
|
+
import { AsyncMutex } from "../utils/async-mutex.js";
|
|
39
5
|
export class StorageManager {
|
|
40
6
|
// --- Concurrency Control ---
|
|
41
7
|
static discussionLock = new AsyncMutex();
|
|
@@ -58,6 +24,14 @@ export class StorageManager {
|
|
|
58
24
|
if (!await this.exists(this.globalBlueprint)) {
|
|
59
25
|
await fs.writeFile(this.globalBlueprint, "# Global Coordination Blueprint\n\nShared meeting space.");
|
|
60
26
|
}
|
|
27
|
+
// Initialize Phase 2 Tasks table (SQLite) - uses dynamic import to avoid circular dependency
|
|
28
|
+
try {
|
|
29
|
+
const { initTasksTable } = await import("./tasks.js");
|
|
30
|
+
initTasksTable();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// SQLite may not be available or database not ready - will be initialized on first use
|
|
34
|
+
}
|
|
61
35
|
}
|
|
62
36
|
/**
|
|
63
37
|
* Proactively reads and validates JSON.
|