micro-models-agent 0.16.3 → 0.16.5
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/dist/cli/repl.js
CHANGED
|
@@ -753,6 +753,19 @@ export class Repl {
|
|
|
753
753
|
}
|
|
754
754
|
});
|
|
755
755
|
}
|
|
756
|
+
// SIGINT: first Ctrl+C sends graceful shutdown, second forces exit
|
|
757
|
+
process.on("SIGINT", () => {
|
|
758
|
+
if (this.agentRunning) {
|
|
759
|
+
console.log(pc.yellow("\n[Ctrl+C] Остановка агента... (ещё раз — принудительно)"));
|
|
760
|
+
this.agent.shutdown();
|
|
761
|
+
this.agentRunning = false;
|
|
762
|
+
// Force exit after 2s if graceful shutdown hangs
|
|
763
|
+
setTimeout(() => process.exit(1), 2000).unref();
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
process.exit(0);
|
|
767
|
+
}
|
|
768
|
+
});
|
|
756
769
|
}
|
|
757
770
|
isMultiLineInput(line) {
|
|
758
771
|
if (line.endsWith("\\"))
|
package/dist/config/config.js
CHANGED
|
@@ -7,13 +7,6 @@ import { MigrationDetector } from '../migration/detect';
|
|
|
7
7
|
import { BackupManager } from '../migration/backup';
|
|
8
8
|
import { validateExpertConfig } from './experts';
|
|
9
9
|
import { ConfigEncryptor } from '../modules/security/encryption';
|
|
10
|
-
/**
|
|
11
|
-
* When the user's config version is older than this, force-overwrite
|
|
12
|
-
* the security bash settings with the current defaults.
|
|
13
|
-
* This ensures critical security changes (like operator allowlists)
|
|
14
|
-
* are applied even if the user has a saved config.
|
|
15
|
-
*/
|
|
16
|
-
const FORCE_SECURITY_UPDATE_VERSION = '2.1.0';
|
|
17
10
|
/**
|
|
18
11
|
* Restore RegExp instances in dangerousPatterns that were serialized as {}
|
|
19
12
|
* (pre-0.8.0 configs) or as {__regex, source, flags} (new format).
|
|
@@ -122,42 +115,6 @@ function applyEnvVars(config) {
|
|
|
122
115
|
result.moe = { ...result.moe, enabled: env.MMA_MOE_ENABLED === 'true' };
|
|
123
116
|
return result;
|
|
124
117
|
}
|
|
125
|
-
/**
|
|
126
|
-
* Force-update security settings when upgrading from an older version.
|
|
127
|
-
* This overrides user config for critical security fields that must
|
|
128
|
-
* match the current code defaults (e.g. dangerousOperators).
|
|
129
|
-
*/
|
|
130
|
-
function forceSecurityUpdate(config) {
|
|
131
|
-
const userVersion = config.version || '0.0.0';
|
|
132
|
-
if (userVersion >= FORCE_SECURITY_UPDATE_VERSION)
|
|
133
|
-
return config;
|
|
134
|
-
// Force-overwrite bash security with current defaults
|
|
135
|
-
const security = config.security || {};
|
|
136
|
-
const userBash = security.bash || {};
|
|
137
|
-
security.bash = {
|
|
138
|
-
...DEFAULT_SECURITY_CONFIG.bash,
|
|
139
|
-
// Keep user's custom blacklist additions, but ensure defaults are present
|
|
140
|
-
blacklist: [...new Set([
|
|
141
|
-
...DEFAULT_SECURITY_CONFIG.bash.blacklist,
|
|
142
|
-
...(userBash.blacklist || []),
|
|
143
|
-
])],
|
|
144
|
-
whitelist: userBash.whitelist || DEFAULT_SECURITY_CONFIG.bash.whitelist,
|
|
145
|
-
dangerousFlags: [...new Set([
|
|
146
|
-
...DEFAULT_SECURITY_CONFIG.bash.dangerousFlags,
|
|
147
|
-
...(userBash.dangerousFlags || []),
|
|
148
|
-
])],
|
|
149
|
-
// dangerousOperators: merge user's additions with defaults (user can add but not remove critical ones)
|
|
150
|
-
dangerousOperators: [...new Set([
|
|
151
|
-
...DEFAULT_SECURITY_CONFIG.bash.dangerousOperators,
|
|
152
|
-
...(userBash.dangerousOperators || []),
|
|
153
|
-
])],
|
|
154
|
-
blockDangerousFlags: DEFAULT_SECURITY_CONFIG.bash.blockDangerousFlags,
|
|
155
|
-
logCommands: DEFAULT_SECURITY_CONFIG.bash.logCommands,
|
|
156
|
-
};
|
|
157
|
-
config.security = security;
|
|
158
|
-
console.log(t('migration.security_updated', { from: userVersion, to: FORCE_SECURITY_UPDATE_VERSION }));
|
|
159
|
-
return config;
|
|
160
|
-
}
|
|
161
118
|
export function loadConfig(options) {
|
|
162
119
|
const globalPath = join(options.configDir, 'config.json');
|
|
163
120
|
mkdirSync(options.configDir, { recursive: true });
|
|
@@ -189,8 +146,6 @@ export function loadConfig(options) {
|
|
|
189
146
|
if (config.security?.contentScan?.dangerousPatterns) {
|
|
190
147
|
config.security.contentScan.dangerousPatterns = restoreDangerousPatterns(config.security.contentScan.dangerousPatterns, DEFAULT_SECURITY_CONFIG.contentScan.dangerousPatterns);
|
|
191
148
|
}
|
|
192
|
-
// Force-update security settings when upgrading from older version
|
|
193
|
-
config = forceSecurityUpdate(config);
|
|
194
149
|
config = applyEnvVars(config);
|
|
195
150
|
// Decrypt sensitive fields in the loaded config
|
|
196
151
|
try {
|
package/dist/config/security.js
CHANGED
package/dist/core/agent.js
CHANGED
|
@@ -9,6 +9,7 @@ const TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000;
|
|
|
9
9
|
export class Agent {
|
|
10
10
|
deps;
|
|
11
11
|
systemPromptAdded = false;
|
|
12
|
+
shutdownRequested = false;
|
|
12
13
|
constructor(deps) {
|
|
13
14
|
this.deps = deps;
|
|
14
15
|
}
|
|
@@ -115,7 +116,7 @@ export class Agent {
|
|
|
115
116
|
const MAX_HALLUCINATION_RETRIES = 3;
|
|
116
117
|
let consecutiveToolFailures = 0;
|
|
117
118
|
const MAX_CONSECUTIVE_TOOL_FAILURES = 5;
|
|
118
|
-
while (iteration < config.maxToolIterations) {
|
|
119
|
+
while (iteration < config.maxToolIterations && !this.shutdownRequested) {
|
|
119
120
|
iteration++;
|
|
120
121
|
pluginManager.runOnBeforeThink({
|
|
121
122
|
iteration,
|
|
@@ -445,6 +446,7 @@ export class Agent {
|
|
|
445
446
|
}
|
|
446
447
|
}
|
|
447
448
|
shutdown() {
|
|
449
|
+
this.shutdownRequested = true;
|
|
448
450
|
const { pluginManager, logger, sessionManager, contextManager } = this.deps;
|
|
449
451
|
contextManager.onCompact = null;
|
|
450
452
|
const killed = processRegistry.killAll();
|
package/dist/i18n/en.json
CHANGED
|
@@ -419,7 +419,6 @@
|
|
|
419
419
|
"migration.dir_bak": "- .mma/ \u2192 .mma.bak/ ({count} files)",
|
|
420
420
|
"migration.migrated": "Migrated:",
|
|
421
421
|
"migration.not_needed": "No migration needed",
|
|
422
|
-
"migration.security_updated": "[MMA] Security config force-updated from v{from} to v{to} (dangerous operators reset to defaults)",
|
|
423
422
|
"ui.error_prefix": "Error: ",
|
|
424
423
|
"ui.success_prefix": "\u2713 ",
|
|
425
424
|
"ui.warning_prefix": "\u26a0 ",
|
package/dist/i18n/ru.json
CHANGED
|
@@ -419,7 +419,6 @@
|
|
|
419
419
|
"migration.dir_bak": "- .mma/ → .mma.bak/ ({count} файлов)",
|
|
420
420
|
"migration.migrated": "Мигрировано:",
|
|
421
421
|
"migration.not_needed": "Миграция не требуется",
|
|
422
|
-
"migration.security_updated": "[MMA] Конфигурация безопасности принудительно обновлена с v{from} до v{to} (опасные операторы сброшены)",
|
|
423
422
|
"ui.error_prefix": "Ошибка: ",
|
|
424
423
|
"ui.success_prefix": "✓ ",
|
|
425
424
|
"ui.warning_prefix": "⚠ ",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_SECURITY_CONFIG } from "../../config/security";
|
|
2
2
|
// Fallback in case DEFAULT_SECURITY_CONFIG is not available
|
|
3
3
|
const FALLBACK_BASH_CONFIG = {
|
|
4
|
-
blacklist: ['rm', 'dd', 'chmod', 'wget', 'curl', 'scp', 'ssh', 'nc', 'netcat'],
|
|
4
|
+
blacklist: ['rm', 'dd', 'chmod', 'wget', 'curl', 'scp', 'ssh', 'nc', 'netcat', 'powershell', 'pwsh', 'cmd'],
|
|
5
5
|
whitelist: [],
|
|
6
6
|
blockDangerousFlags: false,
|
|
7
7
|
dangerousFlags: ['--force', '-rf', '--no-preserve-root'],
|
|
@@ -32,8 +32,7 @@ function extractBaseCommand(trimmed) {
|
|
|
32
32
|
i++;
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
|
-
if (tok === "sudo" || tok === "env" || tok === "command" || tok === "exec" || tok === "nohup"
|
|
36
|
-
tok === "powershell" || tok === "pwsh" || tok === "cmd") {
|
|
35
|
+
if (tok === "sudo" || tok === "env" || tok === "command" || tok === "exec" || tok === "nohup") {
|
|
37
36
|
i++;
|
|
38
37
|
continue;
|
|
39
38
|
}
|
|
@@ -44,7 +43,9 @@ function extractBaseCommand(trimmed) {
|
|
|
44
43
|
// Extract basename from path (e.g. /usr/bin/rm → rm)
|
|
45
44
|
const raw = tokens[i];
|
|
46
45
|
const parts = raw.split(/[\\/]/);
|
|
47
|
-
|
|
46
|
+
const basename = parts[parts.length - 1] || raw;
|
|
47
|
+
// Strip .exe/.cmd/.bat extensions for blacklist matching (e.g. powershell.exe → powershell)
|
|
48
|
+
return basename.replace(/\.(exe|cmd|bat)$/i, '') || basename;
|
|
48
49
|
}
|
|
49
50
|
/**
|
|
50
51
|
* Check if a shell operator appears as a standalone token in the command.
|
|
@@ -115,7 +116,7 @@ export function isCommandAllowed(command, securityConfig) {
|
|
|
115
116
|
};
|
|
116
117
|
}
|
|
117
118
|
// Also check the raw first token in case it's a simple name
|
|
118
|
-
const rawFirst = trimmedCommand.split(/\s+/)[0];
|
|
119
|
+
const rawFirst = trimmedCommand.split(/\s+/)[0].replace(/\.(exe|cmd|bat)$/i, '');
|
|
119
120
|
if (rawFirst !== baseCommand && config.blacklist.includes(rawFirst)) {
|
|
120
121
|
return {
|
|
121
122
|
allowed: false,
|