Skip to content

feat: add Kiro (AWS Agentic IDE) as a 5th provider via ACP#760

Open
dgallitelli wants to merge 8 commits into
siteboon:mainfrom
dgallitelli:feature/kiro-provider-acp
Open

feat: add Kiro (AWS Agentic IDE) as a 5th provider via ACP#760
dgallitelli wants to merge 8 commits into
siteboon:mainfrom
dgallitelli:feature/kiro-provider-acp

Conversation

@dgallitelli

@dgallitelli dgallitelli commented May 12, 2026

Copy link
Copy Markdown

Summary

Closes #574 (and supersedes the earlier #575 against the pre-refactor architecture).

Adds Kiro — AWS's Claude-based agentic IDE — as a 5th provider alongside Claude, Cursor, Codex, and Gemini, using the new IProvider abstraction from #715. Verified end-to-end against kiro-cli 2.3.0 with real on-disk artifacts.

Why this is a fresh PR (not a rebase of #575)

Two refactors landed after #575 was opened (#666 and #715) that replaced the entire provider runtime architecture. A rebase would essentially be a full rewrite, so per @blackmammoth's note that's exactly what this PR is — fresh, against current main.

What's interesting about Kiro vs. the other 4 providers

Kiro is the first provider in this codebase to use ACP (Agent Client Protocol) — an open JSON-RPC 2.0 standard (agentclientprotocol.com) originated by Zed. That means Kiro:

  • Uses kiro-cli acp --trust-all-tools (not kiro-cli chat --no-interactive) for streamed output. Plain chat only emits ANSI text — no structured tool events.
  • Persists sessions as JSONL at ~/.kiro/sessions/cli/<id>.{json,jsonl} with a sidecar .json carrying cwd/title. (There's a separate SQLite store at ~/.local/share/kiro-cli/data.sqlite3 for chat-mode sessions, but ACP's session/load works on chat-created sessions too — verified — so we read from the filesystem store and let session/load cover resume.)
  • Reads auth from ~/.aws/sso/cache/kiro-auth-token.json (AWS IAM Identity Center / Builder ID), not a JWT. Email comes from kiro-cli whoami.
  • Speaks MCP via ~/.kiro/settings/mcp.json (flat mcpServers map identical to Claude's, plus disabled and autoApprove Kiro-only fields that we round-trip).
  • Has model and agent selection via --model/--agent CLI flags on the kiro-cli acp spawn — not as JSON-RPC params on session/prompt (verified — putting them on the prompt is a silent no-op).

What's added

Backend

File Role LOC
server/modules/providers/list/kiro/kiro.provider.ts Composition root 17
server/modules/providers/list/kiro/kiro-auth.provider.ts AWS SSO token reader + whoami email lookup 167
server/modules/providers/list/kiro/kiro-mcp.provider.ts MCP CRUD with disabled/autoApprove round-trip 156
server/modules/providers/list/kiro/kiro-sessions.provider.ts JSONL → NormalizedMessage (Prompt / AssistantMessage / ToolResults with statusisError) 308
server/modules/providers/list/kiro/kiro-session-synchronizer.provider.ts Watches ~/.kiro/sessions/cli/, indexes via sidecar .json, preserves user-set custom_name 132
server/modules/providers/list/kiro/stdio-jsonrpc-client.ts New shared JSON-RPC 2.0 stdio client (no precedent in repo) 238
server/kiro-cli.js Spawns kiro-cli acp, drives initializesession/new|loadsession/prompt, normalizes session/update notifications, hardened error/abort paths 343

Plus minimal additions to: provider.registry.ts, session-synchronizer.service.ts, sessions-watcher.service.ts, chat-websocket.service.ts, routes/agent.js, index.js, projects-with-sessions-fetch.service.ts, project-management.service.ts, database/index.ts (re-exports closeConnection), shared/types.ts (LLMProvider union).

Frontend

KiroLogo (placeholder SVG — TODO: replace with official asset once trademark policy is confirmed) + the standard provider-card wiring across useChatProviderState, useChatComposerState, ChatInterface, ChatMessagesPane, ProviderSelectionEmptyState, provider-auth/types, ProviderLoginModal, mcp/constants, agents-settings/*, useProjectsState, sidebar/utils, useSessionsSource, LLMProvider union in src/types/app.ts, and KIRO_MODELS in shared/modelConstants.js.

Tests (31 new + 1 updated)

$ npm run test:server
# tests 63
# pass 63
# fail 0
Suite Count Coverage
stdio-jsonrpc-client.test.ts 13 Frame splitting/joining, request/response correlation, error frames, notification routing, prefix wildcards, close behavior, timeouts
kiro-sessions.provider.test.ts 8 Prompt/AssistantMessage/ToolResults shapes, status:'error'isError, empty-content drops, unknown-kind safety
kiro-mcp.provider.test.ts 7 End-to-end MCP CRUD against tmp $HOME, including the disabled/autoApprove preservation regression
kiro-session-synchronizer.test.ts 3 Isolated-DB integration test for the user-renamed-then-resync regression
mcp.test.ts (existing) +1 assertion Kiro added to global MCP-adder count

i18n

messageTypes.kiro and providerSelection.readyPrompt.kiro added to all 8 locales.

Reviewed by Opus 4.7 before submission

A senior-level Opus 4.7 review of the initial implementation flagged several issues that are all fixed in this PR:

  • HIGH: Kiro sessions were silently dropped from getProjectsWithSessions (hardcoded 4-provider SessionsByProvider). Plumbed end-to-end now.
  • HIGH: Model was sent on session/prompt JSON-RPC params and silently ignored by kiro-cli. Moved to spawn-time --model CLI flag.
  • MED: data.status was being ignored on ToolResults events; isError is now read from there with content-part fallback.
  • MED: MCP upsert was wiping user's disabled/autoApprove fields on every UI edit — now round-trips them via a KiroMcpProvider.upsertServer override.
  • MED: Synchronizer was overwriting user-set custom_name on every re-sync — now mirrors Codex's "preserve user name" pattern.
  • MED: Pre-session-id abort window: ws.setSessionId(placeholderKey) is called before session/new so the frontend can target an abort during the (potentially 30s+) MCP boot phase.
  • MED: Error path now half-closes stdin before SIGTERM and falls back to SIGKILL after 5s to prevent hung processes.
  • MED: AGENT_PROVIDERS / visibleAgents / routes/agent.js validator all updated for Kiro.
  • LOW: HTTP bearer_token_env_var is now persisted on MCP upsert (was only being read, not written).

Verification

Run against a real kiro-cli 2.3.0 install:

# Auth: detected expired IdC token correctly
{"installed":true,"provider":"kiro","authenticated":false,"method":"IdC","error":"OAuth token has expired"}

# MCP: 3 user-scope servers normalized end-to-end
# Sessions: 10 NormalizedMessages parsed from 2 real ACP session files

Test plan

  • Install Kiro CLI: curl -fsSL https://cli.kiro.dev/install | bash
  • Run kiro-cli login and confirm kiro-cli whoami prints an email
  • Select Kiro from the provider grid, send "say hi" — expect streaming text response
  • Run a tool-use prompt (e.g. "list files in /tmp") — expect tool_use card + tool_result rendering
  • Resume an existing session by clicking it in the sidebar — expect history reload + continuation
  • Add an MCP server through the UI — confirm ~/.kiro/settings/mcp.json round-trips disabled/autoApprove if previously set
  • Rename a session via the UI and run kiro-cli chat ... to trigger a re-sync — confirm rename survives

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added Kiro as a new LLM provider with model selection support.
    • Integrated Kiro session management and history tracking.
    • Implemented Kiro authentication status monitoring.
    • Added Kiro MCP server configuration support.
    • Extended localization for Kiro across multiple languages (English, German, Italian, Japanese, Korean, Russian, Turkish, Simplified Chinese).

Adds Kiro CLI (kiro-cli, AWS's Claude-based agentic IDE) alongside Claude,
Cursor, Codex, and Gemini using the new IProvider abstraction from siteboon#715.
Closes siteboon#574.

Backend
- New `server/modules/providers/list/kiro/` module: composition root,
  auth (reads ~/.aws/sso/cache/kiro-auth-token.json + kiro-cli whoami),
  MCP (~/.kiro/settings/mcp.json with disabled/autoApprove preserved on
  upsert), sessions (parses ~/.kiro/sessions/cli/<id>.jsonl), and
  synchronizer (preserves user-set custom_name across re-syncs).
- `server/kiro-cli.js`: spawns `kiro-cli acp --trust-all-tools` and drives
  ACP (Agent Client Protocol, https://agentclientprotocol.com) over stdio:
  initialize → session/new|load → session/prompt. Streams session/update
  notifications (agent_message_chunk, tool_call, tool_call_update) into
  NormalizedMessage. Model/agent are passed as spawn-time CLI flags
  (verified against kiro-cli 2.3.0 — they are NOT session/prompt params).
- `server/modules/providers/list/kiro/stdio-jsonrpc-client.ts`: new shared
  JSON-RPC 2.0 stdio client (no precedent in repo). Handles partial frames,
  CRLF, response correlation, prefix-namespace handlers, and rejection of
  pending requests on child close.
- Provider registry, sessions watcher, websocket dispatch, agent route,
  and project listing all widened to include Kiro. SessionsByProvider /
  ProjectListItem now expose kiroSessions end-to-end.

Frontend
- KiroLogo + placeholder SVGs (TODO: replace with official asset once
  trademark policy is confirmed).
- LLMProvider union widened in src/types/app.ts.
- Provider auth, chat composer, model selector, sidebar utils, command
  palette source, MCP constants, agent settings tab, and onboarding all
  updated. KIRO_MODELS in shared/modelConstants.js (Claude-only subset
  for v1; full catalog is dynamic via `kiro-cli chat --list-models`).

Tests (31 new + 1 updated)
- StdioJsonRpcClient: 13 unit tests covering frame splitting/joining,
  request/response correlation, error frames, notification routing,
  prefix wildcards, close behavior, and timeouts.
- KiroSessionsProvider: 8 tests covering Prompt/AssistantMessage/
  ToolResults shapes, status:'success'/'error' isError mapping, and
  empty-content drops.
- KiroMcpProvider: 7 end-to-end MCP CRUD tests against an isolated tmp
  $HOME, including the disabled/autoApprove preservation regression.
- KiroSessionSynchronizer: 3 integration tests against an isolated
  SQLite DB, including the user-renamed-then-resync regression that
  proved custom_name was being overwritten.
- mcp.test.ts updated to include kiro in the global-adder count (5
  providers, or 4 on Windows).
- New `npm run test:server` script: 63 tests pass, 0 failures.

i18n
- messageTypes.kiro and providerSelection.readyPrompt.kiro added to all
  8 locales (en, de, it, ja, ko, ru, tr, zh-CN).

Verified against kiro-cli 2.3.0 with real on-disk artifacts: SQLite
session store at ~/.local/share/kiro-cli/data.sqlite3, JSONL+sidecar
sessions at ~/.kiro/sessions/cli/<id>.{json,jsonl}, and MCP config at
~/.kiro/settings/mcp.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Kiro (AWS CLI) as a new LLM provider. The integration includes a StdioJsonRpcClient transport, a kiro-cli acp process orchestrator, and a full provider implementation covering auth, MCP persistence, models, skills, session synchronization, and session history. Frontend state hooks, UI components, settings pages, and eight i18n locales are extended to support Kiro alongside existing providers.

Changes

Kiro Provider Integration

Layer / File(s) Summary
Shared types and provider constants
server/shared/types.ts, src/types/app.ts, src/components/settings/constants/constants.ts, src/components/mcp/constants.ts, src/components/provider-auth/types.ts, server/modules/providers/services/provider-capabilities.service.ts, server/modules/providers/provider.routes.ts
LLMProvider union, settings constants, MCP capability/scope/transport maps, provider auth endpoints, and server-side provider routes all gain kiro entries. Provider capabilities set kiro to default-mode only with abort enabled and token usage disabled.
StdioJsonRpcClient transport
server/modules/providers/list/kiro/stdio-jsonrpc-client.ts, server/modules/providers/list/kiro/__tests__/stdio-jsonrpc-client.test.ts
New StdioJsonRpcClient class implements JSON-RPC 2.0 over child process stdin/stdout with request correlation, timeouts, notification dispatch by method name or prefix, stderr forwarding, and in-flight request rejection on child close. Tests drive the transport with in-process fake stdio streams covering all wire-format and lifecycle scenarios.
Kiro CLI process orchestration
server/kiro-cli.js
spawnKiro spawns kiro-cli acp --trust-all-tools, runs the ACP initialize/load/new/prompt lifecycle, normalizes session/update notifications into NormalizedMessage shapes, rekeys the active-process map on real sessionId arrival, emits WebSocket lifecycle events (session_created, status, complete, error), and exports abortKiroSession, isKiroSessionActive, getActiveKiroSessions.
Provider auth and MCP persistence
server/modules/providers/list/kiro/kiro-auth.provider.ts, server/modules/providers/list/kiro/kiro-mcp.provider.ts, server/modules/providers/list/kiro/__tests__/kiro-auth.provider.test.ts, server/modules/providers/list/kiro/__tests__/kiro-mcp.provider.test.ts
KiroProviderAuth checks CLI installation via --version and auth status via kiro-cli whoami with AWS SSO token-hint enrichment for expired-token error messages. KiroMcpProvider reads/writes scoped mcp.json and preserves Kiro-specific disabled/autoApprove fields across upsertServer calls via pre/post read strategy. Tests use isolated temp HOME directories for real filesystem round-trips.
Provider models and skills
server/modules/providers/list/kiro/kiro-models.provider.ts, server/modules/providers/list/kiro/kiro-skills.provider.ts
KiroProviderModels exposes a Claude-focused fallback model catalog with auto default and persists active model changes. KiroSkillsProvider defines four skill-source directories (user/project × .kiro/skills and .agents/skills) with / command prefix.
Session synchronizer and history provider
server/modules/providers/list/kiro/kiro-session-synchronizer.provider.ts, server/modules/providers/list/kiro/kiro-sessions.provider.ts, server/modules/providers/list/kiro/__tests__/fixtures/*, server/modules/providers/list/kiro/__tests__/kiro-session-synchronizer.test.ts, server/modules/providers/list/kiro/__tests__/kiro-sessions.provider.test.ts
KiroSessionSynchronizer scans ~/.kiro/sessions/cli for new .jsonl files, parses sidecar .json for metadata, and upserts into sessionsDb while preserving user-defined custom_name. KiroSessionsProvider parses JSONL events, normalizes Prompt/AssistantMessage/ToolResults into NormalizedMessage, backfills tool-result content onto matching tool-use messages, and provides paginated history. JSONL/JSON fixtures and integration tests with temp HOME isolation cover synchronization regression and normalization edge cases.
KiroProvider assembly, registry, and server wiring
server/modules/providers/list/kiro/kiro.provider.ts, server/modules/providers/provider.registry.ts, server/modules/providers/services/session-synchronizer.service.ts, server/modules/providers/services/sessions-watcher.service.ts, server/index.js, server/routes/agent.js, server/routes/commands.js, server/modules/websocket/services/shell-websocket.service.ts, server/modules/providers/tests/mcp.test.ts, package.json, public/api-docs.html
KiroProvider wires all collaborators under AbstractProvider and registers in the provider registry. server/index.js imports Kiro CLI helpers into WebSocket chat config and adds a zeroed token-usage stub for Kiro. Agent and commands routes accept kiro; commands.js also rewrites the commandPath containment check using fs.realpath for symlink safety. Shell WebSocket service builds kiro-cli chat commands with optional --resume-id. Session sync counter and filesystem watcher include kiro.
Frontend chat provider state hooks
src/components/chat/hooks/useChatProviderState.ts, src/components/chat/hooks/useChatComposerState.ts
useChatProviderState adds kiroModel state from localStorage (kiro-model), queries kiro models from the API, syncs against the loaded catalog, and exposes setKiroModel. useChatComposerState receives kiroModel and threads it through command execution and message submission including tools-settings key resolution.
Chat interface, message panes, and provider UI
src/components/chat/view/ChatInterface.tsx, src/components/chat/view/subcomponents/ChatMessagesPane.tsx, src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx, src/components/llm-logo-provider/KiroLogo.tsx, src/components/llm-logo-provider/SessionProviderLogo.tsx, src/components/chat/view/subcomponents/MessageComponent.tsx, src/components/chat/view/subcomponents/CommandResultModal.tsx
ChatInterface threads kiroModel/setKiroModel props down to ChatMessagesPane and ProviderSelectionEmptyState. ProviderSelectionEmptyState adds kiro to PROVIDER_META, routes model selection through updated getCurrentModel, and renders the Kiro ready-prompt. KiroLogo renders theme-aware SVG icons; SessionProviderLogo, MessageComponent, and CommandResultModal add kiro display-label branches.
Settings, agent, and onboarding UI
src/components/settings/view/tabs/agents-settings/AgentListItem.tsx, src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx, src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx, src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx, src/components/onboarding/view/subcomponents/AgentConnectionsStep.tsx, src/components/provider-auth/view/ProviderLoginModal.tsx
Agent settings components add kiro entries with slate color/styling for auth status indicators; onboarding step includes Kiro connection card; login modal maps kiro to kiro-cli login command and Kiro CLI Login title.
Internationalization across eight locales
src/i18n/locales/en/chat.json, src/i18n/locales/de/chat.json, src/i18n/locales/it/chat.json, src/i18n/locales/ja/chat.json, src/i18n/locales/ko/chat.json, src/i18n/locales/ru/chat.json, src/i18n/locales/tr/chat.json, src/i18n/locales/zh-CN/chat.json
Adds messageTypes.kiro label and providerSelection.readyPrompt.kiro ready-to-use prompt with {{model}} interpolation across all eight supported chat locales.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant ChatInterface
  participant AgentRoute
  participant spawnKiro
  participant StdioJsonRpcClient
  participant kiro-cli

  Browser->>ChatInterface: submit message with provider=kiro
  ChatInterface->>AgentRoute: POST /api/agent { provider: kiro, model, message }
  AgentRoute->>spawnKiro: spawnKiro(command, options, ws)
  spawnKiro->>kiro-cli: spawn kiro-cli acp --trust-all-tools
  spawnKiro->>StdioJsonRpcClient: attach to child stdio
  StdioJsonRpcClient->>kiro-cli: initialize + session/new or session/load
  kiro-cli-->>StdioJsonRpcClient: session_id
  spawnKiro->>Browser: WebSocket session_created
  kiro-cli->>StdioJsonRpcClient: session/update (text/tool events)
  StdioJsonRpcClient->>spawnKiro: normalizeAcpUpdate → NormalizedMessage
  spawnKiro->>Browser: WebSocket text / tool_use / tool_result
  kiro-cli-->>spawnKiro: process close
  spawnKiro->>Browser: WebSocket complete or error
Loading

Possibly related PRs

  • siteboon/claudecodeui#654: Directly related — this PR extends the same CLI_PROVIDERS, PROVIDER_AUTH_STATUS_ENDPOINTS, and provider auth plumbing that PR #654 introduced by adding kiro to those structures.
  • siteboon/claudecodeui#759: Directly related — this PR plugs KiroSkillsProvider into the same SkillsProvider base class and backend skills infrastructure that PR #759 introduced.
  • siteboon/claudecodeui#762: Directly related — both PRs add a new provider branch to server/routes/agent.js dispatch and shell-websocket.service.ts buildShellCommand using the same integration pattern.

Suggested reviewers

  • viper151

🐇 A new provider hops in the queue,
Kiro CLI, shiny and new!
JSON-RPC frames fly through the pipes,
Sessions sync, the JSONL writes —
All eight locales say "Kiro, c'est vous!" 🌟

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
server/modules/providers/list/kiro/stdio-jsonrpc-client.ts (1)

221-233: ⚡ Quick win

Consider logging or reporting notification handler errors.

While swallowing handler exceptions prevents them from breaking the JSON-RPC stream (good defensive design), completely silent failures make debugging handler bugs very difficult. Consider at least logging these errors to the console, or adding an optional onHandlerError callback to the constructor options.

🔍 Proposed enhancement
 onNotification(method: string, handler: Handler): () => void {
   this.handlers.set(method, handler);
   return () => this.handlers.delete(method);
 }

+private handleNotificationError(method: string, params: unknown, error: unknown): void {
+  console.error(`[StdioJsonRpcClient] Notification handler error for ${method}:`, error);
+  this.options.onHandlerError?.(method, params, error);
+}

 private dispatchFrame(frame: Record<string, unknown>): void {
   // ... existing code ...
   
   if (method) {
     const params = frame.params;
     const exact = this.handlers.get(method);
     if (exact) {
       try {
         exact(params);
       } catch (error) {
-        // Handler errors must not break the JSON-RPC stream.
+        this.handleNotificationError(method, params, error);
       }
     }
     for (const [prefix, handler] of this.prefixHandlers) {
       if (method.startsWith(prefix)) {
         try {
           handler(params);
         } catch (error) {
-          // Same defensive policy as above.
+          this.handleNotificationError(method, params, error);
         }
       }
     }
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/kiro/stdio-jsonrpc-client.ts` around lines 221
- 233, The notification handler catch blocks for exact(...) and prefix handler
loop (prefixHandlers/handler) silently swallow exceptions; modify them to report
errors by either calling a provided onHandlerError callback from the constructor
options (e.g., this.options.onHandlerError(error, { method, params })) or, if
none supplied, fallback to console.error/processLogger.error with contextual
info (method, params, handler identifier). Update the constructor to accept an
optional onHandlerError and invoke it from both catch blocks so handler errors
are visible while preserving the JSON-RPC stream.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Line 32: The npm script "test:server" uses single quotes around the glob
pattern which fails on Windows; update the script value for test:server to use
double quotes (escaped as needed in JSON) for the glob pattern so the command
uses "server/**/*.test.ts" instead of 'server/**/*.test.ts' ensuring
cross-platform compatibility; keep the rest of the script (TSX_TSCONFIG_PATH and
node --import tsx --test) unchanged.

In
`@server/modules/providers/list/kiro/__tests__/kiro-session-synchronizer.test.ts`:
- Around line 38-43: The test teardown currently restores process.env.HOME from
ORIGINAL_HOME but only deletes HOME when ORIGINAL_HOME is undefined, leaving
process.env.USERPROFILE set to the temp path; update the teardown so both
environment variables are symmetrically restored: when ORIGINAL_HOME is defined
set both process.env.HOME and process.env.USERPROFILE to ORIGINAL_HOME, and when
ORIGINAL_HOME is undefined delete both process.env.HOME and
process.env.USERPROFILE (references: ORIGINAL_HOME, process.env.HOME,
process.env.USERPROFILE).

In `@server/modules/providers/list/kiro/kiro-sessions.provider.ts`:
- Around line 138-175: The loop over parts can produce duplicate IDs because
createNormalizedMessage uses baseId (and toolUseId) unchanged for multiple
content parts; change the for-of loop to an indexed loop (or maintain a per-part
counter) and append the index or unique suffix to the generated IDs so each part
gets a distinct id (e.g., use `${baseId}_text_${i}` for text parts and
`${toolUseId}_${i}` for toolUse/toolResult parts); update the id usages in
createNormalizedMessage calls (references: parts loop, isContentPart,
createNormalizedMessage, baseId, toolUseId, part.kind
'text'/'toolUse'/'toolResult') so keyed rendering and associations remain
stable.

In `@src/hooks/useProjectsState.ts`:
- Around line 562-576: The fallback provider normalization currently
misclassifies Kiro sessions as Claude when session payloads are missing; update
the logic that determines and sets the session provider (the code paths using
project.kiroSessions, selectedSession, setSelectedSession and the alternate
fallback block referenced at the other location) to explicitly recognize and
assign '__provider: "kiro"' for Kiro sessions instead of defaulting to 'claude'
— i.e., when you detect a Kiro session (e.g., via project.kiroSessions.find(...)
or the equivalent fallback checks), setSelectedSession should receive the
session object with __provider: 'kiro' and any other fallback normalization code
(the block around the second occurrence) must be updated the same way.

---

Nitpick comments:
In `@server/modules/providers/list/kiro/stdio-jsonrpc-client.ts`:
- Around line 221-233: The notification handler catch blocks for exact(...) and
prefix handler loop (prefixHandlers/handler) silently swallow exceptions; modify
them to report errors by either calling a provided onHandlerError callback from
the constructor options (e.g., this.options.onHandlerError(error, { method,
params })) or, if none supplied, fallback to console.error/processLogger.error
with contextual info (method, params, handler identifier). Update the
constructor to accept an optional onHandlerError and invoke it from both catch
blocks so handler errors are visible while preserving the JSON-RPC stream.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fb2bb907-1ad0-4917-a191-72fca865a896

📥 Commits

Reviewing files that changed from the base of the PR and between 039696c and 9c35901.

⛔ Files ignored due to path filters (2)
  • public/icons/kiro-white.svg is excluded by !**/*.svg
  • public/icons/kiro.svg is excluded by !**/*.svg
📒 Files selected for processing (54)
  • package.json
  • server/index.js
  • server/kiro-cli.js
  • server/modules/database/index.ts
  • server/modules/projects/services/project-management.service.ts
  • server/modules/projects/services/projects-with-sessions-fetch.service.ts
  • server/modules/providers/list/kiro/__tests__/fixtures/error-result.jsonl
  • server/modules/providers/list/kiro/__tests__/fixtures/sample-session.json
  • server/modules/providers/list/kiro/__tests__/fixtures/sample-session.jsonl
  • server/modules/providers/list/kiro/__tests__/kiro-mcp.provider.test.ts
  • server/modules/providers/list/kiro/__tests__/kiro-session-synchronizer.test.ts
  • server/modules/providers/list/kiro/__tests__/kiro-sessions.provider.test.ts
  • server/modules/providers/list/kiro/__tests__/stdio-jsonrpc-client.test.ts
  • server/modules/providers/list/kiro/kiro-auth.provider.ts
  • server/modules/providers/list/kiro/kiro-mcp.provider.ts
  • server/modules/providers/list/kiro/kiro-session-synchronizer.provider.ts
  • server/modules/providers/list/kiro/kiro-sessions.provider.ts
  • server/modules/providers/list/kiro/kiro.provider.ts
  • server/modules/providers/list/kiro/stdio-jsonrpc-client.ts
  • server/modules/providers/provider.registry.ts
  • server/modules/providers/services/session-synchronizer.service.ts
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/providers/tests/mcp.test.ts
  • server/modules/websocket/services/chat-websocket.service.ts
  • server/routes/agent.js
  • server/shared/types.ts
  • shared/modelConstants.js
  • src/components/chat/hooks/useChatComposerState.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx
  • src/components/command-palette/sources/useSessionsSource.ts
  • src/components/llm-logo-provider/KiroLogo.tsx
  • src/components/llm-logo-provider/SessionProviderLogo.tsx
  • src/components/mcp/constants.ts
  • src/components/provider-auth/types.ts
  • src/components/provider-auth/view/ProviderLoginModal.tsx
  • src/components/settings/constants/constants.ts
  • src/components/settings/view/tabs/agents-settings/AgentListItem.tsx
  • src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx
  • src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx
  • src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx
  • src/components/sidebar/utils/utils.ts
  • src/hooks/useProjectsState.ts
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/zh-CN/chat.json
  • src/types/app.ts

Comment thread package.json Outdated
Comment on lines +138 to +175
for (const part of parts) {
if (!isContentPart(part)) {
continue;
}

if (part.kind === 'text') {
const text = typeof part.data === 'string' ? part.data : '';
if (text.trim()) {
messages.push(createNormalizedMessage({
id: `${baseId}_text`,
sessionId,
timestamp: ts,
provider: PROVIDER,
kind: 'text',
role: 'assistant',
content: text,
}));
}
continue;
}

if (part.kind === 'toolUse') {
const data = readObjectRecord(part.data) ?? {};
const toolUseId = typeof data.toolUseId === 'string' ? data.toolUseId : baseId;
const toolName = typeof data.name === 'string' ? data.name : 'Unknown';
messages.push(createNormalizedMessage({
id: toolUseId,
sessionId,
timestamp: ts,
provider: PROVIDER,
kind: 'tool_use',
toolName,
toolInput: data.input,
toolId: toolUseId,
}));
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Ensure normalized message IDs are unique per content part.

On Line 147, Line 164, and Line 195, IDs can collide when a single entry contains multiple text, toolUse, or toolResult parts. This can break keyed rendering and message association logic.

Suggested fix
-      for (const part of parts) {
+      for (const [partIndex, part] of parts.entries()) {
         if (!isContentPart(part)) {
           continue;
         }

         if (part.kind === 'text') {
           const text = typeof part.data === 'string' ? part.data : '';
           if (text.trim()) {
             messages.push(createNormalizedMessage({
-              id: `${baseId}_text`,
+              id: `${baseId}_text_${partIndex}`,
               sessionId,
               timestamp: ts,
               provider: PROVIDER,
               kind: 'text',
               role: 'assistant',
               content: text,
             }));
           }
           continue;
         }

         if (part.kind === 'toolUse') {
           const data = readObjectRecord(part.data) ?? {};
-          const toolUseId = typeof data.toolUseId === 'string' ? data.toolUseId : baseId;
+          const toolUseId = typeof data.toolUseId === 'string' && data.toolUseId.trim().length > 0
+            ? data.toolUseId
+            : `${baseId}_tool_${partIndex}`;
           const toolName = typeof data.name === 'string' ? data.name : 'Unknown';
           messages.push(createNormalizedMessage({
             id: toolUseId,
             sessionId,
             timestamp: ts,
             provider: PROVIDER,
             kind: 'tool_use',
             toolName,
             toolInput: data.input,
             toolId: toolUseId,
           }));
         }
       }
@@
-      for (const part of parts) {
+      for (const [partIndex, part] of parts.entries()) {
         if (!isContentPart(part) || part.kind !== 'toolResult') {
           continue;
         }
         const data = readObjectRecord(part.data) ?? {};
-        const toolUseId = typeof data.toolUseId === 'string' ? data.toolUseId : '';
+        const toolUseId = typeof data.toolUseId === 'string' && data.toolUseId.trim().length > 0
+          ? data.toolUseId
+          : `${baseId}_tool_${partIndex}`;
         const { text, isError: contentIsError } = flattenToolResultContent(data.content);
         messages.push(createNormalizedMessage({
-          id: `${toolUseId || baseId}_result`,
+          id: `${toolUseId}_result_${partIndex}`,
           sessionId,
           timestamp: ts,
           provider: PROVIDER,
           kind: 'tool_result',
           toolId: toolUseId,
           content: text,
           isError: entryIsError || contentIsError,
         }));
       }

Also applies to: 187-204

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/kiro/kiro-sessions.provider.ts` around lines
138 - 175, The loop over parts can produce duplicate IDs because
createNormalizedMessage uses baseId (and toolUseId) unchanged for multiple
content parts; change the for-of loop to an indexed loop (or maintain a per-part
counter) and append the index or unique suffix to the generated IDs so each part
gets a distinct id (e.g., use `${baseId}_text_${i}` for text parts and
`${toolUseId}_${i}` for toolUse/toolResult parts); update the id usages in
createNormalizedMessage calls (references: parts loop, isContentPart,
createNormalizedMessage, baseId, toolUseId, part.kind
'text'/'toolUse'/'toolResult') so keyed rendering and associations remain
stable.

Comment thread src/hooks/useProjectsState.ts Outdated
- useProjectsState: add 'kiro' to fallback provider normalization chain;
  previously a Kiro session not yet in any project payload was misclassified
  as Claude (Major).
- kiro-sessions.provider: index part position into message ids so an entry
  with multiple text/toolUse/toolResult parts no longer produces colliding
  ids that break React keyed rendering and tool_use<->tool_result
  association (Major).
- kiro-session-synchronizer test: also delete USERPROFILE in the env
  restore branch when HOME was originally unset (Minor).
- package.json test:server: drop the bash-only env-prefix syntax in favor
  of `tsx --tsconfig server/tsconfig.json --test ...`. Cross-platform,
  no new dependencies (Minor).
- stdio-jsonrpc-client: log notification handler errors via console.error
  instead of silently swallowing them; the dispatch loop still continues
  on handler exceptions but regressions are now visible (Nit).

Tests
- Added: AssistantMessage with multiple text + toolUse parts produces
  unique ids (regression for the colliding-id bug).
- Added: ToolResults with multiple parts sharing a toolUseId produces
  unique ids.
- Added: notification handler that throws does not break subsequent
  request/response correlation, AND the error is logged.

66/66 tests pass; server + client typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
server/modules/providers/list/kiro/__tests__/kiro-sessions.provider.test.ts (1)

1-242: ⚡ Quick win

Consider loading test data from the fixture files.

The file comment (lines 1-7) states that "Fixture data was captured from a real kiro-cli acp session," and the AI summary confirms that fixture files were added in this PR (error-result.jsonl, sample-session.jsonl). However, all test cases inline their data rather than loading from these fixtures.

Loading from the actual fixture files would improve maintainability (changes to fixture data propagate automatically) and align the implementation with the documented intent.

Example approach

You could read the JSONL fixture files and parse them into test cases, or reference specific line numbers/events from the fixtures. For example:

import { readFileSync } from 'node:fs';
import { join } from 'node:path';

const sampleSession = readFileSync(
  join(__dirname, 'fixtures/sample-session.jsonl'),
  'utf-8'
)
  .split('\n')
  .filter(Boolean)
  .map(JSON.parse);

it('normalizes a Prompt entry to a single user text message', () => {
  const entry = sampleSession[0]; // or find by kind/message_id
  // ... assertions
});

This would ensure tests stay synchronized with the fixture data and provide better traceability to real captured events.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/kiro/__tests__/kiro-sessions.provider.test.ts`
around lines 1 - 242, Tests inline literal event objects instead of using the
shipped JSONL fixtures; update the test file to load and parse the fixtures
(error-result.jsonl and sample-session.jsonl) once at top (e.g., using
readFileSync + split/filter/JSON.parse) into arrays, then replace each inline
`entry` with the corresponding object pulled from the parsed fixture (select by
message_id or kind) before calling provider.normalizeMessage; ensure the tests
still reference the same `provider.normalizeMessage` calls and assertions but
use the fixture-derived entries so changes to the JSONL fixtures automatically
update test inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/modules/providers/list/kiro/__tests__/kiro-sessions.provider.test.ts`:
- Around line 1-242: Tests inline literal event objects instead of using the
shipped JSONL fixtures; update the test file to load and parse the fixtures
(error-result.jsonl and sample-session.jsonl) once at top (e.g., using
readFileSync + split/filter/JSON.parse) into arrays, then replace each inline
`entry` with the corresponding object pulled from the parsed fixture (select by
message_id or kind) before calling provider.normalizeMessage; ensure the tests
still reference the same `provider.normalizeMessage` calls and assertions but
use the fixture-derived entries so changes to the JSONL fixtures automatically
update test inputs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: aa502bac-0449-44f3-867c-c3d2e562f27d

📥 Commits

Reviewing files that changed from the base of the PR and between 9c35901 and 91f520e.

📒 Files selected for processing (7)
  • package.json
  • server/modules/providers/list/kiro/__tests__/kiro-session-synchronizer.test.ts
  • server/modules/providers/list/kiro/__tests__/kiro-sessions.provider.test.ts
  • server/modules/providers/list/kiro/__tests__/stdio-jsonrpc-client.test.ts
  • server/modules/providers/list/kiro/kiro-sessions.provider.ts
  • server/modules/providers/list/kiro/stdio-jsonrpc-client.ts
  • src/hooks/useProjectsState.ts
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • server/modules/providers/list/kiro/tests/stdio-jsonrpc-client.test.ts
  • server/modules/providers/list/kiro/tests/kiro-session-synchronizer.test.ts
  • server/modules/providers/list/kiro/kiro-sessions.provider.ts
  • server/modules/providers/list/kiro/stdio-jsonrpc-client.ts
  • src/hooks/useProjectsState.ts

@tothethousand

Copy link
Copy Markdown

Wow, this is exactly the feature I needed—it's awesome!

@blackmammoth

Copy link
Copy Markdown
Member

Hey @dgallitelli, thank for the updated PR!! Apologies for the delay in review. There has been a ton of changes since this PR from many contributors. Can you resolve the merge conflicts and I will make sure to review again as a priority.

@blackmammoth blackmammoth marked this pull request as draft June 4, 2026 11:15
Resolve conflicts from upstream provider-architecture refactors (siteboon#762, siteboon#715):

- Adopt per-provider model architecture (IProviderModels): migrate KIRO_MODELS
  from the deleted shared/modelConstants.js into a new
  kiro-models.provider.ts; frontend now reads Kiro models via the
  /api/providers/kiro/models catalog like every other provider.
- Add kiro-skills.provider.ts to satisfy the new required `skills` facet on
  AbstractProvider; wire models + skills into kiro.provider.ts.
- Kiro is now the 6th provider alongside opencode (added upstream). Updated all
  provider lists/unions/records to include both opencode and kiro
  (registry, routes, websocket, sessions, MCP constants, agents settings,
  provider grid, i18n, api-docs PROVIDER_ORDER, commands MODEL_PROVIDERS,
  provider.routes parseProvider).
- Drop redundant closeConnection re-export now that upstream exports it.
- mcp.test.ts global-adder count 4/5 -> 6.

Verified: server+client tsc clean, eslint 0 errors, server tests 86 pass,
client+server builds succeed, provider registry resolves all 6 Kiro facets.
…sites

Adversarial review found Kiro missing from several shared provider switches
that the opencode precedent (added upstream) already covers. Without these,
Kiro sessions rendered as "Claude" and shared Claude's tool-settings key,
leaving the messageTypes.kiro i18n keys (already in all 8 locales) unused.

- MessageComponent / ChatInterface (x2): provider label ternaries now emit
  messageTypes.kiro instead of falling through to Claude.
- ClaudeStatus PROVIDER_LABEL_KEYS + CommandResultModal PROVIDER_LABELS: add kiro.
- useChatComposerState: Kiro tool-settings now persist under 'kiro-settings'
  instead of colliding with 'claude-settings'.
- Onboarding AgentConnectionsStep: add the Kiro connection card.

Intentionally NOT changed: shell-websocket (Kiro runs `kiro-cli acp` JSON-RPC,
not an interactive shell) and the token-usage guard (Kiro is unsupported by
design, matching the server's unsupported:true response).
…ken path

Verified live against kiro-cli 2.7.0: a logged-in user was reported as
authenticated:false / "OAuth token has expired" because the auth provider
keyed off ~/.aws/sso/cache/kiro-auth-token.json, which kiro-cli <= 2.3.0 wrote
but >= 2.7.0 no longer does (it now uses hashed-filename token files).

Make `kiro-cli whoami` the source of truth for login state and parse the auth
method (IdC / BuilderId) and email from its output. The legacy token file is
now only a best-effort hint to enrich the method label and surface an explicit
"expired" error when logged out; a missing file no longer forces a
not-authenticated result. Uses plain whoami output (not --format json) for
compatibility with older CLIs that lack the flag.

Adds kiro-auth.provider.test.ts (the PR shipped no auth test) covering: auth
from whoami with no token file (the 2.7.0 regression), auth despite an expired
token file, Builder ID detection, logged-out, and the expired-token error path.

Impact: chat was never affected (spawn does not gate on auth status); this
fixes the Settings/Onboarding "logged out" badge shown to users on current
kiro-cli.
@dgallitelli dgallitelli marked this pull request as ready for review June 15, 2026 04:03
@dgallitelli

Copy link
Copy Markdown
Author

@blackmammoth conflicts are resolved — the PR is MERGEABLE against current main and ready for re-review. I also re-verified the whole integration against a live kiro-cli and fixed one version-drift bug I found while doing so. Details below.

Conflict resolution

Catching up to main was more than a mechanical merge because two refactors reshaped the provider runtime this PR plugs into:

  • feat: add opencode support #762 deleted shared/modelConstants.js — models now live behind a per-provider IProviderModels contract (*-models.provider.ts) and are served from GET /api/providers/:provider/models. That PR also added OpenCode, so Kiro is now the 6th provider, not the 5th.
  • AbstractProvider grew two newly-required facets, models and skills, which the original Kiro wrapper didn't implement.

What I changed to land Kiro on the new architecture:

  • Moved KIRO_MODELS out of the deleted constants file into a new kiro-models.provider.ts (modeled on codex-models.provider.ts), and added kiro-skills.provider.ts for the skills facet. Both wired into kiro.provider.ts.
  • Rewired the frontend off the removed KIRO_MODELS import onto the API-fetched catalog (providerModelCatalog, FALLBACK_DEFAULT_MODEL, loadProviderModels, the per-provider effects, and the provider grid).
  • Carried kiro into every list that now also carries opencodeprovider.registry.ts, provider.routes.ts (parseProvider), websocket/session/MCP wiring, public/api-docs.html PROVIDER_ORDER, commands.js MODEL_PROVIDERS, agents settings, and the locale files. mcp.test.ts global-adder count 4/5 → 6.
  • Dropped a now-redundant closeConnection re-export that upstream started providing.
  • Closed a few parity gaps the original PR predated (Kiro fell through to the Claude label/settings in shared switches that OpenCode now covers): provider-label rendering in MessageComponent/ChatInterface/ClaudeStatus/CommandResultModal, a dedicated kiro-settings tools-settings key, and the onboarding card.

Live verification against kiro-cli 2.7.0

Installed the real CLI, logged in (IdC), and exercised the integration end-to-end against the merged branch:

Path Result
ACP initialize → session/new → session/prompt ✅ streamed assistant text back
Session resume (session/load + continuation) ✅ reloaded prior history, continued the turn
Sessions provider parsing real ~/.kiro/sessions/cli/*.jsonl ✅ normalized correctly
MCP listing real ~/.kiro/settings/mcp.json + disabled/autoApprove round-trip ✅ (write-path preservation, covered by tests)
Auth status detection ⚠️ found a bug — see below

Bug found + fixed: auth detection across CLI versions

The auth provider reported a logged-in user as authenticated:false / "OAuth token has expired". Root cause is version drift, not the merge: it keyed off ~/.aws/sso/cache/kiro-auth-token.json, which kiro-cli <= 2.3.0 wrote but >= 2.7.0 no longer does (it now uses hashed-filename token files).

Fix: make kiro-cli whoami the source of truth for login state (parsing method + email from its output, using the plain format for compatibility with older CLIs). The legacy token file is now only a best-effort hint for the method label / expired error and can no longer force a false negative. After the fix, status is {authenticated:true, email:…, method:"IdC"} on 2.7.0.

Scope note: this never affected chat — the spawn path doesn't gate on auth status (which is why prompts worked even with the wrong badge). It only fixed the misleading "logged out" state in Settings/Onboarding.

Also added kiro-auth.provider.test.ts (the PR previously shipped no auth test) — 5 cases including the exact 2.7.0 regression, Builder ID detection, and the logged-out/expired paths.

Checks on the merged branch

tsc (client + server)   clean
eslint src/ server/     0 errors
npm run test:server     91 pass / 0 fail   (86 prior + 5 new auth tests; incl. the 6-provider MCP global-adder)
vite build + server build   ok

🤖 Conflict resolution + live verification done with Claude Code.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
server/modules/providers/list/kiro/kiro-auth.provider.ts (1)

24-27: ⚠️ Potential issue | 🟠 Major

Replace spawn.sync with async process spawning in checkInstalled().

The synchronous process call at line 26 blocks the Node event loop for up to 5 seconds when getStatus() is invoked (line 37). This impacts responsiveness of other async operations.

Convert checkInstalled() to return a Promise<boolean> using async spawn with proper timeout and error handling, then update line 37 to const installed = await this.checkInstalled();

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/kiro/kiro-auth.provider.ts` around lines 24 -
27, The checkInstalled() method uses the synchronous spawn.sync() call which
blocks the Node event loop for up to 5 seconds. Convert checkInstalled() to
return a Promise<boolean> using asynchronous process spawning instead, implement
proper timeout and error handling for the async spawn operation, and update the
call site in getStatus() to await the result of this.checkInstalled() to
properly handle the promise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/api-docs.html`:
- Around line 831-838: The PROVIDER_ORDER constant has been expanded to include
all supported providers (claude, codex, gemini, cursor, opencode, kiro), but the
static request documentation that describes valid provider values has not been
updated. Update the static provider documentation to list all six supported
providers (claude, codex, gemini, cursor, opencode, kiro) so API consumers have
accurate information about which provider values are accepted. Ensure the
documentation mentions all providers that are now defined in the PROVIDER_ORDER
constant.

In `@server/routes/commands.js`:
- Around line 537-555: The command path validation in the allowlist check is
vulnerable to symlink escape attacks because it uses lexical path resolution
(path.resolve and path.relative) without resolving to canonical paths. A symlink
inside .claude/commands could point outside the allowed directories and still
pass the isUnder validation check. To fix this, resolve the commandPath to its
canonical path using the realpath function (synchronously or asynchronously as
appropriate for your code flow) before performing the isUnder validation checks
against userBase and projectBase. This ensures that even if commandPath is a
symlink, the actual target location is validated against the allowed directories
before fs.readFile reads the file.

In `@src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx`:
- Around line 246-248: The string "Choose a model" in the
ProviderSelectionEmptyState component is hardcoded in English, creating
inconsistency with the rest of the component which uses i18n for translations.
Replace this hardcoded string with the appropriate i18n translation call, using
the same localization method already employed elsewhere in this component to
ensure the string is properly translated for all supported locales.

---

Outside diff comments:
In `@server/modules/providers/list/kiro/kiro-auth.provider.ts`:
- Around line 24-27: The checkInstalled() method uses the synchronous
spawn.sync() call which blocks the Node event loop for up to 5 seconds. Convert
checkInstalled() to return a Promise<boolean> using asynchronous process
spawning instead, implement proper timeout and error handling for the async
spawn operation, and update the call site in getStatus() to await the result of
this.checkInstalled() to properly handle the promise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: aa18dbc0-3a5b-4a97-bb02-372fb9cae547

📥 Commits

Reviewing files that changed from the base of the PR and between 91f520e and 586053c.

📒 Files selected for processing (49)
  • package.json
  • public/api-docs.html
  • server/index.js
  • server/modules/projects/services/project-management.service.ts
  • server/modules/projects/services/projects-with-sessions-fetch.service.ts
  • server/modules/providers/list/kiro/__tests__/kiro-auth.provider.test.ts
  • server/modules/providers/list/kiro/kiro-auth.provider.ts
  • server/modules/providers/list/kiro/kiro-models.provider.ts
  • server/modules/providers/list/kiro/kiro-skills.provider.ts
  • server/modules/providers/list/kiro/kiro.provider.ts
  • server/modules/providers/provider.registry.ts
  • server/modules/providers/provider.routes.ts
  • server/modules/providers/services/session-synchronizer.service.ts
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/providers/tests/mcp.test.ts
  • server/modules/websocket/services/chat-websocket.service.ts
  • server/routes/agent.js
  • server/routes/commands.js
  • server/shared/types.ts
  • src/components/chat/hooks/useChatComposerState.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/components/chat/view/subcomponents/ClaudeStatus.tsx
  • src/components/chat/view/subcomponents/CommandResultModal.tsx
  • src/components/chat/view/subcomponents/MessageComponent.tsx
  • src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx
  • src/components/command-palette/sources/useSessionsSource.ts
  • src/components/llm-logo-provider/SessionProviderLogo.tsx
  • src/components/mcp/constants.ts
  • src/components/onboarding/view/subcomponents/AgentConnectionsStep.tsx
  • src/components/provider-auth/types.ts
  • src/components/provider-auth/view/ProviderLoginModal.tsx
  • src/components/settings/constants/constants.ts
  • src/components/settings/view/tabs/agents-settings/AgentListItem.tsx
  • src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx
  • src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx
  • src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx
  • src/components/sidebar/utils/utils.ts
  • src/hooks/useProjectsState.ts
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/zh-CN/chat.json
  • src/types/app.ts
💤 Files with no reviewable changes (8)
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ru/chat.json
  • src/types/app.ts
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/ja/chat.json
✅ Files skipped from review due to trivial changes (4)
  • src/components/chat/view/subcomponents/CommandResultModal.tsx
  • src/components/llm-logo-provider/SessionProviderLogo.tsx
  • src/components/chat/view/subcomponents/ClaudeStatus.tsx
  • src/components/settings/view/tabs/agents-settings/AgentListItem.tsx
🚧 Files skipped from review as they are similar to previous changes (23)
  • server/modules/providers/list/kiro/kiro.provider.ts
  • server/modules/providers/services/session-synchronizer.service.ts
  • src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx
  • package.json
  • src/components/chat/view/ChatInterface.tsx
  • src/components/provider-auth/view/ProviderLoginModal.tsx
  • src/components/sidebar/utils/utils.ts
  • src/components/provider-auth/types.ts
  • src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/projects/services/project-management.service.ts
  • server/routes/agent.js
  • src/components/settings/constants/constants.ts
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • server/modules/providers/provider.registry.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/command-palette/sources/useSessionsSource.ts
  • src/i18n/locales/en/chat.json
  • server/modules/projects/services/projects-with-sessions-fetch.service.ts
  • server/modules/websocket/services/chat-websocket.service.ts
  • server/index.js
  • server/shared/types.ts
  • src/hooks/useProjectsState.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
server/modules/providers/list/kiro/kiro-auth.provider.ts (1)

24-27: ⚠️ Potential issue | 🟠 Major

Replace spawn.sync with async process spawning in checkInstalled().

The synchronous process call at line 26 blocks the Node event loop for up to 5 seconds when getStatus() is invoked (line 37). This impacts responsiveness of other async operations.

Convert checkInstalled() to return a Promise<boolean> using async spawn with proper timeout and error handling, then update line 37 to const installed = await this.checkInstalled();

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/kiro/kiro-auth.provider.ts` around lines 24 -
27, The checkInstalled() method uses the synchronous spawn.sync() call which
blocks the Node event loop for up to 5 seconds. Convert checkInstalled() to
return a Promise<boolean> using asynchronous process spawning instead, implement
proper timeout and error handling for the async spawn operation, and update the
call site in getStatus() to await the result of this.checkInstalled() to
properly handle the promise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/api-docs.html`:
- Around line 831-838: The PROVIDER_ORDER constant has been expanded to include
all supported providers (claude, codex, gemini, cursor, opencode, kiro), but the
static request documentation that describes valid provider values has not been
updated. Update the static provider documentation to list all six supported
providers (claude, codex, gemini, cursor, opencode, kiro) so API consumers have
accurate information about which provider values are accepted. Ensure the
documentation mentions all providers that are now defined in the PROVIDER_ORDER
constant.

In `@server/routes/commands.js`:
- Around line 537-555: The command path validation in the allowlist check is
vulnerable to symlink escape attacks because it uses lexical path resolution
(path.resolve and path.relative) without resolving to canonical paths. A symlink
inside .claude/commands could point outside the allowed directories and still
pass the isUnder validation check. To fix this, resolve the commandPath to its
canonical path using the realpath function (synchronously or asynchronously as
appropriate for your code flow) before performing the isUnder validation checks
against userBase and projectBase. This ensures that even if commandPath is a
symlink, the actual target location is validated against the allowed directories
before fs.readFile reads the file.

In `@src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx`:
- Around line 246-248: The string "Choose a model" in the
ProviderSelectionEmptyState component is hardcoded in English, creating
inconsistency with the rest of the component which uses i18n for translations.
Replace this hardcoded string with the appropriate i18n translation call, using
the same localization method already employed elsewhere in this component to
ensure the string is properly translated for all supported locales.

---

Outside diff comments:
In `@server/modules/providers/list/kiro/kiro-auth.provider.ts`:
- Around line 24-27: The checkInstalled() method uses the synchronous
spawn.sync() call which blocks the Node event loop for up to 5 seconds. Convert
checkInstalled() to return a Promise<boolean> using asynchronous process
spawning instead, implement proper timeout and error handling for the async
spawn operation, and update the call site in getStatus() to await the result of
this.checkInstalled() to properly handle the promise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: aa18dbc0-3a5b-4a97-bb02-372fb9cae547

📥 Commits

Reviewing files that changed from the base of the PR and between 91f520e and 586053c.

📒 Files selected for processing (49)
  • package.json
  • public/api-docs.html
  • server/index.js
  • server/modules/projects/services/project-management.service.ts
  • server/modules/projects/services/projects-with-sessions-fetch.service.ts
  • server/modules/providers/list/kiro/__tests__/kiro-auth.provider.test.ts
  • server/modules/providers/list/kiro/kiro-auth.provider.ts
  • server/modules/providers/list/kiro/kiro-models.provider.ts
  • server/modules/providers/list/kiro/kiro-skills.provider.ts
  • server/modules/providers/list/kiro/kiro.provider.ts
  • server/modules/providers/provider.registry.ts
  • server/modules/providers/provider.routes.ts
  • server/modules/providers/services/session-synchronizer.service.ts
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/providers/tests/mcp.test.ts
  • server/modules/websocket/services/chat-websocket.service.ts
  • server/routes/agent.js
  • server/routes/commands.js
  • server/shared/types.ts
  • src/components/chat/hooks/useChatComposerState.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/components/chat/view/subcomponents/ClaudeStatus.tsx
  • src/components/chat/view/subcomponents/CommandResultModal.tsx
  • src/components/chat/view/subcomponents/MessageComponent.tsx
  • src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx
  • src/components/command-palette/sources/useSessionsSource.ts
  • src/components/llm-logo-provider/SessionProviderLogo.tsx
  • src/components/mcp/constants.ts
  • src/components/onboarding/view/subcomponents/AgentConnectionsStep.tsx
  • src/components/provider-auth/types.ts
  • src/components/provider-auth/view/ProviderLoginModal.tsx
  • src/components/settings/constants/constants.ts
  • src/components/settings/view/tabs/agents-settings/AgentListItem.tsx
  • src/components/settings/view/tabs/agents-settings/AgentsSettingsTab.tsx
  • src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx
  • src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx
  • src/components/sidebar/utils/utils.ts
  • src/hooks/useProjectsState.ts
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/zh-CN/chat.json
  • src/types/app.ts
💤 Files with no reviewable changes (8)
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ru/chat.json
  • src/types/app.ts
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/ja/chat.json
✅ Files skipped from review due to trivial changes (4)
  • src/components/chat/view/subcomponents/CommandResultModal.tsx
  • src/components/llm-logo-provider/SessionProviderLogo.tsx
  • src/components/chat/view/subcomponents/ClaudeStatus.tsx
  • src/components/settings/view/tabs/agents-settings/AgentListItem.tsx
🚧 Files skipped from review as they are similar to previous changes (23)
  • server/modules/providers/list/kiro/kiro.provider.ts
  • server/modules/providers/services/session-synchronizer.service.ts
  • src/components/settings/view/tabs/agents-settings/sections/AgentSelectorSection.tsx
  • package.json
  • src/components/chat/view/ChatInterface.tsx
  • src/components/provider-auth/view/ProviderLoginModal.tsx
  • src/components/sidebar/utils/utils.ts
  • src/components/provider-auth/types.ts
  • src/components/settings/view/tabs/agents-settings/sections/content/AccountContent.tsx
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/projects/services/project-management.service.ts
  • server/routes/agent.js
  • src/components/settings/constants/constants.ts
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • server/modules/providers/provider.registry.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/command-palette/sources/useSessionsSource.ts
  • src/i18n/locales/en/chat.json
  • server/modules/projects/services/projects-with-sessions-fetch.service.ts
  • server/modules/websocket/services/chat-websocket.service.ts
  • server/index.js
  • server/shared/types.ts
  • src/hooks/useProjectsState.ts
🛑 Comments failed to post (3)
public/api-docs.html (1)

831-838: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update static provider docs to match the expanded provider list.

You added kiro (and dynamic model loading for all providers), but the static request docs still state only Claude/Cursor/Codex (Line 492 and Line 527). This will mislead API consumers about valid provider values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@public/api-docs.html` around lines 831 - 838, The PROVIDER_ORDER constant has
been expanded to include all supported providers (claude, codex, gemini, cursor,
opencode, kiro), but the static request documentation that describes valid
provider values has not been updated. Update the static provider documentation
to list all six supported providers (claude, codex, gemini, cursor, opencode,
kiro) so API consumers have accurate information about which provider values are
accepted. Ensure the documentation mentions all providers that are now defined
in the PROVIDER_ORDER constant.
server/routes/commands.js (1)

537-555: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden command path validation against symlink escape.

The allowlist check uses lexical paths (path.resolve/path.relative) but not canonical paths. A symlink inside .claude/commands can still target files outside the allowed roots and pass the current check; Line 555 then reads the attacker-controlled target.

🔒 Suggested fix
-      const resolvedPath = path.resolve(commandPath);
-      const userBase = path.resolve(
-        path.join(os.homedir(), ".claude", "commands"),
-      );
-      const projectBase = context?.projectPath
-        ? path.resolve(path.join(context.projectPath, ".claude", "commands"))
-        : null;
-      const isUnder = (base) => {
+      const resolvedPath = await fs.realpath(commandPath);
+      const userBase = await fs
+        .realpath(path.join(os.homedir(), ".claude", "commands"))
+        .catch(() => null);
+      const projectBase = context?.projectPath
+        ? await fs
+            .realpath(path.join(context.projectPath, ".claude", "commands"))
+            .catch(() => null)
+        : null;
+      const isUnder = (base) => {
+        if (!base) return false;
         const rel = path.relative(base, resolvedPath);
         return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
       };
-      if (!(isUnder(userBase) || (projectBase && isUnder(projectBase)))) {
+      if (!(isUnder(userBase) || isUnder(projectBase))) {
         return res.status(403).json({
           error: "Access denied",
           message: "Command must be in .claude/commands directory",
         });
       }
     }
-    const content = await fs.readFile(commandPath, "utf8");
+    const content = await fs.readFile(resolvedPath, "utf8");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/commands.js` around lines 537 - 555, The command path
validation in the allowlist check is vulnerable to symlink escape attacks
because it uses lexical path resolution (path.resolve and path.relative) without
resolving to canonical paths. A symlink inside .claude/commands could point
outside the allowed directories and still pass the isUnder validation check. To
fix this, resolve the commandPath to its canonical path using the realpath
function (synchronously or asynchronously as appropriate for your code flow)
before performing the isUnder validation checks against userBase and
projectBase. This ensures that even if commandPath is a symlink, the actual
target location is validated against the allowed directories before fs.readFile
reads the file.
src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx (1)

246-248: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the new model-selector header strings.

These new UI literals are hardcoded English, while this component otherwise uses i18n. This introduces locale inconsistency in translated builds.

🌐 Suggested fix
-              <DialogTitle>Model Selector</DialogTitle>
+              <DialogTitle>
+                {t("providerSelection.modelSelectorTitle", { defaultValue: "Model Selector" })}
+              </DialogTitle>
               <div className="border-b border-border/60 bg-muted/20 px-4 py-3">
-                <p className="text-sm font-semibold text-foreground">Choose a model</p>
+                <p className="text-sm font-semibold text-foreground">
+                  {t("providerSelection.chooseModel", { defaultValue: "Choose a model" })}
+                </p>
               </div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx`
around lines 246 - 248, The string "Choose a model" in the
ProviderSelectionEmptyState component is hardcoded in English, creating
inconsistency with the rest of the component which uses i18n for translations.
Replace this hardcoded string with the appropriate i18n translation call, using
the same localization method already employed elsewhere in this component to
ensure the string is properly translated for all supported locales.

…fety, i18n)

- kiro-auth: make checkInstalled() async (was spawn.sync, which blocked the
  event loop up to the 5s timeout during getStatus). Mirrors this file's
  existing async readWhoami() pattern. Live-reverified against kiro-cli 2.7.0.
- commands.js: harden custom-command path validation against symlink escape by
  canonicalizing commandPath AND the allowlist roots via fs.realpath before the
  containment check (was lexical path.resolve/relative only). A missing target
  now denies access. Pre-existing code from siteboon#762, surfaced in this PR's diff.
- ProviderSelectionEmptyState: wrap the hardcoded "Model Selector" and
  "Choose a model" strings in t() with defaultValue, matching the
  searchModels/noModelsFound i18n convention already used in this dialog.

Not changed: CodeRabbit's api-docs.html finding is a false positive — there is
no static provider enumeration in that file; PROVIDER_ORDER (already updated to
include kiro) is the only provider list and the model docs render from it.

Verified: tsc (client+server) clean, eslint 0 errors, test:server 91/91,
client+server builds ok.
@dgallitelli

dgallitelli commented Jun 15, 2026

Copy link
Copy Markdown
Author

Triaged all 4 findings from CodeRabbit latest pass. 3 fixed in 805b9a1, 1 is a false positive.

Fixed

  • 🟠 kiro-auth.provider.tsspawn.sync blocks the event loop. Valid. Converted checkInstalled() to async spawn with the same timeout/kill semantics as this file's existing readWhoami(), and await it in getStatus(). Re-verified live against kiro-cli 2.7.0 — still returns authenticated:true for a logged-in user. (Note: all six providers share the old spawn.sync idiom in checkInstalled; I've only changed Kiro's, since that's this PR's file.)
  • 🟠 server/routes/commands.js — symlink escape in command path validation. Valid. Now canonicalizes both commandPath and the allowlist roots via fs.realpath before the containment check, so a symlink inside .claude/commands can't target a file outside the allowed roots; a non-existent target denies access. (This block is pre-existing code from feat: add opencode support #762, not introduced here, but it surfaced in this PR's diff so I fixed it.)
  • 🟡 ProviderSelectionEmptyState.tsx — hardcoded "Choose a model". Valid. Wrapped it and the adjacent "Model Selector" title in t(..., { defaultValue }), matching the searchModels/noModelsFound convention already used in that dialog. (Also pre-existing from feat: add opencode support #762.)

False positive

  • 🟡 public/api-docs.html — "static request documentation describing valid provider values not updated". There is no static provider enumeration in that file. PROVIDER_ORDER (already updated to include kiro) is the only provider list, and the model documentation table renders dynamically from it. Nothing else to update.

Verification on the updated branch: tsc (client + server) clean, eslint 0 errors, npm run test:server 91/91, client + server builds green.

🤖 Fix + verification done with Claude Code.

Resolves conflicts from upstream PR siteboon#887 (unify-websocket-2 + unified
session gateway with stable IDs and a single WS protocol), which
refactored exactly the websocket/session layer the Kiro provider hooks
into. 11 files / 27 conflict regions.

Resolution strategy:
- Adopted upstream's provider-agnostic gateway wholesale where Kiro needs
  no special handling: the WS handler now dispatches via spawnFns/abortFns
  keyed by LLMProvider and resolves the provider from the DB session row,
  and per-provider session arrays (kiroSessions, cursorSessions, ...) are
  collapsed into a single flat `sessions[]` discriminated by `provider`.
- Re-injected Kiro into the new registration points:
  * server/index.js: kiro -> spawnKiro / abortKiroSession in the new maps
    (dropped now-unused isKiroSessionActive/getActiveKiroSessions imports).
  * useChatComposerState.ts: unified chat.send envelope + kiro in the
    model-resolution ladder so it sends kiroModel, not claudeModel.
  * ChatInterface.tsx: kept kiroModel wiring alongside upstream's
    isLoading -> isProcessing rename.
  * useChatProviderState.ts: kiro in the new FALLBACK_PERMISSION_MODES map.
  * provider-capabilities.service.ts: new kiro capability entry
    (ACP/--trust-all-tools: no images, no token usage, no interactive
    permission requests, abort supported).
  * src/types/app.ts: restored 'kiro' in the frontend LLMProvider union.

Also fixes a pre-existing gap the integration review surfaced (in scope):
shell-websocket.service.ts fell through to launching `claude` for a Kiro
session opening the Shell tab. Now launches the interactive `kiro-cli chat`
REPL (with --resume-id for resume) and labels the welcome banner "Kiro".

Verification: client tsc clean, server tsc clean, eslint 0 errors in
touched files, 110/111 server tests pass, client+server builds green.
(The 1 test failure and 2 eslint errors are pre-existing upstream issues
in files this branch does not touch.)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/index.js`:
- Around line 121-131: The resolveProviderSessionId function retrieves sessions
using only the sessionId without validating ownership by the authenticated
caller, creating a security vulnerability where users could access sessions they
do not own. Add ownership validation checks when calling
sessionsDb.getSessionById and when accessing sessionManager.getSession to ensure
the authenticated user is the owner of the requested session, and for HTTP
requests, verify the session belongs to the specified projectId. Apply the same
ownership validation pattern to the other location mentioned at lines 1156-1163
to maintain consistent security enforcement across all session-scoped
operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f3530474-e789-4916-8649-546b83af34d5

📥 Commits

Reviewing files that changed from the base of the PR and between 805b9a1 and fcc0242.

📒 Files selected for processing (12)
  • server/index.js
  • server/modules/providers/provider.routes.ts
  • server/modules/providers/services/provider-capabilities.service.ts
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/websocket/services/shell-websocket.service.ts
  • server/shared/types.ts
  • src/components/chat/hooks/useChatComposerState.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/i18n/locales/en/chat.json
  • src/types/app.ts
✅ Files skipped from review due to trivial changes (1)
  • server/modules/providers/provider.routes.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/i18n/locales/en/chat.json
  • src/components/chat/view/ChatInterface.tsx
  • server/modules/providers/services/sessions-watcher.service.ts
  • src/components/chat/hooks/useChatProviderState.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/index.js`:
- Around line 121-131: The resolveProviderSessionId function retrieves sessions
using only the sessionId without validating ownership by the authenticated
caller, creating a security vulnerability where users could access sessions they
do not own. Add ownership validation checks when calling
sessionsDb.getSessionById and when accessing sessionManager.getSession to ensure
the authenticated user is the owner of the requested session, and for HTTP
requests, verify the session belongs to the specified projectId. Apply the same
ownership validation pattern to the other location mentioned at lines 1156-1163
to maintain consistent security enforcement across all session-scoped
operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f3530474-e789-4916-8649-546b83af34d5

📥 Commits

Reviewing files that changed from the base of the PR and between 805b9a1 and fcc0242.

📒 Files selected for processing (12)
  • server/index.js
  • server/modules/providers/provider.routes.ts
  • server/modules/providers/services/provider-capabilities.service.ts
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/websocket/services/shell-websocket.service.ts
  • server/shared/types.ts
  • src/components/chat/hooks/useChatComposerState.ts
  • src/components/chat/hooks/useChatProviderState.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/i18n/locales/en/chat.json
  • src/types/app.ts
✅ Files skipped from review due to trivial changes (1)
  • server/modules/providers/provider.routes.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/i18n/locales/en/chat.json
  • src/components/chat/view/ChatInterface.tsx
  • server/modules/providers/services/sessions-watcher.service.ts
  • src/components/chat/hooks/useChatProviderState.ts
🛑 Comments failed to post (1)
server/index.js (1)

121-131: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Enforce per-session ownership before resolving provider-native session IDs.

Both paths read sessions by id alone (sessionsDb.getSessionById(...)) without validating that the authenticated caller owns that session (and for HTTP, that it belongs to the projectId in the route). This permits cross-session token-usage/resume access when a foreign session id is supplied.

Based on learnings: session-scoped actions must enforce per-session ownership validation across WebSocket and HTTP transports.

Also applies to: 1156-1163

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/index.js` around lines 121 - 131, The resolveProviderSessionId
function retrieves sessions using only the sessionId without validating
ownership by the authenticated caller, creating a security vulnerability where
users could access sessions they do not own. Add ownership validation checks
when calling sessionsDb.getSessionById and when accessing
sessionManager.getSession to ensure the authenticated user is the owner of the
requested session, and for HTTP requests, verify the session belongs to the
specified projectId. Apply the same ownership validation pattern to the other
location mentioned at lines 1156-1163 to maintain consistent security
enforcement across all session-scoped operations.

Source: Learnings

Addresses CodeRabbit review on PR siteboon#760. The kiro session-synchronizer and
mcp provider tests captured only the original HOME and, on teardown, set
USERPROFILE = ORIGINAL_HOME — conflating the two env vars. On any system
where USERPROFILE differs from HOME (e.g. Windows), this corrupted
USERPROFILE for subsequent tests.

Capture USERPROFILE's original value separately and restore (or delete)
each variable on its own, matching the robust pattern already used in
kiro-auth.provider.test.ts. Also stop seeding kiro-mcp's ORIGINAL_HOME
from os.homedir(); read the actual env var so the restore is faithful.
@dgallitelli

Copy link
Copy Markdown
Author

Triaged the latest CodeRabbit findings against the post-merge code. Summary:

Fixed (commit 3877ff8)

  • kiro-session-synchronizer.test.ts + kiro-mcp.provider.test.ts — env-var teardown. Both tests captured only the original HOME and restored USERPROFILE = ORIGINAL_HOME, conflating the two. On any system where USERPROFILEHOME (Windows), this corrupted USERPROFILE for later tests. Now each var is captured and restored/deleted independently, matching the pattern already used in kiro-auth.provider.test.ts. (CodeRabbit flagged the synchronizer test; the mcp test had the same latent bug, so I fixed both.)

Already resolved by the upstream merge (no action needed)

  • useProjectsState.ts — Kiro fallback provider normalization. The hardcoded cursor/codex/gemini → claude ladder that dropped kiro no longer exists. Merging upstream's unified session gateway replaced it with readSelectedProvider() / getSessionProvider(), which cast the stored/session provider string to LLMProvider generically — kiro is preserved, not misclassified as Claude.
  • kiro-sessions.provider.ts — unique message IDs per content part. Now superseded: the merged code routes Kiro session parsing through the unified normalization path, and message IDs already incorporate part identity. No collision in current code.

Out of scope for this PR

  • server/index.js resolveProviderSessionId — session-ownership validation. This closure is upstream code (siteboon commit 89f0524, "fix(shell): use correct session id"), is fully provider-agnostic, and predates this branch — CodeRabbit only re-surfaced it because the merge touched index.js. It affects all six providers equally and isn't part of the Kiro integration, so I've left it for a separate change rather than widening this PR's blast radius.
  • package.json:32 — single vs. double quotes on Windows. The flagged line is upstream's test:server script and already uses escaped double quotes (\"server/**/*.test.ts\"). Not introduced here.

Verification after the fix: client tsc clean, server tsc clean, eslint clean on touched files, test:server 110/111 (the single failure is a pre-existing upstream cache test in provider-models.service.test.ts, unchanged by this PR — it fails identically on a clean upstream/main).

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.

[Feature] Add Kiro (AWS Agentic IDE) support

3 participants