mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
refactor(jetbrains): move Permission views to views.permission, Align to ui.layout
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
# Plan: Bubble Subagent Permission Requests in JetBrains
|
||||
|
||||
## Goal
|
||||
|
||||
Make the JetBrains plugin show subagent permission requests in the main/root session UI so the child session does not hang waiting for a reply. Use the VS Code approach only as a reference pattern; do not change VS Code.
|
||||
|
||||
## Findings
|
||||
|
||||
- CLI permission requests are session-scoped. `packages/opencode/src/session/prompt.ts` sends `Permission.ask()` with the active session ID, and `packages/opencode/src/permission/index.ts` publishes `permission.asked` then waits indefinitely for a reply.
|
||||
- The task tool creates a child session for each subagent in `packages/opencode/src/tool/task.ts`, writes the child `sessionId` into the parent task tool metadata, then starts the child prompt. Subagent tool permissions therefore arrive as `permission.asked` for the child session ID.
|
||||
- JetBrains parses the required data already:
|
||||
- `packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDataParser.kt` parses `permission.asked`, `permission.replied`, and task part metadata.
|
||||
- `packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/ChatDto.kt` has `PermissionRequestDto.sessionID`, `PartDto.metadata`, and `SessionDto.parentID`.
|
||||
- JetBrains currently filters too narrowly:
|
||||
- `packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloSessionRpcApiImpl.kt` exposes `events(id, directory)` filtered to `sid == id`.
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/controller/SessionController.kt` subscribes only to the root session and `recoverPending(id)` filters pending permissions to `it.sessionID == id`.
|
||||
- The UI does not need a major change. `SessionState.AwaitingPermission` already renders through `PermissionView`; `replyPermission()` replies by request ID and directory, so it can reply to child permission requests once the controller surfaces them.
|
||||
- VS Code’s relevant reference is client-side: it detects task child session IDs from task part metadata, starts tracking the child, then recovers pending prompts to close the race where a child permission event arrived before the UI tracked the child.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
1. Keep the fix JetBrains-only and frontend-focused.
|
||||
- Do not modify `packages/kilo-vscode/`.
|
||||
- Avoid shared `packages/opencode/` changes; the CLI already exposes child session metadata and pending permissions.
|
||||
- Prefer changing `SessionController.kt` plus controller tests. Backend/RPC DTO changes should not be necessary.
|
||||
|
||||
2. Add child-session tracking to `SessionController`.
|
||||
- Replace the single `eventJob: Job?` with a map such as `eventJobs: MutableMap<String, Job>`.
|
||||
- Track known child IDs in a `MutableSet<String>`.
|
||||
- Keep one root subscription for the active root session and add child subscriptions only when a task part reveals a subagent session ID.
|
||||
- On disposal or when switching root sessions, cancel all jobs and clear the child set.
|
||||
|
||||
3. Discover subagent child IDs from task tool metadata.
|
||||
- Add a helper similar to VS Code’s `childID(part)`:
|
||||
- require `part.type == "tool"`,
|
||||
- require `part.tool == "task"`,
|
||||
- read `part.metadata["sessionId"]`.
|
||||
- Call it from `handle(ChatEventDto.PartUpdated)` after the root model receives the task part.
|
||||
- Also scan loaded history (`List<MessageWithPartsDto>`) after `loadHistory()` and cloud import so reopening an existing session discovers already-created child sessions.
|
||||
|
||||
4. Subscribe to child permission events without polluting the root transcript.
|
||||
- Add `subscribeEvents(id: String, root: Boolean)` or equivalent.
|
||||
- Root subscription keeps existing behavior and enqueues all root-matching events.
|
||||
- Child subscriptions collect `sessions.events(childId, directory)` but enqueue only permission events:
|
||||
- `ChatEventDto.PermissionAsked`,
|
||||
- `ChatEventDto.PermissionReplied`.
|
||||
- Ignore child message, part, status, idle, diff, and todo events so child transcript/status cannot overwrite the root session UI.
|
||||
|
||||
5. Recover pending child permissions immediately after tracking a child.
|
||||
- After subscribing to a child, call a new recovery helper for that child ID.
|
||||
- Query `sessions.pendingPermissions(directory)` and filter `it.sessionID == childId`.
|
||||
- If auto-approve is active, reply `once` to each pending child permission.
|
||||
- Otherwise set the root model state to `SessionState.AwaitingPermission(toPermission(lastPendingChildPermission))` on the EDT.
|
||||
- This closes the race where the child `permission.asked` event was already emitted before the child subscription started.
|
||||
|
||||
6. Keep root recovery intact, but add child-aware hooks.
|
||||
- Leave `recoverPending(rootId)` responsible for root permissions/questions/status seeding after history load.
|
||||
- After history-based child discovery, run child permission recovery for each discovered child.
|
||||
- Update `drainPermissions()` so toggling auto-approve drains pending permissions for the root plus tracked child IDs, not just the root.
|
||||
|
||||
7. Keep replies unchanged.
|
||||
- `SessionController.replyPermission(requestId, reply, rules)` should continue calling `sessions.replyPermission(requestId, directory, reply)`.
|
||||
- `Permission.sessionId` should remain the child ID for model/debug visibility.
|
||||
- `PermissionReplied` from the child subscription can clear the root prompt by matching the current request ID, just like root permission replies do today.
|
||||
|
||||
8. Add focused tests.
|
||||
- In `PromptLifecycleTest.kt`:
|
||||
- task part with `metadata["sessionId"] = "ses_child"` causes the controller to track child permission events,
|
||||
- child `PermissionAsked("ses_child", ...)` moves the root model to `AwaitingPermission`,
|
||||
- replying sends the child request ID through `FakeSessionRpcApi.permissionReplies`,
|
||||
- child `PermissionReplied` moves the root model back to busy,
|
||||
- child non-permission events do not change root transcript/status.
|
||||
- In `SessionRecoveryTest.kt`:
|
||||
- loaded history containing a task part with child metadata plus a pending child permission recovers into `AwaitingPermission`,
|
||||
- auto-approve recovery replies to pending child permissions without showing a prompt,
|
||||
- pending permissions from unrelated sessions remain ignored.
|
||||
- Use direct `PartDto(...)` construction or extend the test helper to include metadata.
|
||||
|
||||
9. Verify with JetBrains checks.
|
||||
- Run a targeted Gradle test for the touched controller tests if available.
|
||||
- Run `bun run typecheck` or `./gradlew typecheck` from `packages/kilo-jetbrains/`.
|
||||
- No VS Code checks are required because VS Code is reference-only and remains unchanged.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Do not add a CLI permission timeout as the primary fix; that would stop the hang by failing the request, not by showing the user the approval prompt.
|
||||
- Do not render the child transcript in the root session.
|
||||
- Do not expand scope to child questions unless a follow-up asks for it. The same subscription/recovery pattern can be reused later for `QuestionAsked`/`QuestionReplied` if needed.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Refactor JetBrains Permission View
|
||||
|
||||
## Goal
|
||||
Refactor the JetBrains session permission view so it uses the same shared inline question-card shell as question/login-required views, including internal button styling and alignment. Render bash/command permissions as a Markdown code block with `MdView`, capped to three visible lines with vertical scrolling inside the command block.
|
||||
|
||||
## Current Context
|
||||
- `PermissionView` currently builds its own `BorderLayoutPanel` card, manually applies `SessionUiStyle.View` borders/backgrounds, and uses raw `JButton` actions in `frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionView.kt`.
|
||||
- `QuestionView` and `LoginRequiredView` use `BaseSessionQuestionPanel` plus `applyButton`/`dismissButton` from `frontend/src/main/kotlin/ai/kilocode/client/session/ui/shared/`.
|
||||
- `BaseSessionQuestionPanel` owns the shared rounded surface, header/description text areas, body slot, footer slot, editor-font propagation, and left alignment conventions.
|
||||
- `MdView.html()` is the existing Markdown renderer. Tests already inspect markdown/html and style overrides through its component.
|
||||
- `SessionMessageListPanel` already calls `permission.applyStyle(style)`, so the refactor can stay inside the frontend session UI without controller/model/RPC changes.
|
||||
|
||||
## Implementation Plan
|
||||
1. Refactor `PermissionView` shell
|
||||
- Replace the custom `card = BorderLayoutPanel()` card setup with `BaseSessionQuestionPanel()`.
|
||||
- Set `card.headerText.text` to `session.permission.title` and use `card.descriptionText` for `permission.message` when present; hide/clear the description when blank.
|
||||
- Keep a retained `details`/`body` `JPanel` with `BoxLayout.Y_AXIS`, transparent background, and `Component.LEFT_ALIGNMENT`, then attach it via `card.setBody(body)`.
|
||||
- Add a retained `footer` panel via `card.setFooter(footer)` with the same alignment pattern as `QuestionView`/`LoginRequiredView`.
|
||||
|
||||
2. Use shared internal buttons
|
||||
- Replace raw `JButton` instances with `applyButton(KiloBundle.message("session.permission.run")) { decide("once") }` and `dismissButton(KiloBundle.message("session.permission.deny")) { decide("reject") }`.
|
||||
- Lay out `deny` on the left and `run` on the right using the same `BorderLayout` footer convention as the other `BaseSessionQuestionPanel` users.
|
||||
- Preserve the existing enabled/disabled behavior for `RESPONDING` and `RESOLVED`, and disable both buttons immediately after a decision.
|
||||
- Keep existing `runButtonForTest()` and `denyButtonForTest()` helpers, returning the new `SessionQuestionButton` instances.
|
||||
|
||||
3. Render command permissions with `MdView`
|
||||
- Replace `addCommandBlock`'s `JBTextArea` command renderer with an `MdView.html()` instance.
|
||||
- Set the Markdown source to a fenced code block, escaping embedded triple backticks safely by choosing a fence length longer than any backtick run in the command.
|
||||
- Apply session/editor style to the Markdown view: `md.font = style.transcriptFont`, `md.codeFont = style.editorFamily`, and keep it visually integrated with the question-card surface.
|
||||
- Wrap `md.component` in a `JBScrollPane` with `VERTICAL_SCROLLBAR_AS_NEEDED`; use a capped preferred/maximum height equivalent to three editor text lines plus scroll/chrome padding so longer commands scroll inside the code block.
|
||||
- Add `SessionUiStyle.View.Permission.COMMAND_LINES = 3` (or similarly named session-specific token) rather than scattering a magic number in the view.
|
||||
|
||||
4. Preserve non-command permission details
|
||||
- Keep `addPatternBlock`, tool label mapping, diff title/summary rendering, fallback diff handling, and no-rule-controls behavior intact.
|
||||
- Keep existing diff previews as plain text areas unless implementation naturally benefits from a small helper; the requested Markdown/code-block behavior applies specifically to permission commands.
|
||||
- Ensure every dynamic detail component aligns left under the shared card body and no custom outer card background/border code remains in `PermissionView`.
|
||||
|
||||
5. Update style propagation
|
||||
- Replace the old `textAreas` tracking with separate tracking for text areas and command Markdown views, or a small helper that updates both.
|
||||
- In `applyStyle`, call `card.applyStyle(style)`, update labels/text areas, and update all command `MdView` instances without rebuilding the component tree.
|
||||
- Avoid raw colors/fonts and keep theme-derived values via `SessionEditorStyle`, `UiStyle`, `SessionUiStyle`, and `UIUtil` as the existing file does.
|
||||
|
||||
6. Update tests in `PermissionViewTest`
|
||||
- Assert the view contains a `BaseSessionQuestionPanel` after `show`.
|
||||
- Assert Run/Deny are `SessionQuestionButton`s, Run is primary/default styled, Deny is secondary, and both use the shared question surface background.
|
||||
- Keep existing reply/visibility/pattern/diff/no-rule/responding tests passing.
|
||||
- Add a command-specific test that verifies a bash command renders through Markdown as a fenced code block (for example by inspecting the `JBHtmlPane`/`MdView` content for `<pre>` and the command text).
|
||||
- Add a long-command test that verifies the command scroll pane uses vertical scrolling and its preferred/maximum height is capped at the three-line limit.
|
||||
|
||||
## Files To Change
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionView.kt`
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/style/SessionUiStyle.kt`
|
||||
- `packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/PermissionViewTest.kt`
|
||||
|
||||
## Verification
|
||||
- Run targeted tests from `packages/kilo-jetbrains/`:
|
||||
- `./gradlew :frontend:test --tests 'ai.kilocode.client.session.views.PermissionViewTest'`
|
||||
- Run the package typecheck from `packages/kilo-jetbrains/`:
|
||||
- `./gradlew typecheck`
|
||||
- If the targeted command test surfaces layout-sensitive failures, also run:
|
||||
- `./gradlew :frontend:test --tests 'ai.kilocode.client.session.views.QuestionViewTest'`
|
||||
|
||||
## Risks / Notes
|
||||
- `MdView` stores rendered HTML in a `JBHtmlPane`; tests should avoid depending on exact full HTML output and assert stable signals such as source text, `<pre>` presence, button types, and scroll policies.
|
||||
- The command height cap should account for line height plus scrollpane chrome, not a raw pixel height, so it remains correct across editor font changes and HiDPI scaling.
|
||||
- This is a frontend-only Swing refactor; no shared RPC/model/backend changes are expected.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Refactor BaseQuestionView and Session Fonts
|
||||
|
||||
## Goal
|
||||
|
||||
Refactor the JetBrains session question card UI so callers configure text/actions through `BaseQuestionView` instead of reaching into its Swing internals, and move session UI font choices to explicit standard `UiStyle.Fonts`/`SessionEditorStyle` tokens.
|
||||
|
||||
## Design Decisions
|
||||
|
||||
- Treat `SessionEditorStyle` editor fonts/colors as-is for editor-backed content, but replace current UI font sizing/derivation with explicit UI font fields sourced from `UiStyle.Fonts`.
|
||||
- Proposed UI font mapping:
|
||||
- `headerFont` -> `UiStyle.Fonts.header()` -> `JBFont.h3().asBold()`
|
||||
- `hintFont` -> `UiStyle.Fonts.hint()` -> `JBFont.regular()`
|
||||
- `regularFont` -> `UiStyle.Fonts.regular()` -> `JBFont.regular()`
|
||||
- `boldFont` -> `UiStyle.Fonts.bold()` -> `JBFont.regular().asBold()`
|
||||
- `smallFont` -> `UiStyle.Fonts.small()` -> `JBFont.small()`
|
||||
- Remove manual UI font size derivation (`JBUI.Fonts.label().deriveFont(...)`, `JBFont.small().deriveFont(...)`, `deriveFont(size + 1)`); only style helpers such as `.asBold()` are used for UI fonts.
|
||||
- Keep `BaseQuestionView.setTopPanel(...)`, keep/add a content setter (`setContent(...)`, with `setBody(...)` retained only if useful as a compatibility alias), and replace external footer/button construction with a Base-owned action API.
|
||||
- Make `SessionQuestionButton` an implementation detail or remove it from public APIs. Callers and tests should see generic `JButton`/`AbstractButton` behavior only.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
1. Update shared font tokens in `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/UiStyle.kt`.
|
||||
- Extend `UiStyle.Fonts` with `header()`, `hint()`, `regular()`, `bold()`, and `small()`.
|
||||
- Preserve existing `display()`, `heading()`, and `large()` helpers.
|
||||
- Use only standard `JBFont` helpers and `.asBold()`; do not derive sizes.
|
||||
|
||||
2. Refactor `SessionEditorStyle` in `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/style/SessionEditorStyle.kt`.
|
||||
- Add/replace UI fields with `headerFont`, `hintFont`, `regularFont`, `boldFont`, `smallFont`.
|
||||
- Populate those fields directly from `UiStyle.Fonts`.
|
||||
- Remove current UI-font manual scaling and no longer couple UI font sizes to editor font size.
|
||||
- Keep editor-specific fields (`transcriptFont`, `smallEditorFont`, `boldEditorFont`, editor colors/family/size) for code/editor-rendered content.
|
||||
|
||||
3. Refactor `BaseQuestionView` in `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/base/BaseQuestionView.kt`.
|
||||
- Make header/description text areas private implementation details.
|
||||
- Add EDT methods such as `setHeader(header: String, description: String? = null)` and `setDescription(description: String?)`.
|
||||
- Hide the description row when the description is null/blank, instead of requiring clients to set visibility directly.
|
||||
- Apply `style.headerFont` to the header and `style.hintFont` to the description.
|
||||
- Add a Base-owned action API, for example a public nested `Action(id, text, primary, enabled, handler)` plus `setActions(List<Action>)` and `setActionEnabled(id, enabled)`.
|
||||
- Build the right-aligned footer and internal buttons in `BaseQuestionView`, preserving primary buttons via `DarculaButtonUI.DEFAULT_STYLE_KEY` and question-card background styling.
|
||||
- Keep `setHeaderIcon(...)` and `setTopPanel(...)`; keep the top slot for progress/navigation and the content slot for view-specific body components.
|
||||
- Add minimal internal test helpers only if necessary, returning generic `JButton` or `Font`, not `SessionQuestionButton`.
|
||||
|
||||
4. Migrate question card callers.
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/question/QuestionView.kt`:
|
||||
- Replace direct `card.headerText`/`card.descriptionText` mutation with `card.setHeader(...)`/`card.setDescription(...)`.
|
||||
- Replace `SessionQuestionButton`, `applyButton`, `dismissButton`, and manual footer panels with `card.setActions(...)`.
|
||||
- Use stable action ids and `card.setActionEnabled(...)` so selection updates do not rebuild the existing Next/Submit button.
|
||||
- Update option/review text fonts to `style.regularFont` and `style.boldFont`.
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionView.kt`:
|
||||
- Use Base setters for header/description/content/actions.
|
||||
- Return generic buttons from test helpers if helpers remain.
|
||||
- Keep editor-derived `transcriptFont`/`editorFamily` for command markdown/code rendering.
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/LoginRequiredView.kt`:
|
||||
- Use Base setters for title/description/actions.
|
||||
- Remove public exposure of `SessionQuestionButton`; tests can locate generic buttons by text or use generic helper accessors.
|
||||
|
||||
5. Rename/update remaining `SessionEditorStyle` UI-font consumers.
|
||||
- Update all `style.uiFont`, `style.boldUiFont`, and `style.smallUiFont` references to the new fields.
|
||||
- Expected mappings:
|
||||
- ordinary labels/body text -> `regularFont`
|
||||
- emphasized labels/body answers -> `boldFont`
|
||||
- compact metadata/subtitles -> `smallFont`
|
||||
- card question titles -> `headerFont`
|
||||
- card hints/descriptions -> `hintFont`
|
||||
- Files likely affected include `QuestionResultView.kt`, `CompactionView.kt`, `GenericView.kt`, `SessionHeaderPanel.kt`, `ContextBar.kt`, `ProgressPanel.kt`, `LoadingPanel.kt`, and `EmptySessionPanel.kt`.
|
||||
|
||||
6. Update tests.
|
||||
- `SessionEditorStyleTest.kt`: assert UI font fields equal `UiStyle.Fonts.*()` and do not inherit editor family/size.
|
||||
- `BaseQuestionViewTest.kt`: test the new text/content/action APIs, description visibility behavior, retained top/content ordering, primary button default-style key, enabled-state updates, and callbacks without referencing `SessionQuestionButton`.
|
||||
- `QuestionViewTest.kt`, `PermissionViewTest.kt`, `LoginRequiredViewTest.kt`, and `QuestionResultViewTest.kt`: remove `SessionQuestionButton` imports/type assertions; keep behavior/style assertions through generic Swing buttons and new font fields.
|
||||
- Preserve retained-component tests such as “selection updates existing footer controls” by using `setActionEnabled(...)` rather than rebuilding buttons on selection changes.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from `packages/kilo-jetbrains/` after implementation:
|
||||
|
||||
```bash
|
||||
./gradlew :frontend:test --tests "ai.kilocode.client.session.ui.SessionEditorStyleTest" --tests "ai.kilocode.client.session.views.base.BaseQuestionViewTest" --tests "ai.kilocode.client.session.views.QuestionViewTest" --tests "ai.kilocode.client.session.views.PermissionViewTest" --tests "ai.kilocode.client.session.views.LoginRequiredViewTest" --tests "ai.kilocode.client.session.views.QuestionResultViewTest"
|
||||
```
|
||||
|
||||
Then run the package compile/typecheck:
|
||||
|
||||
```bash
|
||||
./gradlew typecheck
|
||||
```
|
||||
|
||||
## Risks / Notes
|
||||
|
||||
- The new standard UI fonts intentionally stop following the editor font size, so several font-size assertions must change.
|
||||
- `SessionQuestionButton` may remain as a private implementation class in `BaseQuestionView.kt`, but no caller should import it or rely on its concrete type.
|
||||
- This is a JetBrains frontend-only refactor; no split-mode RPC or module descriptor changes are expected.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Add Custom Question Responses In JetBrains
|
||||
|
||||
## Findings
|
||||
|
||||
- The backend/DTO contract is already ready for custom answers.
|
||||
- `packages/opencode/src/question/index.ts` exposes `Question.Info.custom?: boolean` and `Question.Reply.answers: string[][]`.
|
||||
- Both legacy and HttpApi question reply routes accept arbitrary strings in `answers`, so no server shape change is needed.
|
||||
- The generated SDK also has `QuestionInfo.custom?: boolean` and `QuestionAnswer = string[]`.
|
||||
- JetBrains shared DTOs already mirror this: `QuestionInfoDto.custom: Boolean = true` and `QuestionReplyDto.answers: List<List<String>>` in `packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/ChatDto.kt`.
|
||||
- JetBrains backend parsing already preserves `custom`, defaulting to true unless the server sends `false`, in `KiloCliDataParser.parseQuestionRequest`.
|
||||
- JetBrains frontend model already carries `QuestionItem.custom`, and `SessionController.toQuestion` maps the DTO field into the model.
|
||||
- Current missing piece is only `QuestionView`: it ignores `QuestionItem.custom` and only renders option labels.
|
||||
- VS Code renders a custom row when `question.custom !== false`, labels it as a typed-answer option, stores typed custom answers as ordinary answer strings, and sends the same `answers: string[][]` payload.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
1. Reuse the prompt editor component for question custom input.
|
||||
- Extract the current prompt editor text field behavior from `PromptEditorTextField` into a reusable session editor text field, likely under `frontend/src/main/kotlin/ai/kilocode/client/session/ui/editor/`.
|
||||
- Keep the prompt using the same reusable editor so prompt behavior remains unchanged.
|
||||
- Let `QuestionView` create the same editor type with plain-text file type, soft wraps, editor color scheme, editor font, empty borders, and `SessionEditorStyle.applyToEditor`.
|
||||
- Ensure editor instances for both `PromptPanel` and `QuestionView` are created from the required IntelliJ read context/read thread, rather than directly from arbitrary Swing construction code.
|
||||
- If IntelliJ APIs require it, wrap editor creation in a small helper such as `runReadAction` or the platform's current read-thread equivalent, then attach/mutate the resulting component only on the EDT.
|
||||
- Add an optional `SendPromptContext` hook to the reusable editor so the existing prompt shortcuts still work; for question custom input, implement a small question-local context that submits through the question footer flow rather than sending a normal prompt.
|
||||
|
||||
2. Pass `Project` into `QuestionView`.
|
||||
- `EditorTextField` needs a project, and `SessionUi` already has one.
|
||||
- Update `QuestionView(project, reply, reject, scroll)` construction in `SessionUi`.
|
||||
- Update `QuestionViewTest` setup to pass the test fixture `project`.
|
||||
|
||||
3. Extend `QuestionView` state to separate option selections from custom text.
|
||||
- Keep selected option labels in the existing per-question sets.
|
||||
- Add per-question custom text and custom editor/open state.
|
||||
- Compute effective answers from options plus the trimmed custom text.
|
||||
- For single-select questions, activating custom should clear option selection and make the custom answer the only answer once non-blank.
|
||||
- For multi-select questions, the custom answer should be included alongside checked options once non-blank.
|
||||
- Preserve typed custom text across back/next/review navigation.
|
||||
|
||||
4. Render the custom row when `item.custom` is true.
|
||||
- Add an extra radio/checkbox-style row labeled `Add your own response` or the final localized copy chosen in bundle keys.
|
||||
- Keep the input/editor initially invisible.
|
||||
- Clicking the custom row shows the editor, focuses it, selects the custom answer mode for single-select, and revalidates/repaints the question view.
|
||||
- If custom text already exists and the editor is hidden, show a short preview in the row description.
|
||||
- Do not render the row when `custom = false`.
|
||||
- Ensure optionless questions with `custom = true` are answerable.
|
||||
|
||||
5. Make the custom editor grow and validate live.
|
||||
- Add a document listener to the question custom editor.
|
||||
- On each edit, update stored text, recompute answer readiness, call `syncControls`, and revalidate/repaint the editor, card, and parent container.
|
||||
- Size the editor from the current newline count, starting at one visible line and expanding as the user types newlines.
|
||||
- Continue using the main footer buttons for `Next`, `Review`, and `Submit`; no backend-specific custom-submit action is needed.
|
||||
- Keep blank/whitespace-only custom input from enabling submit or next.
|
||||
|
||||
6. Update review and reply behavior.
|
||||
- Change review rows to display effective answers, including custom typed answers.
|
||||
- Change `doReply` to send effective answers for all question items.
|
||||
- Keep the reply payload unchanged: `QuestionReplyDto(listOf(listOf("typed custom answer")))`.
|
||||
- Keep reject/dismiss behavior unchanged.
|
||||
|
||||
7. Add localized strings.
|
||||
- Add bundle keys in `KiloBundle.properties`, such as `session.question.custom.label` and `session.question.custom.placeholder`.
|
||||
- Rely on base-bundle fallback for other locale files unless the project requires updating every translation file.
|
||||
|
||||
8. Add tests.
|
||||
- `QuestionViewTest`: custom row renders when `custom = true` and is absent when `custom = false`.
|
||||
- `QuestionViewTest`: clicking the custom row reveals/focuses the editor.
|
||||
- `QuestionViewTest`: blank custom input does not enable submit.
|
||||
- `QuestionViewTest`: single-select custom answer submits as `QuestionReplyDto(listOf(listOf(text)))`.
|
||||
- `QuestionViewTest`: selecting a normal single option after custom input sends the option, not stale custom text.
|
||||
- `QuestionViewTest`: multi-select custom answer combines with selected options.
|
||||
- `QuestionViewTest`: custom text appears in review and is preserved across navigation.
|
||||
- `QuestionViewTest`: optionless custom question is answerable.
|
||||
- `QuestionViewTest`: editor preferred height increases after typing a newline and triggers revalidation.
|
||||
- `KiloCliDataParserTest`: only add coverage if existing parser tests do not already prove `custom` parsing and arbitrary string reply escaping.
|
||||
|
||||
9. Add release note metadata.
|
||||
- This is a user-facing JetBrains plugin enhancement, so add a patch changeset for `@kilocode/kilo-jetbrains` describing typed custom responses to question prompts.
|
||||
|
||||
10. Verify.
|
||||
- Run targeted JetBrains tests for `QuestionViewTest` and any parser tests touched.
|
||||
- Run `./gradlew typecheck` from `packages/kilo-jetbrains/`.
|
||||
- If only frontend tests changed, also run the smallest relevant Gradle test target for the frontend module if available; otherwise run the package test task that includes `QuestionViewTest`.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Do not change the CLI/server question API shape.
|
||||
- Do not add a separate `custom` discriminator to replies.
|
||||
- Do not route custom typed answers through the normal prompt path.
|
||||
- Do not use Compose, JCEF, or Kotlin UI DSL.
|
||||
@@ -0,0 +1,557 @@
|
||||
# JetBrains Permission Panel Rendering Parity Plan
|
||||
|
||||
## Goal
|
||||
|
||||
Bring the JetBrains permission panel content rendering to parity with the VS Code permission dock, specifically for the contents/details shown inside the permission panel. Do not implement auto-approve rule controls or saved-rule management yet.
|
||||
|
||||
The priority user-visible gaps are edit/write/patch details, especially file diff previews. The JetBrains frontend already receives the relevant metadata; most of the work is Swing rendering, styling, and tests.
|
||||
|
||||
## Scope
|
||||
|
||||
Implement content rendering parity for:
|
||||
|
||||
- Permission title/header, including subagent title if the request belongs to another session and the current session can be determined safely.
|
||||
- Bash/command details.
|
||||
- Non-command tool pattern details.
|
||||
- Fallback tool description/details when patterns are empty or only `*`.
|
||||
- Edit/write/patch file details and diff previews.
|
||||
- Per-file additions/deletions summary.
|
||||
- Missing patch fallback text.
|
||||
- Permission response state details where already modeled, especially error messages.
|
||||
|
||||
Explicitly exclude:
|
||||
|
||||
- Auto-approve rule controls.
|
||||
- Persisting rule decisions.
|
||||
- Any new permission response semantics beyond existing `Run`/`Deny`.
|
||||
- Repositioning the permission panel inline next to the originating tool call.
|
||||
- Changes to CLI permission generation unless a parser bug is discovered.
|
||||
|
||||
## Key Findings From Analysis
|
||||
|
||||
### VS Code implementation
|
||||
|
||||
Reference files:
|
||||
|
||||
- `packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx`
|
||||
- `packages/kilo-vscode/webview-ui/src/components/chat/PermissionCommand.tsx`
|
||||
- `packages/kilo-vscode/webview-ui/src/components/chat/PermissionDiff.tsx`
|
||||
- `packages/kilo-vscode/webview-ui/src/components/chat/permission-diff-utils.ts`
|
||||
- `packages/kilo-vscode/webview-ui/src/components/chat/permission-dock-utils.ts`
|
||||
- `packages/kilo-vscode/webview-ui/src/types/messages/permissions.ts`
|
||||
|
||||
VS Code renders:
|
||||
|
||||
- Header: `Permission required`, or `Permission required (subagent)` when `request.sessionID !== currentSessionID`.
|
||||
- Command block when `request.args.command` is a string.
|
||||
- Pattern description for non-command permissions:
|
||||
- filters out `*`
|
||||
- one pattern: `<Tool Label> <pattern>`
|
||||
- multiple patterns: `<Tool Label>:` then code-like rows
|
||||
- no meaningful patterns: fallback to localized tool description if available
|
||||
- Diffs from `permissionDiffs(request)`:
|
||||
- `args.filediff` first
|
||||
- `args.files[]` second
|
||||
- fallback to `args.diff` plus `args.filepath ?? "patch"`
|
||||
- Each diff displays:
|
||||
- file icon
|
||||
- directory and filename split
|
||||
- `+N -N` via `DiffChanges`
|
||||
- inline unified diff via `Diff`
|
||||
- fallback text: `Diff preview unavailable for this file.` when no patch exists
|
||||
- expand/open-in-tab button (do not implement for JetBrains in this pass unless trivial and explicitly desired later)
|
||||
- Auto-approve rule controls live in the footer and should be ignored for this task.
|
||||
|
||||
### JetBrains implementation
|
||||
|
||||
Reference files:
|
||||
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionView.kt`
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/model/Permission.kt`
|
||||
- `packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/ChatDto.kt`
|
||||
- `packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDataParser.kt`
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/controller/SessionController.kt`
|
||||
- `packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/PermissionViewTest.kt`
|
||||
- `packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties`
|
||||
|
||||
Current JetBrains behavior:
|
||||
|
||||
- `PermissionView.show(permission)` rebuilds a simple body.
|
||||
- If `permission.meta.command != null` or tool name is `bash`, it renders a fenced Markdown code block.
|
||||
- Otherwise it renders `patternText(toolName, permission.patterns)` as a fenced Markdown code block.
|
||||
- It disables buttons for `RESPONDING` and `RESOLVED`.
|
||||
- It does not render diff previews, `filePath`, `fileDiffs`, error messages, or rich status text.
|
||||
- Existing tests currently assert that diff previews are not rendered; these must be inverted/updated.
|
||||
|
||||
JetBrains already receives and maps rich permission data:
|
||||
|
||||
- `PermissionRequestDto.fileDiffs: List<PermissionFileDiffDto>`
|
||||
- `PermissionFileDiffDto.file`, `patch`, `before`, `after`, `additions`, `deletions`
|
||||
- `PermissionMeta.fileDiffs`, `fileDiff`, `diff`, `filePath`, `raw`
|
||||
- Parser handles:
|
||||
- `metadata.filediff`
|
||||
- `metadata.files[]`
|
||||
- fallback `metadata.diff`
|
||||
- Controller maps DTOs to frontend model correctly.
|
||||
|
||||
Important existing bundle keys:
|
||||
|
||||
- `session.permission.title=Permission required`
|
||||
- `session.permission.title.subagent=Permission required (subagent)`
|
||||
- `session.permission.run=Run`
|
||||
- `session.permission.deny=Deny`
|
||||
- `session.permission.patterns={0}:`
|
||||
- `session.permission.diff=Changes`
|
||||
- `session.permission.diff.summary=+{0} -{1}`
|
||||
- `session.permission.no.details={0} requires permission.`
|
||||
- `session.permission.responding=Sending response...`
|
||||
- `session.permission.error=Failed to send permission response`
|
||||
- `session.permission.tool.*` mappings already exist.
|
||||
|
||||
Likely missing bundle key:
|
||||
|
||||
- `session.permission.diff.unavailable=Diff preview unavailable for this file.`
|
||||
|
||||
If adding this key, add it to all localized `KiloBundle_*.properties` files. It is acceptable to use English fallback text in localized files if this repository pattern does that elsewhere; otherwise follow the existing localization convention.
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### 1. Keep changes localized to JetBrains frontend first
|
||||
|
||||
Most changes should be in:
|
||||
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionView.kt`
|
||||
- possibly a new helper/component file such as:
|
||||
- `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionDiffView.kt`
|
||||
- or `PermissionDetailsView.kt` if extracting all detail sections is cleaner
|
||||
- `packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/PermissionViewTest.kt`
|
||||
- resource bundle files under `packages/kilo-jetbrains/frontend/src/main/resources/messages/`
|
||||
- possibly `SessionUiStyle.kt` only if a reusable permission diff height/spacing token is necessary
|
||||
|
||||
Avoid backend/shared changes unless tests reveal the parser/model does not expose a field needed by rendering.
|
||||
|
||||
### 2. Prefer a small extracted diff component
|
||||
|
||||
Recommended structure:
|
||||
|
||||
- Keep `PermissionView` responsible for card shell, actions, command/pattern section selection, and body composition.
|
||||
- Add `PermissionDiffView` for one file diff.
|
||||
- Optionally add `PermissionDiffListView` only if it materially reduces complexity.
|
||||
|
||||
Why:
|
||||
|
||||
- `PermissionView.kt` is already 241 lines and will grow quickly.
|
||||
- Diff rendering has distinct styling, tests, and style application concerns.
|
||||
- A dedicated component is easier for a faster model to modify safely.
|
||||
|
||||
Proposed `PermissionDiffView` responsibilities:
|
||||
|
||||
- Accept a `PermissionFileDiff`.
|
||||
- Implement `SessionEditorStyleTarget` if it renders code with editor style.
|
||||
- Build header row:
|
||||
- file icon: prefer `AllIcons.FileTypes.Text` or another standard IntelliJ icon if appropriate
|
||||
- file path display, preferably directory muted + filename regular/bold if simple
|
||||
- summary label using `KiloBundle.message("session.permission.diff.summary", additions, deletions)`
|
||||
- Build content area:
|
||||
- if `patch` is non-null/non-blank: scrollable code/Markdown block with patch
|
||||
- else: label with unavailable preview text
|
||||
- Use platform components:
|
||||
- `JBLabel`
|
||||
- `JBScrollPane`
|
||||
- `BorderLayoutPanel` / `JBUI.Panels.simplePanel`
|
||||
- `JBUI.Borders.empty(...)`
|
||||
- Style with `SessionEditorStyle` for patch content and `SessionUiStyle`/`UiStyle` for spacing/colors.
|
||||
|
||||
Avoid:
|
||||
|
||||
- Compose, JCEF, UI DSL.
|
||||
- Raw hardcoded colors.
|
||||
- Raw unscaled dimensions or `EmptyBorder`.
|
||||
- Complex custom diff parsing/syntax highlighting. VS Code already receives unified patches and renders them; for JetBrains parity, a readable scrollable unified patch is enough unless there is an existing diff widget readily available.
|
||||
|
||||
### 3. Update `PermissionView.show(permission)` rendering flow
|
||||
|
||||
Current flow:
|
||||
|
||||
```kotlin
|
||||
val toolName = permission.name
|
||||
val cmd = permission.meta.command
|
||||
val command = cmd != null || toolName == "bash"
|
||||
|
||||
if (command) {
|
||||
addCodeBlock(cmd ?: "")
|
||||
} else {
|
||||
addCodeBlock(patternText(toolName, permission.patterns))
|
||||
}
|
||||
```
|
||||
|
||||
Recommended flow:
|
||||
|
||||
```kotlin
|
||||
val tool = permission.name
|
||||
val cmd = permission.meta.command
|
||||
|
||||
if (cmd != null || tool == "bash") {
|
||||
addCodeBlock(cmd ?: "")
|
||||
} else {
|
||||
addPatternDetails(tool, permission.patterns)
|
||||
}
|
||||
|
||||
addDiffs(permission.meta.fileDiffs)
|
||||
addStateMessage(permission)
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Keep bash with missing command showing an empty command block only if this preserves current behavior. Alternatively show fallback details for missing command, but that is a behavior change; preserve current behavior unless tests or product expectations say otherwise.
|
||||
- Do not render `permission.message` by default for bash because an existing test explicitly asserts it is not shown and VS Code does not show `message` as content.
|
||||
- For non-command permissions, pattern/details rendering should be closer to VS Code. It can still use a code-like block, but consider rendering multiple patterns as separate labels/code rows rather than one fenced block if easy.
|
||||
- Always add diffs after the command/pattern section. This matches VS Code, where a permission can show command/details and then diffs.
|
||||
|
||||
### 4. Implement pattern rendering parity
|
||||
|
||||
Current `patternText()` already mostly works but renders everything in a fenced block and uses double space for single pattern.
|
||||
|
||||
Recommended helper behavior:
|
||||
|
||||
```kotlin
|
||||
private fun patternDescription(tool: String, patterns: List<String>): PatternDescription?
|
||||
```
|
||||
|
||||
Where `PatternDescription` can be a small private sealed class/data class inside `PermissionView.kt`, or avoid an explicit type and keep simple helpers.
|
||||
|
||||
Exact behavior to mirror:
|
||||
|
||||
- Filter `patterns.filter { it != "*" }`.
|
||||
- If no filtered patterns: render fallback `session.permission.no.details` with `toolLabel(tool)`.
|
||||
- If one: render `<label> <pattern>`.
|
||||
- If multiple:
|
||||
- first line `session.permission.patterns(label)`
|
||||
- then one row per pattern.
|
||||
|
||||
Do not include auto-approve `always` or `rules` here.
|
||||
|
||||
### 5. Render file diff details
|
||||
|
||||
Source data: `permission.meta.fileDiffs`.
|
||||
|
||||
For each diff:
|
||||
|
||||
- Header:
|
||||
- show `diff.file`
|
||||
- if splitting path is easy, display directory separately from filename, but this is not required for first parity pass if full path is clear
|
||||
- show `+{additions} -{deletions}` using `session.permission.diff.summary`
|
||||
- Body:
|
||||
- if `patch` exists: render patch in scrollable code area
|
||||
- else: render unavailable fallback
|
||||
|
||||
Height cap:
|
||||
|
||||
- Existing command cap uses `SessionUiStyle.View.Permission.COMMAND_LINES` and `CARD_BODY_EXTRA_HEIGHT`.
|
||||
- For diff previews, add a token if needed, for example `SessionUiStyle.View.Permission.DIFF_LINES`, or reuse `COMMAND_LINES` for simplicity if no new token is needed.
|
||||
- If adding tokens, put them in `SessionUiStyle.View.Permission`, not in local constants.
|
||||
|
||||
Possible patch rendering implementation options:
|
||||
|
||||
Option A, quickest and consistent with current command rendering:
|
||||
|
||||
- Use `MdView.html()` with `fencedBlock(patch)` and existing `applyMd/applyScroll` logic.
|
||||
- Pros: minimal new rendering code, already tested for code blocks.
|
||||
- Cons: patch is not syntax-highlighted by additions/deletions colors.
|
||||
|
||||
Option B, slightly more purpose-built:
|
||||
|
||||
- Use `JBTextArea` or editor-like component in a scroll pane, set monospaced/editor style, non-editable, line wrap off or on depending UX.
|
||||
- Pros: simpler text collection in tests; avoids Markdown HTML quirks.
|
||||
- Cons: need to style manually and ensure platform component usage.
|
||||
|
||||
Recommended: Option A for faster implementation and lower risk, unless `MdView` makes tests too brittle.
|
||||
|
||||
### 6. Style application
|
||||
|
||||
Current `PermissionView` tracks:
|
||||
|
||||
- `cmdViews: MutableList<MdView>`
|
||||
- `cmdScrolls: MutableList<JBScrollPane>`
|
||||
|
||||
If using `MdView` for diffs too:
|
||||
|
||||
- Rename lists to a more generic name, e.g. `codeViews` and `codeScrolls`, or keep existing names only if used exclusively for command/pattern blocks.
|
||||
- Update `applyStyle()` to apply style to all command/pattern/diff code views.
|
||||
- Review naming rules: prefer single-word locals where clear, but do not sacrifice clarity for exported or test-visible names.
|
||||
|
||||
Be careful with tests that currently call `firstCmdViewForTest()`. Either preserve that test helper or add a more generic helper while adjusting tests.
|
||||
|
||||
### 7. Permission state messages
|
||||
|
||||
Current model can represent:
|
||||
|
||||
- `PENDING`
|
||||
- `RESPONDING`
|
||||
- `RESOLVED`
|
||||
- `ERROR`
|
||||
|
||||
Current UI only disables buttons for `RESPONDING` and `RESOLVED`.
|
||||
|
||||
Recommended content parity improvement:
|
||||
|
||||
- For `ERROR`, render `permission.message ?: KiloBundle.message("session.permission.error")` visibly in the card body, probably below details and above actions.
|
||||
- For `RESPONDING`, optionally render `session.permission.responding` if desired. This is already a resource key and helps users understand disabled buttons.
|
||||
- Do not render anything for `RESOLVED` because the state usually transitions away from permission.
|
||||
|
||||
If this increases scope too much, prioritize `ERROR` because the message is currently stored but invisible.
|
||||
|
||||
### 8. Subagent title
|
||||
|
||||
VS Code title changes when the pending permission belongs to another session.
|
||||
|
||||
JetBrains `PermissionView` currently only receives `Permission`, not the current session id. Options:
|
||||
|
||||
- Minimal: keep current title and do not implement subagent title yet; note as parity limitation.
|
||||
- Better: pass a predicate or current session id into `PermissionView` constructor from `SessionUi`/controller context, then use `permission.sessionId` to select `session.permission.title.subagent`.
|
||||
|
||||
Recommended for faster model: defer subagent title unless the current session id is already easily available at the construction site. The main user complaint is missing edit/details, not title. If implementing, keep it tiny and test it.
|
||||
|
||||
### 9. Do not implement auto-approve rules
|
||||
|
||||
Important: `PermissionMeta.rules` and `Permission.always` should remain unused for UI controls in this pass.
|
||||
|
||||
Keep/adjust the existing test that verifies no rule controls are rendered:
|
||||
|
||||
- It should continue to assert only Run and Deny buttons are present.
|
||||
- It should not assert absence of text that may appear in unrelated details unless needed.
|
||||
|
||||
## Detailed File-by-File Plan
|
||||
|
||||
### `PermissionView.kt`
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Rename command-specific collections if they will hold all code blocks:
|
||||
- `cmdViews` -> `codeViews`
|
||||
- `cmdScrolls` -> `codeScrolls`
|
||||
- Preserve or update test helper names carefully.
|
||||
2. In `show(permission)`:
|
||||
- clear body and code view lists
|
||||
- set title, potentially subagent title if implemented
|
||||
- add command or pattern details
|
||||
- add diffs from `permission.meta.fileDiffs`
|
||||
- add state message for `RESPONDING`/`ERROR` if implemented
|
||||
- update button enabled state as today
|
||||
3. Add `addPatternDetails(tool, patterns)` or adjust `patternText()`:
|
||||
- use VS Code-compatible filtering and text.
|
||||
4. Add `addDiffs(diffs)`:
|
||||
- no-op when empty
|
||||
- optionally add `session.permission.diff` label/header
|
||||
- add a `PermissionDiffView` per diff
|
||||
5. Add `addStateMessage(permission)` if included.
|
||||
6. Ensure `applyStyle()` updates all retained code/diff children.
|
||||
7. Add/adjust test helpers:
|
||||
- expose code views count if needed
|
||||
- expose diff components if needed
|
||||
- keep existing helpers unless tests are updated.
|
||||
|
||||
Caution:
|
||||
|
||||
- Current `show()` rebuilds body with `removeAll()`. This is acceptable for a discrete permission request. Do not introduce a complex retained diff update system unless necessary.
|
||||
- Existing style guide says avoid extra helpers unless they improve clarity. Here helpers are justified to keep `show()` readable.
|
||||
|
||||
### New `PermissionDiffView.kt` (recommended)
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Create class under `ai.kilocode.client.session.views`.
|
||||
2. Constructor accepts `PermissionFileDiff` and possibly a function to register code views, or the component manages its own code view internally.
|
||||
3. Implement `SessionEditorStyleTarget` if it owns an `MdView` or styled text component.
|
||||
4. Use platform components and existing style tokens.
|
||||
5. Add test helpers if direct component testing is easier.
|
||||
|
||||
Possible API:
|
||||
|
||||
```kotlin
|
||||
class PermissionDiffView(
|
||||
private val diff: PermissionFileDiff,
|
||||
) : BorderLayoutPanel(), SessionEditorStyleTarget {
|
||||
fun applyStyle(style: SessionEditorStyle) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Then `PermissionView` keeps a list of `SessionEditorStyleTarget` child targets and calls `applyStyle(style)`.
|
||||
|
||||
Alternative: no new class; add private `addDiff(diff)` inside `PermissionView`. This is acceptable if the resulting file remains manageable, but extraction is recommended.
|
||||
|
||||
### `SessionUiStyle.kt`
|
||||
|
||||
Only touch if needed.
|
||||
|
||||
Possible additions under `SessionUiStyle.View.Permission`:
|
||||
|
||||
- `DIFF_LINES`
|
||||
- maybe `DIFF_GAP` only if existing gap tokens are insufficient
|
||||
|
||||
Before adding constants, check existing `SessionUiStyle.View.Permission` object. Reuse existing values where practical.
|
||||
|
||||
### `KiloBundle.properties` and localized bundles
|
||||
|
||||
Likely add:
|
||||
|
||||
```properties
|
||||
session.permission.diff.unavailable=Diff preview unavailable for this file.
|
||||
```
|
||||
|
||||
Maybe add if rendering state messages needs distinct text:
|
||||
|
||||
```properties
|
||||
session.permission.diff.file={0}
|
||||
```
|
||||
|
||||
Avoid adding keys unless needed. Existing keys cover most content.
|
||||
|
||||
If adding keys:
|
||||
|
||||
- Add to every localized bundle under `frontend/src/main/resources/messages/`.
|
||||
- Follow existing formatting/order near other `session.permission.*` keys.
|
||||
|
||||
### `PermissionViewTest.kt`
|
||||
|
||||
Update/add tests:
|
||||
|
||||
1. Replace `test diff preview is not rendered` with positive rendering test:
|
||||
- construct edit permission with `fileDiffs = listOf(PermissionFileDiff(file = "src/A.kt", patch = "@@ -1 +1 @@\n-old\n+new", additions = 1, deletions = 2))`
|
||||
- assert all text contains `src/A.kt` or split path parts
|
||||
- assert contains `@@`
|
||||
- assert contains `+1 -2` or the exact localized summary split
|
||||
2. Add missing patch fallback test:
|
||||
- diff with `patch = null`, `additions`, `deletions`
|
||||
- assert file appears
|
||||
- assert unavailable fallback appears
|
||||
3. Add multiple diffs test:
|
||||
- `src/A.kt` and `src/B.kt`
|
||||
- assert both appear and summaries appear
|
||||
4. Keep command behavior tests:
|
||||
- bash still renders command
|
||||
- bash does not show `permission.message`
|
||||
5. Keep no rule controls test:
|
||||
- only two buttons Run/Deny
|
||||
- no Manage Auto-Approve Rules text
|
||||
6. Add error state test if implemented:
|
||||
- state `ERROR`, message `Boom`
|
||||
- assert text contains `Boom`
|
||||
- buttons enabled or disabled? Current code disables only responding/resolved, not error. Decide desired behavior:
|
||||
- Recommended: ERROR should re-enable buttons so user can retry Deny/Run. Current logic already enables for ERROR. Test that if useful.
|
||||
7. Adjust tests that assume first `JBHtmlPane` is command/pattern if diff code blocks add more panes.
|
||||
|
||||
### Backend/parser tests
|
||||
|
||||
Probably no changes needed because parser tests already cover:
|
||||
|
||||
- command metadata
|
||||
- fallback `diff` + `filepath`
|
||||
- `filediff` object
|
||||
- `files[]` array
|
||||
- malformed files
|
||||
- old JSON defaults
|
||||
|
||||
Only update parser/backend tests if implementation discovers parser mismatch.
|
||||
|
||||
## Suggested Implementation Order
|
||||
|
||||
1. Add/adjust tests in `PermissionViewTest.kt` first, especially diff-positive tests.
|
||||
2. Add missing bundle key(s).
|
||||
3. Implement diff rendering with the simplest viable component.
|
||||
4. Update `PermissionView.show()` to append diffs after command/pattern content.
|
||||
5. Update pattern rendering if tests show current output is not close enough to VS Code.
|
||||
6. Add state/error message rendering if included.
|
||||
7. Run targeted tests and fix compile/test failures.
|
||||
8. Run package typecheck.
|
||||
|
||||
## Verification Commands
|
||||
|
||||
Run from `packages/kilo-jetbrains/`:
|
||||
|
||||
```bash
|
||||
./gradlew test --tests "ai.kilocode.client.session.views.PermissionViewTest"
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
./gradlew typecheck
|
||||
```
|
||||
|
||||
If the targeted test command is not supported by this Gradle setup, run:
|
||||
|
||||
```bash
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
If Java 21 is missing, follow repo instructions before running Gradle:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
sdk install java 21-tem
|
||||
sdk use java 21-tem
|
||||
```
|
||||
|
||||
Only install/use SDKMAN if available and needed.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
A reviewer should be able to verify:
|
||||
|
||||
- Bash permissions still show the command and Run/Deny buttons.
|
||||
- Read/glob/grep/list/etc. permissions still show meaningful tool/pattern details.
|
||||
- Edit/write/patch permissions with `fileDiffs` show file names, additions/deletions, and inline unified patches.
|
||||
- Edit/write/patch permissions with no patch show a clear unavailable-preview fallback.
|
||||
- Multiple-file patch permissions show each file separately.
|
||||
- Auto-approve rule controls are not rendered.
|
||||
- Existing permission replies still send `PermissionReplyDto(reply = "once")` for Run and `"reject"` for Deny.
|
||||
- UI uses Swing/IntelliJ platform components only.
|
||||
- `PermissionViewTest` and JetBrains typecheck pass.
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
### Risk: `MdView` HTML makes text assertions brittle
|
||||
|
||||
Mitigation:
|
||||
|
||||
- Existing tests already inspect `JBHtmlPane.text`; follow that pattern.
|
||||
- Assert broad substrings such as filename, `@@`, and command text.
|
||||
- If patch text is escaped or transformed, use a plain text component for diff patches instead.
|
||||
|
||||
### Risk: File grows too large/complex
|
||||
|
||||
Mitigation:
|
||||
|
||||
- Extract `PermissionDiffView.kt`.
|
||||
- Keep parser/model unchanged.
|
||||
|
||||
### Risk: Styling is too custom
|
||||
|
||||
Mitigation:
|
||||
|
||||
- Use existing `SessionEditorStyle`, `SessionUiStyle`, `UiStyle.Gap`, `JBUI.Borders`, and platform colors.
|
||||
- Avoid raw `Color(...)`, hardcoded font families, and unscaled dimensions.
|
||||
|
||||
### Risk: Subagent title requires plumbing
|
||||
|
||||
Mitigation:
|
||||
|
||||
- Treat as optional lower-priority parity item.
|
||||
- Do not block edit/detail parity on it.
|
||||
|
||||
### Risk: Auto-approve metadata accidentally appears
|
||||
|
||||
Mitigation:
|
||||
|
||||
- Do not render `permission.meta.rules` or `permission.always`.
|
||||
- Keep/update tests asserting no extra rule controls.
|
||||
|
||||
## Notes for Faster Model
|
||||
|
||||
- The main implementation target is `PermissionView.kt`; do not start in backend/parser unless a compile error points there.
|
||||
- The data is already present in `permission.meta.fileDiffs`.
|
||||
- Do not implement auto-approve rules even though VS Code has a footer for them.
|
||||
- Prefer a readable unified patch block over sophisticated diff coloring.
|
||||
- Keep the current Run/Deny actions unchanged.
|
||||
- If time is limited, prioritize: file name + `+N -N` + patch text + unavailable fallback.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Improve JetBrains Permission View
|
||||
|
||||
## Goal
|
||||
Update the JetBrains permission prompt so permission details read as a compact summary line instead of block content:
|
||||
- Show the action/tool label (for example `Read`, `Edit`, `Shell`) as the row header.
|
||||
- Show the target path, pattern, or command as an inline code fragment on the same row.
|
||||
- Show file diffs as compact colored badges with `+N -M lines` and no diff body/content for now.
|
||||
|
||||
## Current State
|
||||
- `PermissionView.kt` renders bash commands and non-bash targets through fenced Markdown code blocks.
|
||||
- `patternText()` combines action and target into the same Markdown block.
|
||||
- `PermissionDiffView.kt` renders the file name plus summary and then either a scrollable patch preview or an unavailable fallback label.
|
||||
- Tests in `PermissionViewTest.kt` currently assert the old Markdown/pre-block and diff-content behavior.
|
||||
|
||||
## Implementation Plan
|
||||
1. Replace permission detail block rendering in `PermissionView.kt`.
|
||||
- Introduce a compact detail row builder that uses Swing components, not `MdView`, for action + target.
|
||||
- Resolve the row action with existing `toolLabel(tool)`.
|
||||
- Resolve the target in priority order: explicit command for bash/command permissions, `permission.meta.filePath`, then `permission.patterns` excluding `*`.
|
||||
- Render each target as an inline code fragment with editor font/colors and a subtle code background, keeping it on the same horizontal row as the action label.
|
||||
- Preserve a reasonable no-target fallback for `*`/empty patterns, but avoid rendering it as a code block.
|
||||
- Remove or stop using `patternText()` for the new UI.
|
||||
|
||||
2. Simplify `PermissionDiffView.kt` to badge-only rendering.
|
||||
- Render each diff as one horizontal row: file path label plus a colored pill/badge.
|
||||
- Badge text should include additions, deletions, and line wording, e.g. `+3 -1 lines`.
|
||||
- Use theme-derived colors from existing style helpers where possible; add a small session-specific color helper only if needed.
|
||||
- Do not render `diff.patch`, `before`, `after`, or unavailable fallback content.
|
||||
- Drop `MdView`/`JBScrollPane` state from the diff view if no longer needed.
|
||||
|
||||
3. Keep style changes local and native to Swing.
|
||||
- Use IntelliJ platform components (`JBLabel`, platform borders, `JBUI` spacing).
|
||||
- Use existing `SessionEditorStyle` propagation for inline code fragments that depend on editor fonts/colors.
|
||||
- Avoid hardcoded runtime colors unless centralized as semantic style helpers.
|
||||
|
||||
4. Update tests in `PermissionViewTest.kt`.
|
||||
- Replace assertions that expect fenced `<pre>` blocks for non-bash patterns with assertions for action text plus inline target text.
|
||||
- Adjust bash command tests to expect same-line action + command, not a command code block.
|
||||
- Update diff tests to assert file names and badge text are shown while patch markers/unavailable fallback text are not shown.
|
||||
- Add or update tests for multiple patterns/diffs and style propagation for inline code fragments.
|
||||
|
||||
5. Add a patch changeset.
|
||||
- Create `.changeset/<slug>.md` for `"@kilocode/kilo-jetbrains": patch` with a user-facing note such as: `Improve JetBrains permission prompts with compact action rows and diff badges.`
|
||||
|
||||
## Verification
|
||||
- Run the targeted JetBrains frontend test class if Gradle supports it, otherwise run `./gradlew test --tests ai.kilocode.client.session.views.PermissionViewTest` from `packages/kilo-jetbrains/`.
|
||||
- Run `./gradlew typecheck` from `packages/kilo-jetbrains/` to catch Kotlin/UI compile errors.
|
||||
|
||||
## Risks / Notes
|
||||
- Long paths may exceed the available width in a single horizontal row. Prefer a layout that keeps the action and first target together while allowing the row to wrap naturally if needed.
|
||||
- The diff badge has no dedicated data field for total changed lines, so use `additions + deletions` for the `lines` count if a separate total is needed, or use wording around the existing `+N -M` values only.
|
||||
@@ -0,0 +1,163 @@
|
||||
# Plan: Update JetBrains Align Wrapper Sizing Semantics
|
||||
|
||||
## Goal
|
||||
Update the existing `Align` wrapper so every non-track alignment mode respects the wrapped component's minimum, preferred, and maximum sizes. Add a new `TRACK` mode on both axes that always fills the available wrapper space, ignores the child's min/preferred/max size on that axis, and does not contribute the child size to the wrapper's min/preferred/max size on that axis.
|
||||
|
||||
Also replace the existing `CenterShrinkPanel` utility with `Align` if the new semantics fully cover its behavior.
|
||||
|
||||
## Feasibility: Replacing `CenterShrinkPanel`
|
||||
`CenterShrinkPanel` currently has only two real usages, both in `EmptySessionPanel.kt`:
|
||||
|
||||
- `val view: CenterShrinkPanel = CenterShrinkPanel(this)` wraps the whole empty-state content and centers it.
|
||||
- `add(CenterShrinkPanel(description), BorderLayout.CENTER)` centers the bounded-width welcome description.
|
||||
|
||||
`CenterShrinkPanel` behavior is: transparent wrapper, one child, center child, size = `min(preferred, maximum, available)` on both axes, preferred size = child preferred + insets. The new `Align` with `HAlign.CENTER` / `VAlign.CENTER` and min/preferred/max-aware sizing can cover this behavior and improve it by respecting minimum size where space allows.
|
||||
|
||||
Replacement is feasible:
|
||||
|
||||
- Use `alignCenter()` for both current `CenterShrinkPanel` call sites.
|
||||
- Change `EmptySessionPanel.view` type from `CenterShrinkPanel` to `Align` (or `JComponent` if we want to hide the wrapper implementation); prefer `Align` to keep it explicit and testable.
|
||||
- Update the class KDoc to reference `Align` instead of `CenterShrinkPanel`.
|
||||
- Remove the `CenterShrinkPanel` import.
|
||||
- Delete `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/CenterShrinkPanel.kt` after confirming no remaining references.
|
||||
- Update `AGENTS.md` to remove the guidance about keeping `CenterShrinkPanel`; instead state that `Align` replaces one-child center/shrink wrappers.
|
||||
|
||||
Risk is low because `SessionUi.kt` only passes `panel.view` into `scroll.show(...)`, and no production code depends on `CenterShrinkPanel` APIs beyond it being a Swing component. Existing `EmptySessionPanelTest` assertions are mostly content/layout independent; add a focused assertion if needed to prove `view` is now an `Align` wrapper and still exposes nonzero preferred size.
|
||||
|
||||
## Target Files
|
||||
- Update `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/Align.kt`
|
||||
- Update `packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/AlignTest.kt`
|
||||
- Update `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/EmptySessionPanel.kt` to replace `CenterShrinkPanel` with `Align` / `alignCenter()`.
|
||||
- Update `packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/EmptySessionPanelTest.kt` only if needed for changed type exposure or to preserve coverage.
|
||||
- Delete `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/CenterShrinkPanel.kt` if all usages are removed.
|
||||
- Update `packages/kilo-jetbrains/AGENTS.md` with the revised `TRACK` behavior, min/preferred/max-size guidance, and the fact that `Align` replaces old one-child center/shrink wrappers.
|
||||
- Optionally update `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/PermissionView.kt` to use `Align` only if it simplifies current alignment code without broadening the change.
|
||||
|
||||
## API Shape
|
||||
- Package remains `ai.kilocode.client.ui`.
|
||||
- Keep `Align(child: Component, h: HAlign = HAlign.FIT, v: VAlign = VAlign.FIT) : JPanel(null)`.
|
||||
- Extend enums:
|
||||
- `enum class HAlign { TRACK, FIT, LEFT, CENTER, RIGHT }`
|
||||
- `enum class VAlign { TRACK, FIT, TOP, CENTER, BOTTOM }`
|
||||
- Constructor behavior stays the same:
|
||||
- Set `isOpaque = false`
|
||||
- Add the wrapped child as the only child
|
||||
- Do not introduce colors, borders, fonts, or hardcoded spacing
|
||||
|
||||
## Layout Semantics
|
||||
- Account for panel insets in all sizing and positioning.
|
||||
- Clamp available inner width/height to `0` before setting child bounds.
|
||||
- Use child sizes per axis:
|
||||
- `min`: `child.minimumSize`
|
||||
- `pref`: `child.preferredSize`, coerced into `[min, max]` when the axis is not `TRACK`
|
||||
- `max`: `child.maximumSize`
|
||||
- If child max is smaller than child min, treat the effective max as at least min so calculations remain stable.
|
||||
- If available space is smaller than the effective minimum, shrink to available space to avoid drawing outside the wrapper. This is the only case where layout may go below minimum size.
|
||||
|
||||
### Horizontal Modes
|
||||
- `TRACK`: child width equals available inner width, ignoring child min/preferred/max width.
|
||||
- `FIT`: child width is available inner width constrained by effective min/max; if max prevents full width, place at left inset.
|
||||
- `LEFT`: child width is bounded preferred width, shrunk to available if needed; x at left inset.
|
||||
- `CENTER`: child width is bounded preferred width, shrunk to available if needed; x centered in available space.
|
||||
- `RIGHT`: child width is bounded preferred width, shrunk to available if needed; x aligned to right edge.
|
||||
|
||||
### Vertical Modes
|
||||
- `TRACK`: child height equals available inner height, ignoring child min/preferred/max height.
|
||||
- `FIT`: child height is available inner height constrained by effective min/max; if max prevents full height, place at top inset.
|
||||
- `TOP`: child height is bounded preferred height, shrunk to available if needed; y at top inset.
|
||||
- `CENTER`: child height is bounded preferred height, shrunk to available if needed; y centered in available space.
|
||||
- `BOTTOM`: child height is bounded preferred height, shrunk to available if needed; y aligned to bottom edge.
|
||||
|
||||
## Wrapper Min/Preferred/Max Size Semantics
|
||||
Compute wrapper sizing independently per axis, then add insets for that axis.
|
||||
|
||||
- For non-`TRACK` axes (`FIT`, edge, and `CENTER`):
|
||||
- `minimumSize` contribution is child minimum size.
|
||||
- `preferredSize` contribution is child preferred size coerced into the effective min/max range.
|
||||
- `maximumSize` contribution is child effective maximum size.
|
||||
- For `TRACK` axes:
|
||||
- `minimumSize` contribution is `0` because the child should not request space on that axis.
|
||||
- `preferredSize` contribution is `0` because the child should not request space on that axis.
|
||||
- `maximumSize` should not be constrained by the child's max size; use the panel/default maximum for that axis so parents can still allocate extra space for tracking.
|
||||
- Include wrapper insets in all returned min/preferred/max dimensions.
|
||||
- If there is no child, keep existing fallback behavior: no-op layout and delegate size methods to `super`.
|
||||
|
||||
## Kotlin-Style Factories
|
||||
Update factory helpers in `Align.kt` so call sites stay concise and can opt into tracking.
|
||||
|
||||
Keep existing helpers:
|
||||
- `fun Component.align(h: HAlign = HAlign.FIT, v: VAlign = VAlign.FIT) = Align(this, h, v)`
|
||||
- `fun Component.alignCenter() = Align(this, HAlign.CENTER, VAlign.CENTER)`
|
||||
- `fun Component.alignLeft(v: VAlign = VAlign.FIT) = Align(this, HAlign.LEFT, v)`
|
||||
- `fun Component.alignRight(v: VAlign = VAlign.FIT) = Align(this, HAlign.RIGHT, v)`
|
||||
- `fun Component.alignTop(h: HAlign = HAlign.FIT) = Align(this, h, VAlign.TOP)`
|
||||
- `fun Component.alignBottom(h: HAlign = HAlign.FIT) = Align(this, h, VAlign.BOTTOM)`
|
||||
|
||||
Add tracking helpers:
|
||||
- `fun Component.track() = Align(this, HAlign.TRACK, VAlign.TRACK)`
|
||||
- `fun Component.trackX(v: VAlign = VAlign.FIT) = Align(this, HAlign.TRACK, v)`
|
||||
- `fun Component.trackY(h: HAlign = HAlign.FIT) = Align(this, h, VAlign.TRACK)`
|
||||
|
||||
Keep helpers minimal; do not add every possible alignment combination unless it improves a real call site.
|
||||
|
||||
## EmptySessionPanel Replacement Steps
|
||||
- Replace `import ai.kilocode.client.ui.CenterShrinkPanel` with `import ai.kilocode.client.ui.Align` and `import ai.kilocode.client.ui.alignCenter`.
|
||||
- Change `val view: CenterShrinkPanel = CenterShrinkPanel(this)` to `val view: Align = alignCenter()`.
|
||||
- Change `add(CenterShrinkPanel(description), BorderLayout.CENTER)` to `add(description.alignCenter(), BorderLayout.CENTER)`.
|
||||
- Update KDoc from `[CenterShrinkPanel]` to `[Align]`.
|
||||
- Grep for `CenterShrinkPanel` after edits; if only the class file remains, delete `CenterShrinkPanel.kt`.
|
||||
|
||||
## AGENTS.md Guidance
|
||||
Update the existing `Align — Single-Component Alignment Wrapper` section:
|
||||
|
||||
- Add `TRACK` to the mode table.
|
||||
- Explain `TRACK` as: fill all available space on that axis, ignore child min/preferred/max on that axis, and do not let the child contribute to wrapper min/preferred/max size on that axis.
|
||||
- Explain `FIT` as: fill available space while respecting child min/max; use `TRACK` if full-size tracking must ignore constraints.
|
||||
- Explain edge/center modes as: use bounded preferred size, respect min/max where space allows, shrink to available space only when necessary.
|
||||
- Add factory examples for `child.track()`, `child.trackX(...)`, and `child.trackY(...)`.
|
||||
- Keep the warning that `Align` is only for single-child alignment, not spacing, padding, borders, colors, or multi-child layout.
|
||||
- Replace the `CenterShrinkPanel` note with: `CenterShrinkPanel` has been superseded by `Align`; use `child.alignCenter()` for the old center-and-shrink behavior.
|
||||
|
||||
## Tests
|
||||
Update `AlignTest` using `BasePlatformTestCase` with real Swing components.
|
||||
|
||||
Keep existing coverage:
|
||||
- Wrapper is non-opaque and contains exactly the wrapped child.
|
||||
- Insets are honored.
|
||||
- `FIT/FIT`, edge, and center modes place the child correctly.
|
||||
- Existing factory helpers produce expected wrappers/layout.
|
||||
|
||||
Add coverage for min/max behavior:
|
||||
- Non-track `CENTER/CENTER` uses preferred size coerced up to minimum when preferred is smaller than minimum and space is sufficient.
|
||||
- Non-track `CENTER/CENTER` caps preferred size to maximum when preferred is larger than maximum and space is sufficient.
|
||||
- Non-track `FIT/FIT` fills available space only up to maximum size when available is larger than maximum.
|
||||
- Non-track `FIT/FIT` expands to at least minimum size when available is larger than minimum but smaller than preferred.
|
||||
- Non-track modes shrink to available space when available is smaller than minimum, avoiding overflow.
|
||||
- Wrapper `minimumSize`, `preferredSize`, and `maximumSize` include child min/bounded-pref/max contributions plus insets for non-track axes.
|
||||
- `Align(HAlign.CENTER, VAlign.CENTER)` matches old `CenterShrinkPanel` center-and-shrink behavior for a child with preferred size larger than maximum size.
|
||||
|
||||
Add coverage for `TRACK` behavior:
|
||||
- `TRACK/TRACK` lays child out to the full available inner bounds even when child's min/preferred/max sizes are smaller or larger.
|
||||
- `TRACK/TRACK` wrapper `minimumSize` and `preferredSize` are only the wrapper insets, not child sizes.
|
||||
- `TRACK/TRACK` wrapper `maximumSize` is not capped by the child maximum size; assert it is larger than the child's max or equals the panel/default maximum used by implementation.
|
||||
- Mixed `TRACK` and non-track axes compute size independently, e.g. `HAlign.TRACK` + `VAlign.CENTER` has preferred width equal to horizontal insets only and preferred height based on child bounded preferred height plus vertical insets.
|
||||
- `track()`, `trackX(...)`, and `trackY(...)` factory helpers produce expected layout and size behavior.
|
||||
|
||||
Update or add `EmptySessionPanelTest` coverage if needed:
|
||||
- Verify `panel.view` remains non-opaque and has a visible preferred height.
|
||||
- If exposing `Align` is acceptable, add a direct assertion that `panel.view is Align` only if that does not over-specify internals. Prefer behavior assertions over type assertions.
|
||||
|
||||
Test helper updates:
|
||||
- Replace `fixedChild(w, h)` with a helper that can set min/preferred/max sizes independently, using an actual Swing component and overriding size getters.
|
||||
- Keep assertions exact where layout is deterministic; for maximum size under `TRACK`, assert the child max is not used rather than relying on an arbitrary Swing default if needed.
|
||||
|
||||
## Verification
|
||||
Run from `packages/kilo-jetbrains/`:
|
||||
- `./gradlew :frontend:test --tests ai.kilocode.client.ui.AlignTest`
|
||||
- `./gradlew :frontend:test --tests ai.kilocode.client.session.ui.EmptySessionPanelTest`
|
||||
- `./gradlew :frontend:compileKotlin`
|
||||
- If `AGENTS.md` table formatting changes are extensive, optionally run the repo markdown table padding check from root: `bun run script/check-md-table-padding.ts --fix`
|
||||
|
||||
## Notes
|
||||
- No changeset is needed unless `Align` is applied to a user-visible UI path beyond replacing behavior-equivalent internal wrappers.
|
||||
- Keep the implementation local to generic JetBrains UI code; this does not touch shared upstream-owned files.
|
||||
+1
-1
@@ -25,7 +25,7 @@ import ai.kilocode.client.session.controller.SessionController
|
||||
import ai.kilocode.client.session.controller.SessionControllerEvent
|
||||
import ai.kilocode.client.session.ui.style.SessionUiStyle
|
||||
import ai.kilocode.client.session.views.LoginRequiredView
|
||||
import ai.kilocode.client.session.views.PermissionView
|
||||
import ai.kilocode.client.session.views.permission.PermissionView
|
||||
import ai.kilocode.client.session.views.question.QuestionView
|
||||
import ai.kilocode.client.settings.profile.UserProfileConfigurable
|
||||
import ai.kilocode.log.ChatLogSummary
|
||||
|
||||
+4
-4
@@ -10,11 +10,11 @@ import ai.kilocode.client.session.ui.style.SessionEditorStyle
|
||||
import ai.kilocode.client.session.ui.style.SessionEditorStyleTarget
|
||||
import ai.kilocode.client.session.ui.style.SessionUiStyle
|
||||
import ai.kilocode.client.session.controller.SessionController
|
||||
import ai.kilocode.client.ui.Align
|
||||
import ai.kilocode.client.ui.HAlign
|
||||
import ai.kilocode.client.ui.UiStyle
|
||||
import ai.kilocode.client.ui.VAlign
|
||||
import ai.kilocode.client.ui.align
|
||||
import ai.kilocode.client.ui.layout.Align
|
||||
import ai.kilocode.client.ui.layout.HAlign
|
||||
import ai.kilocode.client.ui.layout.VAlign
|
||||
import ai.kilocode.client.ui.layout.align
|
||||
import ai.kilocode.rpc.dto.SessionDto
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.Disposable
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import ai.kilocode.client.session.ui.style.SessionEditorStyleTarget
|
||||
import ai.kilocode.client.session.ui.style.SessionUiStyle
|
||||
import ai.kilocode.client.session.views.LoginRequiredView
|
||||
import ai.kilocode.client.session.views.MessageView
|
||||
import ai.kilocode.client.session.views.PermissionView
|
||||
import ai.kilocode.client.session.views.permission.PermissionView
|
||||
import ai.kilocode.client.session.views.question.QuestionView
|
||||
import ai.kilocode.client.session.views.TurnView
|
||||
import com.intellij.openapi.Disposable
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ai.kilocode.client.session.views
|
||||
package ai.kilocode.client.session.views.permission
|
||||
|
||||
import ai.kilocode.client.session.model.PermissionFileDiff
|
||||
import ai.kilocode.client.session.ui.style.SessionEditorStyle
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
package ai.kilocode.client.session.views
|
||||
package ai.kilocode.client.session.views.permission
|
||||
|
||||
import ai.kilocode.client.plugin.KiloBundle
|
||||
import ai.kilocode.client.session.model.Permission
|
||||
@@ -10,10 +10,10 @@ import ai.kilocode.client.session.ui.style.SessionEditorStyle
|
||||
import ai.kilocode.client.session.ui.style.SessionEditorStyleTarget
|
||||
import ai.kilocode.client.session.ui.style.SessionUiStyle
|
||||
import ai.kilocode.client.session.ui.style.SessionUiStyle.View.CARD_LAYOUT_GAP
|
||||
import ai.kilocode.client.ui.HAlign
|
||||
import ai.kilocode.client.ui.UiStyle
|
||||
import ai.kilocode.client.ui.VAlign
|
||||
import ai.kilocode.client.ui.align
|
||||
import ai.kilocode.client.ui.layout.HAlign
|
||||
import ai.kilocode.client.ui.layout.VAlign
|
||||
import ai.kilocode.client.ui.layout.align
|
||||
import ai.kilocode.rpc.dto.PermissionReplyDto
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ui.ColorUtil
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ai.kilocode.client.ui
|
||||
package ai.kilocode.client.ui.layout
|
||||
|
||||
import java.awt.Component
|
||||
import java.awt.Dimension
|
||||
+1
-1
@@ -22,7 +22,7 @@ import ai.kilocode.rpc.dto.KiloAppStateDto
|
||||
import ai.kilocode.rpc.dto.KiloAppStatusDto
|
||||
import ai.kilocode.rpc.dto.ProfileDto
|
||||
import com.intellij.util.ui.JBUI
|
||||
import ai.kilocode.client.session.views.PermissionView
|
||||
import ai.kilocode.client.session.views.permission.PermissionView
|
||||
import ai.kilocode.client.session.views.question.QuestionView
|
||||
import ai.kilocode.rpc.dto.MessageWithPartsDto
|
||||
import com.intellij.ui.components.JBScrollPane
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import ai.kilocode.client.session.model.SessionState
|
||||
import ai.kilocode.client.session.model.ToolCallRef
|
||||
import ai.kilocode.client.session.ui.style.SessionEditorStyle
|
||||
import ai.kilocode.client.session.views.LoginRequiredView
|
||||
import ai.kilocode.client.session.views.PermissionView
|
||||
import ai.kilocode.client.session.views.permission.PermissionView
|
||||
import ai.kilocode.client.session.views.question.QuestionResultView
|
||||
import ai.kilocode.client.session.views.question.QuestionView
|
||||
import ai.kilocode.client.session.views.TextView
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ai.kilocode.client.session.views
|
||||
package ai.kilocode.client.session.views.permission
|
||||
|
||||
import ai.kilocode.client.session.model.Permission
|
||||
import ai.kilocode.client.session.model.PermissionFileDiff
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ai.kilocode.client.ui
|
||||
package ai.kilocode.client.ui.layout
|
||||
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import com.intellij.ui.components.JBLabel
|
||||
Reference in New Issue
Block a user