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("\\"))
@@ -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 {
@@ -41,6 +41,9 @@ export const DEFAULT_SECURITY_CONFIG = {
41
41
  "mkfs",
42
42
  "mount",
43
43
  "umount",
44
+ "powershell",
45
+ "pwsh",
46
+ "cmd",
44
47
  ],
45
48
  // If whitelist is non-empty, only these commands are allowed
46
49
  whitelist: [],
@@ -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
- return parts[parts.length - 1] || raw;
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.16.3",
3
+ "version": "0.16.5",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {