Skip to content

feat: 添加命令行选项支持stdout输出可读日志#135

Merged
MistEO merged 28 commits intoMistEO:mainfrom
ShadowLemoon:feat/stdout
Apr 4, 2026
Merged

feat: 添加命令行选项支持stdout输出可读日志#135
MistEO merged 28 commits intoMistEO:mainfrom
ShadowLemoon:feat/stdout

Conversation

@ShadowLemoon
Copy link
Copy Markdown
Contributor

@ShadowLemoon ShadowLemoon commented Mar 30, 2026

closes: #136

Summary by Sourcery

添加一个由命令行标志控制的可选控制台日志功能,并将关键运行时事件输出到 stdout,以便在从终端启动时更容易调试。

New Features:

  • 引入 --console 命令行选项,在从终端启动应用时启用控制台/stdout 日志。
  • 为 MaaFramework 回调事件和代理输出行添加可读性良好的控制台输出,包括时间戳和简化后的消息。

Enhancements:

  • 在 Windows 上初始化控制台附加功能,并将控制台日志接入现有的启动流程,包括在不同平台上对 stdout 的安全处理。

Build:

  • windows crate 中启用 Win32_System_Console 功能,以支持在 Windows 上附加控制台。
Original summary in English

Summary by Sourcery

Add optional console logging controlled by a command-line flag and surface key runtime events to stdout for easier debugging when launched from a terminal.

New Features:

  • Introduce a --console command-line option that enables console/stdout logging when the app is launched from a terminal.
  • Add human-readable console output for MaaFramework callback events and agent output lines, including timestamps and simplified messages.

Enhancements:

  • Initialize console attachment on Windows and wire console logging into the existing startup flow, including safe handling of stdout on different platforms.

Build:

  • Enable the Win32_System_Console feature in the windows crate to support console attachment on Windows.

Summary by Sourcery

添加可配置的控制台日志模式,并将前端日志桥接到后端 stdout,以改进终端调试,同时优化应用状态持久化的订阅逻辑。

New Features:

  • 暴露 Tauri 命令,用于查询控制台日志的可用性/模式,以及向已附加的控制台打印格式化日志行。
  • 将选定的 UI 和 Maa 回调日志事件通过共享的控制台桥接进行路由,使它们可以基于所选日志模式,携带任务上下文和时间戳输出到 stdout。

Enhancements:

  • 引入详细(verbose)任务级控制台日志,带有缓冲与延迟重放机制,直到任务 ID 映射可用为止,并在详细日志中增加原始任务名称。
  • 优化状态持久化订阅逻辑,仅对持久化的切片进行快照,避免在每次变更时对整个 store 进行 JSON 比较。
  • 调整后端日志目标,使其仅在 raw 模式下有条件地输出到 stdout,并根据新的日志模式标志初始化平台相关的控制台附加和 CRT/stdout 重定向。
  • 在详细控制台模式启用时禁用 MaaFramework 自身的 stdout 日志,以防止重复输出。

Build:

  • 在 windows crate 中启用 Win32_System_Console 功能,以支持在 Windows 上的控制台附加及相关句柄设置。
Original summary in English

Summary by Sourcery

Add configurable console logging modes and bridge front-end logs to backend stdout for improved terminal debugging, while optimizing app state persistence subscriptions.

New Features:

  • Expose Tauri commands to query console logging availability/mode and to print formatted log lines to an attached console.
  • Route selected UI and Maa callback log events through a shared console bridge so they can be output with task context and timestamps to stdout based on the chosen log mode.

Enhancements:

  • Introduce verbose task-level console logging with buffering and delayed replay until task ID mappings are available, and enrich verbose logs with raw task names.
  • Refine state persistence subscription logic by snapshotting only the persisted slice and avoiding full-store JSON comparisons on every change.
  • Adjust backend logging targets to conditionally log to stdout only in raw mode and initialize platform-specific console attachment and CRT/stdout redirection according to the new log-mode flag.
  • Disable MaaFramework's own stdout logging when verbose console mode is active to prevent duplicate output.

Build:

  • Enable the Win32_System_Console feature in the windows crate to support console attachment and handle setup on Windows.

新功能:

  • 暴露 Tauri 命令,用于报告控制台日志的可用性和模式,并将格式化后的日志行打印到已附加的控制台。
  • 在 app store 和 Maa 回调 logger 中引入支持控制台的日志记录,使选定的 UI 日志事件也可以携带任务上下文和时间戳输出到 stdout。

