Skip to content

Conversation

@eudresfs
Copy link

@eudresfs eudresfs commented Dec 31, 2025

Summary

  • Add new oh-my-opencode logs CLI command for viewing and managing plugin logs
  • Enables users to self-diagnose issues without manually finding log files
  • Complements the existing doctor command for debugging

Features

Command Description
logs Show last 50 log entries with colors
logs -n 100 Show last 100 entries
logs -f Follow logs in real-time (tail -f style)
logs --level error Filter by level (all, info, warn, error)
logs --json Output in JSON format for automation
logs --clear Clear the log file
logs --path Show log file path

Files Added

src/cli/logs/
├── types.ts       # Interfaces (LogsOptions, LogEntry, LogLevel)
├── constants.ts   # Colors, symbols, keywords
├── parser.ts      # Log line parser
├── formatter.ts   # Output formatting
├── runner.ts      # Main command logic
├── index.ts       # Barrel export
└── logs.test.ts   # 22 tests

Test Plan

  • bun test src/cli/logs/logs.test.ts passes (22 tests)
  • bun run build succeeds
  • Manual testing of all command options

Summary by cubic

Add a new oh-my-opencode logs CLI command to view, filter, and follow plugin logs. This helps users quickly diagnose issues and complements the doctor command.

  • New Features
    • View last N entries (default 50) with colored formatting.
    • Filter by level: all, info, warn, error.
    • Follow logs in real time (tail -f style).
    • Output logs as JSON for automation.
    • Clear the log file or show its path.

Written for commit 02062e5. Summary will update on new commits.

Add new CLI command to view, filter, and manage oh-my-opencode logs:

- View last N log entries with colors and formatting
- Filter by log level (all, info, warn, error)
- Follow logs in real-time (tail -f style)
- Output in JSON format for automation
- Clear log file
- Show log file path

Includes 22 tests for parser functionality.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 31, 2025

All contributors have signed the CLA. Thank you! ✅
Posted by the CLA Assistant Lite bot.

@greptile-apps
Copy link

greptile-apps bot commented Dec 31, 2025

Greptile Summary

Adds logs command to CLI for viewing and managing plugin logs. Implements view, follow, filter, clear, and path operations with colored output and JSON format support.

Key changes:

  • Registered new logs subcommand in CLI with 6 options (-n, -f, --level, --json, --clear, --path)
  • Created log parser that extracts timestamp, message, JSON data, source component, and detected log level
  • Implements real-time log following with 500ms polling interval
  • Provides filtering by log level (all/info/warn/error) based on keyword detection

Issues found:

  • parser.ts:64 contains a greedy regex bug that will misparse log messages containing braces

Confidence Score: 3/5

  • Safe to merge with fix for JSON parsing bug
  • Well-structured implementation with comprehensive tests, but contains a critical regex bug in parser.ts that will cause incorrect parsing when log messages contain braces. The bug is fixable and isolated to one line.
  • src/cli/logs/parser.ts requires fixing the greedy regex on line 64

Important Files Changed

