@jshookmcp/jshook 0.1.5 → 0.1.7
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 +72 -40
- package/README.zh.md +77 -40
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +13 -1
- package/dist/index.js +0 -0
- package/dist/modules/analyzer/IntelligentAnalyzer.js +19 -11
- package/dist/modules/browser/BrowserModeManager.d.ts +5 -0
- package/dist/modules/browser/BrowserModeManager.js +96 -10
- package/dist/modules/browser/CamoufoxBrowserManager.d.ts +4 -0
- package/dist/modules/browser/CamoufoxBrowserManager.js +64 -3
- package/dist/modules/browser/TabRegistry.js +3 -2
- package/dist/modules/browser/UnifiedBrowserManager.d.ts +5 -0
- package/dist/modules/browser/UnifiedBrowserManager.js +62 -9
- package/dist/modules/debugger/DebuggerSessionManager.d.ts +4 -0
- package/dist/modules/debugger/DebuggerSessionManager.js +29 -19
- package/dist/modules/debugger/ScriptManager.impl.class.d.ts +4 -0
- package/dist/modules/debugger/ScriptManager.impl.class.js +46 -21
- package/dist/modules/emulator/EnvironmentEmulator.js +2 -2
- package/dist/modules/monitor/NetworkMonitor.impl.d.ts +1 -0
- package/dist/modules/monitor/NetworkMonitor.impl.js +22 -15
- package/dist/modules/monitor/PerformanceMonitor.js +64 -32
- package/dist/modules/process/LinuxProcessManager.d.ts +3 -1
- package/dist/modules/process/LinuxProcessManager.js +7 -3
- package/dist/modules/process/MacProcessManager.d.ts +3 -1
- package/dist/modules/process/MacProcessManager.js +7 -3
- package/dist/modules/process/ProcessManager.impl.d.ts +5 -1
- package/dist/modules/process/ProcessManager.impl.js +54 -13
- package/dist/modules/process/index.d.ts +3 -1
- package/dist/modules/process/index.js +2 -2
- package/dist/modules/process/memory/AuditTrail.d.ts +25 -0
- package/dist/modules/process/memory/AuditTrail.js +44 -0
- package/dist/modules/process/memory/linux/mapsParser.d.ts +16 -0
- package/dist/modules/process/memory/linux/mapsParser.js +28 -0
- package/dist/modules/process/memory/regions.enumerate.js +45 -1
- package/dist/modules/process/memory/regions.protection.js +48 -2
- package/dist/modules/process/memory/scanner.d.ts +4 -1
- package/dist/modules/process/memory/scanner.js +225 -24
- package/dist/native/NativeMemoryManager.impl.d.ts +4 -0
- package/dist/native/NativeMemoryManager.impl.js +72 -24
- package/dist/native/NativeMemoryManager.utils.d.ts +1 -0
- package/dist/native/NativeMemoryManager.utils.js +44 -1
- package/dist/server/MCPServer.search.d.ts +3 -0
- package/dist/server/MCPServer.search.js +21 -2
- package/dist/server/ToolCallContextGuard.d.ts +2 -0
- package/dist/server/ToolCallContextGuard.js +29 -14
- package/dist/server/ToolSearch.js +11 -5
- package/dist/server/domains/browser/handlers/tab-workflow.js +6 -4
- package/dist/server/domains/maintenance/handlers.extensions.js +46 -26
- package/dist/server/domains/process/definitions.js +20 -7
- package/dist/server/domains/process/handlers.impl.core.runtime.base.d.ts +35 -0
- package/dist/server/domains/process/handlers.impl.core.runtime.base.js +107 -1
- package/dist/server/domains/process/handlers.impl.core.runtime.inject.js +111 -2
- package/dist/server/domains/process/handlers.impl.core.runtime.memory.d.ts +9 -0
- package/dist/server/domains/process/handlers.impl.core.runtime.memory.js +282 -31
- package/dist/server/domains/process/manifest.js +1 -0
- package/dist/server/domains/workflow/handlers.impl.workflow-api.js +14 -4
- package/dist/server/registry/discovery.js +17 -12
- package/dist/server/registry/index.js +10 -2
- package/dist/utils/TokenBudgetManager.d.ts +1 -0
- package/dist/utils/TokenBudgetManager.js +22 -0
- package/package.json +28 -41
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { AuditEntry } from '../../../modules/process/memory/AuditTrail.js';
|
|
1
2
|
import { ProcessToolHandlersBase } from '../../domains/process/handlers.impl.core.runtime.base.js';
|
|
2
3
|
export declare class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
4
|
+
private safeBuildMemoryDiagnostics;
|
|
5
|
+
protected recordMemoryAudit(entry: Omit<AuditEntry, 'timestamp' | 'user'>): void;
|
|
3
6
|
handleMemoryRead(args: Record<string, unknown>): Promise<{
|
|
4
7
|
content: {
|
|
5
8
|
type: string;
|
|
@@ -18,6 +21,12 @@ export declare class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
|
18
21
|
text: string;
|
|
19
22
|
}[];
|
|
20
23
|
}>;
|
|
24
|
+
handleMemoryAuditExport(args: Record<string, unknown>): Promise<{
|
|
25
|
+
content: {
|
|
26
|
+
type: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}[];
|
|
29
|
+
}>;
|
|
21
30
|
handleMemoryCheckProtection(args: Record<string, unknown>): Promise<{
|
|
22
31
|
content: {
|
|
23
32
|
type: string;
|
|
@@ -14,14 +14,67 @@ function normalizePatternType(value) {
|
|
|
14
14
|
}
|
|
15
15
|
return 'hex';
|
|
16
16
|
}
|
|
17
|
+
function getOptionalPid(value) {
|
|
18
|
+
const pid = Number(value);
|
|
19
|
+
return Number.isInteger(pid) && pid > 0 ? pid : undefined;
|
|
20
|
+
}
|
|
21
|
+
function getOptionalString(value) {
|
|
22
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
23
|
+
}
|
|
24
|
+
function getOptionalPositiveNumber(value) {
|
|
25
|
+
const size = Number(value);
|
|
26
|
+
return Number.isFinite(size) && size > 0 ? size : undefined;
|
|
27
|
+
}
|
|
28
|
+
function getWriteSize(data, encoding) {
|
|
29
|
+
if (encoding === 'hex') {
|
|
30
|
+
const normalized = data.replace(/\s+/g, '');
|
|
31
|
+
return Math.ceil(normalized.length / 2);
|
|
32
|
+
}
|
|
33
|
+
return Buffer.from(data, 'base64').length;
|
|
34
|
+
}
|
|
17
35
|
export class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
36
|
+
async safeBuildMemoryDiagnostics(input) {
|
|
37
|
+
try {
|
|
38
|
+
return await this.buildMemoryDiagnostics(input);
|
|
39
|
+
}
|
|
40
|
+
catch (diagnosticError) {
|
|
41
|
+
logger.warn('Memory diagnostics generation failed:', diagnosticError);
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
recordMemoryAudit(entry) {
|
|
46
|
+
try {
|
|
47
|
+
this.auditTrail.record(entry);
|
|
48
|
+
}
|
|
49
|
+
catch (auditError) {
|
|
50
|
+
logger.warn('Memory audit trail recording failed:', auditError);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
18
53
|
async handleMemoryRead(args) {
|
|
54
|
+
const startedAt = Date.now();
|
|
19
55
|
try {
|
|
20
56
|
const pid = validatePid(args.pid);
|
|
21
57
|
const address = requireString(args.address, 'address');
|
|
22
58
|
const size = requirePositiveNumber(args.size, 'size');
|
|
23
59
|
const availability = await this.memoryManager.checkAvailability();
|
|
24
60
|
if (!availability.available) {
|
|
61
|
+
const errorMessage = availability.reason ?? 'Memory operations not available';
|
|
62
|
+
const diagnostics = await this.safeBuildMemoryDiagnostics({
|
|
63
|
+
pid,
|
|
64
|
+
address,
|
|
65
|
+
size,
|
|
66
|
+
operation: 'memory_read',
|
|
67
|
+
error: errorMessage,
|
|
68
|
+
});
|
|
69
|
+
this.recordMemoryAudit({
|
|
70
|
+
operation: 'memory_read',
|
|
71
|
+
pid,
|
|
72
|
+
address,
|
|
73
|
+
size,
|
|
74
|
+
result: 'failure',
|
|
75
|
+
error: errorMessage,
|
|
76
|
+
durationMs: Date.now() - startedAt,
|
|
77
|
+
});
|
|
25
78
|
return {
|
|
26
79
|
content: [
|
|
27
80
|
{
|
|
@@ -34,38 +87,82 @@ export class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
|
34
87
|
requestedAddress: address,
|
|
35
88
|
requestedSize: size,
|
|
36
89
|
pid,
|
|
90
|
+
diagnostics,
|
|
37
91
|
}, null, 2),
|
|
38
92
|
},
|
|
39
93
|
],
|
|
40
94
|
};
|
|
41
95
|
}
|
|
42
96
|
const result = await this.memoryManager.readMemory(pid, address, size);
|
|
97
|
+
const diagnostics = !result.success
|
|
98
|
+
? await this.safeBuildMemoryDiagnostics({
|
|
99
|
+
pid,
|
|
100
|
+
address,
|
|
101
|
+
size,
|
|
102
|
+
operation: 'memory_read',
|
|
103
|
+
error: result.error,
|
|
104
|
+
})
|
|
105
|
+
: undefined;
|
|
106
|
+
this.recordMemoryAudit({
|
|
107
|
+
operation: 'memory_read',
|
|
108
|
+
pid,
|
|
109
|
+
address,
|
|
110
|
+
size,
|
|
111
|
+
result: result.success ? 'success' : 'failure',
|
|
112
|
+
error: result.error,
|
|
113
|
+
durationMs: Date.now() - startedAt,
|
|
114
|
+
});
|
|
115
|
+
const payload = {
|
|
116
|
+
success: result.success,
|
|
117
|
+
data: result.data,
|
|
118
|
+
error: result.error,
|
|
119
|
+
pid,
|
|
120
|
+
address,
|
|
121
|
+
size,
|
|
122
|
+
platform: this.platform,
|
|
123
|
+
};
|
|
124
|
+
if (!result.success) {
|
|
125
|
+
payload.diagnostics = diagnostics;
|
|
126
|
+
}
|
|
43
127
|
return {
|
|
44
128
|
content: [
|
|
45
129
|
{
|
|
46
130
|
type: 'text',
|
|
47
|
-
text: JSON.stringify(
|
|
48
|
-
success: result.success,
|
|
49
|
-
data: result.data,
|
|
50
|
-
error: result.error,
|
|
51
|
-
pid,
|
|
52
|
-
address,
|
|
53
|
-
size,
|
|
54
|
-
platform: this.platform,
|
|
55
|
-
}, null, 2),
|
|
131
|
+
text: JSON.stringify(payload, null, 2),
|
|
56
132
|
},
|
|
57
133
|
],
|
|
58
134
|
};
|
|
59
135
|
}
|
|
60
136
|
catch (error) {
|
|
61
137
|
logger.error('Memory read failed:', error);
|
|
138
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
139
|
+
const pid = getOptionalPid(args.pid);
|
|
140
|
+
const address = getOptionalString(args.address);
|
|
141
|
+
const size = getOptionalPositiveNumber(args.size);
|
|
142
|
+
const diagnostics = await this.safeBuildMemoryDiagnostics({
|
|
143
|
+
pid,
|
|
144
|
+
address,
|
|
145
|
+
size,
|
|
146
|
+
operation: 'memory_read',
|
|
147
|
+
error: errorMessage,
|
|
148
|
+
});
|
|
149
|
+
this.recordMemoryAudit({
|
|
150
|
+
operation: 'memory_read',
|
|
151
|
+
pid: pid ?? null,
|
|
152
|
+
address: address ?? null,
|
|
153
|
+
size: size ?? null,
|
|
154
|
+
result: 'failure',
|
|
155
|
+
error: errorMessage,
|
|
156
|
+
durationMs: Date.now() - startedAt,
|
|
157
|
+
});
|
|
62
158
|
return {
|
|
63
159
|
content: [
|
|
64
160
|
{
|
|
65
161
|
type: 'text',
|
|
66
162
|
text: JSON.stringify({
|
|
67
163
|
success: false,
|
|
68
|
-
error:
|
|
164
|
+
error: errorMessage,
|
|
165
|
+
diagnostics,
|
|
69
166
|
}, null, 2),
|
|
70
167
|
},
|
|
71
168
|
],
|
|
@@ -73,13 +170,32 @@ export class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
|
73
170
|
}
|
|
74
171
|
}
|
|
75
172
|
async handleMemoryWrite(args) {
|
|
173
|
+
const startedAt = Date.now();
|
|
76
174
|
try {
|
|
77
175
|
const pid = validatePid(args.pid);
|
|
78
176
|
const address = requireString(args.address, 'address');
|
|
79
177
|
const data = requireString(args.data, 'data');
|
|
80
178
|
const encoding = args.encoding || 'hex';
|
|
179
|
+
const size = getWriteSize(data, encoding);
|
|
81
180
|
const availability = await this.memoryManager.checkAvailability();
|
|
82
181
|
if (!availability.available) {
|
|
182
|
+
const errorMessage = availability.reason ?? 'Memory operations not available';
|
|
183
|
+
const diagnostics = await this.safeBuildMemoryDiagnostics({
|
|
184
|
+
pid,
|
|
185
|
+
address,
|
|
186
|
+
size,
|
|
187
|
+
operation: 'memory_write',
|
|
188
|
+
error: errorMessage,
|
|
189
|
+
});
|
|
190
|
+
this.recordMemoryAudit({
|
|
191
|
+
operation: 'memory_write',
|
|
192
|
+
pid,
|
|
193
|
+
address,
|
|
194
|
+
size,
|
|
195
|
+
result: 'failure',
|
|
196
|
+
error: errorMessage,
|
|
197
|
+
durationMs: Date.now() - startedAt,
|
|
198
|
+
});
|
|
83
199
|
return {
|
|
84
200
|
content: [
|
|
85
201
|
{
|
|
@@ -93,39 +209,85 @@ export class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
|
93
209
|
dataLength: data != null ? data.length : 0,
|
|
94
210
|
encoding,
|
|
95
211
|
pid,
|
|
212
|
+
diagnostics,
|
|
96
213
|
}, null, 2),
|
|
97
214
|
},
|
|
98
215
|
],
|
|
99
216
|
};
|
|
100
217
|
}
|
|
101
218
|
const result = await this.memoryManager.writeMemory(pid, address, data, encoding);
|
|
219
|
+
const diagnostics = !result.success
|
|
220
|
+
? await this.safeBuildMemoryDiagnostics({
|
|
221
|
+
pid,
|
|
222
|
+
address,
|
|
223
|
+
size,
|
|
224
|
+
operation: 'memory_write',
|
|
225
|
+
error: result.error,
|
|
226
|
+
})
|
|
227
|
+
: undefined;
|
|
228
|
+
this.recordMemoryAudit({
|
|
229
|
+
operation: 'memory_write',
|
|
230
|
+
pid,
|
|
231
|
+
address,
|
|
232
|
+
size,
|
|
233
|
+
result: result.success ? 'success' : 'failure',
|
|
234
|
+
error: result.error,
|
|
235
|
+
durationMs: Date.now() - startedAt,
|
|
236
|
+
});
|
|
237
|
+
const payload = {
|
|
238
|
+
success: result.success,
|
|
239
|
+
bytesWritten: result.bytesWritten,
|
|
240
|
+
error: result.error,
|
|
241
|
+
pid,
|
|
242
|
+
address,
|
|
243
|
+
dataLength: data.length,
|
|
244
|
+
encoding,
|
|
245
|
+
platform: this.platform,
|
|
246
|
+
};
|
|
247
|
+
if (!result.success) {
|
|
248
|
+
payload.diagnostics = diagnostics;
|
|
249
|
+
}
|
|
102
250
|
return {
|
|
103
251
|
content: [
|
|
104
252
|
{
|
|
105
253
|
type: 'text',
|
|
106
|
-
text: JSON.stringify(
|
|
107
|
-
success: result.success,
|
|
108
|
-
bytesWritten: result.bytesWritten,
|
|
109
|
-
error: result.error,
|
|
110
|
-
pid,
|
|
111
|
-
address,
|
|
112
|
-
dataLength: data.length,
|
|
113
|
-
encoding,
|
|
114
|
-
platform: this.platform,
|
|
115
|
-
}, null, 2),
|
|
254
|
+
text: JSON.stringify(payload, null, 2),
|
|
116
255
|
},
|
|
117
256
|
],
|
|
118
257
|
};
|
|
119
258
|
}
|
|
120
259
|
catch (error) {
|
|
121
260
|
logger.error('Memory write failed:', error);
|
|
261
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
262
|
+
const pid = getOptionalPid(args.pid);
|
|
263
|
+
const address = getOptionalString(args.address);
|
|
264
|
+
const data = getOptionalString(args.data);
|
|
265
|
+
const encoding = args.encoding || 'hex';
|
|
266
|
+
const size = data ? getWriteSize(data, encoding) : undefined;
|
|
267
|
+
const diagnostics = await this.safeBuildMemoryDiagnostics({
|
|
268
|
+
pid,
|
|
269
|
+
address,
|
|
270
|
+
size,
|
|
271
|
+
operation: 'memory_write',
|
|
272
|
+
error: errorMessage,
|
|
273
|
+
});
|
|
274
|
+
this.recordMemoryAudit({
|
|
275
|
+
operation: 'memory_write',
|
|
276
|
+
pid: pid ?? null,
|
|
277
|
+
address: address ?? null,
|
|
278
|
+
size: size ?? null,
|
|
279
|
+
result: 'failure',
|
|
280
|
+
error: errorMessage,
|
|
281
|
+
durationMs: Date.now() - startedAt,
|
|
282
|
+
});
|
|
122
283
|
return {
|
|
123
284
|
content: [
|
|
124
285
|
{
|
|
125
286
|
type: 'text',
|
|
126
287
|
text: JSON.stringify({
|
|
127
288
|
success: false,
|
|
128
|
-
error:
|
|
289
|
+
error: errorMessage,
|
|
290
|
+
diagnostics,
|
|
129
291
|
}, null, 2),
|
|
130
292
|
},
|
|
131
293
|
],
|
|
@@ -133,12 +295,28 @@ export class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
|
133
295
|
}
|
|
134
296
|
}
|
|
135
297
|
async handleMemoryScan(args) {
|
|
298
|
+
const startedAt = Date.now();
|
|
136
299
|
try {
|
|
137
300
|
const pid = validatePid(args.pid);
|
|
138
301
|
const pattern = requireString(args.pattern, 'pattern');
|
|
139
302
|
const patternType = normalizePatternType(args.patternType);
|
|
140
303
|
const availability = await this.memoryManager.checkAvailability();
|
|
141
304
|
if (!availability.available) {
|
|
305
|
+
const errorMessage = availability.reason ?? 'Memory operations not available';
|
|
306
|
+
const diagnostics = await this.safeBuildMemoryDiagnostics({
|
|
307
|
+
pid,
|
|
308
|
+
operation: 'memory_scan',
|
|
309
|
+
error: errorMessage,
|
|
310
|
+
});
|
|
311
|
+
this.recordMemoryAudit({
|
|
312
|
+
operation: 'memory_scan',
|
|
313
|
+
pid,
|
|
314
|
+
address: null,
|
|
315
|
+
size: null,
|
|
316
|
+
result: 'failure',
|
|
317
|
+
error: errorMessage,
|
|
318
|
+
durationMs: Date.now() - startedAt,
|
|
319
|
+
});
|
|
142
320
|
return {
|
|
143
321
|
content: [
|
|
144
322
|
{
|
|
@@ -151,43 +329,116 @@ export class ProcessToolHandlersMemory extends ProcessToolHandlersBase {
|
|
|
151
329
|
requestedPattern: pattern,
|
|
152
330
|
patternType,
|
|
153
331
|
pid,
|
|
332
|
+
diagnostics,
|
|
154
333
|
}, null, 2),
|
|
155
334
|
},
|
|
156
335
|
],
|
|
157
336
|
};
|
|
158
337
|
}
|
|
159
338
|
const result = await this.memoryManager.scanMemory(pid, pattern, patternType);
|
|
339
|
+
const diagnostics = !result.success
|
|
340
|
+
? await this.safeBuildMemoryDiagnostics({
|
|
341
|
+
pid,
|
|
342
|
+
operation: 'memory_scan',
|
|
343
|
+
error: result.error,
|
|
344
|
+
})
|
|
345
|
+
: undefined;
|
|
346
|
+
this.recordMemoryAudit({
|
|
347
|
+
operation: 'memory_scan',
|
|
348
|
+
pid,
|
|
349
|
+
address: null,
|
|
350
|
+
size: null,
|
|
351
|
+
result: result.success ? 'success' : 'failure',
|
|
352
|
+
error: result.error,
|
|
353
|
+
durationMs: Date.now() - startedAt,
|
|
354
|
+
});
|
|
355
|
+
const payload = {
|
|
356
|
+
success: result.success,
|
|
357
|
+
addresses: result.addresses,
|
|
358
|
+
error: result.error,
|
|
359
|
+
pid,
|
|
360
|
+
pattern,
|
|
361
|
+
patternType,
|
|
362
|
+
platform: this.platform,
|
|
363
|
+
};
|
|
364
|
+
if (!result.success) {
|
|
365
|
+
payload.diagnostics = diagnostics;
|
|
366
|
+
}
|
|
160
367
|
return {
|
|
161
368
|
content: [
|
|
162
369
|
{
|
|
163
370
|
type: 'text',
|
|
164
|
-
text: JSON.stringify(
|
|
165
|
-
success: result.success,
|
|
166
|
-
addresses: result.addresses,
|
|
167
|
-
error: result.error,
|
|
168
|
-
pid,
|
|
169
|
-
pattern,
|
|
170
|
-
patternType,
|
|
171
|
-
platform: this.platform,
|
|
172
|
-
}, null, 2),
|
|
371
|
+
text: JSON.stringify(payload, null, 2),
|
|
173
372
|
},
|
|
174
373
|
],
|
|
175
374
|
};
|
|
176
375
|
}
|
|
177
376
|
catch (error) {
|
|
178
377
|
logger.error('Memory scan failed:', error);
|
|
378
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
379
|
+
const pid = getOptionalPid(args.pid);
|
|
380
|
+
const diagnostics = await this.safeBuildMemoryDiagnostics({
|
|
381
|
+
pid,
|
|
382
|
+
operation: 'memory_scan',
|
|
383
|
+
error: errorMessage,
|
|
384
|
+
});
|
|
385
|
+
this.recordMemoryAudit({
|
|
386
|
+
operation: 'memory_scan',
|
|
387
|
+
pid: pid ?? null,
|
|
388
|
+
address: null,
|
|
389
|
+
size: null,
|
|
390
|
+
result: 'failure',
|
|
391
|
+
error: errorMessage,
|
|
392
|
+
durationMs: Date.now() - startedAt,
|
|
393
|
+
});
|
|
179
394
|
return {
|
|
180
395
|
content: [
|
|
181
396
|
{
|
|
182
397
|
type: 'text',
|
|
183
398
|
text: JSON.stringify({
|
|
184
399
|
success: false,
|
|
185
|
-
error:
|
|
400
|
+
error: errorMessage,
|
|
401
|
+
diagnostics,
|
|
402
|
+
}, null, 2),
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
async handleMemoryAuditExport(args) {
|
|
409
|
+
try {
|
|
410
|
+
const exportedJson = this.auditTrail.exportJson();
|
|
411
|
+
const entries = JSON.parse(exportedJson);
|
|
412
|
+
const clear = args.clear === true;
|
|
413
|
+
const count = this.auditTrail.size();
|
|
414
|
+
if (clear) {
|
|
415
|
+
this.auditTrail.clear();
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
content: [
|
|
419
|
+
{
|
|
420
|
+
type: 'text',
|
|
421
|
+
text: JSON.stringify({
|
|
422
|
+
success: true,
|
|
423
|
+
count,
|
|
424
|
+
cleared: clear,
|
|
425
|
+
entries,
|
|
186
426
|
}, null, 2),
|
|
187
427
|
},
|
|
188
428
|
],
|
|
189
429
|
};
|
|
190
430
|
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
logger.error('Memory audit export failed:', error);
|
|
433
|
+
return {
|
|
434
|
+
content: [
|
|
435
|
+
{
|
|
436
|
+
type: 'text',
|
|
437
|
+
text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2),
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
};
|
|
441
|
+
}
|
|
191
442
|
}
|
|
192
443
|
async handleMemoryCheckProtection(args) {
|
|
193
444
|
try {
|
|
@@ -36,6 +36,7 @@ const manifest = {
|
|
|
36
36
|
{ tool: t('memory_batch_write'), domain: DOMAIN, bind: b((h, a) => h.handleMemoryBatchWrite(a)) },
|
|
37
37
|
{ tool: t('memory_dump_region'), domain: DOMAIN, bind: b((h, a) => h.handleMemoryDumpRegion(a)) },
|
|
38
38
|
{ tool: t('memory_list_regions'), domain: DOMAIN, bind: b((h, a) => h.handleMemoryListRegions(a)) },
|
|
39
|
+
{ tool: t('memory_audit_export'), domain: DOMAIN, bind: b((h, a) => h.handleMemoryAuditExport(a)) },
|
|
39
40
|
{ tool: t('inject_dll'), domain: DOMAIN, bind: b((h, a) => h.handleInjectDll(a)) },
|
|
40
41
|
{ tool: t('module_inject_dll'), domain: DOMAIN, bind: b((h, a) => h.handleInjectDll(a)) },
|
|
41
42
|
{ tool: t('inject_shellcode'), domain: DOMAIN, bind: b((h, a) => h.handleInjectShellcode(a)) },
|
|
@@ -119,8 +119,7 @@ export class WorkflowHandlersApi extends WorkflowHandlersBase {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
var results = {};
|
|
122
|
-
|
|
123
|
-
var path = paths[i];
|
|
122
|
+
async function probePath(path) {
|
|
124
123
|
try {
|
|
125
124
|
var opts = {method: method, headers: headers};
|
|
126
125
|
if (bodyTemplate && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
|
|
@@ -137,11 +136,22 @@ export class WorkflowHandlersApi extends WorkflowHandlersBase {
|
|
|
137
136
|
snippet = '[HTML/XML response suppressed]';
|
|
138
137
|
}
|
|
139
138
|
}
|
|
140
|
-
|
|
139
|
+
return [path, {status: resp.status, contentType: ct.split(';')[0].trim(), snippet: snippet}];
|
|
141
140
|
} catch(e) {
|
|
142
|
-
|
|
141
|
+
return [path, {status: -1, error: e instanceof Error ? e.message : String(e)}];
|
|
143
142
|
}
|
|
144
143
|
}
|
|
144
|
+
|
|
145
|
+
var nextIndex = 0;
|
|
146
|
+
var maxConcurrency = Math.min(paths.length, 6);
|
|
147
|
+
await Promise.all(Array.from({ length: maxConcurrency }, async function() {
|
|
148
|
+
while (nextIndex < paths.length) {
|
|
149
|
+
var currentIndex = nextIndex++;
|
|
150
|
+
var currentPath = paths[currentIndex];
|
|
151
|
+
var entry = await probePath(currentPath);
|
|
152
|
+
results[entry[0]] = entry[1];
|
|
153
|
+
}
|
|
154
|
+
}));
|
|
145
155
|
return {probed: paths.length, method: method, baseUrl: baseUrl, results: results};
|
|
146
156
|
})()`;
|
|
147
157
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readdir, stat } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { fileURLToPath
|
|
2
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { logger } from '../../utils/logger.js';
|
|
5
5
|
function isDomainManifest(value) {
|
|
6
6
|
if (!value || typeof value !== 'object')
|
|
@@ -35,24 +35,29 @@ async function discoverManifestPaths() {
|
|
|
35
35
|
logger.error('[discovery] Cannot read domains directory:', err);
|
|
36
36
|
return [];
|
|
37
37
|
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
if (!entry.isDirectory())
|
|
41
|
-
continue;
|
|
38
|
+
const directories = entries.filter(e => e.isDirectory());
|
|
39
|
+
const resolved = await Promise.all(directories.map(async (entry) => {
|
|
42
40
|
for (const ext of ['manifest.js', 'manifest.ts']) {
|
|
43
41
|
const manifestPath = join(domainsDir, entry.name, ext);
|
|
44
42
|
try {
|
|
45
43
|
const s = await stat(manifestPath);
|
|
46
|
-
if (s.isFile())
|
|
47
|
-
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
44
|
+
if (s.isFile())
|
|
45
|
+
return manifestPath;
|
|
50
46
|
}
|
|
51
47
|
catch {
|
|
52
48
|
}
|
|
53
49
|
}
|
|
50
|
+
return null;
|
|
51
|
+
}));
|
|
52
|
+
return resolved.filter((value) => value !== null);
|
|
53
|
+
}
|
|
54
|
+
function toImportSpecifier(absPath) {
|
|
55
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
56
|
+
const relPath = relative(currentDir, absPath).split(sep).join('/');
|
|
57
|
+
if (relPath.startsWith('.')) {
|
|
58
|
+
return relPath;
|
|
54
59
|
}
|
|
55
|
-
return
|
|
60
|
+
return `./${relPath}`;
|
|
56
61
|
}
|
|
57
62
|
export async function discoverDomainManifests() {
|
|
58
63
|
const files = await discoverManifestPaths();
|
|
@@ -61,7 +66,7 @@ export async function discoverDomainManifests() {
|
|
|
61
66
|
const seenDepKeys = new Set();
|
|
62
67
|
for (const absPath of files) {
|
|
63
68
|
try {
|
|
64
|
-
const mod = await import(
|
|
69
|
+
const mod = await import(toImportSpecifier(absPath));
|
|
65
70
|
const manifest = extractManifest(mod);
|
|
66
71
|
if (!manifest) {
|
|
67
72
|
logger.warn('[discovery] Skipping ' + absPath + ': no valid DomainManifest export');
|
|
@@ -3,6 +3,8 @@ import { logger } from '../../utils/logger.js';
|
|
|
3
3
|
let _manifests = null;
|
|
4
4
|
let _registrations = null;
|
|
5
5
|
let _initPromise = null;
|
|
6
|
+
let _domainsView = null;
|
|
7
|
+
let _toolNamesView = null;
|
|
6
8
|
async function init() {
|
|
7
9
|
if (_manifests !== null)
|
|
8
10
|
return;
|
|
@@ -26,6 +28,8 @@ async function init() {
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
_registrations = [...uniqueByToolName.values()];
|
|
31
|
+
_domainsView = new Set(_manifests.map(m => m.domain));
|
|
32
|
+
_toolNamesView = new Set(_registrations.map(r => r.tool.name));
|
|
29
33
|
})();
|
|
30
34
|
await _initPromise;
|
|
31
35
|
}
|
|
@@ -49,10 +53,14 @@ export function getAllRegistrations() {
|
|
|
49
53
|
return getRegistrations();
|
|
50
54
|
}
|
|
51
55
|
export function getAllDomains() {
|
|
52
|
-
|
|
56
|
+
if (!_domainsView)
|
|
57
|
+
throw new Error('[registry] Not initialised - call initRegistry() first.');
|
|
58
|
+
return _domainsView;
|
|
53
59
|
}
|
|
54
60
|
export function getAllToolNames() {
|
|
55
|
-
|
|
61
|
+
if (!_toolNamesView)
|
|
62
|
+
throw new Error('[registry] Not initialised - call initRegistry() first.');
|
|
63
|
+
return _toolNamesView;
|
|
56
64
|
}
|
|
57
65
|
export function buildToolGroups() {
|
|
58
66
|
const groups = {};
|
|
@@ -45,6 +45,7 @@ export declare class TokenBudgetManager {
|
|
|
45
45
|
recordToolCall(toolName: string, request: unknown, response: unknown): void;
|
|
46
46
|
private isRecord;
|
|
47
47
|
private hasDetailedSummarySize;
|
|
48
|
+
private tryEstimateMcpEnvelope;
|
|
48
49
|
private calculateSize;
|
|
49
50
|
private normalizeForSizeEstimate;
|
|
50
51
|
private estimateTokens;
|
|
@@ -74,11 +74,33 @@ export class TokenBudgetManager {
|
|
|
74
74
|
const { size } = summary;
|
|
75
75
|
return typeof size === 'number' && Number.isFinite(size) && size > 0;
|
|
76
76
|
}
|
|
77
|
+
tryEstimateMcpEnvelope(data) {
|
|
78
|
+
if (!this.isRecord(data))
|
|
79
|
+
return null;
|
|
80
|
+
const content = data['content'];
|
|
81
|
+
if (!Array.isArray(content) || content.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
const first = content[0];
|
|
84
|
+
if (!this.isRecord(first))
|
|
85
|
+
return null;
|
|
86
|
+
if (first['type'] !== 'text' || typeof first['text'] !== 'string')
|
|
87
|
+
return null;
|
|
88
|
+
const text = first['text'];
|
|
89
|
+
const truncated = text.length > this.MAX_ESTIMATION_STRING_LENGTH
|
|
90
|
+
? `${text.slice(0, this.MAX_ESTIMATION_STRING_LENGTH)}...[truncated:${text.length}]`
|
|
91
|
+
: text;
|
|
92
|
+
const overhead = 42 + (data['isError'] === true ? 14 : 0);
|
|
93
|
+
const textBytes = Buffer.byteLength(truncated, 'utf8');
|
|
94
|
+
return Math.min(overhead + textBytes, this.MAX_ESTIMATION_BYTES);
|
|
95
|
+
}
|
|
77
96
|
calculateSize(data) {
|
|
78
97
|
try {
|
|
79
98
|
if (this.hasDetailedSummarySize(data)) {
|
|
80
99
|
return Math.min(data.summary.size, this.MAX_ESTIMATION_BYTES);
|
|
81
100
|
}
|
|
101
|
+
const mcpSize = this.tryEstimateMcpEnvelope(data);
|
|
102
|
+
if (mcpSize !== null)
|
|
103
|
+
return mcpSize;
|
|
82
104
|
const normalized = this.normalizeForSizeEstimate(data, 0, new WeakSet());
|
|
83
105
|
const serialized = JSON.stringify(normalized);
|
|
84
106
|
if (!serialized) {
|