Skip to content

[Bug]: CLI ignores permission.nativeDelete - deletions still go to the Recycle Bin while the Desktop app permanently deletes (Windows, 0.6.13) #529

Open

Description

@HowHaoChih

Product or interface

CLI - headless (mcode exec) and CLI - interactive TUI.

The Desktop app (Electron, same 0.6.13 runtime) behaves differently from the CLI while reading the exact same config.yaml, so the two surfaces disagree. This report is about the CLI side.

Version

  • CLI: @minimax-ai/code@0.6.13 (mcode --version → 0.6.13)
  • Node.js v24.14.1, npm 11.13.0
  • Desktop app for comparison: same 0.6.13 runtime.
  • Note: the open-source main branch of this repo is still at 0.6.5 and does not contain permission.nativeDelete at all (it was introduced in the published 0.6.9). This report is therefore based on the published npm artifact; the fix will need to land on top of 0.6.13.

Platform

Windows

OS version and architectu

Windows 11 專業版, 10.0.26100, x64. PowerShell 5.1.26100.9711.

Issue area

Tool call / permission / sandbox

Steps to reproduce

  1. Install the CLI: npm install -g @minimax-ai/code (0.6.13).
  2. Enable native deletion in the shared runtime config. Both surfaces use the same data directory, so edit <data-dir>/config.yaml (default ~/.minimax/config.yaml):
    permission:
      nativeDelete: true
  3. Create a probe file: Set-Content -LiteralPath 'D:\MiniMax\_ndtest\cli_rm.txt' -Value 'probe'
  4. Run one headless task that deletes it:
    mcode exec --output-format json --permission full --cwd 'D:\MiniMax\_ndtest' \
      "使用 bash 工具執行這一行(不要改寫指令):rm -- 'D:\MiniMax\_ndtest\cli_rm.txt'"
    
  5. Inspect the Windows Recycle Bin (e.g. Shell.Application → Namespace(10)).

Expected and actual behavior

Expected: per the 0.6.9 changelog entry that introduced the flag, permission.nativeDelete: true means "use the selected shell's native deletion instead of enforcing recoverable deletion". The file should be permanently removed, and the CLI should behave the same as the Desktop app, which does honor the flag.

Actual: the file is deleted but recoverably — it lands in the Windows Recycle Bin with its original path preserved (orig=D:\MiniMax\_ndtest), instead of being permanently removed.

The same config.yaml produces different results on the two surfaces:

Surface Command Result
Desktop app Remove-Item 'D:\MiniMax\_ndtest\app_literal.txt' -Force permanently deleted, not in Recycle Bin
CLI rm -- 'D:\MiniMax\_ndtest\cli_rm.txt' deleted, present in Recycle Bin

The key observation is that this is not merely a difference in which delete command each surface prefers. In the published CLI bundle, the recoverable-rewrite of rm is explicitly gated on the flag being off:

if (u) return s("recoverable-delete-rewrite", { ... });          // recoverable windows delete
if (!n?.nativeDelete && bs(t)) return s("rm-rewrite", { ... });   // POSIX rm -> trash

So the fact that the CLI rewrote rm into the trash launcher proves that nativeDelete was read as false inside the permission check, even though the same file sets it to true.

Redacted error summary

No error is raised. The behavior is a silent fallback to the recoverable-delete path, so there is nothing in the logs to quote.

Suspected root cause

The flag is parsed correctly and then lost during the config merge, so it never reaches the permission check.

parsePermissionConfig() in packages/config/src/permission-config.ts does parse it (obj.nativeDelete === true), and PERMISSION_CONFIG_DEFAULTS includes nativeDelete: false, so the value enters the config correctly:

const nativeDelete = obj.nativeDelete === true;
return { policyOwner, storageWriteVersion, classifierTimeoutMs, userConfirmationEnabled, nativeDelete };

However, the config-merge step rebuilds the permission object from four fields only and drops nativeDelete. In main this shape lives in packages/local-runtime/src/permissions/service.ts → toRuntimeConfig() (lines 225-241):

permission: {
  policyOwner: local.permission?.policyOwner ?? getConfig().permission?.policyOwner ?? 'core',
  storageWriteVersion:
    local.permission?.storageWriteVersion ?? getConfig().permission?.storageWriteVersion ?? 2,
  classifierTimeoutMs:
    local.permission?.classifierTimeoutMs ??
    getConfig().permission?.classifierTimeoutMs ??
    AUTO_CLASSIFIER_TIMEOUT_MS_DEFAULT,
  userConfirmationEnabled:
    local.permission?.userConfirmationEnabled ??
    getConfig().permission?.userConfirmationEnabled ??
    true,
},

The same four-field rebuild is present in the published CLI bundle (IMr() in chunks/chunk-H6JEREKX.js).

Every downstream consumer then reads the rebuilt object rather than the raw config, e.g.:

const nativeDelete = unresolvedParams.nativeDeleteSnapshot ?? config.permission?.nativeDelete === true;

Because nativeDelete was never copied into the rebuilt object, this resolves to undefined → false, and the permission checker keeps enforcing recoverable deletion.

Two things would make this concrete for whoever picks it up:

  1. Confirm whether the 0.6.13 config-merge path is the same four-field rebuild as the one in main (the flag does not exist in main, so it cannot be observed there directly).
  2. If so, nativeDelete needs to be carried through the merge alongside the other four fields.

A secondary, Windows-specific limitation worth considering while fixing this: the CLI's Bash tool runs a POSIX shell on Windows, so the native-delete command subset the runtime recognizes (del/erase/rd/rmdir for cmd, remove-item/ri for PowerShell) is not directly expressible — Remove-Item is simply command not found in the CLI's shell. Even with the flag correctly threaded through, the CLI would still fall back to rm, so the POSIX rm path needs to honor nativeDelete too.

Screenshots

N/A — reproducible from the CLI alone.

Before submitting

  • I have searched existing issues.
  • I have included my version and removed sensitive information.

Activity

  1. yujiachen-y commented on Oct 24, 2026

    @yujiachen-y
    Collaborator

    Hi @HowHaoChih , I cannot reproduce your issue. Can check again for your version? Or you can submit a feedback vim /feedback command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions