Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions FIX_SUBMISSION.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
```python
import argparse

def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('type', choices=['bug', 'feature'])
parser.add_argument('message', nargs='+')
parser.add_argument('--session', help='session ID')
return parser.parse_args()

def save_feedback(args):
message = ' '.join(args.message)
if args.session:
# Save feedback with session ID
feedback = {'type': args.type, 'message': message, 'session_id': args.session}
else:
# Save feedback without session ID
feedback = {'type': args.type, 'message': message}
# Save feedback to file
with open('~/.cortex/feedback/feedback.json', 'w') as f:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fixed filename will overwrite previous feedback submissions.

The Rust CLI in bins/bounty-cli/src/main.rs uses timestamped filenames ({timestamp}.json) to preserve each submission. This script uses a fixed feedback.json, so every new submission discards the previous one.

🔧 Proposed fix to match Rust behavior
+import time
+
 def save_feedback(args):
     # ...
-    with open(os.path.join(feedback_dir, 'feedback.json'), 'w') as f:
+    filename = f'{int(time.time())}.json'
+    with open(os.path.join(feedback_dir, filename), 'w') as f:
         json.dump(feedback, f)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@FIX_SUBMISSION.patch` at line 20, Currently the script always writes to
'~/.cortex/feedback/feedback.json' which overwrites previous submissions; change
the file creation logic used in the open(...) call to mirror the Rust CLI
behavior by generating a unique timestamped filename (e.g. include a UTC
timestamp or ISO datetime) and expanding the user path before opening; also
ensure the directory exists (create ~/.cortex/feedback if missing) and then open
the timestamped file for writing so each submission is preserved (refer to the
existing open('~/.cortex/feedback/feedback.json', 'w') usage to locate the
change).

import json
json.dump(feedback, f)
Comment on lines +20 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: ~ is not expanded by Python's open().

The path '~/.cortex/feedback/feedback.json' will be interpreted literally, attempting to create a directory named ~ in the current working directory rather than resolving to the user's home directory. Use os.path.expanduser() or pathlib.Path.

Additionally, the directory may not exist, causing a FileNotFoundError.

🐛 Proposed fix
+import os
+
 def save_feedback(args):
     message = ' '.join(args.message)
     if args.session:
         # Save feedback with session ID
         feedback = {'type': args.type, 'message': message, 'session_id': args.session}
     else:
         # Save feedback without session ID
         feedback = {'type': args.type, 'message': message}
     # Save feedback to file
-    with open('~/.cortex/feedback/feedback.json', 'w') as f:
-        import json
+    feedback_dir = os.path.expanduser('~/.cortex/feedback')
+    os.makedirs(feedback_dir, exist_ok=True)
+    with open(os.path.join(feedback_dir, 'feedback.json'), 'w') as f:
         json.dump(feedback, f)

Also move import json to the top of the file alongside import os.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@FIX_SUBMISSION.patch` around lines 20 - 22, The open(...) call uses a literal
'~' so expand the user's home and ensure the parent directory exists before
writing: replace the string literal passed to open in the block containing
open('~/.cortex/feedback/feedback.json', 'w') with a path created via
os.path.expanduser(...) or pathlib.Path.home()/joinpath and call
os.makedirs(..., exist_ok=True) (or Path.mkdir(parents=True, exist_ok=True)) on
the parent directory first to avoid FileNotFoundError; also move import json to
the module top alongside import os as suggested so json.dump(feedback, f)
remains valid.


def main():
args = parse_args()
save_feedback(args)

if __name__ == '__main__':
main()
```
28 changes: 26 additions & 2 deletions bins/bounty-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod views;
use anyhow::Result;
use console::style;
use dialoguer::{Input, Select};
use structopt::StructOpt;

const DEFAULT_RPC_URL: &str = "https://chain.platform.network";

Expand All @@ -19,8 +20,19 @@ const MENU_ITEMS: &[&str] = &[
"Claim Bounty",
"Change RPC URL",
"Quit",
"Cortex Feedback",
];

