Skip to content

Codebase-wide bug fixes and cleanup (audit) + Gemini support for pi - #55

Merged
shreyashankar merged 11 commits into
mainfrom
claude/codebase-refactor
Jul 8, 2026
Merged

Codebase-wide bug fixes and cleanup (audit) + Gemini support for pi#55
shreyashankar merged 11 commits into
mainfrom
claude/codebase-refactor

Conversation

@shreyashankar

@shreyashankar shreyashankar commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Hosted-independent fixes surfaced by a full-codebase audit, plus Gemini model support for the pi provider. These touch files untouched by the hosted-deployment overlay, so they belong on main and flow to landing via the sync workflow. The hosted-coupled subset (authFetch adoption, multi-tenant correctness) stays on PR #51.

npm run check and npm run build both pass; check is clean (0 errors, 0 warnings).

Editor (correctness bugs)

  • ySyncPluginKey imported from the wrong package. TiptapEditor and comment-overlay imported it from y-prosemirror, but the Collaboration extension installs its sync plugin from @tiptap/y-tiptap, so the two PluginKey('y-sync') instances never matched. Consequences: agent/remote Yjs transactions were misclassified as user edits for the idle timer, and the entire RelativePosition comment-anchoring tier was dead at runtime (comments silently fell back to first-match indexOf). editor-extensions now re-exports the key/rel-pos helpers as the single source.
  • Store-subscription leak in TiptapEditor. 11 manual .subscribe() calls were never torn down and leaked on every tab-switch remount, firing overlay updates against destroyed editors. Converted to $store auto-subscription; collapsed 5 duplicated mirror-var pairs.
  • Dead diff-overlay mode removed. The non-round diff path has been unreachable since per-round review; it included a whole-doc word-diff recomputed on every review change and never used. Also removed the .diff-removed-widget CSS.
  • unescapeMarkdown removed. A tiptap-markdown-era vestige that corrupted user-typed backslashes (\[, \{) in LaTeX on copy and in diff line-matching.
  • Dead symbols removed (hasPendingProposal, computeDetachedThreads, markdownToPlainText, unused imports/exports).

Providers (permission bug)

  • allowedTools/canUseTool were silently ignored by openai/cursor/pi, so plan-mode's mutation-tool removal and the scratch-only Edit/Write guard were enforced only on claude/codex (pi even exposed tools during warmup). A shared wrapToolsForProvider now filters by allowedTools and gates each tool through canUseTool in all non-Claude adapters.
  • Deduped the proposal-event mapping, lazy SDK loader, prompt concat, and stale-session event into providers/shared.ts (all five adapters, including claude).

Gemini support for pi (new)

  • Models: Gemini 3.1 Pro (google/gemini-3.1-pro-preview — the id pi-ai 0.80.x's catalog resolves) and Gemini 3.5 Flash added to the pi model lists (server + client mirror).
  • Keys: the API-keys panel gains a settable Gemini row (GEMINI_API_KEY), and pi counts as usable with a Gemini key even without a Together key (new altEnvVars on ProviderKeySpec).
  • e2e: pi smoke accepts GEMINI_API_KEY as credentials and defaults to google/gemini-3.5-flash when it's the only key; the workflow passes a GEMINI_API_KEY secret through (⚠️ needs the secret added in repo settings).
  • Bug found while testing: a pi model-call failure (e.g. invalid API key) ends the message with stopReason: 'error' but still resolves session.prompt(), so renders completed as a silent "made no edits" no-op. pi.ts now surfaces it as a visible render error. Verified live end-to-end up to Google's API (which rejected the test key — the error now renders in the history pane).

UI

  • Removed OutlinePane's unreachable review-sidebar mode (~575 lines): the right sidebar is already gone from the layout, so this was dead markup/script/CSS plus a 15s polling interval and 6 review-store subscriptions the live TOC paid for on every change. Dropped the dead cross-tab producer and allTabPendingRounds/showHistory/selectedAction stores and the unused togglePinnedDiffRound helper.
  • TabBar tablist a11y fix.

Types

  • Deleted dead InlineFeedback; wired classifyRoundKind to TINY_EDIT_THRESHOLD instead of a hardcoded literal; import AgentSettings/Rule/default from $lib/types instead of re-declaring them.

Docs

  • CLAUDE.md and ARCHITECTURE.md brought in line with the code: removed the fictional state.json dual-write, yjs-agent.ts/AGENT_APPLY_KEY/ydoc-registry.ts references, server-side UndoManager, and stale gotchas; documented the real layout (dock + CommentGutter), undo model, and the ySyncPluginKey package-matching gotcha.

⚠️ Needs a runtime pass before merge

check and build can't catch an anchoring or timing regression. The two behavior-changing editor fixes — the ySyncPluginKey unification (reactivates the RelativePosition anchoring tier) and the subscription-leak refactor (moves overlay triggers to $effect) — should be exercised in the running app (comments landing on the right passage, agent edits, diff overlay) or via the e2e smoke before merging. A green pi-with-Gemini run also still needs a valid GEMINI_API_KEY (the test key was rejected by Google as invalid).

🤖 Generated with Claude Code

claude added 5 commits July 6, 2026 17:01
General fixes surfaced by a full-codebase audit, on files untouched by
the hosted-deployment overlay. No hosted/multi-tenant coupling.

Editor (correctness):
- Fix ySyncPluginKey imported from the wrong package. TiptapEditor and
  comment-overlay imported it from y-prosemirror while the Collaboration
  extension installs the sync plugin from @tiptap/y-tiptap, so the keys
  never matched: agent/remote Yjs transactions were misclassified as user
  edits for the idle timer, and the RelativePosition comment-anchoring
  tier was dead (comments fell back to first-match indexOf). editor-
  extensions now re-exports the key/rel-pos helpers as the single source.
- Fix TiptapEditor store-subscription leak: 11 manual .subscribe() calls
  were never torn down and leaked on every tab-switch remount. Converted
  to $store auto-subscription; collapsed 5 duplicated mirror-var pairs.
- Delete the unreachable non-round diff mode in diff-overlay (dead since
  per-round review; removes a whole-doc word-diff computed every review
  change and never used) and the .diff-removed-widget CSS.
- Delete unescapeMarkdown: a tiptap-markdown-era vestige that corrupted
  user-typed backslashes (\[, \{) in LaTeX on copy and diff line-matching.
- Remove dead symbols (hasPendingProposal, computeDetachedThreads,
  markdownToPlainText, unused imports/exports).

Providers (permission bug):
- openai/cursor/pi silently ignored allowedTools and canUseTool, so plan
  mode's mutation-tool removal and the scratch-only Edit/Write guard were
  enforced only on claude/codex (pi even exposed tools during warmup). Add
  a shared wrapToolsForProvider that filters by allowedTools and gates
  each execute through canUseTool; adopt in all non-Claude adapters.
- Dedupe the proposal-event mapping, lazy SDK loader, prompt concat, and
  stale-session event into providers/shared.ts.

Types/dedup:
- Delete dead InlineFeedback; wire classifyRoundKind to TINY_EDIT_THRESHOLD
  instead of a hardcoded literal; import AgentSettings/Rule/default from
  $lib/types instead of re-declaring them in runtime-state.

UI:
- TabBar tablist a11y (tabindex) + drop a no-op drag-over rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
The right-hand review sidebar was already gone from the layout (the sole
OutlinePane instance is the left TOC, showReview={false}), leaving ~575
lines of unreachable review markup/script/CSS plus a 15s polling interval
and 6 review-store subscriptions the live TOC paid for on every change.

- Reduce OutlinePane to the TOC (heading observer + scroll-to-heading).
- Drop the dead cross-tab producer in +page.svelte's syncAllTabsState and
  the allTabPendingRounds store it fed.
- Delete other now-unused UI stores (showHistory, selectedAction) and the
  unused togglePinnedDiffRound helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
The OutlinePane review-sidebar mode this PR removes was still documented
as a live right-hand pane. Describe the actual layout: single TOC-only
OutlinePane, floating AgentDockShell/HistoryPane, in-editor CommentGutter
for pending edits, and toast-surfaced rule/hook proposals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
…pe claude.ts proposal events

Documentation (every claim verified against the current tree):
- Persistence: drop the state.json "JSON mirror" (removed long ago; only
  stale comments referenced it); document hooks.json; SQLite is the single
  source of truth for runtime state.
- Undo: there is no server-side UndoManager. Client undo is the custom
  Y.UndoManager in editor-extensions.ts (fragment + review array +
  comments map, trackedOrigins {ySyncPluginKey, USER_ORIGIN}); replace the
  stale yjs-agent.ts / AGENT_APPLY_KEY / ydoc-registry.ts descriptions
  (none of those exist).
- Layout: ARCHITECTURE.md's three-pane diagram, OutlinePane/HistoryPane
  component table, and store list updated to the dock-based layout and the
  stores that actually exist (userMd/annotations/activeTabKind are gone).
- Editor update loop: agent-vs-user classification is
  getMeta(ySyncPluginKey), with the @tiptap/y-tiptap package caveat.
- Gotchas: replace tiptap-markdown escaping / StarterKit undoRedo / Link
  (all removed machinery) with the real ones — ySyncPluginKey package
  matching, plain-text serialization, shared origin constants.
- Conventions: multi-provider model selection; $store auto-subscription
  allowed (capture unsubscribers if subscribing manually); 500ms flush tick.

Code:
- claude.ts adopts emitProposalEvents from providers/shared.ts, deleting
  the last hand-rolled copy of the rule/hook proposal mapping (the other
  four adapters already use it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
pi-ai already speaks to Google's Generative Language API natively (via
GEMINI_API_KEY); this wires DocWriter's plumbing around it:

- Model catalog: add Gemini 3.1 Pro (google/gemini-3.1-pro-preview, the
  ids pi-ai 0.80.x's catalog actually resolves) and Gemini 3.5 Flash to
  the pi fallback lists (server + client mirror), alongside the existing
  2.5 entries.
- API keys: the panel gains a settable Gemini row (GEMINI_API_KEY), and
  the pi provider now counts as usable when a Gemini key is present even
  without a Together key (new altEnvVars mechanism on ProviderKeySpec).
- e2e harness: pi credentials accept GEMINI_API_KEY, and when it is the
  only key available the pi smoke defaults to google/gemini-3.5-flash;
  the workflow passes a GEMINI_API_KEY secret through.
- Bug fix surfaced by testing: a pi model-call failure (e.g. invalid
  API key) ends the assistant message with stopReason 'error' but still
  RESOLVES session.prompt(), so renders completed as a silent "made no
  edits" no-op. pi.ts now captures message_end stopReason errors and
  throws, so the render endpoint emits a visible error event.

Verified live: /api/keys reports pi usable from GEMINI_API_KEY alone,
the smoke harness selects the Gemini default, pi-ai resolves both new
model ids, and the request reaches Google (which rejected the test key
as invalid — the error now renders in the history pane instead of a
silent timeout).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
@shreyashankar shreyashankar changed the title Codebase-wide bug fixes and cleanup (audit) Codebase-wide bug fixes and cleanup (audit) + Gemini support for pi Jul 7, 2026
@shreyashankar
shreyashankar marked this pull request as ready for review July 8, 2026 05:31
@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Replace the buried Settings > Provider and Settings > Model submenus with
two Cursor-style pill buttons in the header, right after the Settings menu:
a provider pill and a model pill. Each shows the live selection, opens its
own dropdown on click, and closes on outside-click / Escape. The model
dropdown gains a type-to-filter box (the pi catalog alone has ~14 models)
plus the existing "Custom model..." entry.

Provider and Model are removed from the Settings dropdown so the pills are
the single control. Front-end only: reuses the selectedProvider /
selectedModel stores and setSelectedProvider / setSelectedModel actions;
no backend change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

- comment-overlay: write the rel-position backfill with SYSTEM_ORIGIN
  instead of USER_ORIGIN. The backfill is machine-generated, but
  USER_ORIGIN is in the UndoManager's trackedOrigins, so the first
  backfill after loading a legacy/agent-created thread planted a phantom
  undo step the user could Cmd+Z into. This path was dead before the
  ySyncPluginKey unification reactivated it.
- stores: pick a valid model for the new provider synchronously in
  setSelectedProvider, before the async /api/models load. The header
  model pill always renders the current model label, so on a provider
  switch it briefly showed the previous provider's raw model id until the
  fetch resolved. Verified across all five providers: no raw-id flash.
- +page: pass models={providerModels} to ModelPicker instead of the
  providerModels.length > 0 ? providerModels : modelOptions fallback.
  The fallback was dead (providerModels is never empty) and modelOptions
  carries duplicate ids across providers, which would throw a duplicate
  key error in the keyed {#each}. The empty-list state already handles
  an empty list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

The settings panel (and the client autonomy-change copy) already promise
that the agent creates its own comment threads at Medium/High autonomy,
but the backend never delivered it: the render prompt told the agent it
"cannot open new threads", comment_doc was in no allowlist, and Claude's
MCP doc-tools server didn't register it at all. The UI was writing a
check the backend couldn't cash.

This brings the backend in line with the UI (matching the model on the
codex/landing-hosted-split branch, minus its hosted-only request-context
plumbing):

- mcp-doc-tools.ts: register a commentDocTool on the docwriter-doc MCP
  server so Claude gains parity with the other providers, backed by a
  shared createAgentCommentThread helper that writes under AGENT_ORIGIN.
  Export COMMENT_DOC_TOOL_NAME; point reply_to_comment at comment_doc for
  new threads.
- render/+server.ts: allowlist comment_doc in fullAllowedTools (not plan
  mode, which stays read-only), and rewrite the autonomy guidance as a
  three-level model — conservative/Low (no proactive comments),
  balanced/Medium (may open comment threads, no unsolicited edits),
  aggressive/High (comments and reviewable edits). Comment routing is
  threaded through the "when in doubt", assistant-text, reply-vs-edit,
  mode-override, and read-vs-write sections.

comment_doc was already handled for the non-Claude providers via
buildToolDefinitions; it just needed allowlisting. No client changes —
the panel, hover preview, and change-copy were already built for this.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

- review-diff: delete buildReviewDiffPreview, its ReviewPreviewLine type,
  the splitLines helper, and the now-orphaned DiffPart / wordDiff imports.
  The function lost its only caller when diff-overlay dropped its import.
- diff-overlay: drop the vestigial DiffState.isPlainText field. The only
  setDiffState caller always passed true, and INITIAL_STATE's false is
  unreachable past the `baseline === null` short-circuit, so the `&&
  isPlainText` guard was always true. Removes a field that implied a
  markdown-stripping mode that no longer exists.
- providers/openai, providers/pi: remove the redundant module-level
  sdkLoaded boolean. makeLazySdkLoader already memoizes the dynamic
  import, so re-destructuring the SDK globals on a warm cache is
  idempotent; the extra flag was a second memo layer.
- Fix two stale comments (+page.svelte "showReview sidebar",
  comment-overlay "tabsBackfilled set") to match the current code.

check and build both clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
@cursor

cursor Bot commented Jul 8, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@shreyashankar
shreyashankar merged commit 3661858 into main Jul 8, 2026
7 checks passed
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