Filename Overview
src/cli/logs/parser.ts Adds log parsing with greedy JSON regex that can misparse messages containing braces
src/cli/logs/runner.ts Implements logs command with view, follow, clear, and path operations
src/cli/index.ts Adds logs command registration to CLI with options and help text

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as CLI (index.ts)
    participant Runner as logs/runner.ts
    participant Parser as logs/parser.ts
    participant Formatter as logs/formatter.ts
    participant Logger as shared/logger.ts
    participant FS as File System

    User->>CLI: bunx oh-my-opencode logs [options]
    CLI->>Runner: logs(options)
    
    alt --path flag
        Runner->>Logger: getLogFilePath()
        Logger-->>Runner: log file path
        Runner->>Formatter: formatPath()
        Formatter-->>Runner: formatted path
        Runner-->>User: display path
    else --clear flag
        Runner->>FS: writeFileSync(logPath, "")
        Runner->>Formatter: formatSuccess()
        Formatter-->>Runner: success message
        Runner-->>User: "Logs cleared"
    else --follow flag
        Runner->>FS: readFileSync(logPath)
        FS-->>Runner: initial content
        Runner->>Parser: parseLogFile(content)
        Parser->>Parser: parseLogLine() for each line
        Parser->>Parser: detectLevel(), extractSource(), extractJsonData()
        Parser-->>Runner: LogEntry[]
        Runner->>Parser: filterByLevel(), getLastNEntries()
        Parser-->>Runner: filtered entries
        Runner->>Formatter: formatLogEntries() / formatJsonOutput()
        Formatter-->>Runner: formatted output
        Runner-->>User: display initial logs
        loop Every 500ms
            Runner->>FS: readFileSync(logPath)
            FS-->>Runner: current content
            Runner->>Parser: parseLogFile(content)
            Parser-->>Runner: all entries
            Runner->>Runner: compare with lastEntries
            alt new entries detected
                Runner->>Parser: filterByLevel(newEntries)
                Parser-->>Runner: filtered new entries
                Runner->>Formatter: formatLogEntries() / formatJsonOutput()
                Formatter-->>Runner: formatted output
                Runner-->>User: display new logs
            end
        end
    else default view
        Runner->>FS: readFileSync(logPath)
        FS-->>Runner: file content
        Runner->>Parser: parseLogFile(content)
        Parser->>Parser: parseLogLine() for each line
        Parser->>Parser: detectLevel(), extractSource(), extractJsonData()
        Parser-->>Runner: LogEntry[]
        Runner->>Parser: filterByLevel(entries, level)
        Parser-->>Runner: filtered entries
        Runner->>Parser: getLastNEntries(filtered, lines)
        Parser-->>Runner: last N entries
        Runner->>Formatter: formatLogEntries() / formatJsonOutput()
        Formatter-->>Runner: formatted output
        Runner-->>User: display logs
    end
    
    Runner-->>CLI: exit code
    CLI-->>User: process.exit()
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (1)

  1. src/cli/logs/parser.ts, line 64 (link)

    logic: greedy regex will incorrectly parse messages containing braces. If message is "User {username} failed" with data {"error": "timeout"}, regex matches from first { in message to last } in JSON, treating {username} failed {"error": "timeout"} as JSON.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link

@cubic-dev-ai cubic-dev-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.

4 issues found across 8 files

Confidence score: 3/5

  • src/cli/index.ts still leaves lines as NaN when the user passes a non-numeric count, so the CLI can behave unpredictably instead of falling back to 50 lines.
  • src/cli/logs/types.ts allows LogEntry objects with level: "all", blurring filter vs entry semantics and risking incorrect downstream handling.
  • Smaller polish gaps remain (unreachable tail code in src/cli/logs/runner.ts and the singular/plural wording in src/cli/logs/formatter.ts), suggesting the CLI experience could be tightened further.
  • Pay close attention to src/cli/index.ts, src/cli/logs/types.ts - input validation and log-level typing still need refinement.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/cli/logs/types.ts">

<violation number="1" location="src/cli/logs/types.ts:37">
P2: Type `LogLevel` conflates two different concepts: filter levels (where &quot;all&quot; means no filtering) and entry levels (where &quot;all&quot; is invalid). A `LogEntry` should never have `level: &quot;all&quot;`, but the current type allows it. Consider separating these:

```typescript
export type LogLevel = &quot;info&quot; | &quot;warn&quot; | &quot;error&quot;
export type LogLevelFilter = &quot;all&quot; | LogLevel

Then use LogLevelFilter for LogsOptions.level and LogLevel for LogEntry.level.

P3: Incorrect pluralization when count is 1 - outputs "1 entries" instead of "1 entry". Consider handling singular/plural cases. P2: `parseInt` returns `NaN` for invalid input, but `??` doesn't catch `NaN` values. If a user types `logs -n abc`, `lines` will be `NaN` instead of falling back to `50`. Consider using `|| 50` instead, or add explicit validation: `Number.isNaN(options.lines) ? 50 : (options.lines ?? 50)`. P2: Unreachable code: `return 0` after `await new Promise(() => {})` will never execute because the promise never resolves. The function only exits via `process.exit(0)` in the signal handlers. Consider removing the unreachable return statement or using a different pattern. ```

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@eudresfs
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Dec 31, 2025
- Separate LogLevel (info/warn/error) from LogLevelFilter (all + LogLevel)
- Fix pluralization in formatLogCount (1 entry vs N entries)
- Handle NaN from parseInt for --lines option
- Refactor followLogs to use Promise resolution instead of process.exit
Copy link

@cubic-dev-ai cubic-dev-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 issue found across 6 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/cli/logs/runner.ts">

<violation number="1" location="src/cli/logs/runner.ts:152">
P2: Signal listeners are never removed after cleanup. Add `process.off()` calls to prevent potential listener accumulation in tests or if the function is reused.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

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.

1 participant