feat(cli): add bolt logs command with tail and follow - #90
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📝 WalkthroughWalkthroughThe pull request adds a ChangesLogs command
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant CLI
participant LogsCommand
participant LogFile
participant DirectoryWatcher
CLI->>LogsCommand: Execute logs with tail and follow options
LogsCommand->>LogFile: Validate and read trailing lines
LogFile-->>LogsCommand: Return log content
LogsCommand-->>CLI: Print trailing lines
LogsCommand->>DirectoryWatcher: Watch the log directory
DirectoryWatcher-->>LogsCommand: Report appended or truncated data
LogsCommand->>LogFile: Read new bytes
LogsCommand-->>CLI: Print appended log data
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Comment |
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/opencode/src/cli/cmd/logs.ts (2)
9-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffNo automated tests for the new command.
The PR description mentions manual CLI verification with seeded and missing log files, but no test file is included for
LogsCommand's tail-count, missing-file, and truncation-reset behavior. Consider adding a small test to lock in this behavior for future changes.Do you want me to draft a test for the tail and missing-file paths?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/opencode/src/cli/cmd/logs.ts` around lines 9 - 52, Add focused automated coverage for LogsCommand, exercising tail-count output, the missing-log-file failure path, and follow-mode offset reset when the log is truncated. Reuse the command’s existing test conventions and mock filesystem/process output as needed, without changing the command behavior.
1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffUse the provided filesystem service and extract log-following logic.
FSUtil.ServiceextendsFileSystem.FileSystemand is available inAppRuntime. Use itswatchand offset-awarestreammethods instead of raw filesystem APIs. Move offset, truncation, and event handling into a helper belowLogsCommand.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/opencode/src/cli/cmd/logs.ts` around lines 1 - 2, Update LogsCommand to use the AppRuntime-provided FSUtil.Service rather than node:fs or node:path, and extract log-following into a helper below LogsCommand. Implement the helper with the service’s offset-aware stream and watch methods, preserving offset tracking, truncation handling, and filesystem event processing.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/opencode/src/cli/cmd/logs.ts`:
- Around line 27-32: Update the log-reading flow around FILE and Effect.promise
to use a fallible promise wrapper such as Effect.tryPromise, converting read
failures into the existing fail(...) CLI error path when the file is removed or
unreadable after the existence check. Also avoid buffering the entire file in
memory for --tail; use a streaming or seek-based approach that retrieves only
the requested final lines while preserving current empty-line and tail-count
behavior.
---
Nitpick comments:
In `@packages/opencode/src/cli/cmd/logs.ts`:
- Around line 9-52: Add focused automated coverage for LogsCommand, exercising
tail-count output, the missing-log-file failure path, and follow-mode offset
reset when the log is truncated. Reuse the command’s existing test conventions
and mock filesystem/process output as needed, without changing the command
behavior.
- Around line 1-2: Update LogsCommand to use the AppRuntime-provided
FSUtil.Service rather than node:fs or node:path, and extract log-following into
a helper below LogsCommand. Implement the helper with the service’s offset-aware
stream and watch methods, preserving offset tracking, truncation handling, and
filesystem event processing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 6b302e9c-0f11-4019-a7e2-3e3343a97d27
📒 Files selected for processing (2)
packages/opencode/src/cli/cmd/logs.tspackages/opencode/src/index.ts
| if (!fs.existsSync(FILE)) return yield* fail(`no log file at ${FILE}`) | ||
| const text = yield* Effect.promise(() => Bun.file(FILE).text()) | ||
| const lines = text.split("\n") | ||
| if (lines.at(-1) === "") lines.pop() | ||
| const count = Math.max(0, Math.floor(args.tail)) | ||
| for (const line of lines.slice(-count)) console.log(line) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Guard against a race between the existence check and the read, and note the full-file read cost.
fs.existsSync(FILE) and Bun.file(FILE).text() are two separate operations. If the file is removed between them, Bun.file(FILE).text() rejects, and since it is wrapped in Effect.promise (which assumes the promise never rejects), the rejection surfaces as an unhandled defect instead of the CLI's normal fail(...) error path. Use Effect.tryPromise (or a similar fallible wrapper) so a missing/unreadable file after the initial check still produces a clean CLI error.
Separately, the whole log file is read into memory to compute the last --tail lines. For a long-lived, unrotated log this reads and buffers the entire file just to print a small tail.
🛡️ Proposed fix for the unhandled rejection path
- if (!fs.existsSync(FILE)) return yield* fail(`no log file at ${FILE}`)
- const text = yield* Effect.promise(() => Bun.file(FILE).text())
+ if (!fs.existsSync(FILE)) return yield* fail(`no log file at ${FILE}`)
+ const text = yield* Effect.tryPromise({
+ try: () => Bun.file(FILE).text(),
+ catch: () => new CliError({ message: `unable to read log file at ${FILE}`, exitCode: 1 }),
+ })📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!fs.existsSync(FILE)) return yield* fail(`no log file at ${FILE}`) | |
| const text = yield* Effect.promise(() => Bun.file(FILE).text()) | |
| const lines = text.split("\n") | |
| if (lines.at(-1) === "") lines.pop() | |
| const count = Math.max(0, Math.floor(args.tail)) | |
| for (const line of lines.slice(-count)) console.log(line) | |
| if (!fs.existsSync(FILE)) return yield* fail(`no log file at ${FILE}`) | |
| const text = yield* Effect.tryPromise({ | |
| try: () => Bun.file(FILE).text(), | |
| catch: () => new CliError({ message: `unable to read log file at ${FILE}`, exitCode: 1 }), | |
| }) | |
| const lines = text.split("\n") | |
| if (lines.at(-1) === "") lines.pop() | |
| const count = Math.max(0, Math.floor(args.tail)) | |
| for (const line of lines.slice(-count)) console.log(line) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/opencode/src/cli/cmd/logs.ts` around lines 27 - 32, Update the
log-reading flow around FILE and Effect.promise to use a fallible promise
wrapper such as Effect.tryPromise, converting read failures into the existing
fail(...) CLI error path when the file is removed or unreadable after the
existence check. Also avoid buffering the entire file in memory for --tail; use
a streaming or seek-based approach that retrieves only the requested final lines
while preserving current empty-line and tail-count behavior.
Issue for this PR
Closes #88
Type of change
What does this PR do?
Ports Crush's
crush logsto bolt. The agent appends everything to one file (~/.local/share/opencode/log/opencode.logviaGlobal.Path.log), but until now there was no CLI to read it.bolt logsprints the last 1000 lines (--tail <n>to change), and--follow/-fstreams new lines. It's aninstance: falsecommand so it skips project bootstrap entirely.Follow mode leans on the log being append-only:
Watching the directory rather than the file handles the file being recreated, and a shrinking size resets the offset instead of streaming garbage. Missing log file fails with a clear message via
fail().How did you verify your code works?
bun run typecheckinpackages/opencodebun src/index.ts logs --tail 2against a seeded log file and got exactly the last two lines; missing-file path prints the error and exits non-zeroScreenshots / recordings
CLI output only.
Checklist
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is enabled.Summary by CodeRabbit
logscommand to view recent application log entries.