osai-agent 4.2.10 → 4.2.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osai-agent",
3
- "version": "4.2.10",
3
+ "version": "4.2.12",
4
4
  "type": "module",
5
5
  "description": "OS AI Agent - YOUR AI AGENT",
6
6
  "main": "src/index.js",
@@ -15,6 +15,8 @@ import { TOOLS, SAFETY_TIERS, MODES, EXECUTION_MODES, READ_ONLY_TOOLS, READ_FRES
15
15
  import { discoverSkills, loadSkill, createSkill, formatSkillsList } from '../../skills/loader.js';
16
16
  import { runSubagent } from '../subagent.js';
17
17
  import { logger } from '../../utils/logger.js';
18
+ import inquirer from 'inquirer';
19
+ import chalk from 'chalk';
18
20
  import path from 'path';
19
21
 
20
22
  // Helper: yield rapide pour ne pas bloquer l'event loop
@@ -235,6 +237,20 @@ export default {
235
237
  }
236
238
  }
237
239
 
240
+ // Sudo password prompt
241
+ if (tool === TOOLS.LOCAL_CMD && /^sudo\b/.test(toolCall.cmd?.trim()) && !this.isSubagent) {
242
+ if (!this.sudoPassword) {
243
+ this.onMarkdown(chalk.dim('\n_This command requires sudo. Enter your password:_\n'));
244
+ const { password } = await inquirer.prompt([{
245
+ type: 'password',
246
+ name: 'password',
247
+ message: ' sudo password:',
248
+ mask: '*',
249
+ }]);
250
+ this.sudoPassword = password;
251
+ }
252
+ }
253
+
238
254
  const safety = checkSafety(toolCall, this.mode);
239
255
 
240
256
  if ((safety.tier === SAFETY_TIERS.READ && this.noConfirm) || !safety.requiresConfirmation) {
@@ -410,7 +426,7 @@ export default {
410
426
 
411
427
  case TOOLS.LOCAL_CMD:
412
428
  default:
413
- return await executeLocal(toolCall.cmd || '');
429
+ return await executeLocal(toolCall.cmd || '', this.sudoPassword || null);
414
430
  }
415
431
  } catch (error) {
416
432
  logger.error('Tool dispatch error', { tool, error: error.message });
@@ -216,6 +216,7 @@ export class AgentLoop {
216
216
 
217
217
  cancel() {
218
218
  this._cancelled = true;
219
+ this.sudoPassword = null;
219
220
  if (this.abortController) {
220
221
  try { this.abortController.abort(); } catch {}
221
222
  }
@@ -236,6 +237,7 @@ export class AgentLoop {
236
237
  }
237
238
 
238
239
  async cleanup() {
240
+ this.sudoPassword = null;
239
241
  if (this.ws) { try { this.ws.close(); } catch {} this.ws = null; }
240
242
  if (this.mode === MODES.NETWORK) closeAllConnections();
241
243
  }
@@ -194,7 +194,7 @@ export const getSystemInfo = () => ({
194
194
  /**
195
195
  * Execute a local shell command with timeout and safety checks.
196
196
  */
197
- export const executeLocal = async (command) => {
197
+ export const executeLocal = async (command, sudoPassword = null) => {
198
198
  const trimmedCmd = (command || '').trim();
199
199
  if (!trimmedCmd) {
200
200
  return { success: false, output: '', error: 'Empty command' };
@@ -214,7 +214,11 @@ export const executeLocal = async (command) => {
214
214
  logger.debug('Executing local command', { cmd: trimmedCmd, timeout: COMMAND_TIMEOUT });
215
215
 
216
216
  const isWindows = detectOS() === 'windows';
217
- const finalCommand = isWindows ? `chcp 65001 >nul 2>&1 && ${trimmedCmd}` : trimmedCmd;
217
+ let finalCommand = isWindows ? `chcp 65001 >nul 2>&1 && ${trimmedCmd}` : trimmedCmd;
218
+
219
+ if (sudoPassword && /^sudo\b/.test(finalCommand)) {
220
+ finalCommand = finalCommand.replace(/^sudo\b/, 'sudo -S');
221
+ }
218
222
 
219
223
  return await new Promise((resolve) => {
220
224
  let output = '';
@@ -235,6 +239,14 @@ export const executeLocal = async (command) => {
235
239
  env: { ...process.env, PYTHONIOENCODING: 'utf-8', LANG: 'en_US.UTF-8' },
236
240
  });
237
241
 
242
+ if (sudoPassword) {
243
+ const writePassword = () => {
244
+ child.stdin.write(sudoPassword + '\n');
245
+ child.stdin.end();
246
+ };
247
+ setTimeout(writePassword, 200);
248
+ }
249
+
238
250
  const timeoutId = setTimeout(() => {
239
251
  timedOut = true;
240
252
  try { child.kill('SIGTERM'); } catch {}