micro-models-agent 0.39.0 → 0.40.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/bin/mma.mjs +41 -41
- package/dist/cli/commands.js +116 -3
- package/dist/cli/main.js +35 -8
- package/dist/cli/repl-commands.js +633 -0
- package/dist/cli/repl.js +110 -611
- package/dist/cli/setup.js +32 -12
- package/dist/config/config.js +46 -30
- package/dist/config/defaults.js +10 -1
- package/dist/config/security.js +15 -8
- package/dist/core/agent-moe.js +24 -12
- package/dist/core/agent.js +281 -47
- package/dist/core/bootstrap.js +52 -36
- package/dist/core/session-logger.js +35 -2
- package/dist/core/workspace.js +76 -0
- package/dist/i18n/en.json +79 -15
- package/dist/i18n/index.js +12 -9
- package/dist/i18n/ru.json +79 -15
- package/dist/index.js +13 -13
- package/dist/llm/openai-compat.js +39 -10
- package/dist/logger/app-logger.js +83 -16
- package/dist/logger/file-log.js +151 -0
- package/dist/main.js +537 -284
- package/dist/modules/browser/bridge-server.mjs +113 -105
- package/dist/modules/browser/session.js +108 -60
- package/dist/modules/certification/cli.js +176 -0
- package/dist/modules/certification/fact-checker.js +84 -0
- package/dist/modules/certification/loader.js +111 -0
- package/dist/modules/certification/manifest.js +50 -0
- package/dist/modules/certification/runner.js +162 -0
- package/dist/modules/certification/scenarios.js +124 -0
- package/dist/modules/certification/types.js +1 -0
- package/dist/modules/context/manager.js +119 -10
- package/dist/modules/execution/auditor.js +33 -39
- package/dist/modules/execution/index.js +8 -6
- package/dist/modules/execution/module.js +474 -32
- package/dist/modules/execution/moe-executor.js +97 -40
- package/dist/modules/execution/plan-coverage.js +68 -0
- package/dist/modules/execution/plan-persister.js +46 -0
- package/dist/modules/execution/plan-store.js +159 -0
- package/dist/modules/execution/planner.js +63 -13
- package/dist/modules/execution/stuck-detector.js +252 -39
- package/dist/modules/execution/tracker.js +21 -7
- package/dist/modules/execution/verifier.js +46 -17
- package/dist/modules/hallucination/confidence.js +7 -2
- package/dist/modules/hallucination/consistency.js +8 -42
- package/dist/modules/hallucination/detector.js +26 -21
- package/dist/modules/hallucination/factual.js +170 -150
- package/dist/modules/hallucination/index.js +5 -4
- package/dist/modules/hallucination/js-identifiers.js +72 -0
- package/dist/modules/hallucination/llm-judge.js +103 -0
- package/dist/modules/index.js +5 -5
- package/dist/modules/lsp/client.js +235 -0
- package/dist/modules/lsp/config.js +81 -0
- package/dist/modules/lsp/index.js +3 -0
- package/dist/modules/lsp/module.js +68 -0
- package/dist/modules/lsp/types.js +1 -0
- package/dist/modules/mcp/client.js +8 -2
- package/dist/modules/memory/store.js +4 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +143 -38
- package/dist/modules/processes/index.js +1 -2
- package/dist/modules/processes/registry.js +125 -35
- package/dist/modules/processes/runner.js +9 -110
- package/dist/modules/security/audit-log.js +30 -10
- package/dist/modules/security/command-validator.js +42 -16
- package/dist/modules/security/content-scanner.js +9 -8
- package/dist/modules/security/network-validator.js +2 -2
- package/dist/modules/security/path-validator.js +64 -10
- package/dist/modules/security/security-policies.js +221 -67
- package/dist/modules/security/session-encryption.js +42 -25
- package/dist/modules/session/manager.js +15 -10
- package/dist/modules/session/store.js +62 -8
- package/dist/modules/skills/index.js +2 -3
- package/dist/modules/skills/module.js +10 -23
- package/dist/tools/bash.js +287 -90
- package/dist/tools/create-dir.js +0 -1
- package/dist/tools/delete-file.js +0 -1
- package/dist/tools/edit-file.js +10 -8
- package/dist/tools/executor.js +57 -7
- package/dist/tools/grep-tool.js +51 -29
- package/dist/tools/index.js +55 -40
- package/dist/tools/load-skill.js +14 -18
- package/dist/tools/move-file.js +3 -2
- package/dist/tools/pipeline-run.js +1 -1
- package/dist/tools/read-file.js +15 -5
- package/dist/tools/search-history.js +42 -22
- package/dist/tools/subagent.js +21 -12
- package/dist/tools/web-browse.js +54 -25
- package/dist/tools/web-fetch.js +60 -34
- package/dist/tools/web-search.js +39 -20
- package/dist/tools/write-file.js +13 -10
- package/dist/ui/diff.js +9 -16
- package/dist/ui/renderer.js +69 -6
- package/package.json +48 -45
- package/dist/modules/context/history.js +0 -15
- package/dist/modules/processes/detect.js +0 -34
- package/dist/modules/skills/matcher.js +0 -27
|
@@ -1,46 +1,134 @@
|
|
|
1
|
-
import { mergeSecurityConfig } from
|
|
1
|
+
import { mergeSecurityConfig, } from "../../config/security";
|
|
2
2
|
/**
|
|
3
3
|
* Strict security policy - maximum security, minimum flexibility
|
|
4
4
|
* Recommended for: production environments, sensitive data, multi-user systems
|
|
5
5
|
*/
|
|
6
6
|
export const STRICT_POLICY = {
|
|
7
|
-
name:
|
|
8
|
-
description:
|
|
9
|
-
preset:
|
|
10
|
-
recommendedFor: [
|
|
7
|
+
name: "Strict",
|
|
8
|
+
description: "Maximum security with minimal flexibility. Blocks most dangerous operations.",
|
|
9
|
+
preset: "strict",
|
|
10
|
+
recommendedFor: ["production", "sensitive-data", "multi-user", "enterprise"],
|
|
11
11
|
config: {
|
|
12
|
+
enabled: true,
|
|
12
13
|
bash: {
|
|
14
|
+
enabled: true,
|
|
13
15
|
blacklist: [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
"rm",
|
|
17
|
+
"dd",
|
|
18
|
+
"chmod",
|
|
19
|
+
"wget",
|
|
20
|
+
"curl",
|
|
21
|
+
"scp",
|
|
22
|
+
"ssh",
|
|
23
|
+
"nc",
|
|
24
|
+
"netcat",
|
|
25
|
+
"mknod",
|
|
26
|
+
"mkfifo",
|
|
27
|
+
"ln",
|
|
28
|
+
"chown",
|
|
29
|
+
"chgrp",
|
|
30
|
+
"useradd",
|
|
31
|
+
"usermod",
|
|
32
|
+
"passwd",
|
|
33
|
+
"sudo",
|
|
34
|
+
"su",
|
|
35
|
+
"exec",
|
|
36
|
+
"eval",
|
|
37
|
+
"source",
|
|
38
|
+
"kill",
|
|
39
|
+
"pkill",
|
|
40
|
+
"killall",
|
|
41
|
+
"shutdown",
|
|
42
|
+
"reboot",
|
|
43
|
+
"halt",
|
|
44
|
+
"poweroff",
|
|
45
|
+
"format",
|
|
46
|
+
"fdisk",
|
|
47
|
+
"parted",
|
|
48
|
+
"mkfs",
|
|
49
|
+
"mount",
|
|
50
|
+
"umount",
|
|
51
|
+
"mv",
|
|
52
|
+
"cp",
|
|
19
53
|
],
|
|
20
|
-
whitelist: [
|
|
54
|
+
whitelist: ["ls", "cat", "echo", "grep", "find", "pwd", "whoami", "date"],
|
|
21
55
|
blockDangerousFlags: true,
|
|
22
56
|
dangerousFlags: [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
57
|
+
"--force",
|
|
58
|
+
"-rf",
|
|
59
|
+
"--no-preserve-root",
|
|
60
|
+
"--recursive",
|
|
61
|
+
"--all",
|
|
62
|
+
"-x",
|
|
63
|
+
"-e",
|
|
64
|
+
"--delete",
|
|
65
|
+
"--remove",
|
|
66
|
+
"--dangerous",
|
|
67
|
+
"--yes",
|
|
68
|
+
"-y",
|
|
69
|
+
"--no-confirm",
|
|
70
|
+
"-R",
|
|
71
|
+
"--no-clobber",
|
|
72
|
+
],
|
|
73
|
+
dangerousOperators: [
|
|
74
|
+
">",
|
|
75
|
+
">>",
|
|
76
|
+
"2>",
|
|
77
|
+
"2>>",
|
|
78
|
+
"|",
|
|
79
|
+
"&&",
|
|
80
|
+
"||",
|
|
81
|
+
";",
|
|
82
|
+
"&",
|
|
83
|
+
"`",
|
|
26
84
|
],
|
|
27
|
-
dangerousOperators: ['>', '>>', '2>', '2>>', '|', '&&', '||', ';', '&', '`'],
|
|
28
85
|
logCommands: true,
|
|
29
86
|
},
|
|
30
87
|
paths: {
|
|
88
|
+
enabled: true,
|
|
31
89
|
denied: [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
90
|
+
".git/",
|
|
91
|
+
"node_modules/",
|
|
92
|
+
".env",
|
|
93
|
+
"*.key",
|
|
94
|
+
"*.pem",
|
|
95
|
+
"*.crt",
|
|
96
|
+
"*.p12",
|
|
97
|
+
"*.pfx",
|
|
98
|
+
"*.secret",
|
|
99
|
+
"*.token",
|
|
100
|
+
"package-lock.json",
|
|
101
|
+
"bun.lock",
|
|
102
|
+
"yarn.lock",
|
|
103
|
+
"pnpm-lock.yaml",
|
|
104
|
+
".ssh/",
|
|
105
|
+
".config/",
|
|
106
|
+
".bashrc",
|
|
107
|
+
".bash_profile",
|
|
108
|
+
".zshrc",
|
|
109
|
+
".profile",
|
|
110
|
+
"/etc/",
|
|
111
|
+
"/usr/",
|
|
112
|
+
"/var/",
|
|
113
|
+
"/bin/",
|
|
114
|
+
"/sbin/",
|
|
115
|
+
"/root/",
|
|
116
|
+
"/home/",
|
|
37
117
|
],
|
|
38
118
|
allowed: [],
|
|
39
119
|
},
|
|
40
120
|
network: {
|
|
121
|
+
enabled: true,
|
|
41
122
|
deniedDomains: [
|
|
42
|
-
|
|
43
|
-
|
|
123
|
+
"localhost",
|
|
124
|
+
"127.0.0.1",
|
|
125
|
+
"0.0.0.0",
|
|
126
|
+
"::1",
|
|
127
|
+
"*.internal",
|
|
128
|
+
"*.local",
|
|
129
|
+
"192.168.*",
|
|
130
|
+
"10.*",
|
|
131
|
+
"172.16.*",
|
|
44
132
|
],
|
|
45
133
|
allowedDomains: [],
|
|
46
134
|
requestTimeout: 10000,
|
|
@@ -81,11 +169,16 @@ export const STRICT_POLICY = {
|
|
|
81
169
|
},
|
|
82
170
|
auditNotifier: {
|
|
83
171
|
enabled: true,
|
|
84
|
-
minSeverity:
|
|
172
|
+
minSeverity: "low",
|
|
85
173
|
eventTypes: [
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
174
|
+
"security_block",
|
|
175
|
+
"bash_command",
|
|
176
|
+
"file_operation",
|
|
177
|
+
"network_request",
|
|
178
|
+
"authentication",
|
|
179
|
+
"configuration_change",
|
|
180
|
+
"session_start",
|
|
181
|
+
"session_end",
|
|
89
182
|
],
|
|
90
183
|
maxRetries: 3,
|
|
91
184
|
},
|
|
@@ -96,37 +189,81 @@ export const STRICT_POLICY = {
|
|
|
96
189
|
* Recommended for: development, single-user systems, general use
|
|
97
190
|
*/
|
|
98
191
|
export const BALANCED_POLICY = {
|
|
99
|
-
name:
|
|
100
|
-
description:
|
|
101
|
-
preset:
|
|
102
|
-
recommendedFor: [
|
|
192
|
+
name: "Balanced",
|
|
193
|
+
description: "Good security with reasonable flexibility. Default policy.",
|
|
194
|
+
preset: "balanced",
|
|
195
|
+
recommendedFor: ["development", "single-user", "general-use", "testing"],
|
|
103
196
|
config: {
|
|
197
|
+
enabled: true,
|
|
104
198
|
bash: {
|
|
199
|
+
enabled: true,
|
|
105
200
|
blacklist: [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
201
|
+
"rm",
|
|
202
|
+
"dd",
|
|
203
|
+
"chmod",
|
|
204
|
+
"wget",
|
|
205
|
+
"curl",
|
|
206
|
+
"scp",
|
|
207
|
+
"ssh",
|
|
208
|
+
"nc",
|
|
209
|
+
"netcat",
|
|
210
|
+
"mknod",
|
|
211
|
+
"mkfifo",
|
|
212
|
+
"useradd",
|
|
213
|
+
"usermod",
|
|
214
|
+
"passwd",
|
|
215
|
+
"sudo",
|
|
216
|
+
"su",
|
|
217
|
+
"shutdown",
|
|
218
|
+
"reboot",
|
|
219
|
+
"halt",
|
|
220
|
+
"poweroff",
|
|
221
|
+
"format",
|
|
222
|
+
"fdisk",
|
|
223
|
+
"parted",
|
|
224
|
+
"mkfs",
|
|
110
225
|
],
|
|
111
226
|
whitelist: [],
|
|
112
227
|
blockDangerousFlags: true,
|
|
113
228
|
dangerousFlags: [
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
229
|
+
"--force",
|
|
230
|
+
"-rf",
|
|
231
|
+
"--no-preserve-root",
|
|
232
|
+
"--recursive",
|
|
233
|
+
"--all",
|
|
234
|
+
"--delete",
|
|
235
|
+
"--remove",
|
|
236
|
+
"--dangerous",
|
|
237
|
+
"--yes",
|
|
238
|
+
"-y",
|
|
239
|
+
"--no-confirm",
|
|
117
240
|
],
|
|
118
|
-
dangerousOperators: [
|
|
241
|
+
dangerousOperators: ["|", "&&", "||", ";", "&", "`"],
|
|
119
242
|
logCommands: true,
|
|
120
243
|
},
|
|
121
244
|
paths: {
|
|
245
|
+
enabled: true,
|
|
122
246
|
denied: [
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
247
|
+
".git/",
|
|
248
|
+
"node_modules/",
|
|
249
|
+
".env",
|
|
250
|
+
"*.key",
|
|
251
|
+
"*.pem",
|
|
252
|
+
"*.crt",
|
|
253
|
+
"*.p12",
|
|
254
|
+
"*.pfx",
|
|
255
|
+
"*.secret",
|
|
256
|
+
"*.token",
|
|
257
|
+
"package-lock.json",
|
|
258
|
+
"bun.lock",
|
|
259
|
+
"yarn.lock",
|
|
260
|
+
"pnpm-lock.yaml",
|
|
261
|
+
".ssh/",
|
|
126
262
|
],
|
|
127
263
|
allowed: [],
|
|
128
264
|
},
|
|
129
265
|
network: {
|
|
266
|
+
enabled: true,
|
|
130
267
|
deniedDomains: [],
|
|
131
268
|
allowedDomains: [],
|
|
132
269
|
requestTimeout: 15000,
|
|
@@ -161,8 +298,13 @@ export const BALANCED_POLICY = {
|
|
|
161
298
|
},
|
|
162
299
|
auditNotifier: {
|
|
163
300
|
enabled: false,
|
|
164
|
-
minSeverity:
|
|
165
|
-
eventTypes: [
|
|
301
|
+
minSeverity: "medium",
|
|
302
|
+
eventTypes: [
|
|
303
|
+
"security_block",
|
|
304
|
+
"bash_command",
|
|
305
|
+
"file_operation",
|
|
306
|
+
"network_request",
|
|
307
|
+
],
|
|
166
308
|
maxRetries: 3,
|
|
167
309
|
},
|
|
168
310
|
},
|
|
@@ -172,27 +314,39 @@ export const BALANCED_POLICY = {
|
|
|
172
314
|
* Recommended for: trusted environments, local development, testing
|
|
173
315
|
*/
|
|
174
316
|
export const PERMISSIVE_POLICY = {
|
|
175
|
-
name:
|
|
176
|
-
description:
|
|
177
|
-
preset:
|
|
178
|
-
recommendedFor: [
|
|
317
|
+
name: "Permissive",
|
|
318
|
+
description: "Minimal security with maximum flexibility. Use with caution.",
|
|
319
|
+
preset: "permissive",
|
|
320
|
+
recommendedFor: ["trusted-environment", "local-dev", "testing", "sandbox"],
|
|
179
321
|
config: {
|
|
322
|
+
enabled: true,
|
|
180
323
|
bash: {
|
|
324
|
+
enabled: true,
|
|
181
325
|
blacklist: [
|
|
182
|
-
|
|
183
|
-
|
|
326
|
+
"rm",
|
|
327
|
+
"dd",
|
|
328
|
+
"shutdown",
|
|
329
|
+
"reboot",
|
|
330
|
+
"halt",
|
|
331
|
+
"poweroff",
|
|
332
|
+
"format",
|
|
333
|
+
"fdisk",
|
|
334
|
+
"parted",
|
|
335
|
+
"mkfs",
|
|
184
336
|
],
|
|
185
337
|
whitelist: [],
|
|
186
338
|
blockDangerousFlags: false,
|
|
187
|
-
dangerousFlags: [
|
|
339
|
+
dangerousFlags: ["--force", "-rf", "--no-preserve-root"],
|
|
188
340
|
dangerousOperators: [],
|
|
189
341
|
logCommands: true,
|
|
190
342
|
},
|
|
191
343
|
paths: {
|
|
192
|
-
|
|
344
|
+
enabled: true,
|
|
345
|
+
denied: [".env", "*.key", "*.pem", "*.crt", "*.p12", "*.pfx"],
|
|
193
346
|
allowed: [],
|
|
194
347
|
},
|
|
195
348
|
network: {
|
|
349
|
+
enabled: true,
|
|
196
350
|
deniedDomains: [],
|
|
197
351
|
allowedDomains: [],
|
|
198
352
|
requestTimeout: 30000,
|
|
@@ -222,8 +376,8 @@ export const PERMISSIVE_POLICY = {
|
|
|
222
376
|
},
|
|
223
377
|
auditNotifier: {
|
|
224
378
|
enabled: false,
|
|
225
|
-
minSeverity:
|
|
226
|
-
eventTypes: [
|
|
379
|
+
minSeverity: "high",
|
|
380
|
+
eventTypes: ["security_block"],
|
|
227
381
|
maxRetries: 2,
|
|
228
382
|
},
|
|
229
383
|
},
|
|
@@ -236,9 +390,9 @@ export const SECURITY_POLICIES = {
|
|
|
236
390
|
balanced: BALANCED_POLICY,
|
|
237
391
|
permissive: PERMISSIVE_POLICY,
|
|
238
392
|
custom: {
|
|
239
|
-
name:
|
|
240
|
-
description:
|
|
241
|
-
preset:
|
|
393
|
+
name: "Custom",
|
|
394
|
+
description: "Custom security configuration",
|
|
395
|
+
preset: "custom",
|
|
242
396
|
recommendedFor: [],
|
|
243
397
|
config: {},
|
|
244
398
|
},
|
|
@@ -247,7 +401,7 @@ export const SECURITY_POLICIES = {
|
|
|
247
401
|
* Security policy manager
|
|
248
402
|
*/
|
|
249
403
|
export class SecurityPolicyManager {
|
|
250
|
-
currentPolicy =
|
|
404
|
+
currentPolicy = "balanced";
|
|
251
405
|
customConfig = {};
|
|
252
406
|
/**
|
|
253
407
|
* Get all available policies
|
|
@@ -265,7 +419,7 @@ export class SecurityPolicyManager {
|
|
|
265
419
|
* Get the current policy
|
|
266
420
|
*/
|
|
267
421
|
getCurrentPolicy() {
|
|
268
|
-
if (this.currentPolicy ===
|
|
422
|
+
if (this.currentPolicy === "custom") {
|
|
269
423
|
return {
|
|
270
424
|
...SECURITY_POLICIES.custom,
|
|
271
425
|
config: this.customConfig,
|
|
@@ -284,7 +438,7 @@ export class SecurityPolicyManager {
|
|
|
284
438
|
*/
|
|
285
439
|
setCustomConfig(config) {
|
|
286
440
|
this.customConfig = config;
|
|
287
|
-
this.currentPolicy =
|
|
441
|
+
this.currentPolicy = "custom";
|
|
288
442
|
}
|
|
289
443
|
/**
|
|
290
444
|
* Get the current security configuration
|
|
@@ -293,7 +447,7 @@ export class SecurityPolicyManager {
|
|
|
293
447
|
const policy = this.getCurrentPolicy();
|
|
294
448
|
return mergeSecurityConfig({
|
|
295
449
|
...policy.config,
|
|
296
|
-
...(this.currentPolicy ===
|
|
450
|
+
...(this.currentPolicy === "custom" ? this.customConfig : {}),
|
|
297
451
|
});
|
|
298
452
|
}
|
|
299
453
|
/**
|
|
@@ -303,7 +457,7 @@ export class SecurityPolicyManager {
|
|
|
303
457
|
this.setPolicy(preset);
|
|
304
458
|
if (customOverrides) {
|
|
305
459
|
this.customConfig = customOverrides;
|
|
306
|
-
this.currentPolicy =
|
|
460
|
+
this.currentPolicy = "custom";
|
|
307
461
|
}
|
|
308
462
|
return this.getConfig();
|
|
309
463
|
}
|
|
@@ -324,25 +478,25 @@ export class SecurityPolicyManager {
|
|
|
324
478
|
allowsAction(action, context) {
|
|
325
479
|
const config = this.getConfig();
|
|
326
480
|
switch (action) {
|
|
327
|
-
case
|
|
481
|
+
case "bash":
|
|
328
482
|
if (context?.command) {
|
|
329
|
-
const cmd = context.command.split(
|
|
483
|
+
const cmd = context.command.split(" ")[0];
|
|
330
484
|
return !config.bash.blacklist.includes(cmd);
|
|
331
485
|
}
|
|
332
486
|
return true;
|
|
333
|
-
case
|
|
487
|
+
case "file_access":
|
|
334
488
|
if (context?.path) {
|
|
335
489
|
for (const denied of config.paths.denied) {
|
|
336
|
-
if (context.path.includes(denied.replace(
|
|
490
|
+
if (context.path.includes(denied.replace("*", ""))) {
|
|
337
491
|
return false;
|
|
338
492
|
}
|
|
339
493
|
}
|
|
340
494
|
}
|
|
341
495
|
return true;
|
|
342
|
-
case
|
|
496
|
+
case "network":
|
|
343
497
|
if (context?.path) {
|
|
344
498
|
for (const denied of config.network.deniedDomains) {
|
|
345
|
-
if (context.path.includes(denied.replace(
|
|
499
|
+
if (context.path.includes(denied.replace("*", ""))) {
|
|
346
500
|
return false;
|
|
347
501
|
}
|
|
348
502
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync, readdirSync, unlinkSync } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import { homedir } from
|
|
4
|
-
import { encryptString, decryptString, isEncryptedString, ConfigEncryptor, } from
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, unlinkSync, } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { encryptString, decryptString, isEncryptedString, ConfigEncryptor, } from "./encryption";
|
|
5
5
|
/**
|
|
6
6
|
* Default session encryption configuration
|
|
7
7
|
*/
|
|
@@ -19,7 +19,7 @@ export class SessionFileEncryptor {
|
|
|
19
19
|
constructor(config) {
|
|
20
20
|
this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
|
|
21
21
|
this.encryptor = new ConfigEncryptor({
|
|
22
|
-
keyPath: config?.keyPath || join(homedir(),
|
|
22
|
+
keyPath: config?.keyPath || join(homedir(), ".mma", ".session-encryption-key"),
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
@@ -58,10 +58,16 @@ export class SessionFileEncryptor {
|
|
|
58
58
|
* Decrypt a JSON string
|
|
59
59
|
*/
|
|
60
60
|
decryptJSON(content) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
let plain = content;
|
|
62
|
+
if (this.config.enabled) {
|
|
63
|
+
plain = this.decryptFileContent(content);
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(plain);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error("Invalid JSON content in session file — file may be corrupted or encrypted with a different key");
|
|
70
|
+
}
|
|
65
71
|
}
|
|
66
72
|
/**
|
|
67
73
|
* Encrypt a JSONL file (one JSON object per line)
|
|
@@ -69,7 +75,7 @@ export class SessionFileEncryptor {
|
|
|
69
75
|
encryptJSONL(lines) {
|
|
70
76
|
if (!this.config.enabled)
|
|
71
77
|
return lines;
|
|
72
|
-
return lines.map(line => this.encryptFileContent(line));
|
|
78
|
+
return lines.map((line) => this.encryptFileContent(line));
|
|
73
79
|
}
|
|
74
80
|
/**
|
|
75
81
|
* Decrypt a JSONL file
|
|
@@ -77,13 +83,13 @@ export class SessionFileEncryptor {
|
|
|
77
83
|
decryptJSONL(lines) {
|
|
78
84
|
if (!this.config.enabled)
|
|
79
85
|
return lines;
|
|
80
|
-
return lines.map(line => this.decryptFileContent(line));
|
|
86
|
+
return lines.map((line) => this.decryptFileContent(line));
|
|
81
87
|
}
|
|
82
88
|
/**
|
|
83
89
|
* Read and decrypt a session file
|
|
84
90
|
*/
|
|
85
91
|
readSessionFile(filePath) {
|
|
86
|
-
const content = readFileSync(filePath,
|
|
92
|
+
const content = readFileSync(filePath, "utf8");
|
|
87
93
|
return this.decryptFileContent(content);
|
|
88
94
|
}
|
|
89
95
|
/**
|
|
@@ -91,13 +97,13 @@ export class SessionFileEncryptor {
|
|
|
91
97
|
*/
|
|
92
98
|
writeSessionFile(filePath, content) {
|
|
93
99
|
const encrypted = this.encryptFileContent(content);
|
|
94
|
-
writeFileSync(filePath, encrypted,
|
|
100
|
+
writeFileSync(filePath, encrypted, "utf8");
|
|
95
101
|
}
|
|
96
102
|
/**
|
|
97
103
|
* Read and decrypt a JSON session file
|
|
98
104
|
*/
|
|
99
105
|
readSessionJSON(filePath) {
|
|
100
|
-
const content = readFileSync(filePath,
|
|
106
|
+
const content = readFileSync(filePath, "utf8");
|
|
101
107
|
return this.decryptJSON(content);
|
|
102
108
|
}
|
|
103
109
|
/**
|
|
@@ -105,23 +111,34 @@ export class SessionFileEncryptor {
|
|
|
105
111
|
*/
|
|
106
112
|
writeSessionJSON(filePath, obj) {
|
|
107
113
|
const content = this.encryptJSON(obj);
|
|
108
|
-
writeFileSync(filePath, content,
|
|
114
|
+
writeFileSync(filePath, content, "utf8");
|
|
109
115
|
}
|
|
110
116
|
/**
|
|
111
117
|
* Read and decrypt a JSONL session file
|
|
112
118
|
*/
|
|
113
119
|
readSessionJSONL(filePath) {
|
|
114
|
-
const content = readFileSync(filePath,
|
|
115
|
-
const lines = content.split(
|
|
120
|
+
const content = readFileSync(filePath, "utf8");
|
|
121
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
116
122
|
const decryptedLines = this.decryptJSONL(lines);
|
|
117
|
-
|
|
123
|
+
// Skip malformed lines instead of crashing the whole session log
|
|
124
|
+
return decryptedLines.flatMap((line) => {
|
|
125
|
+
try {
|
|
126
|
+
return [JSON.parse(line)];
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
118
132
|
}
|
|
119
133
|
/**
|
|
120
134
|
* Append an encrypted entry to a JSONL file
|
|
121
135
|
*/
|
|
122
136
|
appendToSessionJSONL(filePath, obj) {
|
|
123
137
|
const encryptedLine = this.encryptFileContent(JSON.stringify(obj));
|
|
124
|
-
writeFileSync(filePath, encryptedLine +
|
|
138
|
+
writeFileSync(filePath, encryptedLine + "\n", {
|
|
139
|
+
flag: "a",
|
|
140
|
+
encoding: "utf8",
|
|
141
|
+
});
|
|
125
142
|
}
|
|
126
143
|
/**
|
|
127
144
|
* Encrypt all session files in a directory
|
|
@@ -132,11 +149,11 @@ export class SessionFileEncryptor {
|
|
|
132
149
|
const files = readdirSync(sessionDir);
|
|
133
150
|
for (const file of files) {
|
|
134
151
|
const filePath = join(sessionDir, file);
|
|
135
|
-
if (existsSync(filePath) && !file.endsWith(
|
|
152
|
+
if (existsSync(filePath) && !file.endsWith(".enc")) {
|
|
136
153
|
try {
|
|
137
|
-
const content = readFileSync(filePath,
|
|
154
|
+
const content = readFileSync(filePath, "utf8");
|
|
138
155
|
const encrypted = this.encryptFileContent(content);
|
|
139
|
-
writeFileSync(filePath +
|
|
156
|
+
writeFileSync(filePath + ".enc", encrypted, "utf8");
|
|
140
157
|
unlinkSync(filePath);
|
|
141
158
|
}
|
|
142
159
|
catch {
|
|
@@ -153,13 +170,13 @@ export class SessionFileEncryptor {
|
|
|
153
170
|
return;
|
|
154
171
|
const files = readdirSync(sessionDir);
|
|
155
172
|
for (const file of files) {
|
|
156
|
-
if (file.endsWith(
|
|
173
|
+
if (file.endsWith(".enc")) {
|
|
157
174
|
const encFilePath = join(sessionDir, file);
|
|
158
175
|
const decFilePath = encFilePath.slice(0, -4); // Remove .enc
|
|
159
176
|
try {
|
|
160
|
-
const content = readFileSync(encFilePath,
|
|
177
|
+
const content = readFileSync(encFilePath, "utf8");
|
|
161
178
|
const decrypted = this.decryptFileContent(content);
|
|
162
|
-
writeFileSync(decFilePath, decrypted,
|
|
179
|
+
writeFileSync(decFilePath, decrypted, "utf8");
|
|
163
180
|
unlinkSync(encFilePath);
|
|
164
181
|
}
|
|
165
182
|
catch {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t } from
|
|
2
|
-
import { createSessionContext, DEFAULT_SESSION_ISOLATION } from
|
|
1
|
+
import { t } from "../../i18n/index";
|
|
2
|
+
import { createSessionContext, DEFAULT_SESSION_ISOLATION, } from "../../modules/security/session-isolation";
|
|
3
3
|
export class SessionManager {
|
|
4
4
|
store;
|
|
5
5
|
activeId = null;
|
|
@@ -32,7 +32,7 @@ export class SessionManager {
|
|
|
32
32
|
create(name, securityOverrides) {
|
|
33
33
|
const now = new Date().toISOString();
|
|
34
34
|
const id = `ses_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
35
|
-
const sessionName = name || t(
|
|
35
|
+
const sessionName = name || t("session.default_name", { date: now.slice(0, 10) });
|
|
36
36
|
const meta = {
|
|
37
37
|
id,
|
|
38
38
|
name: sessionName,
|
|
@@ -73,7 +73,7 @@ export class SessionManager {
|
|
|
73
73
|
rename(id, name) {
|
|
74
74
|
const meta = this.store.loadMeta(id);
|
|
75
75
|
if (!meta)
|
|
76
|
-
throw new Error(t(
|
|
76
|
+
throw new Error(t("session.not_found", { id }));
|
|
77
77
|
meta.name = name;
|
|
78
78
|
this.store.saveMeta(id, meta);
|
|
79
79
|
}
|
|
@@ -87,13 +87,13 @@ export class SessionManager {
|
|
|
87
87
|
}
|
|
88
88
|
setActive(id) {
|
|
89
89
|
if (!this.store.sessionExists(id)) {
|
|
90
|
-
throw new Error(t(
|
|
90
|
+
throw new Error(t("session.not_found", { id }));
|
|
91
91
|
}
|
|
92
92
|
this.activeId = id;
|
|
93
93
|
}
|
|
94
94
|
appendMessage(msg) {
|
|
95
95
|
if (!this.activeId)
|
|
96
|
-
throw new Error(t(
|
|
96
|
+
throw new Error(t("session.no_active"));
|
|
97
97
|
this.store.appendMessage(this.activeId, msg);
|
|
98
98
|
}
|
|
99
99
|
appendLog(entry) {
|
|
@@ -117,6 +117,9 @@ export class SessionManager {
|
|
|
117
117
|
/**
|
|
118
118
|
* Get the session context for a specific session
|
|
119
119
|
*/
|
|
120
|
+
getSessionDirectory(id) {
|
|
121
|
+
return this.store.getSessionDir(id);
|
|
122
|
+
}
|
|
120
123
|
getSessionContextById(sessionId) {
|
|
121
124
|
if (!this.sessionContexts.has(sessionId)) {
|
|
122
125
|
const meta = this.store.loadMeta(sessionId);
|
|
@@ -148,10 +151,12 @@ export class SessionManager {
|
|
|
148
151
|
return {
|
|
149
152
|
maxFileOperations: overrides.maxFileOperations,
|
|
150
153
|
maxRecursionDepth: overrides.maxRecursionDepth,
|
|
151
|
-
rateLimits: overrides.rateLimits
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
rateLimits: overrides.rateLimits
|
|
155
|
+
? {
|
|
156
|
+
maxRequestsPerMinute: overrides.rateLimits.maxRequestsPerMinute ?? 60,
|
|
157
|
+
maxParallelTasks: overrides.rateLimits.maxParallelTasks ?? 5,
|
|
158
|
+
}
|
|
159
|
+
: undefined,
|
|
155
160
|
};
|
|
156
161
|
}
|
|
157
162
|
enforceMaxSessions() {
|