#[derive(StructOpt)]
struct CortexFeedback {
#[structopt(short = "s", long = "session")]
session: Option<String>,
#[structopt(short = "b", long = "bug")]
bug: Option<String>,
#[structopt(short = "m", long = "message")]
message: String,
}

Comment on lines +26 to +35
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The bug field is accepted but silently discarded.

CortexFeedback defines a bug field with -b/--bug, but lines 89-92 only persist session_id and message to JSON—the bug value is never written.

If this field should be persisted:

 let json = serde_json::json!({
     "session_id": feedback.session.unwrap_or_default(),
+    "bug": feedback.bug,
     "message": feedback.message,
 });

If the field is intentionally ignored, remove it from the struct to avoid confusing users who provide --bug expecting it to be saved.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bins/bounty-cli/src/main.rs` around lines 26 - 35, CortexFeedback declares a
bug field that is currently accepted but never persisted; update the code path
that builds the JSON payload (the logic that writes session_id and message) to
include the bug value (e.g., add a "bug" key with CortexFeedback.bug when Some)
so user-provided --bug/-b is saved, or if you prefer to intentionally ignore it
remove the bug field from the CortexFeedback struct to avoid confusion; ensure
any serialization/struct-to-JSON helper and related tests are updated
accordingly.

fn print_header(rpc_url: &str) {
println!();
println!(" {}", style("bounty-challenge").cyan().bold());
Expand Down Expand Up @@ -69,7 +81,19 @@ async fn main() -> Result<()> {
);
Ok(())
}
9 => break,
9 => {
let feedback = CortexFeedback::from_args();
let mut file_path = std::path::PathBuf::from("~/.cortex/feedback");
file_path.push(format!("{}.json", chrono::Utc::now().timestamp()));
let mut file = std::fs::File::create(file_path)?;
let json = serde_json::json!({
"session_id": feedback.session.unwrap_or_default(),
"message": feedback.message,
});
serde_json::to_writer_pretty(&mut file, &json)?;
Ok(())
}
Comment on lines +84 to +95
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Multiple critical issues in feedback handler.

  1. Wrong context for from_args() (Line 85): This code runs when a user selects menu item 9 interactively. CortexFeedback::from_args() parses CLI arguments from program launch, not from interactive input. Users will get an error or unexpected behavior since no --message argument exists at that point.

  2. Tilde not expanded (Line 86): PathBuf::from("~/.cortex/feedback") does NOT expand ~. This creates a literal directory named ~ in the current working directory. Use dirs::home_dir() or std::env::var("HOME") instead.

  3. Directory may not exist (Line 88): File::create will fail if ~/.cortex/feedback/ doesn't exist. Add std::fs::create_dir_all().

  4. Missing dependency: chrono is not in the Cargo manifest.

  5. Guideline violation: Uses synchronous file I/O in an async context. Per coding guidelines, database and file operations should be async using tokio.

🐛 Proposed fix
 9 => {
-    let feedback = CortexFeedback::from_args();
-    let mut file_path = std::path::PathBuf::from("~/.cortex/feedback");
+    // Prompt user for feedback in interactive mode
+    let message: String = Input::new()
+        .with_prompt("Enter feedback message")
+        .interact_text()?;
+    let session: String = Input::new()
+        .with_prompt("Session ID (optional)")
+        .allow_empty(true)
+        .interact_text()?;
+    
+    let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
+    let mut file_path = std::path::PathBuf::from(home);
+    file_path.push(".cortex/feedback");
+    std::fs::create_dir_all(&file_path)?;
     file_path.push(format!("{}.json", chrono::Utc::now().timestamp()));
     let mut file = std::fs::File::create(file_path)?;
     let json = serde_json::json!({
-        "session_id": feedback.session.unwrap_or_default(),
-        "message": feedback.message,
+        "session_id": session,
+        "message": message,
     });
     serde_json::to_writer_pretty(&mut file, &json)?;
+    println!("  {} Feedback saved.", style("✓").green());
     Ok(())
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bins/bounty-cli/src/main.rs` around lines 84 - 95, Replace the interactive
feedback handler that incorrectly calls CortexFeedback::from_args() with logic
that collects input interactively (e.g., prompt/read stdin or use an interactive
constructor on CortexFeedback) instead of parsing CLI args; expand the tilde by
resolving the user home (e.g., dirs::home_dir() or std::env::var("HOME")) rather
than PathBuf::from("~/.cortex/feedback"); ensure the directory exists before
creating the file by calling std::fs::create_dir_all (or the async equivalent)
on the parent path of file_path; switch synchronous file ops to Tokio async
equivalents (use tokio::fs::create_dir_all and tokio::fs::File::create /
tokio::io::AsyncWriteExt with serde_json::to_writer or serialize to string and
write) to comply with async guidelines; and add the chrono dependency to
Cargo.toml (or replace timestamp generation with an existing async-safe
timestamp source) so the timestamping code in the filename works.

10 => break,
_ => break,
};

Expand All @@ -84,4 +108,4 @@ async fn main() -> Result<()> {

println!("{}", style("Goodbye!").dim());
Ok(())
}
}
2 changes: 1 addition & 1 deletion bins/bounty-cli/src/tui/leaderboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,4 @@ pub async fn run(rpc_url: &str) -> Result<()> {

super::restore_terminal(&mut terminal)?;
Ok(())
}
}
30 changes: 30 additions & 0 deletions bins/bounty-cli/src/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ use crossterm::{
};
use ratatui::prelude::*;
use std::io;
use structopt::StructOpt;

#[derive(StructOpt)]
struct FeedbackOptions {
#[structopt(short = "s", long = "session")]
session: Option<String>,
#[structopt()]
message: String,
}

pub fn setup_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>> {
enable_raw_mode()?;
Expand All @@ -25,3 +34,24 @@ pub fn restore_terminal(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) -
terminal.show_cursor()?;
Ok(())
}

pub fn run_feedback(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) -> Result<()> {
let args: Vec<String> = std::env::args().collect();
let options = FeedbackOptions::from_args(&args[1..]);
let message = options.message;
let session = options.session;

if let Some(session_id) = session {
// Save feedback with session_id
println!("Feedback saved with session_id: {}", session_id);
// Save JSON with session_id and message
// ...
} else {
// Save feedback without session_id
println!("Feedback saved without session_id");
// Save JSON with message only
// ...
}

Ok(())
}
Comment on lines +38 to +57
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Incorrect StructOpt API usage and incomplete implementation.

  1. API Error (Line 40): FeedbackOptions::from_args(&args[1..]) is invalid. StructOpt::from_args() takes no arguments—it reads directly from std::env::args(). To parse a custom iterator, use from_iter() or from_iter_safe():

    let options = FeedbackOptions::from_iter(&args[1..]);
  2. Unused parameter: terminal is passed but never used.

  3. Incomplete implementation: The function has placeholder comments but no actual JSON persistence logic—meanwhile main.rs line 84-94 implements the real persistence. This function appears redundant.

  4. Guideline violation: Uses println! instead of tracing for logging. As per coding guidelines, errors should be logged with tracing.

Suggested removal or fix

If this function is intended to be used, fix the API and add actual logic:

-pub fn run_feedback(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) -> Result<()> {
-    let args: Vec<String> = std::env::args().collect();
-    let options = FeedbackOptions::from_args(&args[1..]);
+pub fn run_feedback(_terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) -> Result<()> {
+    let options = FeedbackOptions::from_args();

Otherwise, consider removing this dead code entirely since main.rs handles feedback directly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bins/bounty-cli/src/tui/mod.rs` around lines 38 - 57, The run_feedback
function currently misuses StructOpt (FeedbackOptions::from_args with args
slice), ignores the terminal parameter, uses println! instead of tracing, and
contains only placeholder persistence; either remove this dead function or fix
it: replace FeedbackOptions::from_args(&args[1..]) with
FeedbackOptions::from_iter or from_iter_safe on the args slice, implement the
actual JSON persistence logic (or delegate to the existing feedback handler used
in main), replace println! calls with tracing::info/tracing::error, and either
use the terminal parameter (if TUI is intended) or remove it from run_feedback's
signature to avoid an unused parameter and duplication with main's feedback
flow.