@hualinge/relay-mcp-server 0.1.3

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/dist/collab.d.ts +8 -0
  4. package/dist/collab.d.ts.map +1 -0
  5. package/dist/collab.js +47 -0
  6. package/dist/collab.js.map +1 -0
  7. package/dist/dare.d.ts +4 -0
  8. package/dist/dare.d.ts.map +1 -0
  9. package/dist/dare.js +46 -0
  10. package/dist/dare.js.map +1 -0
  11. package/dist/index.d.ts +4 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +47 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/memory.d.ts +8 -0
  16. package/dist/memory.d.ts.map +1 -0
  17. package/dist/memory.js +47 -0
  18. package/dist/memory.js.map +1 -0
  19. package/dist/server-toolsets.d.ts +13 -0
  20. package/dist/server-toolsets.d.ts.map +1 -0
  21. package/dist/server-toolsets.js +119 -0
  22. package/dist/server-toolsets.js.map +1 -0
  23. package/dist/tools/callback-memory-tools.d.ts +46 -0
  24. package/dist/tools/callback-memory-tools.d.ts.map +1 -0
  25. package/dist/tools/callback-memory-tools.js +59 -0
  26. package/dist/tools/callback-memory-tools.js.map +1 -0
  27. package/dist/tools/callback-outbox.d.ts +15 -0
  28. package/dist/tools/callback-outbox.d.ts.map +1 -0
  29. package/dist/tools/callback-outbox.js +162 -0
  30. package/dist/tools/callback-outbox.js.map +1 -0
  31. package/dist/tools/callback-retry.d.ts +14 -0
  32. package/dist/tools/callback-retry.d.ts.map +1 -0
  33. package/dist/tools/callback-retry.js +58 -0
  34. package/dist/tools/callback-retry.js.map +1 -0
  35. package/dist/tools/callback-tools.d.ts +444 -0
  36. package/dist/tools/callback-tools.d.ts.map +1 -0
  37. package/dist/tools/callback-tools.js +771 -0
  38. package/dist/tools/callback-tools.js.map +1 -0
  39. package/dist/tools/evidence-tools.d.ts +36 -0
  40. package/dist/tools/evidence-tools.d.ts.map +1 -0
  41. package/dist/tools/evidence-tools.js +87 -0
  42. package/dist/tools/evidence-tools.js.map +1 -0
  43. package/dist/tools/file-tools.d.ts +78 -0
  44. package/dist/tools/file-tools.d.ts.map +1 -0
  45. package/dist/tools/file-tools.js +178 -0
  46. package/dist/tools/file-tools.js.map +1 -0
  47. package/dist/tools/index.d.ts +13 -0
  48. package/dist/tools/index.d.ts.map +1 -0
  49. package/dist/tools/index.js +18 -0
  50. package/dist/tools/index.js.map +1 -0
  51. package/dist/tools/limb-tools.d.ts +113 -0
  52. package/dist/tools/limb-tools.d.ts.map +1 -0
  53. package/dist/tools/limb-tools.js +120 -0
  54. package/dist/tools/limb-tools.js.map +1 -0
  55. package/dist/tools/reflect-tools.d.ts +23 -0
  56. package/dist/tools/reflect-tools.d.ts.map +1 -0
  57. package/dist/tools/reflect-tools.js +52 -0
  58. package/dist/tools/reflect-tools.js.map +1 -0
  59. package/dist/tools/rich-block-rules-tool.d.ts +17 -0
  60. package/dist/tools/rich-block-rules-tool.d.ts.map +1 -0
  61. package/dist/tools/rich-block-rules-tool.js +36 -0
  62. package/dist/tools/rich-block-rules-tool.js.map +1 -0
  63. package/dist/tools/schedule-tools.d.ts +134 -0
  64. package/dist/tools/schedule-tools.d.ts.map +1 -0
  65. package/dist/tools/schedule-tools.js +397 -0
  66. package/dist/tools/schedule-tools.js.map +1 -0
  67. package/dist/tools/session-chain-tools.d.ts +99 -0
  68. package/dist/tools/session-chain-tools.d.ts.map +1 -0
  69. package/dist/tools/session-chain-tools.js +288 -0
  70. package/dist/tools/session-chain-tools.js.map +1 -0
  71. package/dist/utils/index.d.ts +6 -0
  72. package/dist/utils/index.d.ts.map +1 -0
  73. package/dist/utils/index.js +11 -0
  74. package/dist/utils/index.js.map +1 -0
  75. package/dist/utils/path-utils.d.ts +6 -0
  76. package/dist/utils/path-utils.d.ts.map +1 -0
  77. package/dist/utils/path-utils.js +63 -0
  78. package/dist/utils/path-utils.js.map +1 -0
  79. package/dist/utils/path-validator.d.ts +45 -0
  80. package/dist/utils/path-validator.d.ts.map +1 -0
  81. package/dist/utils/path-validator.js +126 -0
  82. package/dist/utils/path-validator.js.map +1 -0
  83. package/package.json +44 -0
@@ -0,0 +1,288 @@
1
+ /*
2
+ * *
3
+ * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.
4
+ *
5
+ */
6
+ /**
7
+ * Session Chain MCP Tools — F24 Phase D + F98
8
+ * Tools for cats to read sealed session transcripts.
9
+ *
10
+ * Tools:
11
+ * - list_session_chain: List sessions for a thread
12
+ * - read_session_events: Paginated event read (view=raw|chat|handoff)
13
+ * - read_session_digest: Read extractive digest
14
+ * - read_invocation_detail: Read all events for a specific invocation
15
+ * - session_search: Full-text search across transcripts/digests
16
+ */
17
+ import { z } from 'zod';
18
+ import { errorResult, successResult } from './file-tools.js';
19
+ const API_URL = process.env['OFFICE_CLAW_API_URL'];
20
+ function resolveToolUserId() {
21
+ return process.env['OFFICE_CLAW_USER_ID'] ?? 'default-user';
22
+ }
23
+ function resolveToolAgentId() {
24
+ return process.env['OFFICE_CLAW_AGENT_ID'];
25
+ }
26
+ function buildAuthHeaders() {
27
+ const headers = {
28
+ 'x-office-claw-user': resolveToolUserId(),
29
+ };
30
+ const agentId = resolveToolAgentId();
31
+ if (agentId)
32
+ headers['x-agent-id'] = agentId;
33
+ return headers;
34
+ }
35
+ // --- list_session_chain ---
36
+ export const listSessionChainInputSchema = {
37
+ threadId: z.string().min(1).describe('Thread ID'),
38
+ agentId: z.string().optional().describe('Filter by agent ID (opus/codex/gemini)'),
39
+ limit: z.number().int().min(1).max(100).optional().describe('Max results'),
40
+ };
41
+ export async function handleListSessionChain(input) {
42
+ const params = new URLSearchParams();
43
+ if (input.agentId)
44
+ params.set('agentId', input.agentId);
45
+ const url = `${API_URL}/api/threads/${input.threadId}/sessions?${params.toString()}`;
46
+ try {
47
+ const res = await fetch(url, {
48
+ headers: buildAuthHeaders(),
49
+ });
50
+ if (!res.ok) {
51
+ return errorResult(`Failed to list sessions (${res.status}): ${await res.text()}`);
52
+ }
53
+ const data = (await res.json());
54
+ const sessions = input.limit ? data.sessions.slice(0, input.limit) : data.sessions;
55
+ if (sessions.length === 0) {
56
+ return successResult('No sessions found for this thread.');
57
+ }
58
+ return successResult(JSON.stringify(sessions, null, 2));
59
+ }
60
+ catch (err) {
61
+ return errorResult(`List sessions failed: ${err instanceof Error ? err.message : String(err)}`);
62
+ }
63
+ }
64
+ // --- read_session_events ---
65
+ export const readSessionEventsInputSchema = {
66
+ sessionId: z.string().min(1).describe('Session ID to read events from'),
67
+ cursor: z.number().int().min(0).optional().describe('Start from event number (0-based)'),
68
+ limit: z.number().int().min(1).max(200).optional().describe('Max events per page (default 50)'),
69
+ view: z
70
+ .enum(['raw', 'chat', 'handoff'])
71
+ .optional()
72
+ .describe('View mode: raw (default, full JSONL events), chat (role/content pairs), handoff (per-invocation summaries)'),
73
+ };
74
+ export async function handleReadSessionEvents(input) {
75
+ const params = new URLSearchParams();
76
+ if (input.cursor != null)
77
+ params.set('cursor', String(input.cursor));
78
+ if (input.limit != null)
79
+ params.set('limit', String(input.limit));
80
+ if (input.view)
81
+ params.set('view', input.view);
82
+ const url = `${API_URL}/api/sessions/${input.sessionId}/events?${params.toString()}`;
83
+ try {
84
+ const res = await fetch(url, {
85
+ headers: buildAuthHeaders(),
86
+ });
87
+ if (!res.ok) {
88
+ return errorResult(`Failed to read events (${res.status}): ${await res.text()}`);
89
+ }
90
+ const view = input.view ?? 'raw';
91
+ if (view === 'chat') {
92
+ const data = (await res.json());
93
+ const lines = [];
94
+ lines.push(`Total events: ${data.total}, messages: ${data.messages.length}`);
95
+ if (data.nextCursor)
96
+ lines.push(`Next cursor: ${data.nextCursor.eventNo}`);
97
+ lines.push('');
98
+ for (const msg of data.messages) {
99
+ lines.push(`[${msg.role}] ${msg.content.slice(0, 300)}`);
100
+ }
101
+ return successResult(lines.join('\n'));
102
+ }
103
+ if (view === 'handoff') {
104
+ const data = (await res.json());
105
+ const lines = [];
106
+ lines.push(`Total events: ${data.total}, invocations: ${data.invocations.length}`);
107
+ if (data.nextCursor)
108
+ lines.push(`Next cursor: ${data.nextCursor.eventNo}`);
109
+ lines.push('');
110
+ for (const inv of data.invocations) {
111
+ const dur = inv.durationMs > 0 ? ` (${Math.round(inv.durationMs / 1000)}s)` : '';
112
+ lines.push(`--- Invocation ${inv.invocationId}${dur} ---`);
113
+ lines.push(` Events: ${inv.eventCount}, Errors: ${inv.errors}`);
114
+ if (inv.toolCalls.length > 0)
115
+ lines.push(` Tools: ${inv.toolCalls.join(', ')}`);
116
+ for (const msg of inv.keyMessages) {
117
+ lines.push(` > ${msg}`);
118
+ }
119
+ lines.push('');
120
+ }
121
+ return successResult(lines.join('\n'));
122
+ }
123
+ // raw view (default)
124
+ const data = (await res.json());
125
+ const lines = [];
126
+ lines.push(`Total events: ${data.total}, returned: ${data.events.length}`);
127
+ if (data.nextCursor)
128
+ lines.push(`Next cursor: ${data.nextCursor.eventNo}`);
129
+ lines.push('');
130
+ for (const evt of data.events) {
131
+ const evtType = evt.event?.type ?? 'unknown';
132
+ lines.push(`[${evt.eventNo}] ${evtType}: ${JSON.stringify(evt.event).slice(0, 300)}`);
133
+ }
134
+ return successResult(lines.join('\n'));
135
+ }
136
+ catch (err) {
137
+ return errorResult(`Read events failed: ${err instanceof Error ? err.message : String(err)}`);
138
+ }
139
+ }
140
+ // --- read_session_digest ---
141
+ export const readSessionDigestInputSchema = {
142
+ sessionId: z.string().min(1).describe('Session ID to read digest from'),
143
+ };
144
+ export async function handleReadSessionDigest(input) {
145
+ const url = `${API_URL}/api/sessions/${input.sessionId}/digest`;
146
+ try {
147
+ const res = await fetch(url, {
148
+ headers: buildAuthHeaders(),
149
+ });
150
+ if (!res.ok) {
151
+ if (res.status === 404) {
152
+ return successResult('No digest found for this session (may not be sealed yet).');
153
+ }
154
+ return errorResult(`Failed to read digest (${res.status}): ${await res.text()}`);
155
+ }
156
+ const data = await res.json();
157
+ return successResult(JSON.stringify(data, null, 2));
158
+ }
159
+ catch (err) {
160
+ return errorResult(`Read digest failed: ${err instanceof Error ? err.message : String(err)}`);
161
+ }
162
+ }
163
+ // --- read_invocation_detail (F98 Gap 2) ---
164
+ export const readInvocationDetailInputSchema = {
165
+ sessionId: z.string().min(1).describe('Session ID containing the invocation'),
166
+ invocationId: z.string().min(1).describe('Invocation ID to read events for'),
167
+ };
168
+ export async function handleReadInvocationDetail(input) {
169
+ const url = `${API_URL}/api/sessions/${input.sessionId}/invocations/${input.invocationId}`;
170
+ try {
171
+ const res = await fetch(url, {
172
+ headers: buildAuthHeaders(),
173
+ });
174
+ if (!res.ok) {
175
+ if (res.status === 404) {
176
+ return successResult('Invocation not found in this session.');
177
+ }
178
+ return errorResult(`Failed to read invocation (${res.status}): ${await res.text()}`);
179
+ }
180
+ const data = (await res.json());
181
+ const lines = [];
182
+ lines.push(`Invocation ${data.invocationId}: ${data.total} event(s)`);
183
+ lines.push('');
184
+ for (const evt of data.events) {
185
+ const evtType = evt.event['type'] ?? 'unknown';
186
+ lines.push(`[${evt.eventNo}] ${evtType}: ${JSON.stringify(evt.event).slice(0, 300)}`);
187
+ }
188
+ return successResult(lines.join('\n'));
189
+ }
190
+ catch (err) {
191
+ return errorResult(`Read invocation failed: ${err instanceof Error ? err.message : String(err)}`);
192
+ }
193
+ }
194
+ // --- session_search ---
195
+ export const sessionSearchInputSchema = {
196
+ threadId: z.string().min(1).describe('Thread ID to search within'),
197
+ query: z.string().min(1).max(500).describe('Search query'),
198
+ agents: z.string().optional().describe('Comma-separated agent IDs to filter'),
199
+ limit: z.number().int().min(1).max(50).optional().describe('Max results (default 10)'),
200
+ scope: z.enum(['digests', 'transcripts', 'both']).optional().describe('Search scope (default both)'),
201
+ };
202
+ export async function handleSessionSearch(input) {
203
+ const params = new URLSearchParams({ q: input.query });
204
+ if (input.agents)
205
+ params.set('agents', input.agents);
206
+ if (input.limit != null)
207
+ params.set('limit', String(input.limit));
208
+ if (input.scope)
209
+ params.set('scope', input.scope);
210
+ const url = `${API_URL}/api/threads/${input.threadId}/sessions/search?${params.toString()}`;
211
+ try {
212
+ const res = await fetch(url, {
213
+ headers: buildAuthHeaders(),
214
+ });
215
+ if (!res.ok) {
216
+ return errorResult(`Search failed (${res.status}): ${await res.text()}`);
217
+ }
218
+ const data = (await res.json());
219
+ if (data.hits.length === 0) {
220
+ return successResult(`No results found for: ${input.query}`);
221
+ }
222
+ const lines = [];
223
+ lines.push(`Found ${data.hits.length} result(s) for "${input.query}":`);
224
+ lines.push('');
225
+ for (const hit of data.hits) {
226
+ lines.push(`[${hit.kind}] session=${hit.sessionId} score=${hit.score}`);
227
+ if (hit.pointer.eventNo != null) {
228
+ lines.push(` eventNo: ${hit.pointer.eventNo}`);
229
+ }
230
+ if (hit.pointer.invocationId) {
231
+ lines.push(` invocationId: ${hit.pointer.invocationId} (use read_invocation_detail to inspect)`);
232
+ }
233
+ lines.push(` > ${hit.snippet.slice(0, 200).replace(/\n/g, ' ')}`);
234
+ lines.push('');
235
+ }
236
+ return successResult(lines.join('\n'));
237
+ }
238
+ catch (err) {
239
+ return errorResult(`Search failed: ${err instanceof Error ? err.message : String(err)}`);
240
+ }
241
+ }
242
+ // --- Tool definitions ---
243
+ export const sessionChainTools = [
244
+ {
245
+ name: 'office_claw_list_session_chain',
246
+ description: 'List session chain for a thread. Shows session IDs, sequence numbers, status, and context health for each agent. ' +
247
+ 'Use when you need to find a specific session ID to drill into (e.g. "what did opus do in thread X?"). ' +
248
+ 'WORKFLOW: list_session_chain → read_session_digest (overview first) → read_session_events (detail). ' +
249
+ 'TIP: Filter by agentId to narrow results when a thread has many sessions from different cats.',
250
+ inputSchema: listSessionChainInputSchema,
251
+ handler: handleListSessionChain,
252
+ },
253
+ {
254
+ name: 'office_claw_read_session_events',
255
+ description: 'Read events from a sealed session transcript. Supports view modes: raw (default, full events), chat (role/content pairs), handoff (per-invocation summaries). Pagination via cursor. ' +
256
+ 'VIEW SELECTION: ' +
257
+ 'handoff (RECOMMENDED first) = per-invocation summaries with tool calls and key messages — best overview of what happened. ' +
258
+ 'chat = role/content message pairs — useful when you need to see the actual conversation flow. ' +
259
+ 'raw = full JSONL events — only when you need low-level event details (rarely needed). ' +
260
+ 'GOTCHA: Only sealed (completed) sessions are readable — in-progress sessions return empty. ' +
261
+ 'TIP: Start with view=handoff to get the big picture, then use read_invocation_detail for specific invocations.',
262
+ inputSchema: readSessionEventsInputSchema,
263
+ handler: handleReadSessionEvents,
264
+ },
265
+ {
266
+ name: 'office_claw_read_session_digest',
267
+ description: 'Read the extractive digest of a sealed session. Contains tool names, files touched, errors, and timing info. ' +
268
+ 'ALWAYS start here before reading full events — the digest gives you a quick overview ' +
269
+ 'so you know which parts of the session are worth drilling into. ' +
270
+ 'GOTCHA: Returns 404 if the session is not yet sealed (still in progress). ' +
271
+ 'TIP: After reading the digest, use read_session_events with view=handoff for more detail, ' +
272
+ 'or read_invocation_detail if the digest mentions a specific invocationId of interest.',
273
+ inputSchema: readSessionDigestInputSchema,
274
+ handler: handleReadSessionDigest,
275
+ },
276
+ {
277
+ name: 'office_claw_read_invocation_detail',
278
+ description: 'Read all events for a specific invocation within a sealed session. ' +
279
+ 'Use AFTER search_evidence or read_session_events (handoff view) returns an invocationId you want to inspect. ' +
280
+ 'This gives you the complete picture of one invocation: every tool call, response, and error. ' +
281
+ 'GOTCHA: You need both sessionId AND invocationId. Get sessionId from list_session_chain, ' +
282
+ 'and invocationId from read_session_events (handoff view) or search_evidence results.',
283
+ inputSchema: readInvocationDetailInputSchema,
284
+ handler: handleReadInvocationDetail,
285
+ },
286
+ // D15: office_claw_session_search removed — superseded by search_evidence unified entry point
287
+ ];
288
+ //# sourceMappingURL=session-chain-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-chain-tools.js","sourceRoot":"","sources":["../../src/tools/session-chain-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Utils Index
3
+ * 导出所有工具函数
4
+ */
5
+ export { ensureDir, getOfficeClawDir, getDefaultConfig, getSafePath, initOfficeClawDir, isPathAllowed, type PathConfig, } from './path-validator.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAMA;;;GAGG;AAEH,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,KAAK,UAAU,GAChB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /*
2
+ * *
3
+ * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.
4
+ *
5
+ */
6
+ /**
7
+ * Utils Index
8
+ * 导出所有工具函数
9
+ */
10
+ export { ensureDir, getOfficeClawDir, getDefaultConfig, getSafePath, initOfficeClawDir, isPathAllowed, } from './path-validator.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,aAAa,GAEd,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function expandHomeDir(inputPath: string): string;
2
+ export declare function resolveAbsolutePath(inputPath: string): string;
3
+ export declare function tryRealpathSync(targetPath: string): string | null;
4
+ export declare function isWithinPath(targetPath: string, baseDir: string): boolean;
5
+ export declare function findDeepestExistingPath(targetPath: string): string | null;
6
+ //# sourceMappingURL=path-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../src/utils/path-utils.ts"],"names":[],"mappings":"AAeA,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMjE;AAWD,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAUzE;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAezE"}
@@ -0,0 +1,63 @@
1
+ /*
2
+ * *
3
+ * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.
4
+ *
5
+ */
6
+ /**
7
+ * Path Utilities
8
+ * 路径处理的内部工具函数
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ export function expandHomeDir(inputPath) {
14
+ if (inputPath === '~') {
15
+ return os.homedir();
16
+ }
17
+ if (inputPath.startsWith('~/')) {
18
+ return path.join(os.homedir(), inputPath.slice(2));
19
+ }
20
+ return inputPath;
21
+ }
22
+ export function resolveAbsolutePath(inputPath) {
23
+ return path.resolve(expandHomeDir(inputPath));
24
+ }
25
+ export function tryRealpathSync(targetPath) {
26
+ try {
27
+ return fs.realpathSync(targetPath);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ function stripTrailingSeparators(targetPath) {
34
+ const root = path.parse(targetPath).root;
35
+ let result = targetPath;
36
+ while (result.length > root.length && result.endsWith(path.sep)) {
37
+ result = result.slice(0, -1);
38
+ }
39
+ return result;
40
+ }
41
+ export function isWithinPath(targetPath, baseDir) {
42
+ const normalizedTarget = stripTrailingSeparators(targetPath);
43
+ const normalizedBase = stripTrailingSeparators(baseDir);
44
+ const baseRoot = path.parse(normalizedBase).root;
45
+ if (normalizedBase === baseRoot) {
46
+ return normalizedTarget.startsWith(normalizedBase);
47
+ }
48
+ return normalizedTarget === normalizedBase || normalizedTarget.startsWith(normalizedBase + path.sep);
49
+ }
50
+ export function findDeepestExistingPath(targetPath) {
51
+ let current = targetPath;
52
+ while (true) {
53
+ if (fs.existsSync(current)) {
54
+ return current;
55
+ }
56
+ const parent = path.dirname(current);
57
+ if (parent === current) {
58
+ return null;
59
+ }
60
+ current = parent;
61
+ }
62
+ }
63
+ //# sourceMappingURL=path-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../src/utils/path-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;IACD,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,UAAkB;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IACzC,IAAI,MAAM,GAAG,UAAU,CAAC;IACxB,OAAO,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAChE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB,EAAE,OAAe;IAC9D,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;IAC7D,MAAM,cAAc,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC;IAEjD,IAAI,cAAc,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,gBAAgB,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,gBAAgB,KAAK,cAAc,IAAI,gBAAgB,CAAC,UAAU,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;AACvG,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,UAAkB;IACxD,IAAI,OAAO,GAAG,UAAU,CAAC;IAEzB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 配置接口
3
+ */
4
+ export interface PathConfig {
5
+ officeClawDir: string;
6
+ allowedDirs: string[];
7
+ }
8
+ /**
9
+ * 获取默认配置
10
+ * 从环境变量读取配置,若未设置则使用默认值
11
+ */
12
+ export declare function getDefaultConfig(): PathConfig;
13
+ /**
14
+ * 验证路径是否在允许的目录内
15
+ * @param targetPath - 要验证的路径
16
+ * @param config - 可选的配置,默认使用 getDefaultConfig()
17
+ * @returns 是否允许访问该路径
18
+ */
19
+ export declare function isPathAllowed(targetPath: string, config?: PathConfig): boolean;
20
+ /**
21
+ * 获取 OfficeClaw 数据目录
22
+ * @param config - 可选的配置
23
+ * @returns OfficeClaw 数据目录路径
24
+ */
25
+ export declare function getOfficeClawDir(config?: PathConfig): string;
26
+ /**
27
+ * 确保目录存在,若不存在则创建
28
+ * @param dirPath - 目录路径
29
+ */
30
+ export declare function ensureDir(dirPath: string): void;
31
+ /**
32
+ * 初始化 OfficeClaw 目录结构
33
+ * 创建 ~/.office-claw/ 及其子目录
34
+ * @param config - 可选的配置
35
+ */
36
+ export declare function initOfficeClawDir(config?: PathConfig): void;
37
+ /**
38
+ * 获取安全的绝对路径
39
+ * 解析路径并验证是否允许访问
40
+ * @param targetPath - 目标路径
41
+ * @param config - 可选的配置
42
+ * @returns 解析后的绝对路径,若不允许则返回 null
43
+ */
44
+ export declare function getSafePath(targetPath: string, config?: PathConfig): string | null;
45
+ //# sourceMappingURL=path-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-validator.d.ts","sourceRoot":"","sources":["../../src/utils/path-validator.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAOD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAsB7C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAqC9E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAG5D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAc3D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAQlF"}
@@ -0,0 +1,126 @@
1
+ /*
2
+ * *
3
+ * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.
4
+ *
5
+ */
6
+ /**
7
+ * Path Validator
8
+ * 路径验证和目录管理工具
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import { findDeepestExistingPath, isWithinPath, resolveAbsolutePath, tryRealpathSync } from './path-utils.js';
14
+ /**
15
+ * 默认的 OfficeClaw 子目录
16
+ */
17
+ const OFFICE_CLAW_SUBDIRS = ['chat', 'memory', 'workspace', 'assets', '.state'];
18
+ /**
19
+ * 获取默认配置
20
+ * 从环境变量读取配置,若未设置则使用默认值
21
+ */
22
+ export function getDefaultConfig() {
23
+ const homeDir = os.homedir();
24
+ const defaultOfficeClawDir = path.join(homeDir, '.office-claw');
25
+ const officeClawDir = process.env['OFFICE_CLAW_DATA_DIR'] ?? defaultOfficeClawDir;
26
+ // 解析允许的工作目录
27
+ const allowedWorkspaceDirs = process.env['ALLOWED_WORKSPACE_DIRS'];
28
+ const additionalDirs = allowedWorkspaceDirs
29
+ ? allowedWorkspaceDirs
30
+ .split(/[:,]/)
31
+ .map((dir) => dir.trim())
32
+ .filter(Boolean)
33
+ : [];
34
+ // 默认允许 office-claw 目录和额外配置的目录
35
+ const allowedDirs = [officeClawDir, ...additionalDirs];
36
+ return {
37
+ officeClawDir,
38
+ allowedDirs,
39
+ };
40
+ }
41
+ /**
42
+ * 验证路径是否在允许的目录内
43
+ * @param targetPath - 要验证的路径
44
+ * @param config - 可选的配置,默认使用 getDefaultConfig()
45
+ * @returns 是否允许访问该路径
46
+ */
47
+ export function isPathAllowed(targetPath, config) {
48
+ const { allowedDirs } = config ?? getDefaultConfig();
49
+ // 解析为绝对路径
50
+ const resolvedPath = resolveAbsolutePath(targetPath);
51
+ const resolvedAllowedDirs = allowedDirs.map(resolveAbsolutePath);
52
+ // Quick reject using pure path prefix check
53
+ const prefixAllowed = resolvedAllowedDirs.some((allowedDir) => isWithinPath(resolvedPath, allowedDir));
54
+ if (!prefixAllowed) {
55
+ return false;
56
+ }
57
+ const realAllowedDirs = resolvedAllowedDirs.map((allowedDir) => tryRealpathSync(allowedDir) ?? allowedDir);
58
+ // If target exists, validate its realpath; otherwise validate the realpath of the deepest
59
+ // existing prefix to prevent symlink escapes like allowed/link -> /etc.
60
+ if (fs.existsSync(resolvedPath)) {
61
+ const realTarget = tryRealpathSync(resolvedPath);
62
+ if (realTarget === null) {
63
+ return false;
64
+ }
65
+ return realAllowedDirs.some((allowedDir) => isWithinPath(realTarget, allowedDir));
66
+ }
67
+ const existingPath = findDeepestExistingPath(resolvedPath);
68
+ if (existingPath === null) {
69
+ return false;
70
+ }
71
+ const realExisting = tryRealpathSync(existingPath);
72
+ if (realExisting === null) {
73
+ return false;
74
+ }
75
+ return realAllowedDirs.some((allowedDir) => isWithinPath(realExisting, allowedDir));
76
+ }
77
+ /**
78
+ * 获取 OfficeClaw 数据目录
79
+ * @param config - 可选的配置
80
+ * @returns OfficeClaw 数据目录路径
81
+ */
82
+ export function getOfficeClawDir(config) {
83
+ const { officeClawDir } = config ?? getDefaultConfig();
84
+ return resolveAbsolutePath(officeClawDir);
85
+ }
86
+ /**
87
+ * 确保目录存在,若不存在则创建
88
+ * @param dirPath - 目录路径
89
+ */
90
+ export function ensureDir(dirPath) {
91
+ if (!fs.existsSync(dirPath)) {
92
+ fs.mkdirSync(dirPath, { recursive: true });
93
+ }
94
+ }
95
+ /**
96
+ * 初始化 OfficeClaw 目录结构
97
+ * 创建 ~/.office-claw/ 及其子目录
98
+ * @param config - 可选的配置
99
+ */
100
+ export function initOfficeClawDir(config) {
101
+ const officeClawDir = getOfficeClawDir(config);
102
+ // 创建主目录
103
+ ensureDir(officeClawDir);
104
+ // 创建子目录
105
+ for (const subdir of OFFICE_CLAW_SUBDIRS) {
106
+ const subdirPath = path.join(officeClawDir, subdir);
107
+ ensureDir(subdirPath);
108
+ }
109
+ // 输出到 stderr(stdout 用于 JSON-RPC)
110
+ console.error(`[office-claw] Initialized directory: ${officeClawDir}`);
111
+ }
112
+ /**
113
+ * 获取安全的绝对路径
114
+ * 解析路径并验证是否允许访问
115
+ * @param targetPath - 目标路径
116
+ * @param config - 可选的配置
117
+ * @returns 解析后的绝对路径,若不允许则返回 null
118
+ */
119
+ export function getSafePath(targetPath, config) {
120
+ const resolvedPath = resolveAbsolutePath(targetPath);
121
+ if (!isPathAllowed(resolvedPath, config)) {
122
+ return null;
123
+ }
124
+ return resolvedPath;
125
+ }
126
+ //# sourceMappingURL=path-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-validator.js","sourceRoot":"","sources":["../../src/utils/path-validator.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@hualinge/relay-mcp-server",
3
+ "version": "0.1.3",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "types": "./dist/index.d.ts"
20
+ }
21
+ },
22
+ "bin": {
23
+ "office-claw-mcp-server": "./dist/index.js",
24
+ "relay-mcp-server": "./dist/index.js"
25
+ },
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.0.0",
28
+ "zod": "^3.22.4",
29
+ "@hualinge/relay-shared": "0.1.3"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.11.0",
33
+ "tsx": "^4.7.0",
34
+ "typescript": "^5.3.3"
35
+ },
36
+ "scripts": {
37
+ "build": "pnpm clean && tsc",
38
+ "dev": "tsx watch src/index.ts",
39
+ "start": "node dist/index.js",
40
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
41
+ "lint": "tsc --noEmit",
42
+ "test": "tsc && node --test test/*.test.js"
43
+ }
44
+ }