Skip to content

refactor: flatten monorepo packages into src/#146

Merged
jbdevprimary merged 53 commits into
mainfrom
feat/production-launch-v2
Feb 24, 2026
Merged

refactor: flatten monorepo packages into src/#146
jbdevprimary merged 53 commits into
mainfrom
feat/production-launch-v2

Conversation

@jbdevprimary
Copy link
Copy Markdown
Contributor

@jbdevprimary jbdevprimary commented Feb 24, 2026

Summary

  • Dissolve all 6 runtime packages (types, config, state, core, ui, agent-intelligence) into src/ subdirectories
  • Decompose agent-intelligence into 7 service directories (ai/, agents/, mcp/, orchestrator/, routing/, skills/, tools/) under src/services/
  • Move dev-tools to tools/ and update build scripts
  • Rewrite all @thumbcode/* imports to @/* path aliases (~100 replacements across ~60 files)
  • Remove workspace ceremony: delete per-package package.json/tsconfig.json, absorb AI SDK deps into root, simplify pnpm-workspace.yaml
  • Update configs: tsconfig.json, vitest.config.ts, pnpm-workspace.yaml
  • Update documentation: CLAUDE.md and AGENTS.md reflect new structure

Also includes a pre-existing commit: feat(mcp): wire real MCP transport via @ai-sdk/mcp

Verification

  • 167 test files, 2076 tests — all passing
  • 0 TypeScript errors
  • 0 lint errors (209 pre-existing warnings)
  • packages/ directory fully removed
  • No remaining @thumbcode/* functional imports

Test plan

  • pnpm typecheck — 0 errors
  • pnpm test — 167/167 files, 2076/2076 tests passing
  • pnpm lint — 0 errors
  • grep -r "@thumbcode/" src/ — only JSDoc comments remain
  • ls packages/ — directory does not exist
  • pnpm dev — verify dev server starts
  • Capacitor build — verify native build still works

🤖 Generated with Claude Code

jbdevprimary and others added 24 commits February 23, 2026 16:17
…gs found

Thorough Playwright MCP testing of all 14 screens at iPhone 14 Pro viewport.
Found infinite re-render loops in AgentDetail and Chat pages caused by
Zustand selectors returning new array references. Report includes design
alignment verification, navigation flow testing, and prioritized fix list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add useShallow from zustand/react/shallow to stabilize array selectors
  that return new references via filter()/sort() on every render
- Fix useAgentDetail hook tasks selector (BUG-001)
- Fix ThreadList pinned/recent thread selectors (BUG-002)
- Fix ChatThread messages/typing selectors (preventive)
- Fix chat empty state layout (missing flex flex-col)
- Fix agent filter button overflow on mobile (add shrink-0 + flex-nowrap)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… 17 files

Add stable empty array constants to all 4 stores (agent, chat, credential,
project) preventing ?? [] from creating new references each render.
Fix 25+ flex-row usages missing display:flex (React Native migration artifact)
and add flex to 5 icon wrapper divs missing items-center alignment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rts)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite AGENTS.md with agent roles, tools, orchestration architecture,
  workflow modes, approval gates, inter-agent communication, and metrics
- Update CLAUDE.md stack table: Vite 7, Capacitor 8, react-router-dom 7,
  Tailwind CSS, Zustand 5, pnpm workspaces (replace stale Expo/NativeWind/
  expo-router/gluestack references)
- Update file structure to reflect current layout (pages/ not app/)
- Add references to AGENTS.md and docs/memory-bank/
- Delete stale root docs migrated to docs/: ARCHITECTURE.md, DECISIONS.md,
  DEVELOPMENT-LOG.md, PROJECT-STATUS.md, thumbcode-agent-playbook.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…yout pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add multi-agent pipeline system enabling sequential agent execution
(Architect -> Implementer -> Reviewer -> Tester) with approval gates
between stages.

Orchestrator changes (packages/agent-intelligence):
- Add Pipeline, PipelineStage, PipelineStatus types to orchestrator
- Add createPipeline() with dependency-chained tasks per stage
- Add advancePipeline(), approvePipelineStage(), cancelPipeline(),
  failPipeline() for lifecycle management
- Pipeline events: created, stage_started/completed, awaiting_approval,
  approval_received, completed, failed, cancelled
- Add pipelines Map to OrchestratorState

Chat service changes (src/services/chat):
- Add isMultiStepRequest() regex detection for pipeline-triggering
  user messages (build, create, implement + app/feature/page etc.)
- Add requestPipelineResponse() for full pipeline execution with
  system handoff messages and approval gates between stages
- Add executePipelineStage() for per-stage agent execution
- Integrate pipeline detection into ChatService.sendMessage()
- Add pipeline event types to ChatEventType

Tests (46 new tests, all passing):
- 28 orchestrator pipeline tests: creation, stage progression,
  approval gates, cancellation, failure, full progression
- 18 routing tests: multi-step detection, pipeline creation,
  system messages, agent store tasks, error handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…xecutionBridge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gistry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cument, audio)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…th design system awareness

- Add AgentSkill interface with tiered context injection and composable tool system
- Add SkillToolDefinition type for skill-provided tools
- Modify BaseAgent to support skills: addSkill(), getSystemPromptWithSkills(),
  getToolsWithSkills(), executeToolWithSkills() with automatic routing
- Create FrontendSkill with P3 "Warm Technical" design system context (4 tiers)
  and 5 tools: list_components, generate_component, analyze_ui_screenshot,
  compare_ui, preview_component
- Attach FrontendSkill to ImplementerAgent by default
- Add barrel exports and package.json export path for skills module
- 29 tests covering interface compliance, context tiers, all tools, BaseAgent
  skill integration, and ImplementerAgent default skill attachment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…th design system awareness

- Add AgentSkill interface with tiered context injection and composable tool system
- Add SkillToolDefinition type for skill-provided tools
- Modify BaseAgent to support skills: addSkill(), getSystemPromptWithSkills(),
  getToolsWithSkills(), executeToolWithSkills() with automatic routing
- Create FrontendSkill with P3 "Warm Technical" design system context (4 tiers)
  and 5 tools: list_components, generate_component, analyze_ui_screenshot,
  compare_ui, preview_component
- Attach FrontendSkill to ImplementerAgent by default
- Add barrel exports and package.json export path for skills module
- 29 tests covering interface compliance, context tiers, all tools, BaseAgent
  skill integration, and ImplementerAgent default skill attachment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…generation

Add generate_variants tool to FrontendSkill that generates 3-4 design variants
of a component (like 21st.dev), each with a different visual approach while
remaining brand-compliant with ThumbCode P3 design system.

Built-in variant presets:
- Minimal: spacious, subtle accents, no shadows
- Rich: full-featured with coral/gold/teal accents and layered shadows
- Compact: dense, information-rich, optimized for lists
- Playful: bold rotations, larger organic shapes, warm gold accents

Each variant includes: unique component code, preview HTML, file name,
style description. Users pick their favorite rather than getting a single
take-it-or-leave-it output.

14 new tests covering variant count, style hints, brand compliance,
shared props, unique file names, preview HTML, and per-preset styles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…upport

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… cloud save foundation

- Create DocumentEngine service with format-specific generators for Word, PowerPoint, Excel, and PDF
- Add document tools (create_document, create_presentation, create_spreadsheet, create_pdf) to ToolExecutionBridge
- Add DocumentEngineLike interface for dependency injection in agent-intelligence package
- Create DocumentCard chat component with organic daube styling and format-specific icons
- Create CloudSaveService foundation with local download support
- Add 40 new tests across 4 test files (DocumentEngine, DocumentTools, DocumentCard, CloudSaveService)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t coverage, and cleanup dead code

- Rewrite ai-client.test.ts and VariantGeneration.test.ts to mock Vercel AI SDK
  (generateText/streamText) instead of old @anthropic-ai/sdk/@openai mocks
- Fix OrchestrationState.test.ts type errors: update TaskAssignment mocks with
  required fields (title, acceptanceCriteria, references, updatedAt), fix
  OrchestratorConfig shape, fix OrchestratorEvent structure, fix TaskResult mocks
- Fix ProjectActions.test.tsx, AgentHistory.test.tsx, ThreadList.test.tsx,
  RepoSelector.test.tsx type errors for evolved interfaces
- Add AIProviderFactory with provider-factory.ts and tests
- Add 50+ new test files across all packages for comprehensive coverage
- Remove dead components (Tooltip, BottomSheet, Pagination, Spacer, workspace)
- Remove stale archives and ralph directory
- Rename useAppRouter to use-app-router (kebab-case convention)

All 155 test files pass (1886 tests), typecheck clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add LivePreview and PreviewPanel components for rendering component
previews in sandboxed iframes, with a preview-sandbox utility for
generating self-contained HTML with ThumbCode design tokens. Wire
preview capability into VariantSelector for inline variant previews.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add LivePreview and PreviewPanel components for rendering component
previews in sandboxed iframes, with a preview-sandbox utility for
generating self-contained HTML with ThumbCode design tokens. Wire
preview capability into VariantSelector for inline variant previews.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ImageMessage: thumbnail with click-to-expand lightbox, loading skeleton, error state
- AudioMessage: custom player with play/pause, waveform visualization, transcript display
- MixedMediaMessage: grid layout for multiple attachments with type-specific rendering
- ChatMessage routing: image → ImageMessage, voice_transcript → AudioMessage,
  mixed_media → MixedMediaMessage
- 29 new tests across 3 test files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 24, 2026

Important

Review skipped

Too many files!

This PR contains 297 files, which is 147 over the limit of 150.

📥 Commits

Reviewing files that changed from the base of the PR and between 27fc191 and 1b271ed.

⛔ Files ignored due to path filters (3)
  • archive/thumbcode-deploy.zip is excluded by !**/*.zip
  • archive/thumbcode-docs.zip is excluded by !**/*.zip
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (297)
  • .github/workflows/android-release.yml
  • .github/workflows/deploy-gh-pages.yml
  • .gitignore
  • .ralph-tui/progress.md
  • AGENTS.md
  • ARCHITECTURE.md
  • CLAUDE.md
  • DECISIONS.md
  • DEVELOPMENT-LOG.md
  • PROJECT-STATUS.md
  • android/app/build.gradle
  • biome.json
  • docs-site/package.json
  • docs/development/TESTING.md
  • docs/e2e-test-report.md
  • docs/features/MULTIMEDIA-AND-FRONTEND-SKILL.md
  • docs/plans/2026-02-24-flatten-packages-design.md
  • docs/plans/2026-02-24-flatten-packages.md
  • e2e/web/dashboard.spec.ts
  • e2e/web/interactions.spec.ts
  • package.json
  • packages/agent-intelligence/README.md
  • packages/agent-intelligence/package.json
  • packages/agent-intelligence/src/__tests__/ai-client.test.ts
  • packages/agent-intelligence/src/components/chat/ActionButton.tsx
  • packages/agent-intelligence/src/components/chat/ChatBubble.tsx
  • packages/agent-intelligence/src/components/chat/ChatInput.tsx
  • packages/agent-intelligence/src/components/chat/CodeBlock.tsx
  • packages/agent-intelligence/src/index.ts
  • packages/agent-intelligence/src/services/ai/index.ts
  • packages/agent-intelligence/src/services/orchestrator/orchestrator.ts
  • packages/agent-intelligence/src/stores/chatStore.ts
  • packages/agent-intelligence/src/theme/organic-styles.ts
  • packages/agent-intelligence/tsconfig.json
  • packages/config/README.md
  • packages/config/package.json
  • packages/core/README.md
  • packages/core/package.json
  • packages/core/tsconfig.json
  • packages/dev-tools/README.md
  • packages/dev-tools/package.json
  • packages/dev-tools/tsconfig.json
  • packages/state/README.md
  • packages/state/package.json
  • packages/types/README.md
  • packages/types/package.json
  • packages/types/src/api.ts
  • packages/types/src/chat.ts
  • packages/types/src/credentials.ts
  • packages/types/src/events.ts
  • packages/types/src/index.ts
  • packages/types/src/navigation.ts
  • packages/types/src/user.ts
  • packages/ui/README.md
  • packages/ui/package.json
  • pnpm-workspace.yaml
  • ralph/archive/2026-02-11-v1.0-full/prd.json
  • ralph/archive/2026-02-11-v1.0-full/progress.txt
  • ralph/prd.json
  • ralph/progress.txt
  • sonar-project.properties
  • src/__tests__/ai-client.test.ts
  • src/__tests__/integration/ai-providers.integration.test.ts
  • src/__tests__/integration/fixtures/ai-providers.json
  • src/__tests__/integration/setup-polly.ts
  • src/__tests__/main.test.ts
  • src/__tests__/orchestrator.test.ts
  • src/__tests__/router.test.tsx
  • src/components/agents/AgentHistory.tsx
  • src/components/agents/AgentMetrics.tsx
  • src/components/agents/__tests__/AgentActions.test.tsx
  • src/components/agents/__tests__/AgentHistory.test.tsx
  • src/components/agents/__tests__/AgentMetrics.test.tsx
  • src/components/chat/ApprovalCard.tsx
  • src/components/chat/AudioMessage.tsx
  • src/components/chat/CameraCapture.tsx
  • src/components/chat/ChatInput.tsx
  • src/components/chat/ChatMessage.tsx
  • src/components/chat/ChatThread.tsx
  • src/components/chat/CodeBlock.tsx
  • src/components/chat/DocumentCard.tsx
  • src/components/chat/ImageMessage.tsx
  • src/components/chat/MixedMediaMessage.tsx
  • src/components/chat/ThreadList.tsx
  • src/components/chat/VariantSelector.tsx
  • src/components/chat/VoiceInputButton.tsx
  • src/components/chat/__tests__/ApprovalCard.test.tsx
  • src/components/chat/__tests__/AudioMessage.test.tsx
  • src/components/chat/__tests__/CameraCapture.test.tsx
  • src/components/chat/__tests__/ChatInput.test.tsx
  • src/components/chat/__tests__/ChatMessage.test.tsx
  • src/components/chat/__tests__/ChatThread.test.tsx
  • src/components/chat/__tests__/CodeBlock.test.tsx
  • src/components/chat/__tests__/DocumentCard.test.tsx
  • src/components/chat/__tests__/ImageMessage.test.tsx
  • src/components/chat/__tests__/MixedMediaMessage.test.tsx
  • src/components/chat/__tests__/ThreadList.test.tsx
  • src/components/chat/__tests__/VariantSelector.test.tsx
  • src/components/chat/__tests__/VoiceInputButton.test.tsx
  • src/components/chat/index.ts
  • src/components/code/DiffViewer.tsx
  • src/components/code/TreeNode.tsx
  • src/components/display/EmptyState.tsx
  • src/components/display/Tooltip.tsx
  • src/components/display/__tests__/Badge.test.tsx
  • src/components/display/__tests__/Tooltip.test.tsx
  • src/components/display/index.ts
  • src/components/error/ErrorFallback.tsx
  • src/components/feedback/BottomSheet.tsx
  • src/components/feedback/Loading.tsx
  • src/components/feedback/Pagination.tsx
  • src/components/feedback/Toast.tsx
  • src/components/feedback/__tests__/BottomSheet.test.tsx
  • src/components/feedback/index.ts
  • src/components/form/TextArea.tsx
  • src/components/form/TextInput.tsx
  • src/components/form/__tests__/TextInput.test.tsx
  • src/components/icons/__tests__/icon-paths.test.ts
  • src/components/icons/__tests__/paint-daube-filter.test.tsx
  • src/components/icons/icon-presets.tsx
  • src/components/icons/index.ts
  • src/components/layout/Spacer.tsx
  • src/components/layout/__tests__/AppProviders.test.tsx
  • src/components/layout/__tests__/Divider.test.tsx
  • src/components/layout/__tests__/RootLayoutNav.test.tsx
  • src/components/layout/__tests__/Stack.test.tsx
  • src/components/layout/index.ts
  • src/components/onboarding/RepoSelector.tsx
  • src/components/onboarding/__tests__/DeviceCodeDisplay.test.tsx
  • src/components/onboarding/__tests__/PollingStatus.test.tsx
  • src/components/onboarding/__tests__/RepoSelector.test.tsx
  • src/components/preview/LivePreview.tsx
  • src/components/preview/PreviewPanel.tsx
  • src/components/preview/__tests__/LivePreview.test.tsx
  • src/components/preview/__tests__/PreviewPanel.test.tsx
  • src/components/preview/index.ts
  • src/components/project/ProjectActions.tsx
  • src/components/project/ProjectFileExplorer.tsx
  • src/components/project/__tests__/ProjectActions.test.tsx
  • src/components/project/__tests__/ProjectFileExplorer.test.tsx
  • src/components/settings/CredentialSection.tsx
  • src/components/settings/SettingsItem.tsx
  • src/components/settings/__tests__/CredentialSection.test.tsx
  • src/components/settings/__tests__/SettingsItem.test.tsx
  • src/components/settings/__tests__/SettingsSection.test.tsx
  • src/components/ui/Button.tsx
  • src/components/ui/Card.tsx
  • src/components/ui/Input.tsx
  • src/components/ui/Text.tsx
  • src/components/ui/__tests__/ThemeProvider.test.tsx
  • src/components/ui/__tests__/re-exports.test.ts
  • src/components/workspace/index.ts
  • src/config/__tests__/constants.test.ts
  • src/config/__tests__/env.test.ts
  • src/config/__tests__/features.test.ts
  • src/config/__tests__/provider-registry.test.ts
  • src/config/constants.ts
  • src/config/env.ts
  • src/config/features.ts
  • src/config/index.ts
  • src/config/provider-registry.ts
  • src/contexts/__tests__/onboarding.test.tsx
  • src/core/__tests__/CertificatePinningService.test.ts
  • src/core/__tests__/CredentialService.test.ts
  • src/core/__tests__/CredentialServicePerf.test.ts
  • src/core/__tests__/GitHubApiService.test.ts
  • src/core/__tests__/GitHubApiServiceExtended.test.ts
  • src/core/__tests__/GitHubAuthService.test.ts
  • src/core/__tests__/GitServicePerf.test.ts
  • src/core/__tests__/RequestSigningService.test.ts
  • src/core/__tests__/RuntimeSecurityService.test.ts
  • src/core/__tests__/api.test.ts
  • src/core/api/api.ts
  • src/core/auth/DeviceFlowHandler.ts
  • src/core/auth/GitHubAuthService.ts
  • src/core/auth/PollingService.ts
  • src/core/auth/TokenManager.ts
  • src/core/auth/__tests__/DeviceFlowHandler.test.ts
  • src/core/auth/__tests__/PollingService.test.ts
  • src/core/auth/__tests__/TokenManager.test.ts
  • src/core/auth/index.ts
  • src/core/auth/types.ts
  • src/core/credentials/CredentialService.ts
  • src/core/credentials/KeyStorage.ts
  • src/core/credentials/KeyValidator.ts
  • src/core/credentials/__tests__/KeyStorage.test.ts
  • src/core/credentials/__tests__/KeyValidator.test.ts
  • src/core/credentials/__tests__/validation.test.ts
  • src/core/credentials/index.ts
  • src/core/credentials/types.ts
  • src/core/credentials/validation.ts
  • src/core/git/GitBranchService.ts
  • src/core/git/GitCloneService.ts
  • src/core/git/GitCommitService.ts
  • src/core/git/GitDiffService.ts
  • src/core/git/GitHttpClient.ts
  • src/core/git/__tests__/GitBranchService.test.ts
  • src/core/git/__tests__/GitCloneService.test.ts
  • src/core/git/__tests__/GitCommitService.test.ts
  • src/core/git/__tests__/GitDiffService.test.ts
  • src/core/git/git-fs.ts
  • src/core/git/index.ts
  • src/core/git/types.ts
  • src/core/github/GitHubApiService.ts
  • src/core/github/index.ts
  • src/core/index.ts
  • src/core/security/CertificatePinningService.ts
  • src/core/security/RequestSigningService.ts
  • src/core/security/RuntimeSecurityService.ts
  • src/core/security/index.ts
  • src/hooks/__tests__/use-agent-detail.test.ts
  • src/hooks/__tests__/use-agent-list.test.ts
  • src/hooks/__tests__/use-app-router.test.ts
  • src/hooks/__tests__/use-camera-capture.test.ts
  • src/hooks/__tests__/use-chat-page.test.ts
  • src/hooks/__tests__/use-home-dashboard.test.ts
  • src/hooks/__tests__/use-network-error.test.ts
  • src/hooks/__tests__/use-project-actions.test.ts
  • src/hooks/__tests__/use-project-commits.test.ts
  • src/hooks/__tests__/use-project-files.test.ts
  • src/hooks/__tests__/use-project-list.test.ts
  • src/hooks/__tests__/use-voice-input.test.ts
  • src/hooks/index.ts
  • src/hooks/use-agent-detail.ts
  • src/hooks/use-agent-list.ts
  • src/hooks/use-app-router.ts
  • src/hooks/use-camera-capture.ts
  • src/hooks/use-chat-page.ts
  • src/hooks/use-home-dashboard.ts
  • src/hooks/use-project-actions.ts
  • src/hooks/use-project-commits.ts
  • src/hooks/use-project-files.ts
  • src/hooks/use-project-list.ts
  • src/hooks/use-voice-input.ts
  • src/hooks/useCreateProject.ts
  • src/layouts/RootLayout.tsx
  • src/layouts/__tests__/OnboardingLayout.test.tsx
  • src/layouts/__tests__/RootLayout.test.tsx
  • src/layouts/__tests__/TabLayout.test.tsx
  • src/lib/__tests__/preview-sandbox.test.ts
  • src/lib/chat-utils.ts
  • src/lib/preview-sandbox.ts
  • src/pages/__tests__/NotFound.test.tsx
  • src/pages/detail/AgentDetail.tsx
  • src/pages/detail/ProjectDetail.tsx
  • src/pages/detail/__tests__/AgentDetail.test.tsx
  • src/pages/detail/__tests__/ProjectDetail.test.tsx
  • src/pages/onboarding/__tests__/api-keys.test.tsx
  • src/pages/onboarding/__tests__/complete.test.tsx
  • src/pages/onboarding/__tests__/create-project.test.tsx
  • src/pages/onboarding/__tests__/github-auth.test.tsx
  • src/pages/onboarding/__tests__/welcome.test.tsx
  • src/pages/onboarding/api-keys.tsx
  • src/pages/onboarding/complete.tsx
  • src/pages/onboarding/github-auth.tsx
  • src/pages/onboarding/welcome.tsx
  • src/pages/placeholder.tsx
  • src/pages/settings/CredentialSettings.tsx
  • src/pages/settings/McpSettings.tsx
  • src/pages/settings/ProviderConfig.tsx
  • src/pages/settings/__tests__/AgentSettings.test.tsx
  • src/pages/settings/__tests__/CredentialSettings.test.tsx
  • src/pages/settings/__tests__/EditorSettings.test.tsx
  • src/pages/settings/__tests__/McpSettings.test.tsx
  • src/pages/settings/__tests__/ProviderConfig.test.tsx
  • src/pages/tabs/__tests__/chat.test.tsx
  • src/pages/tabs/__tests__/settings.test.tsx
  • src/pages/tabs/agents.tsx
  • src/pages/tabs/settings.tsx
  • src/router.tsx
  • src/services/__tests__/auth-flow.integration.test.ts
  • src/services/__tests__/chat-flow.integration.test.ts
  • src/services/agents/Committable.ts
  • src/services/agents/Promptable.ts
  • src/services/agents/Reviewable.ts
  • src/services/agents/architect-agent.ts
  • src/services/agents/base-agent.ts
  • src/services/agents/implementer-agent.ts
  • src/services/agents/index.ts
  • src/services/agents/reviewer-agent.ts
  • src/services/agents/tester-agent.ts
  • src/services/agents/types.ts
  • src/services/ai/__tests__/format-content-blocks.test.ts
  • src/services/ai/__tests__/multimodal-types.test.ts
  • src/services/ai/__tests__/provider-factory.test.ts
  • src/services/ai/anthropic-client.ts
  • src/services/ai/index.ts
  • src/services/ai/openai-client.ts
  • src/services/ai/openai-helpers.ts
  • src/services/ai/openai-stream-parser.ts
  • src/services/ai/provider-factory.ts
  • src/services/ai/types.ts
  • src/services/chat/AgentPrompts.ts
  • src/services/chat/AgentResponseService.ts
  • src/services/chat/ChatService.ts
  • src/services/chat/MessageStore.ts
  • src/services/chat/StreamHandler.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/production-launch-v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@jbdevprimary
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 24, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@amazon-q-developer amazon-q-developer Bot left a comment

Choose a reason for hiding this comment

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

Review Summary

This is an ambitious production launch PR delivering 24 commits across 18 user stories with comprehensive features. All tests pass (2064 tests) and TypeScript typechecks cleanly. However, I've identified 6 critical security and logic issues that must be addressed before merge:

Critical Security Issues 🔴

  1. XSS Vulnerability in preview-sandbox.ts: The customCss parameter is injected without sanitization, allowing CSS injection attacks
  2. Incomplete XSS Protection: The sanitizeHtml function has regex gaps that miss unquoted attributes and edge cases
  3. Color Injection Risk: Color values lack validation before HTML interpolation

Logic Errors 🟡

  1. Race Condition in MCP Client: The disconnect() method updates connection state before deleting it, creating unnecessary intermediate state
  2. Poor Error Handling: Variant generation silently swallows all errors without logging, making debugging impossible
  3. Incorrect Message Filtering: The toAIMessages filter uses redundant logic that doesn't properly exclude system messages

Impact Assessment

The security vulnerabilities in the preview sandbox are high severity - they could allow attackers to inject malicious code through CSS parameters or bypass HTML sanitization. The logic errors reduce reliability and debuggability but don't prevent core functionality.

Architecture Strengths

✅ Unified AI SDK with 10 providers
✅ Comprehensive test coverage (2064 tests passing)
✅ Clean TypeScript with 0 type errors
✅ Well-structured multi-agent orchestration
✅ Proper credential management with SecureStore

Recommendation

Request changes - The security vulnerabilities must be fixed before production deployment. Once the 6 issues are addressed, this PR will be ready to merge.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.


⚠️ This PR contains more than 30 files. Amazon Q is better at reviewing smaller PRs, and may miss issues in larger changesets.

Comment thread src/lib/preview-sandbox.ts Outdated
Comment thread src/lib/preview-sandbox.ts
Comment thread src/lib/preview-sandbox.ts
Comment thread src/services/orchestrator/orchestrator.ts
Comment thread packages/agent-intelligence/src/services/mcp/McpClient.ts Outdated
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @jbdevprimary, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request marks a significant milestone, delivering a production-ready application by implementing a wide array of features across core functionalities. It establishes a sophisticated multi-agent system capable of dynamic task orchestration and intelligent routing based on AI provider capabilities. The user experience is enhanced with rich multimodal interactions and specialized agent skills for frontend development, supported by a robust testing framework and updated documentation.

Highlights

  • Comprehensive Production Launch: This pull request completes 24 commits across 18 user stories, transitioning the project from partial implementation to full production readiness, encompassing core agent infrastructure, AI/provider systems, chat/multimedia features, and development tools.
  • Unified AI SDK Integration: All 10 AI providers (Anthropic, OpenAI, Google, Azure, xAI, Bedrock, Mistral, Cohere, Groq, DeepSeek) are now integrated through a single Vercel AI SDK interface, enhancing flexibility and future extensibility.
  • Multi-Agent Orchestration & Routing: The multi-agent system now features robust pipeline orchestration, capability-aware agent routing with graceful degradation, and a new skill system allowing agents to acquire specialized abilities like frontend development awareness.
  • Multimodal Chat & Frontend Skill System: New multimedia capabilities enable camera capture, voice input, and document handling within chat. A dedicated Frontend Skill module empowers agents with design system awareness, screenshot-to-code workflows, and live component previews.
  • Extensive Testing & Code Quality: Test coverage significantly increased to 2064 passing tests across 169 files, with a clean TypeScript typecheck. Approximately 2000 lines of dead code were removed, and E2E tests were enabled and fixed.
  • Documentation & Architecture Updates: Key documentation files like AGENTS.md and CLAUDE.md have been modernized and expanded, providing detailed insights into agent protocols, architecture, and brand guidelines. New E2E test reports and feature specifications were added.
Changelog
  • .gitignore
    • Added a new entry to ignore archive binary files.
  • AGENTS.md
    • Completely rewrote the agent coordination protocol, detailing agent roles, orchestration architecture, task lifecycle, workflow modes, approval gates, inter-agent communication, and metrics.
  • ARCHITECTURE.md
    • Removed the architecture documentation file.
  • CLAUDE.md
    • Updated the technology stack to React 18 + Vite 7 and Capacitor 8, replacing Expo/React Native. Revised the monorepo package structure, memory bank references, key decisions, and anti-patterns.
  • DECISIONS.md
    • Removed the technical decisions registry file.
  • DEVELOPMENT-LOG.md
    • Removed the development history log file.
  • PROJECT-STATUS.md
    • Removed the project status file.
  • docs/e2e-test-report.md
    • Added a detailed E2E test report, outlining critical bugs, minor issues, design alignment verification, and navigation flow.
  • docs/features/MULTIMEDIA-AND-FRONTEND-SKILL.md
    • Added a new architecture proposal detailing multimedia capabilities and a frontend agent skill system.
  • e2e/web/dashboard.spec.ts
    • Unskipped the test for chat tab navigation.
  • e2e/web/interactions.spec.ts
    • Unskipped full flow tests and updated onboarding navigation logic.
  • package.json
    • Added document generation libraries: docx, exceljs, jspdf, and pptxgenjs.
  • packages/agent-intelligence/package.json
    • Added numerous @ai-sdk/* packages and the 'ai' package for Vercel AI SDK integration. Exported new modules for skills, routing, and MCP.
  • packages/agent-intelligence/src/tests/ai-client.test.ts
    • Updated AI client tests to mock the Vercel AI SDK and adjusted assertions.
  • packages/agent-intelligence/src/components/chat/tests/chat-components.test.tsx
    • Added unit tests for ActionButton, ChatBubble, ChatInput, and CodeBlock components.
  • packages/agent-intelligence/src/index.ts
    • Exported new modules: tools, skills, routing, and mcp.
  • packages/agent-intelligence/src/services/agents/base-agent.ts
    • Introduced skill and MCP client integration, modifying tool handling and system prompt generation.
  • packages/agent-intelligence/src/services/agents/implementer-agent.ts
    • Modified the constructor to attach the FrontendSkill by default.
  • packages/agent-intelligence/src/services/ai/tests/format-content-blocks.test.ts
    • Added tests for multimodal content block formatting for the Anthropic API.
  • packages/agent-intelligence/src/services/ai/tests/multimodal-types.test.ts
    • Added tests for new multimodal content block types (image, document, audio).
  • packages/agent-intelligence/src/services/ai/tests/provider-factory.test.ts
    • Added tests for the new Vercel AI SDK provider factory.
  • packages/agent-intelligence/src/services/ai/anthropic-client.ts
    • Modified content block formatting to support image and document types.
  • packages/agent-intelligence/src/services/ai/index.ts
    • Updated AI client creation and model retrieval to use the new provider factory.
  • packages/agent-intelligence/src/services/ai/provider-factory.ts
    • Added the Vercel AI SDK provider factory, integrating 10 AI providers into a unified client interface.
  • packages/agent-intelligence/src/services/ai/types.ts
    • Expanded AIProvider enum and added interfaces for multimodal content blocks and sources.
  • packages/agent-intelligence/src/services/mcp/McpClient.ts
    • Added the MCP client for managing server connections and tool execution.
  • packages/agent-intelligence/src/services/mcp/McpToolBridge.ts
    • Added the MCP tool bridge for converting and routing MCP tools.
  • packages/agent-intelligence/src/services/mcp/tests/McpClient.test.ts
    • Added tests for the McpClient.
  • packages/agent-intelligence/src/services/mcp/tests/McpToolBridge.test.ts
    • Added tests for the McpToolBridge.
  • packages/agent-intelligence/src/services/mcp/index.ts
    • Exported MCP client and tool bridge components.
  • packages/agent-intelligence/src/services/mcp/types.ts
    • Defined types for MCP transport, tools, results, and connections.
  • packages/agent-intelligence/src/services/orchestrator/OrchestrationState.ts
    • Added pipeline management to the orchestration state.
  • packages/agent-intelligence/src/services/orchestrator/tests/OrchestrationState.test.ts
    • Added tests for the OrchestrationStateManager.
  • packages/agent-intelligence/src/services/orchestrator/tests/Pipeline.test.ts
    • Added tests for multi-agent pipeline creation and progression.
  • packages/agent-intelligence/src/services/orchestrator/tests/VariantGeneration.test.ts
    • Added tests for the universal variant generation mode.
  • packages/agent-intelligence/src/services/orchestrator/orchestrator.ts
    • Introduced variant generation, selection, and pipeline management functionalities.
  • packages/agent-intelligence/src/services/orchestrator/types.ts
    • Defined interfaces for variant generation, pipelines, and related events.
  • packages/agent-intelligence/src/services/routing/AgentRouter.ts
    • Added the AgentRouter for capability-aware agent routing.
  • packages/agent-intelligence/src/services/routing/tests/AgentRouter.test.ts
    • Added tests for the AgentRouter.
  • packages/agent-intelligence/src/services/routing/index.ts
    • Exported AgentRouter and its types.
  • packages/agent-intelligence/src/services/routing/types.ts
    • Defined types for routing decisions, rules, and capabilities.
  • packages/agent-intelligence/src/services/skills/FrontendSkill.ts
    • Added the FrontendSkill, providing design system awareness and frontend development tools to agents.
  • packages/agent-intelligence/src/services/skills/tests/FrontendSkill.test.ts
    • Added tests for the FrontendSkill and its integration with BaseAgent.
  • packages/agent-intelligence/src/services/skills/index.ts
    • Exported FrontendSkill and skill types.
  • packages/agent-intelligence/src/services/skills/types.ts
    • Defined interfaces for AgentSkill, SkillToolDefinition, and ContextTier.
  • packages/agent-intelligence/src/services/tools/ToolExecutionBridge.ts
    • Added the ToolExecutionBridge, connecting agent tools to git services and handling document generation.
  • packages/agent-intelligence/src/services/tools/tests/DocumentTools.test.ts
    • Added tests for document generation tools in the ToolExecutionBridge.
  • packages/agent-intelligence/src/services/tools/tests/ToolExecutionBridge.test.ts
    • Added tests for the ToolExecutionBridge.
  • packages/agent-intelligence/src/services/tools/index.ts
    • Exported ToolExecutionBridge and its types.
  • packages/agent-intelligence/src/services/tools/types.ts
    • Defined interfaces for various service-like dependencies and tool results.
  • packages/agent-intelligence/src/stores/tests/chatStore.test.ts
    • Added unit tests for the chatStore.
  • packages/agent-intelligence/src/theme/tests/organic-styles.test.ts
    • Added tests for organic border radius styles.
  • packages/config/package.json
    • Removed 'react-native' from peerDependencies and added 'provider-registry' export.
  • packages/config/src/tests/provider-registry.test.ts
    • Added tests for the new provider capability registry.
  • packages/config/src/index.ts
    • Exported new provider-registry types and functions.
  • packages/config/src/provider-registry.ts
    • Added the provider capability registry, defining capabilities and quirks for 10 AI providers.
  • packages/core/package.json
    • Removed 'react-native' from peerDependencies.
  • packages/core/src/tests/api.test.ts
    • Added tests for secureFetch with MCP signing.
  • packages/state/package.json
    • Removed '@react-native-async-storage/async-storage' dependency.
  • packages/state/src/tests/chatStore-multimodal.test.ts
    • Added tests for multimodal message types in the chatStore.
  • packages/state/src/tests/chatStore.test.ts
    • Added comprehensive tests for chatStore thread and message operations, approvals, typing indicators, and selectors.
  • packages/state/src/tests/mcpStore.test.ts
    • Added tests for the new mcpStore.
  • packages/state/src/agentStore.ts
    • Added stable empty array constants to prevent unnecessary re-renders.
  • packages/state/src/chatStore.ts
    • Introduced stable empty array constants. Expanded MessageContentType, added MediaAttachment interface, and new multimodal message interfaces. Updated selectors.
  • packages/state/src/credentialStore.ts
    • Added a stable empty array constant for credentials.
  • packages/state/src/index.ts
    • Exported new chat message types and MCP store components.
  • packages/state/src/mcpStore.ts
    • Added the MCP store, managing server configurations and providing curated suggestions.
  • packages/state/src/projectStore.ts
    • Added a stable empty array constant for open files and updated its selector.
  • packages/ui/src/tests/form-input.test.tsx
    • Added tests for the Input component.
  • packages/ui/src/tests/iconMap.test.ts
    • Added tests for the iconMap.
  • packages/ui/src/tests/layout.test.tsx
    • Added tests for Container and Header components.
  • packages/ui/src/tests/organicStyles.test.ts
    • Added tests for organic border radius and shadow styles.
  • packages/ui/src/tests/primitives.test.tsx
    • Added tests for primitive UI components (Box, Button, Image, List, ScrollArea, Switch, TextInput).
  • packages/ui/src/tests/theme.test.tsx
    • Added tests for ThemeProvider, useColor, and useSpacing hooks.
  • ralph/archive/2026-02-11-v1.0-full/prd.json
    • Removed the old PRD JSON file.
  • ralph/archive/2026-02-11-v1.0-full/progress.txt
    • Removed the old progress tracking file.
  • ralph/prd.json
    • Removed the old PRD JSON file.
  • ralph/progress.txt
    • Removed the old progress tracking file.
  • src/tests/main.test.ts
    • Added a test to ensure main.tsx module imports correctly.
  • src/tests/router.test.tsx
    • Added a test for AppRoutes rendering.
  • src/components/agents/tests/AgentActions.test.tsx
    • Added tests for the AgentActions component.
  • src/components/agents/tests/AgentHistory.test.ts
    • Added tests for the AgentHistory component.
  • src/components/agents/tests/AgentMetrics.test.tsx
    • Added tests for the AgentMetrics component.
  • src/components/chat/ApprovalCard.tsx
    • Updated Tailwind CSS class for flex-row to 'flex flex-row' for compatibility.
  • src/components/chat/AudioMessage.tsx
    • Added a new component for rendering audio messages in chat.
  • src/components/chat/CameraCapture.tsx
    • Added a new component for camera input within chat.
  • src/components/chat/ChatInput.tsx
    • Enhanced ChatInput with variant mode toggle, camera button, voice input button, and attachment preview. Updated message sending logic.
  • src/components/chat/ChatMessage.tsx
    • Integrated new multimodal message components and updated rendering logic for various content types. Adjusted Tailwind CSS classes.
  • src/components/chat/CodeBlock.tsx
    • Updated Tailwind CSS class for flex-row to 'flex flex-row' for compatibility.
  • src/components/chat/DocumentCard.tsx
    • Added a new component for rendering agent-generated document output messages.
  • src/components/chat/ImageMessage.tsx
    • Added a new component for rendering image messages with lightbox functionality.
  • src/components/chat/MixedMediaMessage.tsx
    • Added a new component for rendering messages with multiple media attachments.
  • src/components/chat/ThreadList.tsx
    • Updated selectors to use useShallow for performance and adjusted Tailwind CSS classes.
  • src/components/chat/VariantSelector.tsx
    • Added a new component for displaying and selecting AI-generated variants.
  • src/components/chat/VoiceInputButton.tsx
    • Added a new component for voice input functionality.
  • src/components/chat/tests/AudioMessage.test.tsx
    • Added tests for the AudioMessage component.
  • src/components/chat/tests/CameraCapture.test.tsx
    • Added tests for the CameraCapture component.
  • src/components/chat/tests/DocumentCard.test.tsx
    • Added tests for the DocumentCard component.
  • src/components/chat/tests/ImageMessage.test.tsx
    • Added tests for the ImageMessage component.
  • src/components/chat/tests/MixedMediaMessage.test.tsx
    • Added tests for the MixedMediaMessage component.
  • src/components/chat/tests/ThreadList.test.tsx
    • Added tests for the ThreadList component.
  • src/components/chat/tests/VariantSelector.test.tsx
    • Added tests for the VariantSelector component.
  • src/components/chat/tests/VoiceInputButton.test.tsx
    • Added tests for the VoiceInputButton component.
  • src/components/chat/index.ts
    • Exported new chat components.
  • src/components/code/DiffViewer.tsx
    • Updated Tailwind CSS class for flex-row to 'flex flex-row' for compatibility.
  • src/components/code/TreeNode.tsx
    • Updated Tailwind CSS class for flex-row to 'flex flex-row' for compatibility.
  • src/components/display/EmptyState.tsx
    • Updated Tailwind CSS class for flex-row to 'flex flex-row' for compatibility.
  • src/components/display/Tooltip.tsx
    • Removed the Tooltip component.
  • src/components/display/index.ts
    • Removed InfoTip and Tooltip exports.
  • src/components/error/ErrorFallback.tsx
    • Updated Tailwind CSS class for flex-row to 'flex flex-row' for compatibility.
  • src/components/feedback/BottomSheet.tsx
    • Removed the BottomSheet component.
  • src/hooks/use-app-router.ts
    • Renamed from useAppRouter.ts.
Activity
  • The pull request author, jbdevprimary, completed 24 commits across 18 user stories, bringing the project to full production readiness.
  • Key features delivered include multi-agent pipeline orchestration, agent read/write tools with approval-triggered commits, and capability-aware agent routing.
  • The AI & Provider System was significantly upgraded with Vercel AI SDK integration for 10 providers and universal variant generation.
  • New Chat & Multimedia features were added, such as multimodal content types, camera/voice input, and multimedia chat components.
  • Development tools were enhanced with an AgentSkill interface, live component preview, MCP registry, and a document generation engine.
  • Testing and cleanup efforts resulted in 169 test files, 2064 passing tests, clean TypeScript typechecks, and the removal of ~2000 lines of dead code.
  • Architectural highlights include a unified AI SDK, MCP integration, capability routing, and sandboxed previews.
  • The author provided a detailed test plan, including typecheck, unit tests, and manual smoke tests for new features.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Comment thread packages/agent-intelligence/src/services/routing/AgentRouter.ts Fixed
Comment thread packages/state/src/__tests__/chatStore.test.ts Fixed
Comment thread packages/state/src/agentStore.ts Fixed
Comment thread packages/state/src/agentStore.ts Fixed
Comment thread packages/state/src/credentialStore.ts Fixed
jbdevprimary and others added 20 commits February 23, 2026 19:34
Remove unused isRecordMode variable, fix import ordering, and apply
Biome formatter fixes to pass CI lint check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The execute() method returned promises without awaiting them inside the
try block, making the catch block unreachable for async rejections.
Fixes SonarCloud S4822 reliability bug (Quality Gate C → A).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All 4 agents (Architect, Implementer, Reviewer, Tester) now route
file I/O tools through ToolExecutionBridge for real workspace
operations. Agent-specific tools remain as orchestration-level
handlers. Updated AGENTS.md to reflect production-ready state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Approved design + 16-task implementation plan to dissolve all 6
runtime packages into src/ and decompose agent-intelligence into
src/services/. Removes all workspace ceremony.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace stub MCP transport with real Vercel AI SDK integration.
McpClient now creates stdio/HTTP/SSE connections, discovers tools
via the SDK, and executes them natively. McpToolBridge converts
SDK tool definitions to agent ToolDefinition format with name
prefixing for collision avoidance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rvices/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jbdevprimary jbdevprimary changed the title feat: Production Launch v2 — Complete all remaining user stories (US-004 through US-036) refactor: flatten monorepo packages into src/ Feb 24, 2026
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/lib/preview-sandbox.ts Fixed
Comment thread src/__tests__/ai-client.test.ts Fixed
- Fix 126 noExplicitAny warnings across 37 test/production files
- Fix noNonNullAssertion, noExcessiveCognitiveComplexity, unused params
- Address all 18 PR review threads (security, CSS, error handling)
- Harden preview-sandbox.ts with iterative sanitization loops
- Use LucideIcon type for Toast.tsx icon prop
- Use GitHubContent type in ProjectFileExplorer test mocks
- Fix Zustand store selector types in test mocks
- Remove unused imports and biome-ignore suppressions
- Auto-fix all Biome formatting violations

Result: 0 TS errors, 0 lint errors, 0 warnings, 2076 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
let sanitized = input;

// Remove <style> and </style> tags (with optional whitespace/attributes)
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<style
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General approach: Ensure that any occurrence of the substring <style (regardless of whether it forms a syntactically complete tag) is removed or neutralized, so an attacker cannot rely on partial or malformed <style markup surviving. This addresses the “incomplete multi-character sanitization” concern by matching the dangerous prefix itself, not only full tags.

Best targeted fix: Extend the existing “Remove <style> and </style> tags” step to also remove any residual <style sequences. We can do this by adding one more replacement call that strips <style prefixes regardless of whether they have a closing >. This keeps behavior aligned with current intent (you already intend to strip styles entirely) and minimizes changes.

Concretely, in sanitizeCss in src/lib/preview-sandbox.ts:

  • Keep the existing line 118 that removes <style> / </style> tags.
  • Immediately after it, add a second replacement, e.g.
    sanitized = sanitized.replace(/<\s*style\b/gi, '');
    This removes any <style opening sequence (with optional whitespace) that could remain or be (re)created by prior transformations, even without a terminating > or attributes.
  • No new imports or helpers are needed; this is a simple regex replacement.

This solves the CodeQL concern by ensuring the sensitive multi-character pattern <style itself cannot persist, independent of tag completeness.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -116,6 +116,8 @@
 
     // Remove <style> and </style> tags (with optional whitespace/attributes)
     sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
+    // Additionally remove any remaining "<style" openings, even if the tag is malformed/incomplete
+    sanitized = sanitized.replace(/<\s*style\b/gi, '');
 
     // Remove <script> tags and their content (handles whitespace in closing tag)
     sanitized = sanitized.replace(
EOF
@@ -116,6 +116,8 @@

// Remove <style> and </style> tags (with optional whitespace/attributes)
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
// Additionally remove any remaining "<style" openings, even if the tag is malformed/incomplete
sanitized = sanitized.replace(/<\s*style\b/gi, '');

// Remove <script> tags and their content (handles whitespace in closing tag)
sanitized = sanitized.replace(
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +121 to +124
sanitized = sanitized.replace(
/<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
''
);

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General approach: Avoid the fragile, complex multi-character <script>...</script> regex that can leave <script behind when used in isolation. Since we already run this in an iterative sanitizer and then strip all HTML tags, we can both (a) simplify script handling and (b) ensure we never depend on that complex multi-character match. A robust fix is to stop using the problematic regex altogether and rely on simpler, more predictable sanitization steps that are safe under iterative application.

Best concrete fix here:

  • Remove the multi-character script-block regex at lines 121–123.
  • Keep (or slightly adjust) the subsequent removal of any remaining <script> tags (/<\/?script\s*[^>]*>/gi).
  • Ensure that, combined with the existing general HTML tag stripper (/<[^>]+>/g), no <script> tags can survive, regardless of how the input is structured.
  • Because we are removing the fragile regex, we eliminate the incomplete multi-character sanitization pattern that CodeQL is flagging, without changing the intended behavior (the goal remains: “no script tags in the sanitized CSS”).

Implementation details in this file:

  • In sanitizeCss in src/lib/preview-sandbox.ts, replace the current two-step script handling:
    • The complex script-block removal (sanitized.replace(/<script\b...<\/\s*script\s*>/gi, ''))
    • Plus the comment that refers to it
  • With a simpler approach that only uses the single-tag regex (to strip any <script ...> or </script>), which is safe even if applied iteratively.
  • Keep the rest of the sanitization logic (style tags, HTML tags, expression(, url(javascript:), @import, etc.) unchanged.

No new imports or external libraries are needed; we are just simplifying regex usage.


Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -117,12 +117,7 @@
     // Remove <style> and </style> tags (with optional whitespace/attributes)
     sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
 
-    // Remove <script> tags and their content (handles whitespace in closing tag)
-    sanitized = sanitized.replace(
-      /<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
-      ''
-    );
-    // Remove any remaining opening/closing script tags
+    // Remove any <script> or </script> tags (handles optional whitespace/attributes)
     sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');
 
     // Remove all remaining HTML tags
EOF
@@ -117,12 +117,7 @@
// Remove <style> and </style> tags (with optional whitespace/attributes)
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

// Remove <script> tags and their content (handles whitespace in closing tag)
sanitized = sanitized.replace(
/<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
''
);
// Remove any remaining opening/closing script tags
// Remove any <script> or </script> tags (handles optional whitespace/attributes)
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');

// Remove all remaining HTML tags
Copilot is powered by AI and may make mistakes. Always verify output.

// Remove <script> tags and their content (handles whitespace in closing tag)
sanitized = sanitized.replace(
/<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,

Check failure

Code scanning / CodeQL

Bad HTML filtering regexp High

This regular expression does not match script end tags like </script\t\n bar>.

Copilot Autofix

AI 3 months ago

In general: do not try to perfectly model browser HTML parsing with complex negative-lookahead regexes. Instead, either use a standard sanitization library or use a conservative, simpler pattern that over-matches (removing more than strictly necessary) but reliably strips all <script> blocks, including weirdly formatted closing tags such as </script foo> or </script\t\nbar>.

Best targeted fix here: replace the fragile multi-line script-block regex with a simpler, greedy pattern that:

  • Starts at <script with optional attributes.
  • Consumes everything up to the first occurrence of a closing tag that starts with </script and continues up to its > (allowing extra junk/attributes after script), by using a negative character class only on < until we see </script, and then a permissive [^>]*> for the closing tag.
  • Remains case-insensitive and global.

Concretely, in src/lib/preview-sandbox.ts inside sanitizeCss, update the line:

sanitized = sanitized.replace(
  /<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
  ''
);

to a more robust version such as:

sanitized = sanitized.replace(
  /<script\b[^>]*>[\s\S]*?<\/script[^>]*>/gi,
  ''
);

This pattern:

  • Allows arbitrary attributes after <script.
  • Matches any content, including newlines ([\s\S]*?, non-greedy).
  • Accepts any closing tag that starts with </script and continues with optional whitespace/attributes until > (<\/script[^>]*>), thereby matching </script foo> and </script\t\n bar> and the like.
  • Keeps overall functionality: remove full <script>...</script> blocks. The follow‑up /</?script\s*[^>]*>/gi call is left intact, still catching leftover standalone/opening/closing tags.

No new imports or helpers are required; we just adjust the regex literal in place.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -117,9 +117,10 @@
     // Remove <style> and </style> tags (with optional whitespace/attributes)
     sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
 
-    // Remove <script> tags and their content (handles whitespace in closing tag)
+    // Remove <script> tags and their content (including malformed closing tags
+    // like </script foo="bar">, while allowing attributes and newlines)
     sanitized = sanitized.replace(
-      /<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
+      /<script\b[^>]*>[\s\S]*?<\/script[^>]*>/gi,
       ''
     );
     // Remove any remaining opening/closing script tags
EOF
@@ -117,9 +117,10 @@
// Remove <style> and </style> tags (with optional whitespace/attributes)
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

// Remove <script> tags and their content (handles whitespace in closing tag)
// Remove <script> tags and their content (including malformed closing tags
// like </script foo="bar">, while allowing attributes and newlines)
sanitized = sanitized.replace(
/<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
/<script\b[^>]*>[\s\S]*?<\/script[^>]*>/gi,
''
);
// Remove any remaining opening/closing script tags
Copilot is powered by AI and may make mistakes. Always verify output.
''
);
// Remove any remaining opening/closing script tags
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General approach: Avoid leaving behind partial <script fragments by ensuring that script tags and their contents are removed using a single, robust pattern, instead of a simpler tag-only regex that could participate in substring recombination. In practice here, that means eliminating the redundant, less-safe script-tag regex and relying on the existing, more complete one that already strips <script> blocks with their content, while still running under the iterative sanitization framework.

Concrete fix for this code: In sanitizeCss, we already have a strong regex on lines 121–123 that removes <script> tags and their content (/<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi). Immediately after that, line 126 runs sanitized.replace(/<\/?script\s*[^>]*>/gi, ''), which CodeQL flags. We can safely remove this second, redundant replacement. Doing so keeps behavior effectively the same for valid <script> blocks, but avoids a second, looser script regex that may participate in incomplete multi-character sanitization patterns. All other HTML-removal logic (/<[^>]+>/g) and CSS-specific removals remain unchanged. This requires only deleting the flagged line and its comment; no imports or new helpers are needed.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -122,8 +122,6 @@
       /<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
       ''
     );
-    // Remove any remaining opening/closing script tags
-    sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');
 
     // Remove all remaining HTML tags
     sanitized = sanitized.replace(/<[^>]+>/g, '');
EOF
@@ -122,8 +122,6 @@
/<script\b[^<]*(?:(?!<\/\s*script\s*>)<[^<]*)*<\/\s*script\s*>/gi,
''
);
// Remove any remaining opening/closing script tags
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');

// Remove all remaining HTML tags
sanitized = sanitized.replace(/<[^>]+>/g, '');
Copilot is powered by AI and may make mistakes. Always verify output.
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');

// Remove all remaining HTML tags
sanitized = sanitized.replace(/<[^>]+>/g, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General approach: ensure that after sanitization, no angle-bracket-delimited HTML constructs can remain, even if multi-character regex replacements behave unexpectedly. A robust way, aligned with the background recommendations, is to eliminate any remaining < and > characters after the existing passes. This converts any would-be HTML elements into plain text, preventing element injection.

Best targeted fix here: keep the existing logic (including the multi-step, iterative regex sanitization) to preserve current behavior as much as possible, but add a final step inside the callback used by sanitizeIteratively that strips any remaining < or > characters. This is a narrow, append-only change to sanitizeCss in src/lib/preview-sandbox.ts. No new imports or helpers are needed; we can simply add:

// Remove any remaining angle brackets to prevent HTML tag injection
sanitized = sanitized.replace(/[<>]/g, '');

right before return sanitized;. This guarantees that even if /<[^>]+>/g were to miss or partially process some sequences (the situation CodeQL worries about), no actual <tag constructs can survive. Functionality impact is minimal: any literal < or > that previously might have survived (e.g., broken HTML fragments) will now be removed, which is acceptable for a CSS sanitizer concerned with XSS defense.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -143,6 +143,9 @@
     // Remove behavior: (IE HTC XSS vector)
     sanitized = sanitized.replace(/behavior\s*:/gi, '');
 
+    // Remove any remaining angle brackets to prevent HTML tag injection
+    sanitized = sanitized.replace(/[<>]/g, '');
+
     return sanitized;
   });
 }
EOF
@@ -143,6 +143,9 @@
// Remove behavior: (IE HTC XSS vector)
sanitized = sanitized.replace(/behavior\s*:/gi, '');

// Remove any remaining angle brackets to prevent HTML tag injection
sanitized = sanitized.replace(/[<>]/g, '');

return sanitized;
});
}
Copilot is powered by AI and may make mistakes. Always verify output.
''
);
// Remove any remaining opening/closing script tags (handles self-closing and orphaned tags)
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

In general, the safest fix is to ensure that sanitization does not rely on single-pass multi-character regexes for high-risk tokens like <script, or to delegate to a mature sanitization library. Within the existing design, the best targeted fix is to add a final, simple, character-level cleanup that removes any residual <script substrings, while keeping the existing behavior intact. This complements the existing iterative framework rather than changing the semantics of earlier regexes.

Concretely, within sanitizeHtml in src/lib/preview-sandbox.ts, after the existing block that strips script tags (lines 163–170), we should add a new replacement that removes any occurrence of <script start sequences regardless of context (e.g., fragments produced by things like <scr<script>ipt>). For example:

sanitized = sanitized.replace(/<\s*script/gi, '');

Because sanitizeIteratively already re-applies this function until the output stops changing, any partial <script fragments introduced by other replacements will eventually be removed as well. This change is local to the sanitizeHtml function; no new imports or helper functions are needed, and we don’t alter the configuration or other parts of the file.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -167,6 +167,8 @@
     );
     // Remove any remaining opening/closing script tags (handles self-closing and orphaned tags)
     sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');
+    // As a final safeguard, remove any residual `<script` start sequences, even if malformed
+    sanitized = sanitized.replace(/<\s*script/gi, '');
 
     // Remove style tags and their content (prevents CSS injection via <style> blocks)
     sanitized = sanitized.replace(
EOF
@@ -167,6 +167,8 @@
);
// Remove any remaining opening/closing script tags (handles self-closing and orphaned tags)
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');
// As a final safeguard, remove any residual `<script` start sequences, even if malformed
sanitized = sanitized.replace(/<\s*script/gi, '');

// Remove style tags and their content (prevents CSS injection via <style> blocks)
sanitized = sanitized.replace(
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +172 to +175
sanitized = sanitized.replace(
/<style\b[^<]*(?:(?!<\/\s*style\s*>)<[^<]*)*<\/\s*style\s*>/gi,
''
);

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<style
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General approach: Avoid multi-character “block” regexes that try to parse an entire tag and its content in one go (e.g., /<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi). Instead, rely on simpler patterns that remove <style> tags and their content more directly and robustly, or use a dedicated sanitization library. Here, we’ll keep existing behavior but remove the complex multi-character regex that CodeQL flags, leveraging the iterative sanitizer and the simpler <style tag regex to ensure all style blocks are stripped over successive passes.

Best targeted fix: In sanitizeHtml, remove the first <style>-handling replace call that uses the complex multi-character regex (lines 172–175), and keep only the second, simpler call that deletes any <style> or </style> tag (/<\/?style\s*[^>]*>/gi). Because sanitizeIteratively re-applies the whole transformation until the string stabilizes, repeatedly stripping <style...> and </style> tags suffices to eradicate style blocks and their contents, even if they were malformed or nested. This eliminates the multi-character “block” regex that is the root of the CodeQL warning, while preserving the intended effect of removing styles as a defense-in-depth measure.

Concretely:

  • In src/lib/preview-sandbox.ts, inside sanitizeHtml:
    • Delete the block:

      // Remove style tags and their content (prevents CSS injection via <style> blocks)
      sanitized = sanitized.replace(
        /<style\b[^<]*(?:(?!<\/\s*style\s*>)<[^<]*)*<\/\s*style\s*>/gi,
        ''
      );
    • Keep the subsequent simpler line:

      sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

No new imports or helper methods are needed; we’re simplifying existing logic, not adding functionality.


Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -169,16 +169,15 @@
     sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');
 
     // Remove style tags and their content (prevents CSS injection via <style> blocks)
-    sanitized = sanitized.replace(
-      /<style\b[^<]*(?:(?!<\/\s*style\s*>)<[^<]*)*<\/\s*style\s*>/gi,
-      ''
-    );
     sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
 
     // Remove event handler attributes (onclick, onerror, onload, etc.)
     // Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
     // Also handles whitespace/newlines between 'on' and '=' and around '='
     sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');
+    // Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
+    // Also handles whitespace/newlines between 'on' and '=' and around '='
+    sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');
 
     // Remove javascript: protocol in href/src/action attributes (quoted and unquoted)
     // Handles whitespace between protocol name and colon
EOF
@@ -169,16 +169,15 @@
sanitized = sanitized.replace(/<\/?script\s*[^>]*>/gi, '');

// Remove style tags and their content (prevents CSS injection via <style> blocks)
sanitized = sanitized.replace(
/<style\b[^<]*(?:(?!<\/\s*style\s*>)<[^<]*)*<\/\s*style\s*>/gi,
''
);
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

// Remove event handler attributes (onclick, onerror, onload, etc.)
// Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
// Also handles whitespace/newlines between 'on' and '=' and around '='
sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');
// Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
// Also handles whitespace/newlines between 'on' and '=' and around '='
sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');

// Remove javascript: protocol in href/src/action attributes (quoted and unquoted)
// Handles whitespace between protocol name and colon
Copilot is powered by AI and may make mistakes. Always verify output.
/<style\b[^<]*(?:(?!<\/\s*style\s*>)<[^<]*)*<\/\s*style\s*>/gi,
''
);
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<style
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General fix: ensure the sanitization of <style> elements cannot leave behind any <style substrings that might form new tags after other replacements. We can achieve this either by (a) repeatedly applying the <style>-related replacements until no more changes occur or (b) using an additional character-level sanitizer that strips all <style substrings regardless of surrounding context. Since we must not modify unseen parts of the code (like sanitizeIteratively), the safest change within the shown snippet is to strengthen the <style>-tag removal so that any residual <style is eliminated, even if it’s not part of a syntactically valid tag.

Best targeted fix: after the existing two <style> sanitization replacements, add a final cleanup that removes any remaining <style sequences (case-insensitive). This addresses CodeQL’s specific concern (“may still contain <style”) and breaks any newly formed <style tags or partial tags, without changing the rest of the sanitizer’s behavior. Concretely, in sanitizeHtml within src/lib/preview-sandbox.ts, directly after:

sanitized = sanitized.replace(
  /<style\b[^<]*(?:(?!<\/\s*style\s*>)<[^<]*)*<\/\s*style\s*>/gi,
  ''
);
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');

we’ll insert:

sanitized = sanitized.replace(/<\s*style/gi, '');

This ensures no <style substring survives, regardless of how the text was transformed by previous replacements in this iteration, while minimally altering the existing logic.

No new imports or external libraries are needed; we only add an extra .replace call using a simple global, case-insensitive regex.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -174,6 +174,9 @@
       ''
     );
     sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
+    // Defense-in-depth: remove any remaining "<style" substrings that might have formed
+    // after previous replacements to avoid incomplete multi-character sanitization.
+    sanitized = sanitized.replace(/<\s*style/gi, '');
 
     // Remove event handler attributes (onclick, onerror, onload, etc.)
     // Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
EOF
@@ -174,6 +174,9 @@
''
);
sanitized = sanitized.replace(/<\/?style\s*[^>]*>/gi, '');
// Defense-in-depth: remove any remaining "<style" substrings that might have formed
// after previous replacements to avoid incomplete multi-character sanitization.
sanitized = sanitized.replace(/<\s*style/gi, '');

// Remove event handler attributes (onclick, onerror, onload, etc.)
// Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
Copilot is powered by AI and may make mistakes. Always verify output.
// Remove event handler attributes (onclick, onerror, onload, etc.)
// Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
// Also handles whitespace/newlines between 'on' and '=' and around '='
sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
on
, which may cause an HTML attribute injection vulnerability.

Copilot Autofix

AI 3 months ago

In general: to fix incomplete multi-character sanitization, ensure that removing one match cannot cause new instances of the same unsafe pattern to appear unnoticed. This can be done by (a) repeatedly applying the same replacement until the string stops changing, or (b) rewriting the pattern so it operates on single characters or simpler units whose removal cannot create fresh matches.

For this specific case, the problematic pattern is the removal of on* event handler attributes:

sanitized = sanitized.replace(
  /\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi,
  ''
);

The safest, least intrusive fix—without changing existing functionality—is to wrap this replacement in a small loop that keeps removing on* attributes until there are none left. Because sanitizeIteratively is outside the visible snippet and cannot be edited, we should make the event-handler removal idempotent by itself: compute a new string with the replacement and, while that string differs from the previous one, reapply the replacement. This only affects the event-handler sanitization step and preserves all other logic.

Concretely, in src/lib/preview-sandbox.ts, around line 181 where the on\w+ replacement is performed, replace the single replace call with a loop that repeatedly applies the same regex until the string no longer changes. No new imports or helpers are strictly necessary; we can implement this inline with a simple do ... while loop.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -178,7 +178,16 @@
     // Remove event handler attributes (onclick, onerror, onload, etc.)
     // Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
     // Also handles whitespace/newlines between 'on' and '=' and around '='
-    sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');
+    // Apply iteratively to avoid incomplete removal when replacements change surrounding text
+    {
+      const eventHandlerAttrRegex =
+        /\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi;
+      let previousSanitized: string;
+      do {
+        previousSanitized = sanitized;
+        sanitized = sanitized.replace(eventHandlerAttrRegex, '');
+      } while (sanitized !== previousSanitized);
+    }
 
     // Remove javascript: protocol in href/src/action attributes (quoted and unquoted)
     // Handles whitespace between protocol name and colon
EOF
@@ -178,7 +178,16 @@
// Remove event handler attributes (onclick, onerror, onload, etc.)
// Handles: double-quoted, single-quoted, backtick-quoted, unquoted values
// Also handles whitespace/newlines between 'on' and '=' and around '='
sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi, '');
// Apply iteratively to avoid incomplete removal when replacements change surrounding text
{
const eventHandlerAttrRegex =
/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s>]*)/gi;
let previousSanitized: string;
do {
previousSanitized = sanitized;
sanitized = sanitized.replace(eventHandlerAttrRegex, '');
} while (sanitized !== previousSanitized);
}

// Remove javascript: protocol in href/src/action attributes (quoted and unquoted)
// Handles whitespace between protocol name and colon
Copilot is powered by AI and may make mistakes. Always verify output.
);

// Remove iframe, object, embed, applet, form tags
sanitized = sanitized.replace(/<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<iframe
, which may cause an HTML element injection vulnerability.

Copilot Autofix

AI 3 months ago

General fix: avoid relying on a single multi-character regex that removes complete disallowed tags in one operation. Instead, either (a) parse and reconstruct allowed HTML, or (b) match and neutralize the dangerous characters (<, >) in disallowed tags or remove those tags via a more robust, iterative or character-based strategy. Since we must not change overall functionality significantly and want to stay within this file, we’ll keep the existing sanitizeHtml structure but refactor the specific <iframe|object|embed|applet|form> removal into a dedicated helper that removes disallowed tags in a loop until none remain. This makes the sanitization explicitly iterative at the tag level and addresses the multi-character sanitization warning.

Concrete approach: inside src/lib/preview-sandbox.ts, define a small helper function above sanitizeHtml that repeatedly strips disallowed tags using the same pattern until the string stabilizes:

function removeDangerousTags(input: string): string {
  const dangerousTagPattern = /<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi;
  let previous: string;
  let current = input;

  do {
    previous = current;
    current = current.replace(dangerousTagPattern, '');
  } while (current !== previous);

  return current;
}

Then, in sanitizeHtml, replace the direct sanitized.replace(/<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi, ''); call with sanitized = removeDangerousTags(sanitized);. This keeps behavior (removing those tags) but ensures that even if partial or overlapping patterns cause new occurrences of <iframe, <object>, etc. to appear after a replacement, they will be removed on subsequent iterations inside removeDangerousTags, independent of what sanitizeIteratively does. No new imports are needed; everything uses built-in JS/TS features.

Suggested changeset 1
src/lib/preview-sandbox.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/preview-sandbox.ts b/src/lib/preview-sandbox.ts
--- a/src/lib/preview-sandbox.ts
+++ b/src/lib/preview-sandbox.ts
@@ -156,6 +156,19 @@
  *
  * This is a defense-in-depth sanitizer for preview content.
  */
