Skip to content

Conversation

@rossmanko
Copy link
Contributor

@rossmanko rossmanko commented Nov 29, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced "No local connections" UI with a command snippet and copy-to-clipboard (with success toast) to enable local execution.
  • Bug Fixes

    • Loosened branch-indicator visibility so it appears when appropriate even if the branched-from title is absent.
  • Documentation

    • Updated all local CLI invocation examples and docs to use the @latest version tag.
  • Chores

    • Updated a social link URL in the sidebar.

✏️ Tip: You can customize this high-level summary in your review settings.

…r UI

- Update all CLI command examples to use @hackerai/local@latest
- Add copy button and improved styling to execution environment selector
- Update documentation and help text with @latest version specifier
@vercel
Copy link

vercel bot commented Nov 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
hackerai Ready Ready Preview Comment Nov 29, 2025 11:43pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 29, 2025

Walkthrough

Updates local CLI invocation to use @hackerai/local@latest across UI and docs, replaces the isLocalSandbox boolean with an exported isE2BSandbox type-guard and adapts runtime options for E2B sandboxes, enhances the SandboxSelector "no connections" UI with a copy button and toast, and loosens branch-indicator visibility in Messages.

Changes

Cohort / File(s) Summary
Local execution package updates
app/components/AgentsTab.tsx, packages/local/README.md, packages/local/src/index.ts
Replace untagged invocations with @hackerai/local@latest in UI command snippets and docs; minor formatting change in packages/local/src/index.ts.
Sandbox detection & runtime options
lib/ai/tools/index.ts, lib/ai/tools/run-terminal-cmd.ts, types/agent.ts
Introduce exported type-guard isE2BSandbox(s) and replace isLocalSandbox boolean with isE2BSandbox in ToolContext; use isE2BSandbox at runtime to conditionally inject { user: "root", cwd: "/home/user" } and simplify E2B-specific messaging.
SandboxSelector UI enhancement
app/components/SandboxSelector.tsx
Replace plain "No local connections" text with a two-line block showing npx @hackerai/local@latest, add a Copy icon/button and toast feedback; import Copy (lucide-react) and toast (sonner).
Messages & small UI formatting
app/components/Messages.tsx, components/ui/badge.tsx
Relax branch-indicator condition to no longer require branchedFromChatTitle truthiness; reflow BadgeProps extends clause (formatting only).
Chat handler formatting
lib/api/chat-handler.ts
Whitespace/indentation adjustments around a conditional expression; no behavior change.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Attention areas:
    • types/agent.ts and lib/ai/tools/index.ts: ensure IsE2BSandboxFn typing and exported isE2BSandbox semantics are correct and all call sites updated.
    • lib/ai/tools/run-terminal-cmd.ts: verify conditional injection of user/cwd only for E2B sandboxes and that retry/timeout messaging remains correct.
    • app/components/SandboxSelector.tsx: test copy-to-clipboard behavior and toast display in different browsers/permission contexts.

Possibly related PRs

  • #98 — Modifies lib/ai/tools/run-terminal-cmd.ts with related sandbox execution and runtime option changes.
  • #72 — Touches sandbox execution logic and PID/background handling in lib/ai/tools/run-terminal-cmd.ts, related to E2B behavior.
  • #114 — Overlaps local-sandbox integration (README and local package changes) and UI snippets referencing the local CLI.

Poem

🐰 I nibble on code with a curious bite,
I tag the local CLI to latest light,
I guard E2B sandboxes with a keen-eyed cheer,
I copy commands and toast when friends draw near,
Hoppity hops — new bits deployed, hip hooray! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Daily branch 2025 11 29' is a generic date-based label that does not convey any meaningful information about the actual changes in the pull request. Consider revising the title to summarize the primary changes, such as 'Update local package references to @latest and refactor sandbox type detection' or a more specific description of the main objectives.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch daily-branch-2025-11-29

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b6c9c1 and 8dfb40d.

📒 Files selected for processing (1)
  • app/components/SidebarUserNav.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: fkesheh
