Skip to content

Feat: Unbounded Dependency Pins in requirements.txt (Closes #47)#53

Open
bradjin8 wants to merge 6 commits into
masterfrom
feat/unbounded-dependency-pins
Open

Feat: Unbounded Dependency Pins in requirements.txt (Closes #47)#53
bradjin8 wants to merge 6 commits into
masterfrom
feat/unbounded-dependency-pins

Conversation

@bradjin8
Copy link
Copy Markdown
Collaborator

@bradjin8 bradjin8 commented May 19, 2026

Summary

Closes #47 — Unbounded Dependency Pins in requirements.txt

Changes

Bounded specifiers

  • requirements.txt: added missing upper bound on pillow (>=10.3.0,<11). flask and fpdf2 already had upper bounds from Missing pyproject.toml / No Python Packaging #45; now all three runtime deps are fully bounded.
  • pyproject.toml: same pillow upper bound applied to [project.dependencies] to keep both files in sync.

Lock file (requirements-lock.txt, new)

  • Generated by pip-compile (pip-tools) from the bounded requirements.txt.
  • Pins the full transitive closure to exact versions: flask==3.1.3, fpdf2==2.8.7, pillow==10.4.0, plus blinker, click, colorama, defusedxml, fonttools, itsdangerous, jinja2, markupsafe, werkzeug.
  • Header comment documents the exact pip-compile invocation to regenerate it.

CI (.github/workflows/tests.yml)

  • Both the unittest and typecheck jobs now install from requirements-lock.txt first, then layer the dev-only dep (pytest>=8,<9 / mypy>=1.10,<2) on top.
  • Replaces the old unbounded pip install 'flask>=3.0' 'fpdf2>=2.7' ... invocations.

Dependabot (.github/dependabot.yml, new)

  • Weekly checks for github-actions (keeps the pinned SHA actions current) and pip (opens PRs for new versions within the bounded ranges in requirements.txt).

Scheduled lock-file refresh (.github/workflows/update-lock.yml, new)

  • Runs pip-compile --upgrade every Monday at 08:00 UTC.
  • Opens a PR via peter-evans/create-pull-request with the refreshed requirements-lock.txt for review before merging.
  • Also triggerable manually from the Actions tab.

Acceptance criteria checklist

  • All runtime deps in requirements.txt have both lower and upper bounds
  • requirements-lock.txt generated and committed
  • CI installs from the lock file for deterministic test results
  • Dependabot + weekly scheduled workflow documented and configured for lock-file maintenance
  • Upper bounds are conservative (current known-compatible major versions)

Summary by CodeRabbit

  • New Features
    • Richer export: IDE composer and CLI session exports now produce unified Markdown with per-message metadata, session summaries, code-edit entries, and tool/command statistics.
  • Chores
    • Deterministic Python builds: CI installs from a committed lockfile and includes a lockfile-check job.
    • Automated weekly lockfile regeneration and Dependabot updates for GitHub Actions and pip.
    • Pillow dependency range tightened to a newer, bounded major-version.
  • Documentation
    • Installation and testing guidance updated to prefer the lockfile and describe the lockfile update workflow.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds bounded Pillow constraints and a pip-compile-generated lockfile, automates lock regeneration and Dependabot updates, updates CI to use the lockfile, updates README, and refactors the Cursor export pipeline to use shared services and a new IDE Markdown exporter.

Changes

Deterministic dependency management via lock file

Layer / File(s) Summary
Dependency bounds
pyproject.toml, requirements.txt
pillow is changed to >=12.2.0,<13 in both manifests.
Pinned lockfile
requirements-lock.txt
Adds a pip-compile-generated requirements-lock.txt with explicit version pins and provenance headers.
Lockfile regeneration workflow
.github/workflows/update-lock.yml
Adds update-lock.yml (weekly cron + manual dispatch) that sets up Python 3.12, installs pip-tools, runs pip-compile --upgrade --allow-unsafe --no-header, restores a pinned header if omitted, and opens a PR when requirements-lock.txt changes.
CI integration with locked deps
.github/workflows/tests.yml
Adds a lockfile job that verifies/regenerates the lock, and updates unittest and typecheck jobs to install from requirements-lock.txt then install pytest>=8,<9 or mypy>=1.10,<2 respectively instead of ad-hoc direct installs.
Dependabot configuration
.github/dependabot.yml
Introduces Dependabot config for github-actions and pip ecosystems to run weekly on Mondays, labeled dependencies, with notes about pinned action SHAs and post-merge lockfile regeneration.
Documentation updates
README.md
Documents reproducible installs using requirements-lock.txt, the pip-compile workflow, CI/Dependabot behavior, and updates the project structure listing.

Export pipeline refactor

Layer / File(s) Summary
Global DB loaders
services/workspace_db.py
Adds _load_bubble_map, _load_project_layouts_map, and _load_code_block_diff_map to materialize KV datasets into in-memory maps.
Workspace listing & tabs
services/workspace_listing.py, services/workspace_tabs.py
Switches listing/tabs code to use shared DB loaders and adds _try_loads_kv_value to safely parse KV JSON values.
Markdown exporter & text utilities
utils/cursor_md_exporter.py, utils/text_extract.py
Adds cursor_ide_chat_to_markdown() to render IDE composer chats to Markdown and introduces slug() in utils.text_extract.
API export route refactor
api/export_api.py
Refactors /api/export to call service helpers, load bubble/diff maps, and delegate per-composer Markdown generation to cursor_ide_chat_to_markdown; updates error handling and removes inline DB plumbing.
CLI/script export refactor
scripts/export.py
Refactors the export script to use service-layer workspace discovery and shared exporters, removes many local helpers, and simplifies manifest/output logic.

Sequence Diagram(s)

sequenceDiagram
  participant ExportAPI as api/export_api.py
  participant WorkspaceService as services.workspace_listing / services.workspace_db
  participant GlobalDB as global SQLite (cursorDiskKV)
  participant MDExporter as utils.cursor_md_exporter.cursor_ide_chat_to_markdown
  participant ZipBuilder as in-memory zip/manifest writer

  ExportAPI->>WorkspaceService: collect workspace entries & composer→workspace map
  WorkspaceService->>GlobalDB: open global DB & load bubble/layout/diff maps
  ExportAPI->>MDExporter: call cursor_ide_chat_to_markdown for composer rows
  MDExporter->>ExportAPI: return Markdown file bytes
  ExportAPI->>ZipBuilder: add exported files and manifest entries
  ZipBuilder->>ExportAPI: return zip bytes / persist export state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • timon0305

Poem

🐰 I nibble pins and chase the lock,
Pip compiles tidy trails of thread,
Dependabot hops in on the clock,
CI reads the lock and keeps us fed,
A little rabbit cheers — versions well-fed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately captures the primary change—adding bounded dependency pins to requirements.txt as described in the main objectives and linked issue #47.
Linked Issues check ✅ Passed All acceptance criteria from issue #47 are met: runtime dependencies now have upper bounds, a lock file is generated and committed, CI uses the lock file, and automated maintenance workflows (Dependabot and scheduled update-lock.yml) are configured.
Out of Scope Changes check ✅ Passed The refactoring of api/export_api.py and scripts/export.py to use service-layer patterns for workspace discovery and Markdown generation is supplementary infrastructure supporting improved export functionality, which is in-scope given the broader architectural improvements to support the bounded-dependency strategy.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/unbounded-dependency-pins

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

Copy link
Copy Markdown

@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: 2

🤖 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 @.github/workflows/update-lock.yml:
- Line 50: Replace the floating tag for the GitHub Action usage of
peter-evans/create-pull-request (currently "uses:
peter-evans/create-pull-request@v7") with a specific immutable commit SHA;
locate the "uses: peter-evans/create-pull-request@v7" line in the workflow, find
the latest verified commit SHA for that action (from the action's repository
tags or the marketplace), and update the string to "uses:
peter-evans/create-pull-request@<commit-sha>" so the workflow is pinned to a
specific commit instead of the v7 tag.

In `@requirements-lock.txt`:
- Line 16: The lockfile currently pins pillow==10.4.0 which contains multiple
high-severity vulnerabilities; update the upstream constraint that produced this
lock (the requirement spec "pillow>=10.3.0,<11") to allow Pillow 12.x (e.g.,
change to "pillow>=12.1.1" or "pillow>=12.2.0") after verifying that dependent
packages (notably fpdf2) are compatible with Pillow 12.2.0, then regenerate the
lock file (re-run your dependency lock/compile step) so the lock reflects
pillow==12.2.0 (or the chosen 12.x release) and ensure CI/tests pass.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67859c4b-d312-4b72-b22c-53f21ba2fc9c

📥 Commits

Reviewing files that changed from the base of the PR and between 04d57fc and dd36d08.

📒 Files selected for processing (6)
  • .github/dependabot.yml
  • .github/workflows/tests.yml
  • .github/workflows/update-lock.yml
  • pyproject.toml
  • requirements-lock.txt
  • requirements.txt

Comment thread .github/workflows/update-lock.yml Outdated
Comment thread requirements-lock.txt Outdated
@bradjin8 bradjin8 requested a review from clean6378-max-it May 19, 2026 14:36
@bradjin8 bradjin8 self-assigned this May 19, 2026
@clean6378-max-it
Copy link
Copy Markdown
Collaborator

README.md — Document lock-file workflow for contributors: CI uses requirements-lock.txt; how to regenerate (pip-compile command from the lock header); Dependabot + “Update dependency lock file” Actions. (Issue #47 asks for a documented update process; it lives only in YAML comments today.)

.github/workflows/tests.yml (new step) — Add a lock freshness check, e.g. run pip-compile with the same flags as update-lock.yml and fail if requirements-lock.txt differs (git diff --exit-code). (Prevents requirements.txt / pyproject.toml edits without regenerating the lock while CI still passes.)

.github/workflows/update-lock.yml:42-46 — Fix the “Restore header comment” step: HEADER is single-quoted, so \n is literal, not newline; printf '%s\n' "$HEADER" will write one malformed line when the workflow prepends the header after pip-compile --no-header. (The committed lock file is correct today; the first automated lock refresh will corrupt the header.)

.github/dependabot.yml + update-lock.yml — Clarify the two-path maintenance model: Dependabot pip PRs may bump bounds in requirements.txt but do not refresh the lock; merging those should trigger (or be followed by) the lock workflow. (Reduces drift between bounds and pinned CI installs.)

requirements.txt / pyproject.toml — Consider compiling from pyproject.toml (pip-compile pyproject.toml) or adding a CI check that [project.dependencies] matches requirements.txt. (Single source of truth; today sync is comment-only.)

requirements-lock.txt — colorama is pinned as a transitive dep (Windows-oriented); harmless for reproducibility on Linux CI but matches the eval’s portability note. (No action required unless you want platform-specific lock files.)

@bradjin8
Copy link
Copy Markdown
Collaborator Author

Here's details for the review comment.

Finding Verdict Action
README — lock workflow Valid — only in YAML/comments Added Dependency bounds and lock file (bounds, pip-compile, Dependabot vs lock workflow); noted requirements-lock.txt in install/tests; updated project tree
tests.yml — lock freshness check Valid — missing New lockfile job: sync check (requirements.txt vs pyproject.toml) + pip-compile pin-line diff
update-lock.yml — \n in HEADER Valid — would break first automated run Replaced with heredoc; always prepend header after compile
Dependabot + update-lock — two paths Valid — under-documented Expanded comments in dependabot.yml and PR body in update-lock.yml
pyproject vs requirements.txt sync Valid — real drift (pillow>=10.3.0 vs pillow>=12.2.0,<13) Fixed requirements.txt; CI sync step enforces match (skipped pip-compile pyproject.toml to keep minimal shim model)
colorama in lock Valid — no action needed Skipped per reviewer

Also fixed: requirements.txt pillow bound brought back in line with pyproject.toml.

Validation: sorted(pyproject deps) == sorted(requirements.txt); pip-compile output matches committed pins; unittest suite passes.

Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (3)
.github/workflows/update-lock.yml (2)

43-46: ⚡ Quick win

Add --upgrade flag to the documented update command in the lock file header.

The header's "Update:" line (which will appear in the generated requirements-lock.txt) documents the pip-compile command for manual regeneration, but omits the --upgrade flag that this workflow actually uses on line 37. Developers copying the command from the header won't pick up newer package versions, contradicting the comment on lines 47-48 about picking up upstream releases.

📝 Proposed fix
           cat > /tmp/lock-header <<'EOF'
           # Pinned lock file — generated by pip-compile (pip-tools).
           # Install: pip install -r requirements-lock.txt
-          # Update:  pip-compile requirements.txt --output-file requirements-lock.txt --no-header --annotation-style=line --allow-unsafe
+          # Update:  pip-compile requirements.txt --output-file requirements-lock.txt --no-header --annotation-style=line --allow-unsafe --upgrade
           # Run periodically (e.g. via the "Update dependency lock file" CI workflow) to pick up
           # upstream patch / security releases within the bounded ranges in requirements.txt.
           EOF
🤖 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 @.github/workflows/update-lock.yml around lines 43 - 46, The "Update:"
documentation line in the heredoc that writes /tmp/lock-header (the pip-compile
usage string) is missing the --upgrade flag; edit that heredoc so the Update
line reads "pip-compile requirements.txt --output-file requirements-lock.txt
--no-header --annotation-style=line --allow-unsafe --upgrade" to match the
workflow's actual behavior and ensure manual regeneration picks up upstream
releases.

20-20: ⚡ Quick win

Consider setting persist-credentials: false for defense-in-depth security.

By default, actions/checkout configures the GITHUB_TOKEN in the local git config. While this workflow doesn't execute untrusted repository code directly, pip-compile does resolve dependencies and can execute setup.py during that process. Setting persist-credentials: false prevents any such code from accessing the token via git commands.

🔒 Proposed fix
-      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4
+      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4
+        with:
+          persist-credentials: false
🤖 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 @.github/workflows/update-lock.yml at line 20, The checkout step using
actions/checkout (the line with uses: actions/checkout@34e11...) should be
updated to set persist-credentials: false to prevent GITHUB_TOKEN from being
written to the repository git config; modify the checkout step configuration for
that uses action to include the persist-credentials: false option so pip-compile
or any dependency setup cannot access the token via git.
.github/workflows/tests.yml (1)

24-24: ⚡ Quick win

Consider setting persist-credentials: false for defense-in-depth security.

By default, actions/checkout configures the GITHUB_TOKEN in the local git config. The lockfile job runs pip-compile, which can execute setup.py during dependency resolution. Setting persist-credentials: false prevents such code from accessing the token via git commands.

🔒 Proposed fix
-      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4
+      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4
+        with:
+          persist-credentials: false
🤖 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 @.github/workflows/tests.yml at line 24, The checkout step using
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 should be updated to
include persist-credentials: false to avoid leaving GITHUB_TOKEN in the local
git config; modify the checkout invocation (the actions/checkout usage) to add
the persist-credentials: false option so subsequent commands like pip-compile
cannot access the token via git.
🤖 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 @.github/workflows/tests.yml:
- Around line 55-56: The "Install pip-tools" step currently installs pip-tools
without a version, causing non-reproducible lock verification; update that step
(the step named "Install pip-tools") to pin pip-tools to the same specific
version used by the update-lock.yml workflow (e.g., change the install command
to include the exact version specifier like pip-tools==<version>) so the
lockfile verification uses the same resolver version.

In @.github/workflows/update-lock.yml:
- Around line 27-28: Summary: The workflow step that runs "python -m pip install
pip-tools" installs an unpinned package which can yield non-reproducible lock
files. Fix: update the "Install pip-tools" run step to install a pinned
pip-tools version instead of the unversioned package; choose and hardcode the
exact pip-tools release used to generate the lock file (for example, the same
version used locally or in CI when creating the lock), so the command in that
step installs that exact version and ensures deterministic lock file generation.

---

Nitpick comments:
In @.github/workflows/tests.yml:
- Line 24: The checkout step using
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 should be updated to
include persist-credentials: false to avoid leaving GITHUB_TOKEN in the local
git config; modify the checkout invocation (the actions/checkout usage) to add
the persist-credentials: false option so subsequent commands like pip-compile
cannot access the token via git.

In @.github/workflows/update-lock.yml:
- Around line 43-46: The "Update:" documentation line in the heredoc that writes
/tmp/lock-header (the pip-compile usage string) is missing the --upgrade flag;
edit that heredoc so the Update line reads "pip-compile requirements.txt
--output-file requirements-lock.txt --no-header --annotation-style=line
--allow-unsafe --upgrade" to match the workflow's actual behavior and ensure
manual regeneration picks up upstream releases.
- Line 20: The checkout step using actions/checkout (the line with uses:
actions/checkout@34e11...) should be updated to set persist-credentials: false
to prevent GITHUB_TOKEN from being written to the repository git config; modify
the checkout step configuration for that uses action to include the
persist-credentials: false option so pip-compile or any dependency setup cannot
access the token via git.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: db91b0fe-5302-413b-bc2b-8e61e768a3f4

📥 Commits

Reviewing files that changed from the base of the PR and between 623370c and 2a135d7.

📒 Files selected for processing (4)
  • .github/dependabot.yml
  • .github/workflows/tests.yml
  • .github/workflows/update-lock.yml
  • README.md
✅ Files skipped from review due to trivial changes (2)
  • README.md
  • .github/dependabot.yml

Comment thread .github/workflows/tests.yml Outdated
Comment thread .github/workflows/update-lock.yml Outdated
bradjin8 added 2 commits May 19, 2026 20:39
Extract _load_bubble_map/_load_project_layouts_map/_load_code_block_diff_map
to services/workspace_db.py; add cursor_ide_chat_to_markdown to
utils/cursor_md_exporter.py; remove private _slug() copies from
api/export_api.py and utils/cursor_md_exporter.py.
Copy link
Copy Markdown

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/export_api.py (1)

210-214: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not return raw exceptions from this endpoint.

str(e) can include absolute paths, SQL details, and other local state. Log the exception server-side and return a generic 500 payload instead.

Proposed fix
-    except Exception as e:
-        print(f"Export error: {e}")
-        import traceback
-        traceback.print_exc()
-        return jsonify({"error": f"Export failed: {str(e)}"}), 500
+    except Exception:
+        current_app.logger.exception("Export failed")
+        return jsonify({"error": "Export failed"}), 500
🤖 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 `@api/export_api.py` around lines 210 - 214, The except block currently prints
the exception and returns its stringified form via jsonify({"error": f"Export
failed: {str(e)}"}), which can leak local paths/SQL; instead, log the full
exception server-side (use your app logger or logging.getLogger(__name__) and
include the traceback) and return a generic JSON error like jsonify({"error":
"Export failed"}) with a 500 status; remove the print(...) and
traceback.print_exc() calls and keep only the server-side logger call and the
sanitized response in the except block.
🧹 Nitpick comments (1)
services/workspace_db.py (1)

38-43: ⚡ Quick win

Narrow the per-row exception handling.

These shared loaders now feed both workspace listing and tabs. Catching Exception here will also hide real regressions and turn them into silent missing data; keep the row-level skip, but limit it to the JSON/type errors you actually expect.

♻️ Suggested tightening
-        except Exception:
-            pass
+        except (TypeError, ValueError):
+            continue
...
-                except Exception:
-                    pass
-        except Exception:
-            pass
+                except (TypeError, ValueError):
+                    continue
+        except (TypeError, ValueError):
+            continue
...
-        except Exception:
-            pass
+        except (TypeError, ValueError):
+            continue

Also applies to: 72-79, 101-109

🤖 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 `@services/workspace_db.py` around lines 38 - 43, The per-row try/except in
services/workspace_db.py is too broad and hides real errors; tighten the
exception handling around json.loads(row["value"]) and the isinstance check so
only expected parsing/type errors are swallowed. Specifically, in the blocks
that populate bubble_map (variables bid and b) and the similar blocks at the
other noted ranges (lines approx. 72-79 and 101-109), replace "except
Exception:" with a narrow clause such as "except (json.JSONDecodeError,
TypeError, ValueError):" so malformed JSON or wrong types are skipped but other
exceptions still surface.
🤖 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 `@api/export_api.py`:
- Around line 151-165: The exporter currently builds searchable text only from
extracted bubble text (bubble_texts via extract_text_from_bubble) so exclusion
rules (is_excluded_by_rules) miss sensitive strings emitted as tool payloads or
synthetic code-edit diffs that cursor_ide_chat_to_markdown renders; update the
searchable content assembly used by build_searchable_text to also collect and
include tool payload text and any synthetic diff/code-edit text produced for
each bubble (the same pieces cursor_ide_chat_to_markdown emits) so
is_excluded_by_rules sees the exact content the exporter will output (use
bubble_map/headers loop to gather these extra strings alongside
extract_text_from_bubble before calling build_searchable_text).

In `@services/workspace_db.py`:
- Around line 97-107: The code currently builds diff entries from
row["key"].split(":") and appends them even when the third segment (diffId) is
missing, producing "diffId": None; update the guard in the block that computes
parts, cid and appends to diff_map so it only proceeds when len(parts) >= 3
(i.e., a valid third segment exists) — keep the existing variables (parts, cid,
d, diff_map) and only call diff_map.setdefault(cid, []).append(...) when the
third segment is present so tab.codeBlockDiffs never receives entries with
diffId == None.

In `@utils/cursor_md_exporter.py`:
- Around line 366-377: The frontmatter assembly in cursor_md_exporter.py builds
fm_lines with manually quoted title and workspace_name and an unquoted model,
which can produce invalid YAML for titles containing newlines, backslashes, or
quotes; update the block that appends title, workspace_name, and model to use
the same string-serialization routine as the CLI exporter (i.e., replace the
manual f-string quoting for title and workspace_name and the unquoted model
entry with the shared frontmatter serializer used elsewhere) so values are
properly escaped/quoted before being appended to fm_lines.

---

Outside diff comments:
In `@api/export_api.py`:
- Around line 210-214: The except block currently prints the exception and
returns its stringified form via jsonify({"error": f"Export failed: {str(e)}"}),
which can leak local paths/SQL; instead, log the full exception server-side (use
your app logger or logging.getLogger(__name__) and include the traceback) and
return a generic JSON error like jsonify({"error": "Export failed"}) with a 500
status; remove the print(...) and traceback.print_exc() calls and keep only the
server-side logger call and the sanitized response in the except block.

---

Nitpick comments:
In `@services/workspace_db.py`:
- Around line 38-43: The per-row try/except in services/workspace_db.py is too
broad and hides real errors; tighten the exception handling around
json.loads(row["value"]) and the isinstance check so only expected parsing/type
errors are swallowed. Specifically, in the blocks that populate bubble_map
(variables bid and b) and the similar blocks at the other noted ranges (lines
approx. 72-79 and 101-109), replace "except Exception:" with a narrow clause
such as "except (json.JSONDecodeError, TypeError, ValueError):" so malformed
JSON or wrong types are skipped but other exceptions still surface.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: c1339897-1bfd-45a0-a440-8152f057033c

📥 Commits

Reviewing files that changed from the base of the PR and between c03ff00 and 7926293.

📒 Files selected for processing (7)
  • api/export_api.py
  • scripts/export.py
  • services/workspace_db.py
  • services/workspace_listing.py
  • services/workspace_tabs.py
  • utils/cursor_md_exporter.py
  • utils/text_extract.py

Comment thread api/export_api.py Outdated
Comment thread services/workspace_db.py Outdated
Comment thread utils/cursor_md_exporter.py Outdated
@clean6378-max-it clean6378-max-it requested a review from wpak-ai May 20, 2026 06:55
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.

Unbounded Dependency Pins in requirements.txt

2 participants