@datafrog-io/n2n-nexus 0.1.8 → 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 +33 -16
- package/README_zh.md +53 -17
- package/build/index.js +38 -22
- package/build/resources/index.js +33 -12
- package/build/storage/index.js +8 -0
- package/build/storage/meetings.js +35 -2
- package/build/storage/sqlite-meeting.js +37 -5
- package/build/storage/sqlite.js +15 -3
- package/build/storage/store.js +11 -4
- package/build/storage/tasks.js +204 -0
- package/build/tools/handlers.js +336 -176
- package/build/tools/index.js +12 -1
- package/build/tools/schemas.js +275 -0
- package/build/utils/auth.js +11 -0
- package/build/utils/error.js +15 -0
- package/docs/ASSISTANT_GUIDE.md +52 -62
- package/docs/CHANGELOG.md +29 -0
- package/docs/CHANGELOG_zh.md +29 -0
- package/package.json +10 -9
- package/build/tools/definitions.js +0 -288
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Project ID validation regex based on Nexus conventions.
|
|
4
|
+
*/
|
|
5
|
+
export const ProjectIdSchema = z.string()
|
|
6
|
+
.describe("Strict flat identifier. MUST start with a type-prefix followed by an underscore.")
|
|
7
|
+
.refine(val => {
|
|
8
|
+
const validPrefixes = ["web_", "api_", "chrome_", "vscode_", "mcp_", "android_", "ios_", "flutter_", "desktop_", "lib_", "bot_", "infra_", "doc_"];
|
|
9
|
+
return validPrefixes.some(p => val.startsWith(p));
|
|
10
|
+
}, "Project ID must start with a valid prefix (e.g., 'web_', 'api_')")
|
|
11
|
+
.refine(val => !val.includes("..") && !val.includes("/") && !val.includes("\\"), "Project ID cannot contain '..' or slashes.");
|
|
12
|
+
/**
|
|
13
|
+
* 1. register_session_context
|
|
14
|
+
*/
|
|
15
|
+
export const RegisterSessionSchema = z.object({
|
|
16
|
+
projectId: ProjectIdSchema
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* 2. sync_project_assets
|
|
20
|
+
*/
|
|
21
|
+
export const SyncProjectAssetsSchema = z.object({
|
|
22
|
+
manifest: z.object({
|
|
23
|
+
id: ProjectIdSchema,
|
|
24
|
+
name: z.string(),
|
|
25
|
+
description: z.string(),
|
|
26
|
+
techStack: z.array(z.string()),
|
|
27
|
+
relations: z.array(z.object({
|
|
28
|
+
targetId: z.string(),
|
|
29
|
+
type: z.enum(["dependency", "parent", "child", "related"])
|
|
30
|
+
})),
|
|
31
|
+
lastUpdated: z.string().describe("ISO timestamp"),
|
|
32
|
+
repositoryUrl: z.string(),
|
|
33
|
+
localPath: z.string().describe("Physical disk path"),
|
|
34
|
+
endpoints: z.array(z.object({
|
|
35
|
+
name: z.string(),
|
|
36
|
+
url: z.string(),
|
|
37
|
+
description: z.string()
|
|
38
|
+
})),
|
|
39
|
+
apiSpec: z.array(z.object({
|
|
40
|
+
method: z.string(),
|
|
41
|
+
path: z.string(),
|
|
42
|
+
summary: z.string()
|
|
43
|
+
}))
|
|
44
|
+
}),
|
|
45
|
+
internalDocs: z.string().describe("Mandatory technical implementation guide (Markdown)")
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Safe file name validation (no path traversal)
|
|
49
|
+
*/
|
|
50
|
+
export const FileNameSchema = z.string()
|
|
51
|
+
.min(1, "File name cannot be empty")
|
|
52
|
+
.max(255, "File name too long")
|
|
53
|
+
.refine(val => !val.includes("/") && !val.includes("\\"), "File name cannot contain slashes")
|
|
54
|
+
.refine(val => !val.includes(".."), "File name cannot contain '..'")
|
|
55
|
+
.refine(val => !val.startsWith("."), "File name cannot start with '.'")
|
|
56
|
+
.describe("Safe file name without path components");
|
|
57
|
+
/**
|
|
58
|
+
* 3. upload_project_asset
|
|
59
|
+
*/
|
|
60
|
+
export const UploadAssetSchema = z.object({
|
|
61
|
+
fileName: FileNameSchema,
|
|
62
|
+
base64Content: z.string()
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* 4. get_global_topology (No arguments)
|
|
66
|
+
*/
|
|
67
|
+
export const EmptySchema = z.object({});
|
|
68
|
+
/**
|
|
69
|
+
* 7. send_message
|
|
70
|
+
*/
|
|
71
|
+
export const SendMessageSchema = z.object({
|
|
72
|
+
message: z.string().min(1, "Message cannot be empty"),
|
|
73
|
+
category: z.enum(["MEETING_START", "PROPOSAL", "DECISION", "UPDATE", "CHAT"]).optional()
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* 8. read_messages
|
|
77
|
+
*/
|
|
78
|
+
export const ReadMessagesSchema = z.object({
|
|
79
|
+
count: z.number().int().positive().optional().default(10),
|
|
80
|
+
meetingId: z.string().optional()
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* 9. update_global_strategy
|
|
84
|
+
*/
|
|
85
|
+
export const UpdateStrategySchema = z.object({
|
|
86
|
+
content: z.string().min(1, "Strategy content cannot be empty")
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* 10. sync_global_doc
|
|
90
|
+
*/
|
|
91
|
+
export const SyncGlobalDocSchema = z.object({
|
|
92
|
+
docId: z.string(),
|
|
93
|
+
title: z.string(),
|
|
94
|
+
content: z.string()
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* 13. update_project
|
|
98
|
+
*/
|
|
99
|
+
export const UpdateProjectSchema = z.object({
|
|
100
|
+
projectId: ProjectIdSchema,
|
|
101
|
+
patch: z.object({}).passthrough().describe("Fields to update (e.g., description, techStack)")
|
|
102
|
+
});
|
|
103
|
+
/**
|
|
104
|
+
* 14. rename_project
|
|
105
|
+
*/
|
|
106
|
+
export const RenameProjectSchema = z.object({
|
|
107
|
+
oldId: ProjectIdSchema,
|
|
108
|
+
newId: ProjectIdSchema
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* 15. moderator_maintenance
|
|
112
|
+
*/
|
|
113
|
+
export const ModeratorMaintenanceSchema = z.object({
|
|
114
|
+
action: z.enum(["prune", "clear"]),
|
|
115
|
+
count: z.number().int().min(0)
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* 16. moderator_delete_project
|
|
119
|
+
*/
|
|
120
|
+
export const ModeratorDeleteSchema = z.object({
|
|
121
|
+
projectId: ProjectIdSchema
|
|
122
|
+
});
|
|
123
|
+
/**
|
|
124
|
+
* 17. start_meeting
|
|
125
|
+
*/
|
|
126
|
+
export const StartMeetingSchema = z.object({
|
|
127
|
+
topic: z.string().min(1, "Topic is required")
|
|
128
|
+
});
|
|
129
|
+
/**
|
|
130
|
+
* 18. end_meeting
|
|
131
|
+
*/
|
|
132
|
+
export const EndMeetingSchema = z.object({
|
|
133
|
+
meetingId: z.string().optional(),
|
|
134
|
+
summary: z.string().optional()
|
|
135
|
+
});
|
|
136
|
+
/**
|
|
137
|
+
* 21. archive_meeting
|
|
138
|
+
*/
|
|
139
|
+
export const ArchiveMeetingSchema = z.object({
|
|
140
|
+
meetingId: z.string()
|
|
141
|
+
});
|
|
142
|
+
/**
|
|
143
|
+
* 22. reopen_meeting
|
|
144
|
+
*/
|
|
145
|
+
export const ReopenMeetingSchema = z.object({
|
|
146
|
+
meetingId: z.string()
|
|
147
|
+
});
|
|
148
|
+
// ============ Phase 2: Task Management Schemas ============
|
|
149
|
+
/**
|
|
150
|
+
* 22. create_task
|
|
151
|
+
*/
|
|
152
|
+
export const CreateTaskSchema = z.object({
|
|
153
|
+
source_meeting_id: z.string().optional().describe("Link task to a meeting for traceability"),
|
|
154
|
+
metadata: z.object({}).passthrough().optional().describe("Custom task parameters"),
|
|
155
|
+
ttl: z.number().int().positive().optional().describe("Time-to-live in milliseconds")
|
|
156
|
+
});
|
|
157
|
+
/**
|
|
158
|
+
* 23. get_task
|
|
159
|
+
*/
|
|
160
|
+
export const GetTaskSchema = z.object({
|
|
161
|
+
taskId: z.string()
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* 24. list_tasks
|
|
165
|
+
*/
|
|
166
|
+
export const ListTasksSchema = z.object({
|
|
167
|
+
status: z.enum(["pending", "running", "completed", "failed", "cancelled"]).optional(),
|
|
168
|
+
limit: z.number().int().positive().optional().default(50)
|
|
169
|
+
});
|
|
170
|
+
/**
|
|
171
|
+
* 25. update_task
|
|
172
|
+
*/
|
|
173
|
+
export const UpdateTaskSchema = z.object({
|
|
174
|
+
taskId: z.string(),
|
|
175
|
+
status: z.enum(["pending", "running", "completed", "failed", "cancelled"]).optional(),
|
|
176
|
+
progress: z.number().min(0).max(1).optional(),
|
|
177
|
+
result_uri: z.string().optional(),
|
|
178
|
+
error_message: z.string().optional()
|
|
179
|
+
});
|
|
180
|
+
/**
|
|
181
|
+
* 26. cancel_task
|
|
182
|
+
*/
|
|
183
|
+
export const CancelTaskSchema = z.object({
|
|
184
|
+
taskId: z.string()
|
|
185
|
+
});
|
|
186
|
+
/**
|
|
187
|
+
* Tool Registry with descriptions and schemas
|
|
188
|
+
*/
|
|
189
|
+
export const TOOL_REGISTRY = {
|
|
190
|
+
register_session_context: {
|
|
191
|
+
description: "[IDENTITY] Declare the PROJECT identity. Format: [prefix]_[technical-identifier]. (e.g., 'web_datafrog.io', 'mcp_nexus-core').",
|
|
192
|
+
schema: RegisterSessionSchema
|
|
193
|
+
},
|
|
194
|
+
sync_project_assets: {
|
|
195
|
+
description: "CRITICAL: [PREREQUISITE: register_session_context] Sync full project state. Both manifest and documentation are MANDATORY.",
|
|
196
|
+
schema: SyncProjectAssetsSchema
|
|
197
|
+
},
|
|
198
|
+
upload_project_asset: {
|
|
199
|
+
description: "Upload a binary file (images, PDFs, etc.) to the current project's asset folder. Requires active session (call register_session_context first). Returns the relative path of the saved file.",
|
|
200
|
+
schema: UploadAssetSchema
|
|
201
|
+
},
|
|
202
|
+
get_global_topology: {
|
|
203
|
+
description: "Retrieve complete project relationship graph. Returns { nodes: [{ id, name }], edges: [{ from, to, type }] }. Use this to visualize dependencies.",
|
|
204
|
+
schema: EmptySchema
|
|
205
|
+
},
|
|
206
|
+
send_message: {
|
|
207
|
+
description: "Post a message to the Nexus collaboration space. If an active meeting exists, the message is automatically routed to that meeting. Otherwise, it goes to the global discussion log. Use this for proposals, decisions, or general coordination.",
|
|
208
|
+
schema: SendMessageSchema
|
|
209
|
+
},
|
|
210
|
+
read_messages: {
|
|
211
|
+
description: "Read recent messages. Automatically reads from the active meeting if one exists, otherwise reads from global logs.",
|
|
212
|
+
schema: ReadMessagesSchema
|
|
213
|
+
},
|
|
214
|
+
update_global_strategy: {
|
|
215
|
+
description: "Overwrite master strategy. Content is MANDATORY.",
|
|
216
|
+
schema: UpdateStrategySchema
|
|
217
|
+
},
|
|
218
|
+
sync_global_doc: {
|
|
219
|
+
description: "Create or update a global document. Returns the document ID.",
|
|
220
|
+
schema: SyncGlobalDocSchema
|
|
221
|
+
},
|
|
222
|
+
update_project: {
|
|
223
|
+
description: "Partially update a project's manifest. Only provided fields will be updated.",
|
|
224
|
+
schema: UpdateProjectSchema
|
|
225
|
+
},
|
|
226
|
+
rename_project: {
|
|
227
|
+
description: "[ASYNC] Rename a project ID with automatic cascading updates to all relation references. Returns task ID.",
|
|
228
|
+
schema: RenameProjectSchema
|
|
229
|
+
},
|
|
230
|
+
moderator_maintenance: {
|
|
231
|
+
description: "[ADMIN ONLY] Manage global discussion logs. 'prune' removes the oldest N entries (keeps newest). 'clear' wipes all logs (use count=0). Returns summary of removed entries. Irreversible.",
|
|
232
|
+
schema: ModeratorMaintenanceSchema
|
|
233
|
+
},
|
|
234
|
+
moderator_delete_project: {
|
|
235
|
+
description: "[ASYNC][ADMIN ONLY] Completely remove a project, its manifest, and all its assets from Nexus Hub. Returns task ID. Irreversible.",
|
|
236
|
+
schema: ModeratorDeleteSchema
|
|
237
|
+
},
|
|
238
|
+
start_meeting: {
|
|
239
|
+
description: "Start a new meeting session. Creates a dedicated file for the meeting. Returns the meeting ID and details.",
|
|
240
|
+
schema: StartMeetingSchema
|
|
241
|
+
},
|
|
242
|
+
end_meeting: {
|
|
243
|
+
description: "End an active meeting. Locks the session for further messages. [RESTRICTED: Only moderator can end].",
|
|
244
|
+
schema: EndMeetingSchema
|
|
245
|
+
},
|
|
246
|
+
archive_meeting: {
|
|
247
|
+
description: "Archive a closed meeting. Archived meetings are read-only and excluded from active queries. [RESTRICTED: Only moderator can archive].",
|
|
248
|
+
schema: ArchiveMeetingSchema
|
|
249
|
+
},
|
|
250
|
+
reopen_meeting: {
|
|
251
|
+
description: "Reopen a closed or archived meeting. [Open to all participants].",
|
|
252
|
+
schema: ReopenMeetingSchema
|
|
253
|
+
},
|
|
254
|
+
// --- Phase 2: Task Management ---
|
|
255
|
+
create_task: {
|
|
256
|
+
description: "[ASYNC] Create a new background task. Returns task ID for polling. Link to meeting for traceability.",
|
|
257
|
+
schema: CreateTaskSchema
|
|
258
|
+
},
|
|
259
|
+
get_task: {
|
|
260
|
+
description: "[ASYNC] Get the status and progress of a task by ID.",
|
|
261
|
+
schema: GetTaskSchema
|
|
262
|
+
},
|
|
263
|
+
list_tasks: {
|
|
264
|
+
description: "[ASYNC] List all tasks with optional status filter.",
|
|
265
|
+
schema: ListTasksSchema
|
|
266
|
+
},
|
|
267
|
+
update_task: {
|
|
268
|
+
description: "[ASYNC][INTERNAL] Update task status, progress, or result. Intended for background workers only - do not call directly from user-facing tools.",
|
|
269
|
+
schema: UpdateTaskSchema
|
|
270
|
+
},
|
|
271
|
+
cancel_task: {
|
|
272
|
+
description: "[ASYNC] Cancel a pending or running task.",
|
|
273
|
+
schema: CancelTaskSchema
|
|
274
|
+
},
|
|
275
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { CONFIG } from "../config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Validates moderator permissions for admin tools.
|
|
5
|
+
* @throws McpError if current session is not in Moderator mode.
|
|
6
|
+
*/
|
|
7
|
+
export function checkModeratorPermission(toolName) {
|
|
8
|
+
if (!CONFIG.isModerator) {
|
|
9
|
+
throw new McpError(ErrorCode.InvalidRequest, `Forbidden: ${toolName} requires Moderator rights.`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error utility functions for path sanitization and reporting.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Strips internal file paths from error messages to prevent sensitive path exposure.
|
|
6
|
+
*/
|
|
7
|
+
export function sanitizeErrorMessage(msg) {
|
|
8
|
+
// Mask Windows paths (e.g. C:\Users\...)
|
|
9
|
+
let sanitized = msg.replace(/[A-Za-z]:\\[^\s:]+/g, "[internal-path]");
|
|
10
|
+
// Mask Unix paths (e.g. /home/user/...)
|
|
11
|
+
sanitized = sanitized.replace(/\/[^\s:]+\/[^\s:]*/g, "[internal-path]");
|
|
12
|
+
// Mask relative parent paths
|
|
13
|
+
sanitized = sanitized.replace(/\.\.[\\/][^\s]*/g, "[internal-path]");
|
|
14
|
+
return sanitized;
|
|
15
|
+
}
|
package/docs/ASSISTANT_GUIDE.md
CHANGED
|
@@ -1,66 +1,56 @@
|
|
|
1
|
-
# Nexus 助手协作指令
|
|
2
|
-
|
|
3
|
-
你现在是 **n2ns Nexus**
|
|
4
|
-
|
|
5
|
-
## 🚦
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- `
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- `
|
|
34
|
-
- `
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* **快速查阅**:直接读取 `mcp://nexus/active-meeting` 资源,获取当前默认活跃会议的完整 transcript。
|
|
51
|
-
* `read_meeting(meetingId)`: 读取指定会议内容,包括 `messages` 和 `decisions`。
|
|
52
|
-
|
|
53
|
-
* **归档**:
|
|
54
|
-
* `archive_meeting(meetingId)`: 将已关闭的会议归档,仅供只读查阅。
|
|
55
|
-
|
|
56
|
-
### 6. 视角切换 (Discovery)
|
|
57
|
-
- 读取 `mcp://hub/registry`:了解公司目前有哪些其他项目。
|
|
58
|
-
- 调用 `get_global_topology`:可视化项目间的依赖关系,避免重复造轮子。
|
|
59
|
-
- 调用 `read_project`:查阅其他项目的 API 定义 (`include: "api"`) 或技术文档 (`include: "docs"`),以便对接。
|
|
1
|
+
# Nexus 助手协作指令 (v0.2.0)
|
|
2
|
+
|
|
3
|
+
你现在是 **n2ns Nexus** 协作网络的一员。该系统集成了实时通信、结构化资产管理以及 **异步任务流 (Task Primitives)**,所有操作均落地在本地文件系统。
|
|
4
|
+
|
|
5
|
+
## 🚦 核心原则:资源读取,工具写入
|
|
6
|
+
为了优化 Token 消耗,Nexus 将**只读信息**暴露为资源 (Resources),将**执行操作**保留为工具 (Tools)。
|
|
7
|
+
|
|
8
|
+
### 1. 状态发现 (Reading via Resources)
|
|
9
|
+
在任何任务开始前,你**必须**了解环境状态。直接读取对应的 URI 即可,无需消耗工具调用额度:
|
|
10
|
+
- **查看身份**:`mcp://nexus/session`(你的 ID 和活跃项目)。
|
|
11
|
+
- **系统状态**:`mcp://nexus/status`(版本、存储模式、活跃会议数)。
|
|
12
|
+
- **项目目录**:`mcp://nexus/hub/registry`(公司目前有哪些其他项目)。
|
|
13
|
+
- **会议目录**:`mcp://nexus/meetings/list`(哪些会议正在进行或已结束)。
|
|
14
|
+
- **任务列表**:`mcp://nexus/tasks/list` (TODO: 资源映射中) 或使用 `list_tasks`。
|
|
15
|
+
- **全局文档列表**:`mcp://nexus/docs/list`(有哪些通用规范)。
|
|
16
|
+
|
|
17
|
+
### 2. 深度查阅 (Deep Reading)
|
|
18
|
+
- **查阅项目**: `mcp://nexus/projects/{id}/manifest` (API 定义/技术栈) 或 `mcp://nexus/projects/{id}/internal-docs` (详细实现文档)。
|
|
19
|
+
- **查阅文档**: `mcp://nexus/docs/{id}`。
|
|
20
|
+
- **查阅会议**: `mcp://nexus/active-meeting` (当前活跃会议全案) 或 `mcp://nexus/meetings/{id}` (指定会议)。
|
|
21
|
+
- **查阅讨论**: `mcp://nexus/chat/global` (全局实时消息流)。
|
|
22
|
+
|
|
23
|
+
### 3. 项目管理 (Writing via Tools)
|
|
24
|
+
当你需要**改变**状态时,调用工具:
|
|
25
|
+
- **声明位置**: `register_session_context(projectId)`。解锁项目写权限。
|
|
26
|
+
- **资产同步**: `sync_project_assets`。
|
|
27
|
+
- **项目维护**: `update_project` 或 `rename_project` (自动处理所有依赖引用)。
|
|
28
|
+
- **素材上传**: `upload_project_asset` (架构图转 Base64)。
|
|
29
|
+
|
|
30
|
+
### 4. 异步任务流 (Tasks - Phase 2)
|
|
31
|
+
对于耗时较长或可能超时的操作(如大规模同步、重构),你**必须**使用任务原语:
|
|
32
|
+
- **创建任务**: `create_task(source_meeting_id?, metadata?)`。返回 `taskId`。
|
|
33
|
+
- **状态轮询**: `get_task(taskId)`。通过 `progress` (0.0-1.0) 了解任务进度。
|
|
34
|
+
- **任务列表**: `list_tasks(status?)`。
|
|
35
|
+
- **取消任务**: `cancel_task(taskId)`。
|
|
36
|
+
|
|
37
|
+
### 5. 即时沟通 (Collaboration via Tools)
|
|
38
|
+
- **发送消息**: `send_message(message, category?)`。
|
|
39
|
+
- **获取上下文**: `read_messages`。虽然已有资源,但当你需要带参数(如 `count`)获取特定数量的历史记录时,此工具更合适。
|
|
40
|
+
- **更新战略**: `update_global_strategy`(修改全球蓝图)。
|
|
41
|
+
- **文档维护**: `sync_global_doc` (创建/更新通用知识库)。
|
|
42
|
+
|
|
43
|
+
### 6. 战术会议 (Tactical Meetings)
|
|
44
|
+
1. **发起**: `start_meeting(topic)`。
|
|
45
|
+
2. **参与**: 发送 category 为 `DECISION` 的消息作为共识。
|
|
46
|
+
3. **结束**: `end_meeting(summary?)`。锁定历史。
|
|
47
|
+
4. **归档**: `archive_meeting(meetingId)`。
|
|
48
|
+
|
|
49
|
+
---
|
|
60
50
|
|
|
61
51
|
## 🛡️ 角色说明
|
|
62
|
-
- **Regular**:
|
|
63
|
-
- **Moderator**:
|
|
52
|
+
- **Regular**: 拥有注册、同步、讨论和维护文档的完整权限。
|
|
53
|
+
- **Moderator**: 额外拥有清理记录(`moderator_maintenance`)及物理删除(`moderator_delete_project`)的权限。
|
|
64
54
|
|
|
65
55
|
## ❌ 退出机制
|
|
66
|
-
|
|
56
|
+
本系统是对本地磁盘的原子写入。请确保同步时提供清晰的 `internalDocs`,以便其他 Assistant 能够无缝接手。
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [v0.2.0] - 2025-12-31
|
|
6
|
+
|
|
7
|
+
### 🚀 Task Primitive System (Phase 2 & 3)
|
|
8
|
+
- **Async Deepening**: Critical blocking operations (`rename_project`, `moderator_delete_project`) migrated to the Task primitive with background cascading updates.
|
|
9
|
+
- **Traceability**: All tasks now support `source_meeting_id` to link execution back to meeting decisions.
|
|
10
|
+
- **Progressive UI**: Added `progress` tracking (0.0-1.0) and `result_uri` for structured task output.
|
|
11
|
+
- **Lifecycle Tools**: Added `create_task`, `get_task`, `list_tasks`, `update_task`, and `cancel_task`.
|
|
12
|
+
|
|
13
|
+
### 🛡️ Type Safety & Security
|
|
14
|
+
- **Defense-in-Depth**: Implemented secondary permission gates inside `handleRemoveProject` and `handleModeratorMaintenance` for maximum project isolation.
|
|
15
|
+
- **Meeting Hardening**: `end_meeting` and `archive_meeting` are now strictly **Moderator-only**.
|
|
16
|
+
- **Zod integration**: All tool definitions migrated to strictly-typed Zod schemas with regex path-traversal protection.
|
|
17
|
+
- **Infrastructure**: Modernized toolchain to **TypeScript 5.9.3**, **Vitest 4.0.16**, and **ESLint 9.39.2**.
|
|
18
|
+
|
|
19
|
+
### ✂️ Code Diet (Architectural Cleanliness)
|
|
20
|
+
- **The Great Purge**: Removed 6 redundant tools (`list_projects`, `read_project`, `list_global_docs`, `read_global_doc`, `list_meetings`, `read_meeting`) in favor of Resource URIs.
|
|
21
|
+
- **Native Zod 4 Schemas**: Removed `zod-to-json-schema` dependency; now using native Zod 4 `toJSONSchema()` generation.
|
|
22
|
+
|
|
23
|
+
## [v0.1.9] - 2025-12-30
|
|
24
|
+
|
|
25
|
+
### 🛡️ Collaboration & Security
|
|
26
|
+
- **Initiator-only Permissions**: Implemented restricted access for `end_meeting` and `archive_meeting`.
|
|
27
|
+
- **Session Presence Awareness**: Automated `[ONLINE/OFFLINE]` status messages in global logs.
|
|
28
|
+
- **Clean Tool Naming**: Finalized transition to `send_message` and `read_messages`.
|
|
29
|
+
|
|
30
|
+
### 🌐 Resource Namespacing (MCP 2025 Standard)
|
|
31
|
+
- **Unified Authority**: All core resource URIs migrated to `mcp://nexus/`.
|
|
32
|
+
- **New Resources**: Added `mcp://nexus/status` and `mcp://nexus/active-meeting`.
|
|
33
|
+
|
|
5
34
|
## [v0.1.8] - 2025-12-30
|
|
6
35
|
|
|
7
36
|
### 🎯 Meeting Architecture (Phase 1 & 2)
|
package/docs/CHANGELOG_zh.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
本项目的所有重要变更都将记录在此文件中。
|
|
4
4
|
|
|
5
|
+
## [v0.2.0] - 2025-12-31
|
|
6
|
+
|
|
7
|
+
### 🚀 任务原语系统 (Phase 2 & 3)
|
|
8
|
+
- **深度异步化**: 关键阻塞操作(项目更名 `rename_project`、资产删除 `moderator_delete_project`)已迁移至异步 Task 模式,支持级联背景更新。
|
|
9
|
+
- **执行溯源**: 所有任务均支持 `source_meeting_id` 字段,可直接追溯至最初的会议决策。
|
|
10
|
+
- **进度追踪**: 增加了 `progress` (0.0-1.0) 进度播报机制及结构化结果 URI (`result_uri`)。
|
|
11
|
+
- **生命周期工具**: 新增 `create_task`, `get_task`, `list_tasks`, `update_task` 与 `cancel_task`。
|
|
12
|
+
|
|
13
|
+
### 🛡️ 安全加固与类型化
|
|
14
|
+
- **深度防御 (Defense-in-Depth)**: 在 `handleRemoveProject` 和 `handleModeratorMaintenance` 内部实现了二次权限校验,提升系统隔离安全性。
|
|
15
|
+
- **会议管理权限**: `end_meeting` 与 `archive_meeting` 现在严格限制为 **Moderator 专属**。
|
|
16
|
+
- **Zod 校验引擎**: 全量迁移工具定义至 Zod 架构,支持正则校验和路径穿透防护。
|
|
17
|
+
- **工具链现代化**: 升级至 **TypeScript 5.9.3**, **Vitest 4.0.16** 与 **ESLint 9.39.2**。
|
|
18
|
+
|
|
19
|
+
### ✂️ 架构清理 (Code Diet)
|
|
20
|
+
- **工具大清洗**: 删除了 6 个冗余读取工具(`read_project` 等),全面转向 **Resource-First** (MCP 资源优先) 模式。
|
|
21
|
+
- **原生 Zod 4 支持**: 彻底移除了 `zod-to-json-schema` 依赖,采用 Zod 4 原生的 `toJSONSchema()` 生成逻辑。
|
|
22
|
+
|
|
23
|
+
## [v0.1.9] - 2025-12-30
|
|
24
|
+
|
|
25
|
+
### 🛡️ 协同与权限强化
|
|
26
|
+
- **会议权限控制**: 实现了 **Initiator-only** 停机策略。只有会议发起者或系统管理员 (Moderator) 才能执行 `end_meeting` 和 `archive_meeting`。
|
|
27
|
+
- **自动在线感知**: 实现了会话生命周期日志。AI 实例启动及关闭(IDE 关闭)时会自动发送 `[ONLINE/OFFLINE]` 状态报文,提升多 Agent 协作透明度。
|
|
28
|
+
- **语义名统一**: 完成了工具命名的零别名集成。全面转向 `send_message` 和 `read_messages` 以获得更好的语义理解。
|
|
29
|
+
|
|
30
|
+
### 🌐 资源命名空间隔离 (MCP 2025)
|
|
31
|
+
- **统一 Authority**: 所有 MCP 资源 URI 已迁移至 `mcp://nexus/` 权威标识符下,防止与其他 MCP Server 发生命名冲突。
|
|
32
|
+
- **状态资源**: 暴露了 `mcp://nexus/status` 和 `mcp://nexus/active-meeting` (当前活跃会议实录) 资源。
|
|
33
|
+
|
|
5
34
|
## [v0.1.8] - 2025-12-30
|
|
6
35
|
|
|
7
36
|
### 🎯 会议架构 (Phase 1 & 2)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datafrog-io/n2n-nexus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Unified Project Asset & Collaboration Hub (MCP Server) designed for AI agent coordination, featuring structured metadata, real-time messaging, and dependency topology.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -46,15 +46,16 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@modelcontextprotocol/sdk": "1.25.1",
|
|
49
|
-
"better-sqlite3": "^12.5.0"
|
|
49
|
+
"better-sqlite3": "^12.5.0",
|
|
50
|
+
"zod": "^4.3.2"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
|
-
"@eslint/js": "^9.
|
|
53
|
+
"@eslint/js": "^9.39.2",
|
|
53
54
|
"@types/better-sqlite3": "^7.6.13",
|
|
54
|
-
"@types/node": "^
|
|
55
|
-
"eslint": "^9.
|
|
56
|
-
"typescript": "^5.
|
|
57
|
-
"typescript-eslint": "^8.
|
|
58
|
-
"vitest": "^
|
|
55
|
+
"@types/node": "^25.0.3",
|
|
56
|
+
"eslint": "^9.39.2",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"typescript-eslint": "^8.51.0",
|
|
59
|
+
"vitest": "^4.0.16"
|
|
59
60
|
}
|
|
60
|
-
}
|
|
61
|
+
}
|