+function removeDangerousTags(input: string): string {
+  const dangerousTagPattern = /<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi;
+  let previous: string;
+  let current = input;
+
+  do {
+    previous = current;
+    current = current.replace(dangerousTagPattern, '');
+  } while (current !== previous);
+
+  return current;
+}
+
 export function sanitizeHtml(html: string): string {
   return sanitizeIteratively(html, (input) => {
     let sanitized = input;
@@ -194,7 +207,7 @@
     );
 
     // Remove iframe, object, embed, applet, form tags
-    sanitized = sanitized.replace(/<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi, '');
+    sanitized = removeDangerousTags(sanitized);
 
     // Remove style attributes containing dangerous values
     // Handles double-quoted, single-quoted, and backtick-quoted attribute values
EOF
@@ -156,6 +156,19 @@
*
* This is a defense-in-depth sanitizer for preview content.
*/
function removeDangerousTags(input: string): string {
const dangerousTagPattern = /<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi;
let previous: string;
let current = input;

do {
previous = current;
current = current.replace(dangerousTagPattern, '');
} while (current !== previous);

return current;
}

export function sanitizeHtml(html: string): string {
return sanitizeIteratively(html, (input) => {
let sanitized = input;
@@ -194,7 +207,7 @@
);

// Remove iframe, object, embed, applet, form tags
sanitized = sanitized.replace(/<\/?(?:iframe|object|embed|applet|form)\b[^>]*>/gi, '');
sanitized = removeDangerousTags(sanitized);

// Remove style attributes containing dangerous values
// Handles double-quoted, single-quoted, and backtick-quoted attribute values
Copilot is powered by AI and may make mistakes. Always verify output.
jbdevprimary and others added 2 commits February 24, 2026 12:36
The generate-tokens.ts script still had '../../../' from when it lived
in packages/dev-tools/. Updated to '..' since tools/ is now at project root.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Trigger on push to main (not just releases/manual)
- Always upload APKs as workflow artifacts (not just workflow_dispatch)
- Add x86 ABI split for emulator support
- Add Android SDK setup step
- Retain artifacts for 30 days

Architectures: armeabi-v7a, arm64-v8a, x86, x86_64, universal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
5 Security Hotspots
76.1% Coverage on New Code (required ≥ 80%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@jbdevprimary jbdevprimary merged commit 7d3f757 into main Feb 24, 2026
16 of 19 checks passed
@jbdevprimary jbdevprimary deleted the feat/production-launch-v2 branch February 24, 2026 18:44
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