增强:

  • 优化应用状态持久化的订阅逻辑,避免在每次变更时对整个 store 做 JSON 字符串化,改为通过缓存快照仅跟踪需要持久化的切片。
  • 改进 Maa 回调日志记录:增加任务级别的控制台输出模式,在任务 ID 建立映射前对任务消息进行缓冲与回放,并在详细日志中补充原始任务名称。

构建:

  • windows crate 中启用 Win32_System_Console 特性,并基于新的 --log-mode 标志初始化平台相关的控制台附加逻辑以及 CRT/stdout 重定向。
Original summary in English

Summary by Sourcery

添加可配置的控制台日志模式,并将前端日志桥接到后端 stdout,以改进终端调试,同时优化应用状态持久化的订阅逻辑。

New Features:

  • 暴露 Tauri 命令,用于查询控制台日志的可用性/模式,以及向已附加的控制台打印格式化日志行。
  • 将选定的 UI 和 Maa 回调日志事件通过共享的控制台桥接进行路由,使它们可以基于所选日志模式,携带任务上下文和时间戳输出到 stdout。

Enhancements:

  • 引入详细(verbose)任务级控制台日志,带有缓冲与延迟重放机制,直到任务 ID 映射可用为止,并在详细日志中增加原始任务名称。
  • 优化状态持久化订阅逻辑,仅对持久化的切片进行快照,避免在每次变更时对整个 store 进行 JSON 比较。
  • 调整后端日志目标,使其仅在 raw 模式下有条件地输出到 stdout,并根据新的日志模式标志初始化平台相关的控制台附加和 CRT/stdout 重定向。
  • 在详细控制台模式启用时禁用 MaaFramework 自身的 stdout 日志,以防止重复输出。

Build:

  • 在 windows crate 中启用 Win32_System_Console 功能,以支持在 Windows 上的控制台附加及相关句柄设置。
Original summary in English

Summary by Sourcery

Add configurable console logging modes and bridge front-end logs to backend stdout for improved terminal debugging, while optimizing app state persistence subscriptions.

New Features:

  • Expose Tauri commands to query console logging availability/mode and to print formatted log lines to an attached console.
  • Route selected UI and Maa callback log events through a shared console bridge so they can be output with task context and timestamps to stdout based on the chosen log mode.

Enhancements:

  • Introduce verbose task-level console logging with buffering and delayed replay until task ID mappings are available, and enrich verbose logs with raw task names.
  • Refine state persistence subscription logic by snapshotting only the persisted slice and avoiding full-store JSON comparisons on every change.
  • Adjust backend logging targets to conditionally log to stdout only in raw mode and initialize platform-specific console attachment and CRT/stdout redirection according to the new log-mode flag.
  • Disable MaaFramework's own stdout logging when verbose console mode is active to prevent duplicate output.

Build:

  • Enable the Win32_System_Console feature in the windows crate to support console attachment and handle setup on Windows.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题

