-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
118 lines (95 loc) · 3.77 KB
/
app.py
File metadata and controls
118 lines (95 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Cursor Chat Browser — Python Edition
A Flask web application for browsing and managing chat histories
from the Cursor editor's AI chat feature.
"""
import sys
from datetime import datetime
from pathlib import Path
from flask import Flask, render_template, send_from_directory
from api.workspaces import bp as workspaces_bp
from api.composers import bp as composers_bp
from api.logs import bp as logs_bp
from api.search import bp as search_bp
from api.export_api import bp as export_bp
from api.pdf import bp as pdf_bp
from api.config_api import bp as config_bp
from utils.exclusion_rules import resolve_exclusion_rules_path, load_rules
def _get_base_path():
"""Return the directory that contains templates/ and static/.
In a PyInstaller bundle the files live under sys._MEIPASS;
otherwise they sit next to this source file.
"""
if getattr(sys, "frozen", False):
return Path(sys._MEIPASS)
return Path(__file__).resolve().parent
def create_app(exclusion_rules_path=None):
base = _get_base_path()
app = Flask(
__name__,
static_folder=str(base / "static"),
template_folder=str(base / "templates"),
)
app.config["JSON_SORT_KEYS"] = False
# Exclusion rules: optional path (CLI or default ~/.cursor-chat-browser/exclusion-rules.txt).
# Rules are loaded once at startup; an app restart is required to pick up changes to the file.
resolved = resolve_exclusion_rules_path(exclusion_rules_path)
app.config["EXCLUSION_RULES_PATH"] = resolved
app.config["EXCLUSION_RULES"] = load_rules(resolved)
@app.context_processor
def inject_year():
return {"current_year": datetime.now().year}
# Register API blueprints
app.register_blueprint(workspaces_bp)
app.register_blueprint(composers_bp)
app.register_blueprint(logs_bp)
app.register_blueprint(search_bp)
app.register_blueprint(export_bp)
app.register_blueprint(pdf_bp)
app.register_blueprint(config_bp)
# ---------- Page routes ----------
@app.route("/")
def home():
return render_template("index.html")
@app.route("/config")
def config_page():
return render_template("config.html")
@app.route("/search")
def search_page():
return render_template("search.html")
@app.route("/workspace/<workspace_id>")
def workspace_page(workspace_id):
return render_template("workspace.html", workspace_id=workspace_id)
# Serve favicon
@app.route("/favicon.ico")
def favicon():
return send_from_directory(app.static_folder, "favicon.ico", mimetype="image/x-icon")
return app
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(description="Cursor Chat Browser (Python)")
parser.add_argument("--port", type=int, default=3000)
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--base-dir", default=None,
help="Override Cursor workspaceStorage path")
parser.add_argument(
"--exclude-rules", "-e",
default=None,
metavar="PATH",
help="Path to exclusion rules file (sensitive projects/chats are omitted). "
"If omitted, uses ~/.cursor-chat-browser/exclusion-rules.txt if present.",
)
args = parser.parse_args()
if args.base_dir:
from utils.workspace_path import set_workspace_path_override
set_workspace_path_override(args.base_dir)
app = create_app(exclusion_rules_path=args.exclude_rules)
print(f"Cursor Chat Browser (Python) running at http://{args.host}:{args.port}")
# Disable reloader on Windows to avoid a socket conflict with Flask's stat reloader.
app.run(
host=args.host,
port=args.port,
debug=True,
use_reloader=(sys.platform != "win32"),
)