Repo: hackerai-tech/hackerai PR: 114
File: lib/ai/tools/utils/convex-sandbox.ts:95-145
Timestamp: 2025-11-28T01:16:26.536Z
Learning: In the local sandbox architecture (lib/ai/tools/utils/convex-sandbox.ts), background command execution semantics are handled by the local sandbox client (packages/local/src/index.ts), not by the ConvexSandbox class. When background: true, the local client immediately submits a result with empty output and PID after spawning the process, causing waitForResult() to resolve immediately and maintaining E2B-compatible non-blocking behavior.
🔇 Additional comments (1)
app/components/SidebarUserNav.tsx (1)

129-137: X/Twitter link target update looks good

The only change is the destination URL in handleXCom; existing window.open usage with "noopener,noreferrer" and newWindow.opener = null is preserved, so behavior and security posture remain correct.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
app/components/SandboxSelector.tsx (1)

201-224: Consider adding error handling for clipboard operations.

The navigator.clipboard.writeText call can fail in certain contexts (e.g., insecure origins, permission denied). Consider wrapping it in a try-catch for robustness.

                 <Button
                   variant="outline"
                   size="icon"
                   className="shrink-0 h-8 w-8"
-                  onClick={() => {
-                    navigator.clipboard.writeText("npx @hackerai/local@latest");
-                    toast.success("Command copied to clipboard");
+                  onClick={async () => {
+                    try {
+                      await navigator.clipboard.writeText("npx @hackerai/local@latest");
+                      toast.success("Command copied to clipboard");
+                    } catch {
+                      toast.error("Failed to copy to clipboard");
+                    }
                   }}
                 >

That said, the existing handleCopyCommand function in AgentsTab.tsx also lacks error handling, so this pattern is consistent with the codebase. Feel free to defer this improvement.

lib/ai/tools/index.ts (1)

23-29: Exported isE2BSandbox guard is correct; consider deduplicating helper

The new isE2BSandbox implementation and its usage in the sandbox managers and ToolContext are type‑safe and behaviorally sound for discriminating E2B vs local sandboxes.

However, there is already an isE2BSandbox helper in lib/ai/tools/utils/sandbox-types.ts with the same logic. Having two independent implementations increases the risk of drift if the discriminator ever changes. Consider centralizing this guard in one module (e.g., re‑export from sandbox-types or import it here) and removing the duplicate.

Also applies to: 47-65, 71-82

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb97916 and 4b6c9c1.

📒 Files selected for processing (10)
  • app/components/AgentsTab.tsx (3 hunks)
  • app/components/Messages.tsx (1 hunks)
  • app/components/SandboxSelector.tsx (3 hunks)
  • components/ui/badge.tsx (1 hunks)
  • lib/ai/tools/index.ts (2 hunks)
  • lib/ai/tools/run-terminal-cmd.ts (2 hunks)
  • lib/api/chat-handler.ts (1 hunks)
  • packages/local/README.md (3 hunks)
  • packages/local/src/index.ts (1 hunks)
  • types/agent.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-11-28T01:16:26.484Z
Learnt from: fkesheh
Repo: hackerai-tech/hackerai PR: 114
File: lib/ai/tools/utils/convex-sandbox.ts:95-145
Timestamp: 2025-11-28T01:16:26.484Z
Learning: In the local sandbox architecture (lib/ai/tools/utils/convex-sandbox.ts), background command execution semantics are handled by the local sandbox client (packages/local/src/index.ts), not by the ConvexSandbox class. When background: true, the local client immediately submits a result with empty output and PID after spawning the process, causing waitForResult() to resolve immediately and maintaining E2B-compatible non-blocking behavior.

Applied to files:

  • types/agent.ts
  • app/components/AgentsTab.tsx
  • lib/ai/tools/index.ts
  • lib/ai/tools/run-terminal-cmd.ts
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Use the `api` object from `convex/_generated/api.ts` to call public functions registered with `query`, `mutation`, or `action`

Applied to files:

  • app/components/AgentsTab.tsx
  • app/components/SandboxSelector.tsx
📚 Learning: 2025-11-12T15:23:01.117Z
Learnt from: fkesheh
Repo: hackerai-tech/hackerai PR: 92
File: lib/ai/tools/utils/sandbox-file-uploader.ts:10-10
Timestamp: 2025-11-12T15:23:01.117Z
Learning: In the hackerai codebase, NEXT_PUBLIC_USE_S3_STORAGE is intentionally used in both client and server code (including server-only files like lib/ai/tools/utils/sandbox-file-uploader.ts) to ensure the frontend and backend stay in sync regarding which storage backend (S3 vs Convex) is being used. This consistency is important for file upload flows that span both environments.

Applied to files:

  • app/components/AgentsTab.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Organize public query, mutation, or action functions thoughtfully within the `convex/` directory using file-based routing

Applied to files:

  • app/components/AgentsTab.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Use the `internal` object from `convex/_generated/api.ts` to call internal functions registered with `internalQuery`, `internalMutation`, or `internalAction`

Applied to files:

  • app/components/AgentsTab.tsx
  • app/components/SandboxSelector.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Convex uses file-based routing; a public function defined in `convex/example.ts` named `f` has a function reference of `api.example.f`

Applied to files:

  • app/components/AgentsTab.tsx
📚 Learning: 2025-09-01T12:44:12.626Z
Learnt from: RostyslavManko
Repo: hackerai-tech/hackerai PR: 17
File: convex/fileStorage.ts:131-149
Timestamp: 2025-09-01T12:44:12.626Z
Learning: In convex/fileStorage.ts, serviceKey parameters are made optional (v.optional(v.string())) for queries like getFileTokensByFileIds to simplify local development workflow - developers don't need to configure service keys in the Convex dashboard when working locally. In production, the serviceKey is always provided, ensuring security. This pattern balances developer experience with production security requirements.

Applied to files:

  • app/components/AgentsTab.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Use `internalQuery`, `internalMutation`, and `internalAction` to register private functions; these are only callable by other Convex functions

Applied to files:

  • app/components/AgentsTab.tsx
  • app/components/SandboxSelector.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/schema.ts : Always define schema in `convex/schema.ts` and import schema definition functions from `convex/server`

Applied to files:

  • app/components/AgentsTab.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Try to use as few calls from actions to queries and mutations as possible to minimize race condition risk

Applied to files:

  • app/components/SandboxSelector.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Use `query`, `mutation`, and `action` to register public functions that are exposed to the public API

Applied to files:

  • app/components/SandboxSelector.tsx
📚 Learning: 2025-11-24T20:59:07.600Z
Learnt from: CR
Repo: hackerai-tech/hackerai PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-24T20:59:07.600Z
Learning: Applies to convex/**/*.{ts,tsx} : Use `ctx.runQuery` to call a query from a query, mutation, or action

Applied to files:

  • app/components/SandboxSelector.tsx
🧬 Code graph analysis (2)
lib/ai/tools/run-terminal-cmd.ts (2)
lib/ai/tools/index.ts (1)
  • isE2BSandbox (27-29)
lib/ai/tools/utils/sandbox-types.ts (1)
  • isE2BSandbox (8-10)
app/components/SandboxSelector.tsx (1)
components/ui/button.tsx (1)
  • Button (59-59)
🔇 Additional comments (11)
lib/api/chat-handler.ts (1)

453-459: LGTM!

The formatting change improves readability of the shouldPersist conditional without altering the logic.

packages/local/README.md (1)

8-8: LGTM!

Using @latest ensures users always install the most recent version of the local sandbox client. This is consistent with the UI component updates and is appropriate for a frequently updated CLI tool.

packages/local/src/index.ts (1)

381-388: LGTM!

The multi-line formatting improves readability of the capabilities constant. The runtime value remains unchanged.

app/components/AgentsTab.tsx (2)

30-31: LGTM!

The comment correctly documents the @latest version requirement for the local package.


349-380: LGTM!

All command blocks consistently use @hackerai/local@latest for both displayed and copied commands, ensuring users always get the latest version.

components/ui/badge.tsx (1)

26-29: LGTM!

Formatting improvement for the interface declaration. No functional changes.

app/components/Messages.tsx (1)

307-312: LGTM!

The branch indicator condition is correctly structured, requiring all necessary fields (branchedFromChatId, branchedFromChatTitle, valid branchBoundaryIndex, and matching index) before rendering. The non-null assertions on lines 546-548 are safe given this guard.

Note: The AI summary incorrectly states that branchedFromChatTitle is no longer required, but the code clearly shows it remains part of the condition.

app/components/SandboxSelector.tsx (1)

5-12: LGTM!

Clean import additions for the Copy icon and Check icon.

types/agent.ts (1)

13-15: IsE2BSandboxFn alias and ToolContext wiring look consistent

The type guard signature matches the runtime implementation and the new ToolContext.isE2BSandbox field gives downstream code a safer discriminator than the previous boolean flag. No issues from a typing or usage perspective.

Also applies to: 26-37

lib/ai/tools/run-terminal-cmd.ts (2)

18-25: Context destructuring and updated wait instructions look consistent

Using isE2BSandbox from ToolContext and updating the guidance strings to describe the tail --pid … -f /dev/null workflow is consistent with the new sandbox‑type detection and timeout behavior. No functional issues here.

Also applies to: 37-40


248-261: I'll help you verify the issues raised in the review comment. Let me start by examining the code and gathering the necessary information.
<function_calls>

find . -type f -name ".ts" -o -name ".js" | head -20

</function_calls>

Let me search for the specific file and the constant mentioned:
<function_calls>

rg -n "MAX_COMMAND_EXECUTION_TIME" --type ts --type js

</function_calls>

Now let me look at the file under review:
<function_calls>

wc -l lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

sed -n '240,270p' lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

sed -n '270,300p' lib/ai/tools/run-terminal-cmd.ts

</function_calls>

Let me also check the broader context to find where MAX_COMMAND_EXECUTION_TIME is defined:
<function_calls>

sed -n '1,50p' lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

rg -n "MAX_COMMAND_EXECUTION_TIME\s*=" lib/ai/tools/run-terminal-cmd.ts

</function_calls>

Let me search more broadly for this constant:
<function_calls>

rg -A 2 "MAX_COMMAND_EXECUTION_TIME" --type ts --type js | head -30

</function_calls>

Let me check a wider range of the file:
<function_calls>

head -100 lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

grep -n "10|7|minute|TIMEOUT" lib/ai/tools/run-terminal-cmd.ts | head -20

</function_calls>

Let me look at the constants file and search for timeout-related constants:
<function_calls>

rg -n "const.*TIMEOUT|const.TIME.=" lib/ai/tools/run-terminal-cmd.ts | head -30

</function_calls>

<function_calls>

sed -n '1,200p' lib/ai/tools/run-terminal-cmd.ts | tail -100

</function_calls>

Let me search for package.json to check the @e2b/code-interpreter version:
<function_calls>

find . -name "package.json" -type f

</function_calls>

<function_calls>

rg "@e2b/code-interpreter" package.json

</function_calls>

<function_calls>

cat package.json | grep -A 2 "@e2b"

</function_calls>

Let me get the full file to understand the structure better:
<function_calls>

cat -n lib/ai/tools/run-terminal-cmd.ts | head -150

</function_calls>

<function_calls>

rg -n "STREAM_TIMEOUT|TIMEOUT_MESSAGE" lib/ai/tools/run-terminal-cmd.ts

</function_calls>

Now let me search for the E2B sandbox usage patterns and the commands.run method:
<function_calls>

rg -n "commands.run|Sandbox" lib/ai/tools/run-terminal-cmd.ts | head -20

</function_calls>

Let me look at the full code section mentioned in the review (around lines 248-261 and 280-288):
<function_calls>

sed -n '230,300p' lib/ai/tools/run-terminal-cmd.ts | cat -n

</function_calls>

<function_calls>

sed -n '1,30p' lib/ai/tools/run-terminal-cmd.ts | cat -n

</function_calls>

Let me search for where user and cwd options are being passed:
<function_calls>

rg -n "user.*root|cwd.*home|{ user" lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

rg -B 5 -A 5 "isE2BSandbox" lib/ai/tools/run-terminal-cmd.ts

</function_calls>

Let me look for constants definitions:
<function_calls>

rg -n "^const|^export const" lib/ai/tools/run-terminal-cmd.ts | head -20

</function_calls>

<function_calls>

sed -n '1,100p' lib/ai/tools/run-terminal-cmd.ts

</function_calls>

Let me check for the constants in a separate constants file:
<function_calls>

find . -name "constants" -o -name "const" | grep -E ".(ts|js)$" | head -20

</function_calls>

<function_calls>

rg -l "MAX_COMMAND_EXECUTION_TIME" --type ts --type js

</function_calls>

<function_calls>

rg "MAX_COMMAND_EXECUTION_TIME" --type ts --type js -B 2 -A 2

</function_calls>

Let me look at the entire run-terminal-cmd.ts file to understand its structure:
<function_calls>

wc -l lib/ai/tools/run-terminal-cmd.ts && echo "---" && head -200 lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

tail -200 lib/ai/tools/run-terminal-cmd.ts | head -100

</function_calls>

Let me search for all constant definitions related to time/timeout:
<function_calls>

rg "const.=.(600000|420000|10.*min|7.*min|[0-9]{6})" lib/ai/tools/run-terminal-cmd.ts

</function_calls>

<function_calls>

rg "* 60.*1000|* 1000" lib/ai/tools/run-terminal-cmd.ts

</function_calls>

Let me look at the entire file structure more carefully:
<function_calls>

cat lib/ai/tools/run-terminal-cmd.ts | grep -n "const|export|TIMEOUT|10|420|600" | head -50

</function_calls>

Let me try a different approach and check the git diff or nearby files:
<function_calls>

git diff HEAD~5 lib/ai/tools/run-terminal-cmd.ts 2>/dev/null | head -200 || echo "Git not available or no recent changes"

</function_calls>

Let me read the file more systematically:
<function_calls>

python3 << 'EOF'
with open('lib/ai/tools/run-terminal-cmd.ts', 'r') as f:
lines = f.readlines()
for i, line in enumerate(lines[:100], 1):
if any(keyword in line.lower() for keyword in ['timeout', 'max_command', 'execution', 'const ', 'export']):
print(f"{i}: {line.rstrip()}")
EOF


</function_calls>

<function_calls>

python3 << 'EOF'
with open('lib/ai/tools/run-terminal-cmd.ts', 'r') as f:
lines = f.readlines()
# Print lines 248-261 and 280-288
print("=== Lines 248-261 ===")
for i in range(247, 261):
print(f"{i+1}: {lines[i].rstrip()}")
print("\n=== Lines 280-288 ===")
for i in range(279, 288):
print(f"{i+1}: {lines[i].rstrip()}")
EOF


</function_calls>

<function_calls>

python3 << 'EOF'
with open('lib/ai/tools/run-terminal-cmd.ts', 'r') as f:
content = f.read()
# Find MAX_COMMAND_EXECUTION_TIME
if 'MAX_COMMAND_EXECUTION_TIME' in content:
idx = content.find('MAX_COMMAND_EXECUTION_TIME')
print("Found at character:", idx)
print(content[max(0, idx-500):idx+500])
else:
print("MAX_COMMAND_EXECUTION_TIME not found in file")
# Search for timeout related constants
import re
matches = re.finditer(r'const\s+\w*[Tt]imeout\w*\s*=.*', content)
for match in matches:
print(f"Found: {match.group()}")
EOF


</function_calls>

Now let me search for @e2b/code-interpreter documentation about the commands.run API:
<function_calls>

@e2b/code-interpreter v2.3.1 sandbox commands.run API documentation options parameters
</function_calls>

@rossmanko rossmanko merged commit 5eb4df7 into main Nov 30, 2025
4 checks passed
This was referenced Jan 3, 2026
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.

2 participants