给 AI Agents 的提示词
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/maa_agent.rs" line_range="38-39" />
<code_context>

 /// 发送 Agent 输出事件
 fn emit_agent_output(app: &tauri::AppHandle, instance_id: &str, stream: &str, line: &str) {
+    let clean_line = strip_ansi_escapes(line);
+    let timestamp = chrono::Local::now().format("%H:%M:%S");
+    cprintln!("[{timestamp}][AGT] {clean_line}");
+
</code_context>
<issue_to_address>
**suggestion (performance):** 当控制台输出被禁用时,跳过与控制台日志相关的工作。

目前即使没有传入 `--console`(此时 `cprintln!` 实际是空操作),仍然会为 `strip_ansi_escapes` 进行分配,并在每次调用时计算时间戳。对于高频率的 Agent 输出,这些开销会比较可观。建议添加一个开销很小的 `is_console_enabled()` 辅助函数(例如放在 `utils` 中),在该函数返回 `false` 时尽早返回或整体包裹这一段逻辑,使得 ANSI 去除和时间戳计算仅在启用控制台输出时才执行。

建议实现:

```rust
use super::types::{AgentConfig, MaaState, TaskConfig};
use super::utils::{emit_callback_event, get_logs_dir, is_console_enabled, normalize_path};
use crate::cprintln;
use regex::Regex;
use std::sync::LazyLock;

```

```rust

```

```rust
    if is_console_enabled() {
        let clean_line = strip_ansi_escapes(line);
        let timestamp = chrono::Local::now().format("%H:%M:%S");
        cprintln!("[{timestamp}][AGT] {clean_line}");
    }

```

1.`super::utils` 中实现一个 `is_console_enabled() -> bool` 辅助函数(很可能在 `src-tauri/src/commands/utils.rs` 或类似文件中)。该函数应在启用 `--console` 时返回 `true`,否则返回 `false`,并复用你现有的控制台输出配置/状态。
2. 确保 `is_console_enabled()` 本身足够轻量(不分配、不进行重锁),因为它会在每条 Agent 输出时调用。
3.`emit_agent_output` 中,将与控制台无关的逻辑(例如通过 `emit_callback_event` 发送 Tauri 事件)保留在 `if is_console_enabled()` 之外,这样事件投递不会受到控制台配置的影响。
</issue_to_address>

### Comment 2
<location path="src-tauri/src/commands/utils.rs" line_range="25-36" />
<code_context>
+        use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
+
+        // 附着到父进程终端(从 cmd/powershell 启动时生效)
+        if unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }.is_ok() {
+            if let Ok(f) = std::fs::OpenOptions::new().write(true).open("CONOUT$") {
+                let _ = CONSOLE_FILE.set(std::sync::Mutex::new(f));
+                CONSOLE_ENABLED.store(true, Ordering::Relaxed);
</code_context>
<issue_to_address>
**suggestion:** 建议在使用 `--console` 时,显式暴露附着父进程控制台失败的情况。

如果使用了 `--console`,但 `AttachConsole` 或打开 `CONOUT$` 失败,目前的实现会静默返回,从而导致控制台日志实际上从未启用,这会让人感觉 `--console` 没有效果。建议在失败时记录一次性警告(例如使用 `log::warn!`),说明为什么控制台输出未能启用。

```suggestion
    #[cfg(windows)]
    {
        use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};

        // 附着到父进程终端(从 cmd/powershell 启动时生效)
        if unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }.is_ok() {
            if let Ok(f) = std::fs::OpenOptions::new().write(true).open("CONOUT$") {
                let _ = CONSOLE_FILE.set(std::sync::Mutex::new(f));
                CONSOLE_ENABLED.store(true, Ordering::Relaxed);
            } else {
                log::warn!(
                    "Failed to open CONOUT$ for console output; `--console` will have no effect."
                );
            }
        } else {
            log::warn!(
                "Failed to attach to the parent console; `--console` will have no effect."
            );
        }
    }
```
</issue_to_address>

Sourcery 对开源项目免费——如果你喜欢我们的代码审查,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的审查。
Original comment in English

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/maa_agent.rs" line_range="38-39" />
<code_context>

 /// 发送 Agent 输出事件
 fn emit_agent_output(app: &tauri::AppHandle, instance_id: &str, stream: &str, line: &str) {
+    let clean_line = strip_ansi_escapes(line);
+    let timestamp = chrono::Local::now().format("%H:%M:%S");
+    cprintln!("[{timestamp}][AGT] {clean_line}");
+
</code_context>
<issue_to_address>
**suggestion (performance):** Skip work for console logging when the console output is disabled.

Currently this still allocates for `strip_ansi_escapes` and computes a timestamp on every call, even when `--console` is not passed and `cprintln!` is a no-op. For high-volume agent output this overhead can be significant. Consider adding a cheap `is_console_enabled()` helper (e.g., in `utils`) and returning early or guarding this whole block so ANSI stripping and timestamp calculation only run when console output is enabled.

Suggested implementation:

```rust
use super::types::{AgentConfig, MaaState, TaskConfig};
use super::utils::{emit_callback_event, get_logs_dir, is_console_enabled, normalize_path};
use crate::cprintln;
use regex::Regex;
use std::sync::LazyLock;

```

```rust

```

```rust
    if is_console_enabled() {
        let clean_line = strip_ansi_escapes(line);
        let timestamp = chrono::Local::now().format("%H:%M:%S");
        cprintln!("[{timestamp}][AGT] {clean_line}");
    }

```

1. Implement an `is_console_enabled() -> bool` helper in `super::utils` (likely `src-tauri/src/commands/utils.rs` or similar). It should return `true` when `--console` has been enabled and `false` otherwise, using whatever configuration/state you already maintain for console output.
2. Ensure `is_console_enabled()` is cheap (no allocation, no heavy locking) since it's called on each agent output.
3. In `emit_agent_output`, keep all non-console-related logic (such as emitting Tauri events via `emit_callback_event`) outside the `if is_console_enabled()` block so that event delivery is not affected by console configuration.
</issue_to_address>

### Comment 2
<location path="src-tauri/src/commands/utils.rs" line_range="25-36" />
<code_context>
+        use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
+
+        // 附着到父进程终端(从 cmd/powershell 启动时生效)
+        if unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }.is_ok() {
+            if let Ok(f) = std::fs::OpenOptions::new().write(true).open("CONOUT$") {
+                let _ = CONSOLE_FILE.set(std::sync::Mutex::new(f));
+                CONSOLE_ENABLED.store(true, Ordering::Relaxed);
</code_context>
<issue_to_address>
**suggestion:** Consider surfacing failures to attach to the parent console when `--console` is requested.

If `--console` is used but `AttachConsole` or opening `CONOUT$` fails, this returns silently and console logging is never enabled, which can make `--console` look ineffective. Consider logging a one-time warning on failure (e.g., via `log::warn!`) to explain why console output wasn’t enabled.

```suggestion
    #[cfg(windows)]
    {
        use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};

        // 附着到父进程终端(从 cmd/powershell 启动时生效)
        if unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }.is_ok() {
            if let Ok(f) = std::fs::OpenOptions::new().write(true).open("CONOUT$") {
                let _ = CONSOLE_FILE.set(std::sync::Mutex::new(f));
                CONSOLE_ENABLED.store(true, Ordering::Relaxed);
            } else {
                log::warn!(
                    "Failed to open CONOUT$ for console output; `--console` will have no effect."
                );
            }
        } else {
            log::warn!(
                "Failed to attach to the parent console; `--console` will have no effect."
            );
        }
    }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src-tauri/src/commands/maa_agent.rs Outdated
Comment thread src-tauri/src/commands/utils.rs Outdated
@ShadowLemoon ShadowLemoon marked this pull request as draft March 30, 2026 23:28
DLmaster361 and others added 2 commits March 31, 2026 15:54
- 引入 LogPrintMode 枚举类型 (None|Raw|Ui|Verbose) 替代简单的布尔标志
- 实现 --log-mode=<none|raw|ui|verbose> 命令行参数解析
- 移除 Windows 平台特定的 CONOUT$ 句柄管理逻辑,统一使用标准输出流
- 简化控制台输出实现,统一使用标准 println! 宏
- 添加 should_log_to_stdout 函数用于 tauri_plugin_log 插件配置
refactor(utils): 重构控制台输出机制支持多种日志模式
@ShadowLemoon ShadowLemoon marked this pull request as ready for review March 31, 2026 18:30
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嗨,我发现了 1 个问题,并给出了一些整体反馈:

  • 关于 Tauri 控制台调用/启用的逻辑(getConsoleInvoke_consoleEnabled_invoke)在 appStore.tsuseMaaCallbackLogger.ts 之间是重复的;建议将其抽取到一个共享工具中,以避免未来实现出现差异,并保持行为一致。
  • 持久化订阅现在在每次变更时都会用 JSON.stringify 序列化选中的 AppState 切片;如果这里将来变成热路径,可以考虑使用更廉价的相等性策略(例如,对已知会变化的字段做浅比较,或者在持久化字段发生变化时递增版本号),以降低 CPU 成本和 GC 压力。
  • 未决控制台日志的映射(pendingTaskConsoleLogspendingTaskConsoleReplayTimerspendingTaskConsoleReplayRetries)是全局的;在实例被移除或者该实例的所有任务被清空时,显式清理相关条目可能是值得的,以避免在边缘情况下产生长生命周期的内存/定时器泄漏。
供 AI Agent 使用的提示词
Please address the comments from this code review:

## Overall Comments
- The logic for Tauri console invocation/enablement (`getConsoleInvoke`, `_consoleEnabled`, `_invoke`) is duplicated between `appStore.ts` and `useMaaCallbackLogger.ts`; consider extracting this into a shared utility to avoid future divergence and keep the behavior consistent.
- The persistence subscription now serializes the selected slice of `AppState` with `JSON.stringify` on every change; if this becomes a hot path, consider a cheaper equality strategy (e.g., shallow compares on fields you know change, or incrementing a version counter when persisted fields mutate) to reduce CPU cost and GC pressure.
- The pending console log maps (`pendingTaskConsoleLogs`, `pendingTaskConsoleReplayTimers`, `pendingTaskConsoleReplayRetries`) are global; it may be worth explicitly clearing related entries when an instance is removed or all tasks for an instance are cleared to avoid long-lived memory/timer leaks in edge cases.

## Individual Comments

### Comment 1
<location path="src/stores/appStore.ts" line_range="45-54" />
<code_context>
+let _consoleEnabled: boolean | null = null;
+let _invoke: ((cmd: string, args?: Record<string, unknown>) => Promise<unknown>) | null = null;
+
+async function getConsoleInvoke() {
+  if (_consoleEnabled === false) return null;
+  if (_invoke && _consoleEnabled === true) return _invoke;
+  if (!isTauri()) {
+    _consoleEnabled = false;
+    return null;
+  }
+  const { invoke } = await import('@tauri-apps/api/core');
+  _invoke = invoke;
+  try {
+    _consoleEnabled = await invoke<boolean>('is_console_enabled');
+  } catch {
+    _consoleEnabled = false;
+  }
+  return _consoleEnabled ? _invoke : null;
+}
+
</code_context>
<issue_to_address>
**suggestion:** Consider de-duplicating the Tauri console invoke/flag logic shared with `useMaaCallbackLogger`

This `getConsoleInvoke` / `_consoleEnabled` / `_invoke` pattern closely mirrors the implementation in `useMaaCallbackLogger.ts`. Duplicating it in two places risks them drifting apart (e.g., command name/behavior changes applied in only one file). Consider extracting a small shared helper (e.g. `consoleBridge.ts`) that provides `getConsoleInvoke()` and possibly `getConsoleOutputMode()`, and using it both here and in the callback logger.

Suggested implementation:

```typescript
import { generateId, initializeAllOptionValues, convertPresetOptionValue } from './helpers';
// 从独立模块导入类型和辅助函数
import type { AppState, LogEntry, TaskRunStatus } from './types';
import { isTauri } from '@/utils/paths';
import { getConsoleInvoke } from '@/utils/consoleBridge';

```

To fully implement the suggestion and avoid duplication, you should also:

1. **Create a shared helper** `src/utils/consoleBridge.ts` (path can be adjusted to your conventions) that encapsulates the console/Tauri logic currently duplicated between `appStore.ts` and `useMaaCallbackLogger.ts`, e.g.:
   - Cache `_consoleEnabled` and `_invoke` at module scope.
   - Implement and export `async function getConsoleInvoke()`.
   - Optionally implement and export `async function getConsoleOutputMode()` or similar if both call sites need it.
2. **Move the existing implementation** of `getConsoleInvoke` (including `_consoleEnabled` / `_invoke` and `is_console_enabled` invoke logic) from `appStore.ts` and `useMaaCallbackLogger.ts` into `consoleBridge.ts`.
3. **Remove the local `getConsoleInvoke` implementation** (function definition and the associated `_consoleEnabled` / `_invoke` variables) from `appStore.ts` and from `useMaaCallbackLogger.ts`.
4. **Import and use the shared helper**:
   - In `appStore.ts`, keep the `getConsoleInvoke(...)` call sites unchanged; they will now reference the imported function.
   - In `useMaaCallbackLogger.ts`, replace any local `getConsoleInvoke` usage with an import from `@/utils/consoleBridge`.
5. If `consoleBridge.ts` now owns the Tauri dependency, you can **remove any now-unused `isTauri` imports** from `appStore.ts` and `useMaaCallbackLogger.ts` (or keep them if used elsewhere in those files).
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,欢迎分享给更多人 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码评审。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The logic for Tauri console invocation/enablement (getConsoleInvoke, _consoleEnabled, _invoke) is duplicated between appStore.ts and useMaaCallbackLogger.ts; consider extracting this into a shared utility to avoid future divergence and keep the behavior consistent.
  • The persistence subscription now serializes the selected slice of AppState with JSON.stringify on every change; if this becomes a hot path, consider a cheaper equality strategy (e.g., shallow compares on fields you know change, or incrementing a version counter when persisted fields mutate) to reduce CPU cost and GC pressure.
  • The pending console log maps (pendingTaskConsoleLogs, pendingTaskConsoleReplayTimers, pendingTaskConsoleReplayRetries) are global; it may be worth explicitly clearing related entries when an instance is removed or all tasks for an instance are cleared to avoid long-lived memory/timer leaks in edge cases.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The logic for Tauri console invocation/enablement (`getConsoleInvoke`, `_consoleEnabled`, `_invoke`) is duplicated between `appStore.ts` and `useMaaCallbackLogger.ts`; consider extracting this into a shared utility to avoid future divergence and keep the behavior consistent.
- The persistence subscription now serializes the selected slice of `AppState` with `JSON.stringify` on every change; if this becomes a hot path, consider a cheaper equality strategy (e.g., shallow compares on fields you know change, or incrementing a version counter when persisted fields mutate) to reduce CPU cost and GC pressure.
- The pending console log maps (`pendingTaskConsoleLogs`, `pendingTaskConsoleReplayTimers`, `pendingTaskConsoleReplayRetries`) are global; it may be worth explicitly clearing related entries when an instance is removed or all tasks for an instance are cleared to avoid long-lived memory/timer leaks in edge cases.

## Individual Comments

### Comment 1
<location path="src/stores/appStore.ts" line_range="45-54" />
<code_context>
+let _consoleEnabled: boolean | null = null;
+let _invoke: ((cmd: string, args?: Record<string, unknown>) => Promise<unknown>) | null = null;
+
+async function getConsoleInvoke() {
+  if (_consoleEnabled === false) return null;
+  if (_invoke && _consoleEnabled === true) return _invoke;
+  if (!isTauri()) {
+    _consoleEnabled = false;
+    return null;
+  }
+  const { invoke } = await import('@tauri-apps/api/core');
+  _invoke = invoke;
+  try {
+    _consoleEnabled = await invoke<boolean>('is_console_enabled');
+  } catch {
+    _consoleEnabled = false;
+  }
+  return _consoleEnabled ? _invoke : null;
+}
+
</code_context>
<issue_to_address>
**suggestion:** Consider de-duplicating the Tauri console invoke/flag logic shared with `useMaaCallbackLogger`

This `getConsoleInvoke` / `_consoleEnabled` / `_invoke` pattern closely mirrors the implementation in `useMaaCallbackLogger.ts`. Duplicating it in two places risks them drifting apart (e.g., command name/behavior changes applied in only one file). Consider extracting a small shared helper (e.g. `consoleBridge.ts`) that provides `getConsoleInvoke()` and possibly `getConsoleOutputMode()`, and using it both here and in the callback logger.

Suggested implementation:

```typescript
import { generateId, initializeAllOptionValues, convertPresetOptionValue } from './helpers';
// 从独立模块导入类型和辅助函数
import type { AppState, LogEntry, TaskRunStatus } from './types';
import { isTauri } from '@/utils/paths';
import { getConsoleInvoke } from '@/utils/consoleBridge';

```

To fully implement the suggestion and avoid duplication, you should also:

1. **Create a shared helper** `src/utils/consoleBridge.ts` (path can be adjusted to your conventions) that encapsulates the console/Tauri logic currently duplicated between `appStore.ts` and `useMaaCallbackLogger.ts`, e.g.:
   - Cache `_consoleEnabled` and `_invoke` at module scope.
   - Implement and export `async function getConsoleInvoke()`.
   - Optionally implement and export `async function getConsoleOutputMode()` or similar if both call sites need it.
2. **Move the existing implementation** of `getConsoleInvoke` (including `_consoleEnabled` / `_invoke` and `is_console_enabled` invoke logic) from `appStore.ts` and `useMaaCallbackLogger.ts` into `consoleBridge.ts`.
3. **Remove the local `getConsoleInvoke` implementation** (function definition and the associated `_consoleEnabled` / `_invoke` variables) from `appStore.ts` and from `useMaaCallbackLogger.ts`.
4. **Import and use the shared helper**:
   - In `appStore.ts`, keep the `getConsoleInvoke(...)` call sites unchanged; they will now reference the imported function.
   - In `useMaaCallbackLogger.ts`, replace any local `getConsoleInvoke` usage with an import from `@/utils/consoleBridge`.
5. If `consoleBridge.ts` now owns the Tauri dependency, you can **remove any now-unused `isTauri` imports** from `appStore.ts` and `useMaaCallbackLogger.ts` (or keep them if used elsewhere in those files).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/stores/appStore.ts Outdated
@ShadowLemoon ShadowLemoon changed the title feat: 添加命令行选项--console支持stdout输出日志 feat: 添加命令行选项支持stdout分级输出日志 Mar 31, 2026
ShadowLemoon and others added 4 commits April 1, 2026 04:39
- 添加逻辑在verbose模式下关闭MaaFramework的stdout日志输出
- 避免与前端转发的结构化控制台日志产生重复
- 添加成功和失败的日志记录用于调试

feat(state): 改进控制台时间戳格式

- 将时间戳格式从%H:%M:%S改为%Y-%m-%d %H:%M:%S.%3f
- 提供更精确的时间显示,包含日期和毫秒信息
fix(maa_core): 在verbose模式下禁用MaaFramework stdout日志
@MistEO MistEO requested a review from Copilot April 2, 2026 09:11
@MistEO
Copy link
Copy Markdown
Owner

MistEO commented Apr 2, 2026

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出一些高层次的反馈:

  • forwardLogToConsole 中,用于移除 HTML 的正则表达式非常宽泛(/<[^>]*>/g),这也会把日志中的任何字面量 <...> 内容一起删除;建议使用更健壮的 HTML 转文本方案(例如基于 DOM 的解析器,或者只针对已知标签的更窄的匹配模式),以避免丢失合法文本。
  • consoleBridge.getConsoleInvokeconsoleLog 中,所有失败都会被静默吞掉;建议至少在控制台检测或调用失败时输出一次调试日志,这样在不刷屏的情况下,也能更容易诊断配置错误的 --log-mode 或 Tauri 命令问题。
给 AI Agent 的提示词
Please address the comments from this code review:

## Overall Comments
- In `forwardLogToConsole` the HTML stripping uses a very broad regex (`/<[^>]*>/g`), which will also remove any literal `<...>` content in messages; consider using a more robust HTML-to-text approach (e.g., a DOM-based parser or a narrower pattern that only targets known tags) to avoid losing legitimate text.
- In `consoleBridge.getConsoleInvoke` and `consoleLog`, all failures are silently swallowed; adding at least a one-time debug log when console detection or invocation fails would make diagnosing misconfigured `--log-mode` or Tauri command issues much easier without spamming the console.

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,欢迎分享给更多人 ✨
帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈不断改进代码评审质量。
Original comment in English

Hey - I've left some high level feedback:

  • In forwardLogToConsole the HTML stripping uses a very broad regex (/<[^>]*>/g), which will also remove any literal <...> content in messages; consider using a more robust HTML-to-text approach (e.g., a DOM-based parser or a narrower pattern that only targets known tags) to avoid losing legitimate text.
  • In consoleBridge.getConsoleInvoke and consoleLog, all failures are silently swallowed; adding at least a one-time debug log when console detection or invocation fails would make diagnosing misconfigured --log-mode or Tauri command issues much easier without spamming the console.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `forwardLogToConsole` the HTML stripping uses a very broad regex (`/<[^>]*>/g`), which will also remove any literal `<...>` content in messages; consider using a more robust HTML-to-text approach (e.g., a DOM-based parser or a narrower pattern that only targets known tags) to avoid losing legitimate text.
- In `consoleBridge.getConsoleInvoke` and `consoleLog`, all failures are silently swallowed; adding at least a one-time debug log when console detection or invocation fails would make diagnosing misconfigured `--log-mode` or Tauri command issues much easier without spamming the console.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 引入一套由启动参数控制的 stdout/控制台日志管线:在不影响现有 UI 日志的前提下,把前端 store 日志与 Maa 关键回调事件转发到后端并输出到终端,便于从命令行启动时调试;同时调整后端日志 target 与 Windows 控制台附着/重定向逻辑。

Changes:

  • 新增 --log-mode 控制的控制台输出系统(后端附着控制台、选择 stdout 输出策略,并提供 Tauri command 供前端转发日志)。
  • 前端新增 consoleBridge,并在 appStore / Maa 回调 logger 中为日志增加可选的控制台转发与任务上下文(含延迟回放)。
  • 优化配置持久化订阅逻辑,减少不必要的 JSON stringify 比较开销。

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/utils/useMaaCallbackLogger.ts 为任务回调构建可选的 verbose 控制台消息,并在 taskId 映射未就绪时做缓冲/回放。
src/utils/consoleBridge.ts 新增前端到后端 stdout 的 invoke 桥接与模式查询缓存。
src/stores/types.ts 扩展 addLog 入参以支持 consoleMessage(可显式抑制单条终端输出)。
src/stores/appStore.ts addLog 中将日志转发到控制台;并重构持久化订阅为缓存快照对比。
src-tauri/src/main.rs 启动时初始化 --log-mode 控制台输出系统。
src-tauri/src/lib.rs 调整 tauri_plugin_log targets:始终写文件,仅 Raw 模式写 stdout;注册新的 console 相关 commands。
src-tauri/src/commands/state.rs 新增 is_console_enabled/get_console_mode/console_log commands,并在后端打印带时间戳的行。
src-tauri/src/commands/mod.rs 暴露 console 模块。
src-tauri/src/commands/maa_core.rs verbose 模式下禁用 MaaFramework 自身 stdout 日志以避免重复。
src-tauri/src/commands/console.rs 新增后端控制台输出核心逻辑(参数解析、Windows 附着、重定向、cprintln 宏等)。
src-tauri/Cargo.toml Windows crate 启用 Win32_System_Console feature。

Comment thread src-tauri/src/commands/console.rs Outdated
Comment thread src-tauri/src/commands/console.rs Outdated
Comment thread src-tauri/src/commands/console.rs Outdated
Comment thread src-tauri/src/commands/state.rs Outdated
Comment thread src/utils/consoleBridge.ts Outdated
Comment thread src-tauri/src/commands/console.rs Outdated
@MistEO
Copy link
Copy Markdown
Owner

MistEO commented Apr 3, 2026

感觉不太对,我们是一个 GUI,我觉得不应该设计这么复杂的输出逻辑,说不好听点这完全就是为了给 MAS 的业务铺路,很奇怪

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

那我恢复我那版不复杂解析,单纯把ui日志转发到管道的?

@DLmaster361
Copy link
Copy Markdown
Contributor

DLmaster361 commented Apr 3, 2026

但是作为gui,没有输出具备可读性的日志,全部都是冗长的人类不可读的的日志条目,对于第三方调度来说,门槛太高了,好歹给个可读的日志,MAS 现在自己可以解析这个复杂日志,但经常失败,太痛苦了...

即使脱离 MAS 这边的需求,给未来 linux 版本的用户做一个可读的终端日志打印,我认为也是值得的

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

要不我这边先把verbose解析逻辑去掉,然后你们讨论一下开个新pr

@ShadowLemoon ShadowLemoon changed the title feat: 添加命令行选项支持stdout分级输出日志 feat: 添加命令行选项支持stdout输出可读日志 Apr 3, 2026
Comment thread src-tauri/src/commands/maa_core.rs Outdated
// 关闭 MaaFramework C++ 端的 stdout 日志输出(仅 --log-stdout 模式)。
// 必须在 Toolkit::init_option 之后调用,因为 init_option 内部的
// apply_option() 会根据配置文件重设 stdout_level(默认 error)。
if super::console::is_log_stdout() {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉不需要这个,有点奇怪。maafw 的日志有单独的控制的,不应该受这个选项影响。两码事.jpg

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个不关掉,会有极其大量的mfw不可读日志污染

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

怎么会呢,除非你手动改过 config/maa_option (

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

比如游戏崩溃的情况 会冒一大堆err

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

还有时不时的info冒出来

Copy link
Copy Markdown
Owner

@MistEO MistEO Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那是要的啊,出问题了终端 error 也非常合理吧


这个 PR 我觉得就是,MXU 缺少终端输出运行信息,所以补上,这很合理。但我们不会为了第三方解析或者调度帮他做什么额外适配

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我认为还是加个参数可以关掉比较好,因为终端容量是有限的,这些不可读日志没法看

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对于人来说,我在终端只需要关心它的状态,具体为什么报错肯定是日志文件解析

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

手动改下 config/maa_option 就能关了

Comment thread src-tauri/src/commands/console.rs Outdated
@@ -0,0 +1,36 @@
//! 控制台日志输出系统
//!
//! 处理 `--log-stdout` 参数解析,仅在管道/重定向场景下输出格式化日志。
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个参数也不用了吧,默认输出就行了

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug情况下需要详细日志 这个输出反而会污染

@MistEO MistEO merged commit 46a2eff into MistEO:main Apr 4, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stdout输出可读日志

4 participants