mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
feat(jetbrains): surface unsupported workspace in session banner
Show unsupported workspace directories (Dev Container / WSL / invalid virtual path) through the standard in-session connection banner instead of a stuck "Loading…" state. The banner includes the workspace path and two clear, localized options: reopen in the container/WSL via JetBrains Gateway, or open from the local filesystem. Expanded error details now fit the full text, capped to the available transcript height. Remove the dev-only kilo.dev.forceUnsupportedWorkspace override used to reproduce the state during development.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# JetBrains: graceful "Dev Container not supported" workspace notice
|
||||
|
||||
## Goal
|
||||
|
||||
When a JetBrains project is opened so that its directory is a **local-IDE + virtual (IJent) path** — e.g. `/$devcontainer.ij/<id>@…podman.sock/…` (the "Model 2" case) — the host-side Kilo CLI cannot resolve the directory, so agent resolution returns HTTP 500 and the workspace fails to load. Today this surfaces as a generic red "Workspace loading failed" banner with a futile "Try again".
|
||||
|
||||
Replace that with a clear, non-error notice that:
|
||||
- explains Kilo can't access the project because it's opened through a Dev Container / remote virtual filesystem, and
|
||||
- recommends running Kilo **inside the container** via JetBrains Remote Development (backend-in-container, the validated "Model 1" flow) as the preferred way, and
|
||||
- offers a "Learn more" link.
|
||||
|
||||
Detection short-circuits workspace load **before** the 3× `/agent` 500 retries.
|
||||
|
||||
## Background (verified in code)
|
||||
|
||||
- Backend workspace load: `packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/workspace/KiloBackendWorkspace.kt` (`load()` fetches agents/providers/commands/skills; failure → `KiloWorkspaceState.Error`).
|
||||
- Backend state model: `.../backend/workspace/KiloWorkspaceState.kt` (`Pending/Loading/Ready/Error`).
|
||||
- RPC DTO: `packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/KiloWorkspaceStateDto.kt` (`KiloWorkspaceStatusDto = PENDING/LOADING/READY/ERROR`).
|
||||
- DTO mapping (exhaustive `when` over sealed state): `.../backend/rpc/KiloWorkspaceRpcApiImpl.kt` `dto(state)` (~line 493). Directory resolution `resolveProjectDirectory` returns `project.basePath`; `localConfig` (~line 343) already throws `InvalidPathException` for IJent paths.
|
||||
- Frontend mapping to UI: `.../frontend/.../session/controller/SessionController.kt` `resolveConnectionState()` (~line 2270) maps `workspace.status == ERROR` → `ConnectionChanged.ShowError`; `retryConnection` reloads the workspace when status is ERROR (~line 622).
|
||||
- Connection banner UI: `.../frontend/.../session/ui/ConnectionPanel.kt` (red/warning label + expandable details + "Try again" `ActionLink`). Events defined in `.../session/controller/SessionControllerEvent.kt` (`ConnectionChanged.{Hide,ShowConnecting,ShowDownloading,ShowError,ShowWarning}`).
|
||||
- Strings: `.../frontend/src/main/resources/messages/KiloBundle.properties` (`session.connection.*`). Only the base bundle needs new keys; other locales fall back.
|
||||
- This builds on the committed fix (`fix(jetbrains): don't surface workspace fetch failures as IDE errors`); genuine 500s from *real* directories keep the existing Error path.
|
||||
|
||||
## Design decisions
|
||||
|
||||
1. **Representation: dedicated non-error state (recommended).** Add a new workspace status rather than reusing `ERROR`, so the UI is informational (not red), retry is suppressed, and there is no 500/log/retry spam.
|
||||
2. **Detection lives in the backend workspace load path**, keyed on the directory string, run before any fetch. Global app load stays `READY` (providers/config are global and unaffected).
|
||||
3. **Detection signals (low false-positive):**
|
||||
- Directory contains the marker `/$devcontainer.ij/`, or
|
||||
- starts with a WSL root `\\wsl$\` or `\\wsl.localhost\`, or
|
||||
- `java.nio.file.Path.of(directory)` (or normalize) throws `InvalidPathException`.
|
||||
Do **not** trigger solely on "path doesn't exist" (avoids false positives on transient FS states / real paths). Real container paths (Model 1, e.g. `/workspaces/podman`) and normal local paths never match.
|
||||
4. **Retry:** hidden for the unsupported state (deterministic; reload would re-detect). The workspace re-evaluates naturally when the directory changes (new workspace instance).
|
||||
5. **Link:** a single "Learn more" hyperlink. Default target `https://kilo.ai/docs/jetbrains/dev-containers` (see Open items — confirm/replace). Keep the URL as one constant so it's trivial to change.
|
||||
6. **Localization:** add keys to base `KiloBundle.properties` only.
|
||||
|
||||
## Implementation tasks (ordered)
|
||||
|
||||
### 1. Shared DTO
|
||||
- `shared/.../rpc/dto/KiloWorkspaceStateDto.kt`: add `UNSUPPORTED` to `KiloWorkspaceStatusDto`. Reuse the existing `error: String?` field to carry a short reason code/message (no new field required); keep `errors` empty for this state.
|
||||
|
||||
### 2. Backend state + detection
|
||||
- `backend/.../workspace/KiloWorkspaceState.kt`: add `data class Unsupported(val reason: String) : KiloWorkspaceState()`.
|
||||
- Add a small pure, unit-testable helper (single-word-friendly names), e.g. `RemoteDirectory.detect(directory: String): String?` returning a reason string when the directory is an unsupported virtual/IJent path, else `null`. Place it in `backend/.../workspace/` (backend-owned; no `kilocode_change` marker needed — new Kilo file in the Kilo plugin).
|
||||
- `backend/.../workspace/KiloBackendWorkspace.kt`: at the very start of `load()`, if `RemoteDirectory.detect(directory) != null`, set `_state.value = KiloWorkspaceState.Unsupported(reason)`, log a single `info`/`warn` line (not `error`), and return without fetching. Ensure no fetch/retry runs.
|
||||
|
||||
### 3. Backend RPC mapping
|
||||
- `backend/.../rpc/KiloWorkspaceRpcApiImpl.kt` `dto(state)`: add branch `is KiloWorkspaceState.Unsupported -> KiloWorkspaceStateDto(status = UNSUPPORTED, error = state.reason)`.
|
||||
|
||||
### 4. Frontend event + controller
|
||||
- `frontend/.../session/controller/SessionControllerEvent.kt`: add `data class ShowNotice(val summary: String, val detail: String?, val learnMoreUrl: String? = null) : ConnectionChanged()`.
|
||||
- `frontend/.../session/controller/SessionController.kt`:
|
||||
- `resolveConnectionState()`: add a branch for `workspace.status == KiloWorkspaceStatusDto.UNSUPPORTED` (place before the generic ERROR branch) returning `ShowNotice(summary=…, detail=…, learnMoreUrl=…)` using new bundle keys.
|
||||
- `retryConnection()` / retry path (~line 622): do **not** call `workspace.reload()` when status is `UNSUPPORTED`.
|
||||
- Confirm `WorkspaceChanged` handling (~line 933) already no-ops for non-READY (it does).
|
||||
|
||||
### 5. Frontend rendering
|
||||
- `frontend/.../session/ui/ConnectionPanel.kt`: handle `ConnectionChanged.ShowNotice`:
|
||||
- Info styling (secondary/label foreground, not `errorLabelForeground`).
|
||||
- Show the guidance text; keep `detail` in the expandable area if used.
|
||||
- Render a "Learn more" link via platform `HyperlinkLabel`/`ActionLink` that opens `learnMoreUrl` with `BrowserUtil.browse(url)`.
|
||||
- Hide the "Try again" retry link for this event.
|
||||
|
||||
### 6. Strings
|
||||
- `frontend/.../messages/KiloBundle.properties`: add keys, e.g.:
|
||||
- `session.connection.notice.devcontainer.summary=Kilo can't access this Dev Container project`
|
||||
- `session.connection.notice.devcontainer.detail=This project is opened through a Dev Container/remote virtual filesystem that the Kilo runtime on your machine can't reach. Run Kilo inside the container using JetBrains Remote Development (the IDE backend runs in the container) — that's the recommended way. Local projects also work.`
|
||||
- `session.connection.notice.learnMore=Learn more`
|
||||
- Store the docs URL as a Kotlin constant referenced by the controller (single source), not in the bundle.
|
||||
|
||||
### 7. Tests
|
||||
- Backend `backend/src/test/.../workspace/KiloBackendWorkspaceTest.kt`:
|
||||
- Given directory `/$devcontainer.ij/abc@…podman.sock/IdeaProjects/x`, workspace state becomes `Unsupported`; assert **no** `/agent` request hit the mock CLI (via `MockCliServer` request log), no retries, and no `ERROR`/500 log lines.
|
||||
- Add a `\\wsl$\Ubuntu\home\x` case and an `InvalidPathException`-triggering case.
|
||||
- Negative: a normal local dir and a real `/workspaces/...`-style dir still load normally (existing tests cover normal load).
|
||||
- Add/extend a mapping assertion: `Unsupported` → `KiloWorkspaceStateDto(status=UNSUPPORTED, error=reason)`.
|
||||
- Frontend `frontend/src/test/.../session/ui/ConnectionPanelTest.kt`: `ShowNotice` renders info label (not error color), shows the summary, exposes the "Learn more" link, and hides retry.
|
||||
- Frontend controller test (`session/controller/…`): `KiloWorkspaceStatusDto.UNSUPPORTED` state produces a `ConnectionChanged.ShowNotice`, and `retryConnection()` does not call `workspace.reload()` for UNSUPPORTED.
|
||||
|
||||
### 8. Changeset
|
||||
- Add `.changeset/<slug>.md` (`"@kilocode/kilo-jetbrains": patch`) describing the user-facing behavior: "Show a clear notice (with guidance to run in a Dev Container) instead of a generic error when a project is opened through a Dev Container/remote virtual filesystem Kilo can't access."
|
||||
|
||||
## Out of scope
|
||||
- Actually supporting Model 2 (running the CLI in-container via Eel/IJent, port forwarding, path translation). This plan only adds graceful communication.
|
||||
- Hardening every directory-scoped RPC (`models`, file search, git) for virtual paths; they already fail soft. The banner communicates the root cause.
|
||||
|
||||
## Failure modes / edge cases
|
||||
- **False positive** on a legitimate directory: mitigated by marker-only + `InvalidPathException` detection (not "not exists").
|
||||
- **Model 1 unaffected:** backend runs in the container, directory is real (`/workspaces/...`), markers don't match → normal load.
|
||||
- **App stays READY:** only the workspace is Unsupported; global providers/config still load, so the rest of the UI (settings, providers) remains usable.
|
||||
- **New enum value:** update the exhaustive `when` in backend `dto()` (compile-enforced). Frontend status checks are equality-based; add the UNSUPPORTED branch in `resolveConnectionState` and confirm no other exhaustive `when(status)` needs a branch (grep `KiloWorkspaceStatusDto.`).
|
||||
|
||||
## Validation
|
||||
- From `packages/kilo-jetbrains/`: `./gradlew :backend:test --tests ai.kilocode.backend.workspace.KiloBackendWorkspaceTest` and the new frontend tests (`./gradlew :frontend:test --tests …ConnectionPanelTest` and the controller test).
|
||||
- From `packages/kilo-jetbrains/`: `bun run typecheck` (or `./gradlew typecheck`) and `./gradlew test`.
|
||||
- Run inspection "Plugin DevKit | Code | Frontend and Backend API Usage" since split-mode code (shared DTO + frontend event) changes.
|
||||
- Manual (optional): reproduce Model 2 on Linux+rootless Podman (local IDE + IJent path) and confirm the info banner + link appears instead of the red error, with no IDE internal-error popup.
|
||||
|
||||
## Open items (non-blocking; recommended defaults chosen)
|
||||
1. **Docs URL** for "Learn more": default `https://kilo.ai/docs/jetbrains/dev-containers`. Confirm the final path or point to an existing page; may require creating that docs page (in `packages/kilo-docs/`) separately. If source URLs under `packages/kilo-vscode`/`opencode` change this doesn't apply, but if a docs page is added, run `bun run script/extract-source-links.ts` only if a tracked source URL changes.
|
||||
2. **Optional telemetry:** capture a "Dev Container Unsupported Shown" event via the existing `capture(...)` pattern in `SessionController` when the notice is first shown. Recommended: include it; low cost.
|
||||
3. **Copy review:** finalize the exact wording of the summary/detail strings.
|
||||
@@ -0,0 +1,177 @@
|
||||
# JetBrains: surface "Dev Container unsupported" via the existing turn‑outcome card
|
||||
|
||||
## Goal
|
||||
|
||||
When a JetBrains project is opened through a local‑IDE + virtual (IJent) path (Model 2 —
|
||||
`/$devcontainer.ij/…podman.sock/…`, `\\wsl$\…`, or an `InvalidPathException` path), the host CLI
|
||||
can't resolve the directory and the workspace can't load. Communicate this **using the existing
|
||||
in‑chat outcome card** (`SessionOutcomeView`), shown **immediately** on open — not with a new
|
||||
ConnectionPanel banner. Extract the outcome card so it renders both inside a session transcript
|
||||
(existing use) and standalone for this workspace‑level condition.
|
||||
|
||||
Decision from planning: **show immediately when the workspace is `UNSUPPORTED`, and extract the
|
||||
common outcome‑card UI so it is reused in the session context and outside it.**
|
||||
|
||||
## Precondition (blocking)
|
||||
|
||||
- The outcome UI (`model/TurnOutcome.kt`, `views/SessionOutcomeView.kt`, `SessionState.TurnEnded`,
|
||||
`SessionMessageListPanel.outcome` wiring, `SessionUi.outcome`) exists on **`origin/main`** (commits
|
||||
`b1a8893f14`, `0116b63641`, `58b6edd04f`, `5ad8db8a6d`) but **NOT** on this branch
|
||||
(`investigate-podman-container-crash`, ~176 commits behind main).
|
||||
- **Task 1 must be merging/rebasing `origin/main` into this branch** so the outcome UI is present.
|
||||
Cherry‑picking just the four commits is a fallback but rebase/merge is required before the PR
|
||||
merges anyway. Do this first; reconcile the existing partial work (below) during the merge.
|
||||
|
||||
## What already exists on this branch (from earlier work) and how to reconcile
|
||||
|
||||
- **Backend (KEEP):** `KiloWorkspaceStatusDto.UNSUPPORTED`, `KiloWorkspaceState.Unsupported(reason)`,
|
||||
`RemoteDirectory.detect(...)` short‑circuit at the top of `KiloBackendWorkspace.load()`, `dto()`
|
||||
mapping branch, the `kilo.dev.forceUnsupportedWorkspace` dev flag, and their tests. No change.
|
||||
- **Frontend (REPLACE):** the `ConnectionChanged.ShowNotice` event + `ConnectionPanel.showNotice`/
|
||||
"Learn more" link + `resolveConnectionState` UNSUPPORTED→ShowNotice branch + `session.connection.notice.*`
|
||||
bundle keys were the "new way to communicate" the user rejected. These must be removed/repurposed.
|
||||
|
||||
## Design
|
||||
|
||||
1. **Backend stays the source of truth.** Workspace load short‑circuits to `Unsupported(reason)`
|
||||
before any fetch (already implemented); app stays `READY`; DTO carries `status = UNSUPPORTED`,
|
||||
`error = reason` (`devcontainer_virtual_filesystem` | `wsl_virtual_filesystem` | `invalid_virtual_path`).
|
||||
2. **Reuse the outcome card, don't invent UI.** `SessionOutcomeView` (a `DialogView`/`SessionView`
|
||||
showing header icon + title + description, plus an optional scrollable error body and a
|
||||
DialogView action footer) is the single card class. It is already constructed in `SessionUi` and
|
||||
injected into `SessionMessageListPanel`; it does not depend on the transcript, so it can be reused
|
||||
standalone. Add one small method for the informational/notice case.
|
||||
3. **Show immediately, no session required.** The transcript body only renders when
|
||||
`model.showSession == true`. For the UNSUPPORTED case there is no session, so route a dedicated
|
||||
body (a standalone `SessionOutcomeView`) as the session content the moment the workspace is
|
||||
UNSUPPORTED, taking precedence over the empty/recents view.
|
||||
4. **No connection banner for this case.** `resolveConnectionState()` returns `Hide` for UNSUPPORTED
|
||||
(connection is healthy); retry ignores UNSUPPORTED.
|
||||
|
||||
## Implementation tasks (ordered)
|
||||
|
||||
### 1. Bring in the outcome UI
|
||||
- Merge/rebase `origin/main` into this branch. Verify `SessionOutcomeView`, `TurnOutcome`,
|
||||
`SessionState.TurnEnded`, and the `SessionMessageListPanel.outcome`/`SessionUi.outcome` wiring are
|
||||
present. Keep backend UNSUPPORTED work; drop the ConnectionPanel notice work (tasks 2–3).
|
||||
|
||||
### 2. Remove the ConnectionPanel notice approach
|
||||
- `frontend/.../session/controller/SessionControllerEvent.kt`: delete `ConnectionChanged.ShowNotice`.
|
||||
- `frontend/.../session/ui/ConnectionPanel.kt`: remove `showNotice`, the `learn` ActionLink, the
|
||||
`actions` `Stack`, the `url` field, and `learnVisible()/learnText()`; restore `retry` directly at
|
||||
`BorderLayout.EAST`; remove the `ShowNotice` branch in `onEvent` and the `BrowserUtil`/`Stack` imports.
|
||||
- `frontend/.../session/controller/SessionController.kt`:
|
||||
- `resolveConnectionState()`: change the `workspace.status == UNSUPPORTED` branch to return
|
||||
`ConnectionChanged.Hide` (place before the READY/warning branches). This prevents the perpetual
|
||||
"Loading…" that would otherwise occur because `workspace != READY`.
|
||||
- `retryConnection()`: keep the guard that returns early (no `workspace.reload()`) when
|
||||
`workspace.status == UNSUPPORTED`.
|
||||
- `setConnectionTargetState()`: remove the `ShowNotice` immediate‑state branch.
|
||||
- `frontend/.../messages/KiloBundle.properties`: remove `session.connection.notice.*` keys.
|
||||
|
||||
### 3. Extract/extend the reusable outcome card
|
||||
- `frontend/.../session/views/SessionOutcomeView.kt`: add an EDT method that reuses the existing
|
||||
card rendering for an informational notice, e.g.:
|
||||
`fun showNotice(title: String, description: String, tone: OutcomeTone, actions: List<DialogView.Action> = emptyList())`
|
||||
— sets header icon (WARNING for informational), `setHeader(title, description)`, `setContent(null)`,
|
||||
`setActions(actions)`, `isVisible = true`, `refresh()`. This reuses the same visual card the
|
||||
transcript uses; it is not a new surface. Confirm `DialogView` exposes `setActions`/`Action` (it
|
||||
does — used by `LoginRequiredView`/`RevertBanner`).
|
||||
- Do not fork the card; the same `SessionOutcomeView` class is used in the transcript and standalone.
|
||||
|
||||
### 4. Route the standalone card in `SessionUi`
|
||||
- `frontend/.../session/SessionUi.kt`:
|
||||
- Own a standalone `SessionOutcomeView` for the workspace notice (separate instance from the
|
||||
transcript's `outcome`), plus a body container following the `blankBody`/`progressBody` pattern,
|
||||
e.g. `unsupportedBody` hosting the standalone view. Register it with `applyStyle`.
|
||||
- `body(state)`: at the top, if `controller.model.workspace.status == KiloWorkspaceStatusDto.UNSUPPORTED`,
|
||||
return `unsupportedBody` (and populate the card via `showNotice(...)` mapping the workspace `error`
|
||||
reason to copy). This wins over `showSession`/empty/progress.
|
||||
- React to workspace changes: in the `SessionControllerEvent.WorkspaceChanged` handler (and on
|
||||
the new `ShowUnsupported` view event, task 5), re‑evaluate the body and populate the card. Keep
|
||||
`prompt.setReady(controller.model.isReady())` — prompt stays disabled since `isReady()` is false
|
||||
when workspace ≠ READY, so the card explains why input is unavailable.
|
||||
|
||||
### 5. Controller view routing for the unsupported case
|
||||
- `frontend/.../session/controller/SessionControllerEvent.kt`: add
|
||||
`data class ShowUnsupported(val reason: String) : ViewChanged()` with a stable `toString()`.
|
||||
- `frontend/.../session/controller/SessionController.kt`:
|
||||
- Add a precedence check so that when `model.workspace.status == UNSUPPORTED` (app READY), the
|
||||
controller emits `ViewChanged.ShowUnsupported(reason)` via `setControllerViewState(...)` instead
|
||||
of `ShowRecents`/`ShowSession`. Gate `canUseRecents()` (and the recents refresh at ~line 992 /
|
||||
`refreshRecents`) to return false when UNSUPPORTED so recents don't clobber the notice.
|
||||
- Handle `ShowUnsupported` in `setControllerViewState` similarly to `ShowRecents`
|
||||
(e.g. `hideAccountOverlay()` or leave account overlay untouched; do not set `model.showSession`).
|
||||
- `SessionUi` handles `ViewChanged.ShowUnsupported` by clearing `empty`, populating the standalone
|
||||
`SessionOutcomeView` from `reason`, and `scroll.show(unsupportedBody)`.
|
||||
|
||||
### 6. Copy / content
|
||||
- `frontend/.../messages/KiloBundle.properties`: add notice copy reused for all virtual‑fs reasons
|
||||
(single title + description is sufficient; the recommendation is the same), e.g.:
|
||||
- `session.unsupported.devcontainer.title=Kilo can't access this Dev Container project`
|
||||
- `session.unsupported.devcontainer.description=This project is opened through a Dev Container or remote virtual filesystem that the Kilo runtime on your machine can't reach. Run Kilo inside the container using JetBrains Remote Development, where the IDE backend runs in the container. Local projects also work.`
|
||||
- Optional: `session.unsupported.learnMore=Learn more`
|
||||
- Note: no‑argument bundle values must use a single apostrophe (`can't`), not `''` (MessageFormat
|
||||
only collapses `''` when args are passed).
|
||||
- Keep the docs URL as one Kotlin constant (reuse the existing `DEVCONTAINER_URL`,
|
||||
default `https://kilo.ai/docs/jetbrains/dev-containers`). If a "Learn more" action is included,
|
||||
wire it as a `DialogView.Action` that calls `BrowserUtil.browse(url)`.
|
||||
- Reason→copy mapping: map all three reasons to the same devcontainer copy for now (a `when(reason)`
|
||||
helper), so wsl/invalid paths also get a clear message. Tone = `OutcomeTone.WARNING` (informational).
|
||||
|
||||
### 7. Tests
|
||||
- Backend (unchanged, keep passing where the env allows): `RemoteDirectoryTest` (pure, incl. forced
|
||||
flag), `KiloBackendWorkspaceTest` UNSUPPORTED cases (no `/agent` fetch), `KiloWorkspaceRpcApiImplTest`
|
||||
mapping. Note: the full backend suite can't run in this worktree because the fake‑CLI `connect()`
|
||||
helper times out here (environmental); `RemoteDirectoryTest` runs fine and should be the primary
|
||||
backend guard.
|
||||
- Frontend:
|
||||
- Remove the obsolete `ConnectionPanelTest` notice test and the `ConnectionDelayTest`
|
||||
unsupported‑notice/retry tests. Replace with: UNSUPPORTED makes `resolveConnectionState` resolve
|
||||
to `Hide` (no connection banner), and `retryConnection()` does not call `projectRpc.reload`.
|
||||
- `SessionOutcomeViewTest`: add a case for the new `showNotice(...)` — asserts header icon/title/
|
||||
description render and (if included) the Learn‑more action is present.
|
||||
- Controller test: workspace `UNSUPPORTED` emits `ViewChanged.ShowUnsupported(reason)` and does
|
||||
**not** emit `ShowRecents`/`ShowSession`; `canUseRecents()` is false.
|
||||
- SessionUi/body test (or `SessionMessageListPanel`‑style test): when workspace is UNSUPPORTED the
|
||||
standalone outcome card body is shown with the devcontainer title/description.
|
||||
|
||||
### 8. Changeset
|
||||
- Update the existing `.changeset/jetbrains-devcontainer-notice.md` (`"@kilocode/kilo-jetbrains": patch`)
|
||||
to describe the final behavior: "When a JetBrains project is opened through a Dev Container / remote
|
||||
virtual filesystem Kilo can't access, show a clear in‑chat notice (with guidance to run Kilo inside
|
||||
the container) instead of a generic loading/error state."
|
||||
|
||||
## Out of scope
|
||||
- Actually supporting Model 2 (running the CLI in‑container via Eel/IJent, path translation). This is
|
||||
communication‑only.
|
||||
- Reworking the transcript's existing failed/interrupted turn outcomes.
|
||||
|
||||
## Risks / edge cases
|
||||
- **Merge scope:** rebasing ~176 commits may conflict on `SessionController.kt`/`ConnectionPanel.kt`/
|
||||
`SessionUi.kt`. Reverting the ConnectionPanel notice (task 2) reduces overlap with main's outcome
|
||||
changes; do task 2 as part of resolving conflicts.
|
||||
- **State‑machine hygiene:** drive the notice from **workspace status** (view routing), not by
|
||||
faking a per‑session `SessionState`, to avoid corrupting the session state machine when there is no
|
||||
session.
|
||||
- **Body precedence:** ensure UNSUPPORTED beats empty/recents/progress and that recents refresh does
|
||||
not overwrite it (`canUseRecents()` guard).
|
||||
- **App stays READY:** global providers/config still load; only the workspace is Unsupported, so the
|
||||
rest of the UI (settings/providers) remains usable and no red connection error appears.
|
||||
- **Manual repro:** `-Pkilo.dev.forceUnsupportedWorkspace=true` on a dev IDE run forces every
|
||||
workspace into UNSUPPORTED to exercise the card without a real IJent path.
|
||||
|
||||
## Validation
|
||||
- From `packages/kilo-jetbrains/`: `./gradlew :backend:test --tests ai.kilocode.backend.workspace.RemoteDirectoryTest`
|
||||
and the frontend tests `./gradlew :frontend:test --tests …SessionOutcomeViewTest --tests …ConnectionDelayTest`
|
||||
plus the new controller/body tests. (Use module‑scoped `:backend:`/`:frontend:` task filters.)
|
||||
- `./gradlew typecheck` and, where the env permits, `./gradlew test`.
|
||||
- Run inspection "Plugin DevKit | Code | Frontend and Backend API Usage" (shared DTO + new frontend
|
||||
view event).
|
||||
- Manual: launch split mode with `-Pkilo.dev.forceUnsupportedWorkspace=true`; confirm the in‑chat
|
||||
outcome card appears immediately, the prompt is disabled, and no red connection banner shows.
|
||||
|
||||
## Open items
|
||||
- Confirm/replace the "Learn more" docs URL (`https://kilo.ai/docs/jetbrains/dev-containers`) and
|
||||
whether to include the Learn‑more action at all (recommended: include it as a `DialogView.Action`).
|
||||
- Final copy review for the notice title/description.
|
||||
@@ -0,0 +1,149 @@
|
||||
# Show unsupported workspace via the standard session error banner + fit-to-transcript error height (JetBrains)
|
||||
|
||||
## Goal
|
||||
|
||||
1. When a JetBrains workspace directory is unsupported for the host-side CLI
|
||||
runtime (devcontainer / WSL / invalid virtual path), surface it through the
|
||||
existing in-session connection banner (`ConnectionPanel`) instead of silently
|
||||
showing "Loading…" forever. It gets the **same** recovery options as other
|
||||
connection errors (Try again → Retry / Restart / Reinstall Core).
|
||||
2. Change the expanded error/detail area so it **fits the whole detail text**,
|
||||
capped to the **available height of the session transcript area** (instead of
|
||||
the current fixed 10-line cap). This becomes the default behavior for **all**
|
||||
connection error/warning banners, not just unsupported.
|
||||
|
||||
## Background / Current State
|
||||
|
||||
- Detection already works end to end. `RemoteDirectory.detect()` returns a reason
|
||||
code and `KiloBackendWorkspace` sets `KiloWorkspaceState.Unsupported(reason)`,
|
||||
mapped to `KiloWorkspaceStateDto(status = UNSUPPORTED, error = reason)`
|
||||
(`KiloWorkspaceRpcApiImpl.kt:507`). Reason string is in the DTO `error` field.
|
||||
Reason codes: `devcontainer_virtual_filesystem`, `wsl_virtual_filesystem`,
|
||||
`invalid_virtual_path`.
|
||||
- The DTO reaches `SessionModel.workspace`; `syncConnectionState()` already runs
|
||||
on every `WorkspaceChanged` (`SessionController.kt:982-984`).
|
||||
- **Gap:** `SessionController.resolveConnectionState()` (`SessionController.kt:2353-2393`)
|
||||
has no `UNSUPPORTED` branch, so it falls through to `ShowConnecting`
|
||||
(line 2392) → banner reads "Loading…" indefinitely.
|
||||
- Banner renderer is `ConnectionPanel` (`session/ui/ConnectionPanel.kt`), driven
|
||||
by `ConnectionChanged.ShowError/ShowWarning/…`. Its "Try again" link opens a
|
||||
popup with Retry / Restart / Reinstall (`recoveryGroup()`).
|
||||
- Height cap today: `DETAILS_LINES = 10` (line 45). `scrollHeight()` coerces the
|
||||
row count to `1..DETAILS_LINES` (line 304), `getPreferredSize()` uses it
|
||||
(line 295-301), and `maxExpandedHeight()` (line 345) exposes the fixed cap.
|
||||
- Overlay placement: `SessionUi.kt:442-452` anchors the banner just above the
|
||||
prompt using `child.preferredSize.height` as the banner height; bottom edge is
|
||||
`promptTop - gap`, and it grows upward.
|
||||
|
||||
All touched files are Kilo-owned JetBrains frontend paths — no `kilocode_change`
|
||||
markers required. No backend / shared DTO changes needed.
|
||||
|
||||
## Design Decisions
|
||||
|
||||
- **Unsupported reuses the standard `ShowError` path unchanged** — same red
|
||||
banner, same "Try again" popup (Retry / Restart / Reinstall). No new event
|
||||
type and no `retry` flag. (Reverses the earlier "hide retry" idea per user.)
|
||||
- **Detail area fits the full text, capped to available transcript height.**
|
||||
Remove the fixed 10-line cap in `ConnectionPanel` so preferred height reflects
|
||||
the whole detail text; clamp the rendered banner height to the transcript space
|
||||
above the prompt in the overlay layout (where pane geometry is known). The
|
||||
existing internal `JBScrollPane` (`VERTICAL_SCROLLBAR_AS_NEEDED`) scrolls the
|
||||
overflow. This applies to every error/warning banner uniformly.
|
||||
|
||||
## Implementation Tasks
|
||||
|
||||
1. **`SessionController.resolveConnectionState()`** (`SessionController.kt:2353`)
|
||||
- Add a branch for `workspace.status == KiloWorkspaceStatusDto.UNSUPPORTED`
|
||||
(place it next to the workspace `ERROR` branch, before the READY branches):
|
||||
- summary = `KiloBundle.message("session.connection.unsupported")`
|
||||
- detail = reason mapped to a localized string (helper below), falling back
|
||||
to the raw `workspace.error`
|
||||
- `source = "workspace"` (retry link shows by default; no flag change)
|
||||
- Add a private helper (single-word name, e.g. `unsupported`) mapping the
|
||||
`workspace.error` reason code to a bundle string:
|
||||
- `devcontainer_virtual_filesystem` → `session.connection.unsupported.devcontainer`
|
||||
- `wsl_virtual_filesystem` → `session.connection.unsupported.wsl`
|
||||
- `invalid_virtual_path` → `session.connection.unsupported.invalid`
|
||||
- else → `session.connection.unsupported.unknown` (or raw reason)
|
||||
|
||||
2. **`KiloBundle.properties`** (`resources/messages/`, after line 17)
|
||||
- Add (finalize exact copy during implementation):
|
||||
- `session.connection.unsupported=Workspace not supported`
|
||||
- `session.connection.unsupported.devcontainer=Dev Container virtual filesystem paths can't be reached by the host-side Kilo runtime.`
|
||||
- `session.connection.unsupported.wsl=WSL virtual filesystem paths aren't supported by the host-side Kilo runtime.`
|
||||
- `session.connection.unsupported.invalid=This workspace path can't be resolved on the local filesystem.`
|
||||
- `session.connection.unsupported.unknown=This workspace isn't supported by the host-side Kilo runtime.`
|
||||
|
||||
3. **`ConnectionPanel.kt`** (`session/ui/`) — remove the fixed cap so details fit
|
||||
the whole text:
|
||||
- Delete `DETAILS_LINES` (line 45) usage in `scrollHeight()` (line 303-306):
|
||||
compute rows from the full logical line count (`coerceAtLeast(1)`), no upper
|
||||
bound. `getPreferredSize()` (line 295-301) then reports the full detail
|
||||
height when expanded.
|
||||
- Remove `maxExpandedHeight()` (line 345) or repurpose it; it encodes the
|
||||
10-line cap and is only used by the outgoing test.
|
||||
- Leave the `JBScrollPane` policies as-is so overflow scrolls when the overlay
|
||||
clamps the banner shorter than preferred.
|
||||
- Note (known limitation, keep behavior parity): row count uses logical lines,
|
||||
not wrapped visual lines, so a wrapped long line may under-estimate height;
|
||||
the scrollbar still covers overflow. Optional follow-up only.
|
||||
|
||||
4. **`SessionUi.kt`** overlay layout for `connection` (lines 442-452) — clamp the
|
||||
banner height to the transcript area above the prompt:
|
||||
- `full = child.preferredSize.height`
|
||||
- `avail = (point.y - gap).coerceAtLeast(0)` (space from pane top to just above
|
||||
the prompt)
|
||||
- `h = full.coerceAtMost(avail)`
|
||||
- Rectangle: `x = point.x + gap`, `y = point.y - h - gap`,
|
||||
`width = (prompt.width - gap*2).coerceAtLeast(0)`, `height = h`
|
||||
- This keeps the bottom anchored at `promptTop - gap` (unchanged) while
|
||||
preventing the top from overflowing above the transcript region; the panel's
|
||||
internal scroll pane handles the remainder. Applies to every banner state.
|
||||
|
||||
## Tests
|
||||
|
||||
- **`ConnectionDelayTest.kt`** (`session/controller/`): add a test mirroring
|
||||
`test persistent workspace error is delayed` — set
|
||||
`projectRpc.state.value = KiloWorkspaceStateDto(status = UNSUPPORTED, error = "wsl_virtual_filesystem")`,
|
||||
assert a `ShowError` with summary "Workspace not supported", the mapped WSL
|
||||
detail, and `source == "workspace"`; assert it no longer resolves to
|
||||
`ShowConnecting`.
|
||||
- **`ConnectionPanelTest.kt`** (`session/ui/`):
|
||||
- Replace `test expanded details height is capped at ten lines` (lines 140-150)
|
||||
with a test asserting the expanded preferred height grows with the full text
|
||||
(e.g. 30 lines yields a preferred height clearly larger than the old
|
||||
10-line height / a computed full-text height), i.e. no fixed cap.
|
||||
- Optionally add a small test that an unsupported-style `ShowError` still shows
|
||||
the retry link and uses the Core recovery group (parity with existing
|
||||
`test retry popup group uses core recovery actions`).
|
||||
- **`SessionUiLayoutTest.kt`**: add a test that with a large detail body and a
|
||||
constrained root/pane height, the expanded banner is clamped to the transcript
|
||||
area — `connection.y >= 0` (does not overflow above the transcript), bottom
|
||||
still anchored at `promptTop - gap`, `detailsVisible()` true, and the internal
|
||||
`JBScrollPane` shows/needs its vertical scrollbar. Reuse the anchoring
|
||||
assertions from `test expanded connection panel remains anchored above prompt`
|
||||
(lines 261-276).
|
||||
|
||||
## Validation
|
||||
|
||||
From `packages/kilo-jetbrains/`:
|
||||
- `./gradlew typecheck`
|
||||
- `./gradlew test` (or targeted: `ConnectionPanelTest`, `ConnectionDelayTest`,
|
||||
`SessionUiLayoutTest`)
|
||||
|
||||
Requires Java 21; only check Java if Gradle fails with a Java-version error.
|
||||
|
||||
## Risks / Notes
|
||||
|
||||
- Removing the fixed cap changes sizing for **all** connection banners; the
|
||||
overlay clamp is what bounds it, so verify very long errors scroll rather than
|
||||
push the banner off the top of the transcript.
|
||||
- No backend / shared DTO changes; `UNSUPPORTED` + `error=reason` already reach
|
||||
the frontend.
|
||||
- Reason codes live only in `RemoteDirectory.kt` today; the new bundle keys are
|
||||
the first human-readable mapping. New reason codes fall back to `unknown`.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Exact user-facing wording for the five `session.connection.unsupported*`
|
||||
strings (placeholder copy above).
|
||||
@@ -359,7 +359,7 @@
|
||||
},
|
||||
"packages/kilo-jetbrains": {
|
||||
"name": "@kilocode/kilo-jetbrains",
|
||||
"version": "7.4.21",
|
||||
"version": "7.4.22",
|
||||
},
|
||||
"packages/kilo-memory": {
|
||||
"name": "@kilocode/kilo-memory",
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$/packages/kilo-jetbrains" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="--no-configuration-cache --purge-old-log-directories -Pkilo.dev.log.level=debug -Pkilo.dev.log.chat.content=off -Pkilo.dev.log.chat.preview.max=160 -Pkilo.splitModeServerPort=0 -Pkilo.dev.storage.isolated=true" />
|
||||
<option name="scriptParameters" value="--no-configuration-cache -Pkilo.dev.log.level=debug -Pkilo.dev.log.chat.content=off -Pkilo.dev.log.chat.preview.max=160 -Pkilo.splitModeServerPort=0 -Pkilo.dev.storage.isolated=true" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value=":runIdeBackend" />
|
||||
<option value="--purge-old-log-directories" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" value="" />
|
||||
@@ -25,4 +26,4 @@
|
||||
<GradleCoverageDisabled>false</GradleCoverageDisabled>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
</component>
|
||||
+3
-2
@@ -6,13 +6,14 @@
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$/packages/kilo-jetbrains" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="--no-configuration-cache --purge-old-log-directories -Pkilo.dev.log.level=debug -Pkilo.dev.log.chat.content=off -Pkilo.dev.log.chat.preview.max=160 -Pkilo.splitModeServerPort=0 -Pkilo.dev.storage.isolated=true" />
|
||||
<option name="scriptParameters" value="--no-configuration-cache -Pkilo.dev.log.level=debug -Pkilo.dev.log.chat.content=off -Pkilo.dev.log.chat.preview.max=160 -Pkilo.splitModeServerPort=0 -Pkilo.dev.storage.isolated=true" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value=":runIdeSplitMode" />
|
||||
<option value="--purge-old-log-directories" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" value="" />
|
||||
@@ -26,4 +27,4 @@
|
||||
<GradleCoverageDisabled>false</GradleCoverageDisabled>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
</component>
|
||||
-12
@@ -9,7 +9,6 @@ internal object RemoteDirectory {
|
||||
private val WSL_LOCALHOST = "\\\\wsl.localhost\\"
|
||||
|
||||
fun detect(directory: String): String? {
|
||||
forced()?.let { return it }
|
||||
val dir = directory.trim()
|
||||
if (dir.contains(DEVCONTAINER)) return "devcontainer_virtual_filesystem"
|
||||
if (dir.startsWith(WSL, ignoreCase = true)) return "wsl_virtual_filesystem"
|
||||
@@ -21,15 +20,4 @@ internal object RemoteDirectory {
|
||||
"invalid_virtual_path"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dev-only override so the unsupported notice can be reproduced without a real
|
||||
* Dev Container / IJent path. Set `-Dkilo.dev.forceUnsupportedWorkspace=<reason>`
|
||||
* (or `=true`) on a dev IDE run to force every workspace into the Unsupported state.
|
||||
*/
|
||||
private fun forced(): String? {
|
||||
val flag = System.getProperty("kilo.dev.forceUnsupportedWorkspace")?.trim().orEmpty()
|
||||
if (flag.isEmpty() || flag.equals("false", ignoreCase = true)) return null
|
||||
return if (flag.equals("true", ignoreCase = true)) "devcontainer_virtual_filesystem" else flag
|
||||
}
|
||||
}
|
||||
|
||||
-20
@@ -1,19 +1,11 @@
|
||||
package ai.kilocode.backend.workspace
|
||||
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class RemoteDirectoryTest {
|
||||
|
||||
private val flag = "kilo.dev.forceUnsupportedWorkspace"
|
||||
|
||||
@AfterTest
|
||||
fun tearDown() {
|
||||
System.clearProperty(flag)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `detects devcontainer virtual path`() {
|
||||
val dir = "/${'$'}devcontainer.ij/abc@u~run~user~1001~podman~podman.sock/workspaces/project"
|
||||
@@ -36,16 +28,4 @@ class RemoteDirectoryTest {
|
||||
assertNull(RemoteDirectory.detect("/Users/dev/project"))
|
||||
assertNull(RemoteDirectory.detect("/workspaces/project"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `forced flag overrides any directory`() {
|
||||
System.setProperty(flag, "true")
|
||||
assertEquals("devcontainer_virtual_filesystem", RemoteDirectory.detect("/Users/dev/project"))
|
||||
|
||||
System.setProperty(flag, "custom_reason")
|
||||
assertEquals("custom_reason", RemoteDirectory.detect("/Users/dev/project"))
|
||||
|
||||
System.setProperty(flag, "false")
|
||||
assertNull(RemoteDirectory.detect("/Users/dev/project"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,9 +276,6 @@ tasks.withType<RunIdeTask> {
|
||||
systemProperty("kilo.dev.log.chat.preview.max", preview)
|
||||
systemProperty("kilo.dev.storage.isolated", isolated.get().toString())
|
||||
systemProperty("kilo.dev.worktree.root", worktreeRoot.get())
|
||||
providers.gradleProperty("kilo.dev.forceUnsupportedWorkspace").orNull?.let {
|
||||
systemProperty("kilo.dev.forceUnsupportedWorkspace", it)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<Delete>("clean") {
|
||||
|
||||
+7
-4
@@ -440,14 +440,17 @@ class SessionUi(
|
||||
)
|
||||
connection = ConnectionPanel(this, controller)
|
||||
root.addOverlay(connection) { pane, child ->
|
||||
val size = child.preferredSize
|
||||
val point = SwingUtilities.convertPoint(prompt.parent ?: root.content, prompt.x, prompt.y, pane)
|
||||
val gap = SessionUiStyle.View.contentGap()
|
||||
val wide = (prompt.width - gap * 2).coerceAtLeast(0)
|
||||
// Fix the banner width before measuring so its word-wrapped detail height is known.
|
||||
child.setSize(wide, child.height)
|
||||
val height = child.preferredSize.height.coerceAtMost((point.y - gap).coerceAtLeast(0))
|
||||
java.awt.Rectangle(
|
||||
point.x + gap,
|
||||
point.y - size.height - gap,
|
||||
(prompt.width - gap * 2).coerceAtLeast(0),
|
||||
size.height,
|
||||
point.y - height - gap,
|
||||
wide,
|
||||
height,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+20
@@ -2378,6 +2378,14 @@ class SessionController(
|
||||
)
|
||||
}
|
||||
|
||||
if (workspace.status == KiloWorkspaceStatusDto.UNSUPPORTED) {
|
||||
return SessionControllerEvent.ConnectionChanged.ShowError(
|
||||
KiloBundle.message("session.connection.unsupported"),
|
||||
unsupported(workspace.error, directory),
|
||||
"workspace",
|
||||
)
|
||||
}
|
||||
|
||||
if (app.status == KiloAppStatusDto.READY && workspace.status == KiloWorkspaceStatusDto.READY && app.warnings.isNotEmpty()) {
|
||||
return SessionControllerEvent.ConnectionChanged.ShowWarning(
|
||||
summary(app.warnings.size),
|
||||
@@ -2576,6 +2584,18 @@ private fun summary(count: Int): String {
|
||||
return "$base ($count)"
|
||||
}
|
||||
|
||||
private fun unsupported(reason: String?, directory: String): String {
|
||||
val detail = when (reason) {
|
||||
"devcontainer_virtual_filesystem" -> KiloBundle.message("session.connection.unsupported.devcontainer")
|
||||
"wsl_virtual_filesystem" -> KiloBundle.message("session.connection.unsupported.wsl")
|
||||
"invalid_virtual_path" -> KiloBundle.message("session.connection.unsupported.invalid")
|
||||
else -> KiloBundle.message("session.connection.unsupported.unknown")
|
||||
}
|
||||
val path = KiloBundle.message("session.connection.unsupported.path", directory)
|
||||
val options = KiloBundle.message("session.connection.unsupported.options")
|
||||
return "$path\n\n$detail\n\n$options"
|
||||
}
|
||||
|
||||
private const val KILO_PROVIDER = "kilo"
|
||||
private const val KILO_AUTO_MODEL = "kilo-auto/free"
|
||||
|
||||
|
||||
+8
-6
@@ -42,7 +42,6 @@ class ConnectionPanel(
|
||||
|
||||
companion object {
|
||||
internal const val CLI_GROUP_ID = "Kilo.CliGroup"
|
||||
private const val DETAILS_LINES = 10
|
||||
private const val CHROME = 2
|
||||
}
|
||||
|
||||
@@ -301,8 +300,14 @@ class ConnectionPanel(
|
||||
}
|
||||
|
||||
private fun scrollHeight(): Int {
|
||||
val rows = details.text.lineSequence().count().coerceIn(1, DETAILS_LINES)
|
||||
return details.getFontMetrics(details.font).height * rows + scrollChrome()
|
||||
val inner = (width - scroll.insets.left - scroll.insets.right).coerceAtLeast(1)
|
||||
// Measure the word-wrapped height at the available width so a single long line that wraps
|
||||
// onto several visual rows still contributes its full height instead of being clipped.
|
||||
details.setSize(inner, Short.MAX_VALUE.toInt())
|
||||
val wrapped = details.preferredSize.height
|
||||
val rows = details.text.lineSequence().count().coerceAtLeast(1)
|
||||
val minimum = details.getFontMetrics(details.font).height * rows
|
||||
return maxOf(wrapped, minimum) + scrollChrome()
|
||||
}
|
||||
|
||||
private fun scrollChrome() = scroll.insets.top + scroll.insets.bottom + JBUI.scale(CHROME)
|
||||
@@ -341,7 +346,4 @@ class ConnectionPanel(
|
||||
internal fun retryFocusable() = retry.isFocusable
|
||||
|
||||
internal fun hasSeparator() = border != null
|
||||
|
||||
internal fun maxExpandedHeight() =
|
||||
header.preferredSize.height + details.getFontMetrics(details.font).height * DETAILS_LINES + scrollChrome()
|
||||
}
|
||||
|
||||
@@ -14,6 +14,13 @@ session.connection.error.app=Connection failed
|
||||
session.connection.error.workspace=Workspace loading failed
|
||||
session.connection.error.unknown=Unknown error
|
||||
session.connection.retry=Try again
|
||||
session.connection.unsupported=Workspace not supported
|
||||
session.connection.unsupported.devcontainer=Kilo runs on your host machine, so it can't reach the files inside this Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo can't resolve this workspace path on your local filesystem.
|
||||
session.connection.unsupported.unknown=Kilo runs on your host machine, so it can't reach this workspace's files.
|
||||
session.connection.unsupported.path=Workspace path: {0}
|
||||
session.connection.unsupported.wsl=Kilo runs on your host machine, so it can't reach the files inside WSL.
|
||||
session.connection.unsupported.options=Option 1: Open the project in the container or WSL with JetBrains Gateway so Kilo runs next to your code.\nOption 2: Open the project directly from your local filesystem so Kilo can reach the files.
|
||||
session.connection.warning.config=Configuration warnings
|
||||
|
||||
notification.group.kilo=Kilo Code
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=فشل الاتصال
|
||||
session.connection.error.workspace=فشل تحميل مساحة العمل
|
||||
session.connection.error.unknown=خطأ غير معروف
|
||||
session.connection.retry=إعادة المحاولة
|
||||
session.connection.unsupported=مساحة العمل غير مدعومة
|
||||
session.connection.unsupported.devcontainer=يعمل Kilo على جهازك المضيف، لذا لا يمكنه الوصول إلى الملفات داخل Dev Container هذا.
|
||||
session.connection.unsupported.invalid=لا يستطيع Kilo تحليل مسار مساحة العمل هذا على نظام الملفات المحلي لديك.
|
||||
session.connection.unsupported.unknown=يعمل Kilo على جهازك المضيف، لذا لا يمكنه الوصول إلى ملفات مساحة العمل هذه.
|
||||
session.connection.unsupported.path=مسار مساحة العمل: {0}
|
||||
session.connection.unsupported.wsl=يعمل Kilo على جهازك المضيف، لذا لا يمكنه الوصول إلى الملفات داخل WSL.
|
||||
session.connection.unsupported.options=الخيار 1: افتح المشروع داخل الحاوية أو WSL باستخدام JetBrains Gateway حتى يعمل Kilo بجوار التعليمات البرمجية الخاصة بك.\nالخيار 2: افتح المشروع مباشرةً من نظام الملفات المحلي لديك حتى يتمكن Kilo من الوصول إلى الملفات.
|
||||
session.connection.warning.config=تحذيرات التكوين
|
||||
|
||||
session.empty.welcome=Kilo Code هو مساعد برمجة بالذكاء الاصطناعي. اطلب منه بناء ميزات أو إصلاح أخطاء أو شرح قاعدة الكود.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Greška pri spajanju
|
||||
session.connection.error.workspace=Greška pri učitavanju radnog prostora
|
||||
session.connection.error.unknown=Nepoznata greška
|
||||
session.connection.retry=Pokušaj ponovo
|
||||
session.connection.unsupported=Radni prostor nije podržan
|
||||
session.connection.unsupported.devcontainer=Kilo se izvršava na vašem host računaru, pa ne može pristupiti datotekama unutar ovog Dev Container-a.
|
||||
session.connection.unsupported.invalid=Kilo ne može razriješiti ovu putanju radnog prostora na vašem lokalnom datotečnom sistemu.
|
||||
session.connection.unsupported.unknown=Kilo se izvršava na vašem host računaru, pa ne može pristupiti datotekama ovog radnog prostora.
|
||||
session.connection.unsupported.path=Putanja radnog prostora: {0}
|
||||
session.connection.unsupported.wsl=Kilo se izvršava na vašem host računaru, pa ne može pristupiti datotekama unutar WSL-a.
|
||||
session.connection.unsupported.options=Opcija 1: Otvorite projekat u kontejneru ili WSL-u pomoću JetBrains Gateway-a kako bi se Kilo izvršavao uz vaš kod.\nOpcija 2: Otvorite projekat direktno sa vašeg lokalnog datotečnog sistema kako bi Kilo mogao pristupiti datotekama.
|
||||
session.connection.warning.config=Upozorenja konfiguracije
|
||||
|
||||
session.empty.welcome=Kilo Code je AI asistent za kodiranje. Zatražite od njega da gradi funkcije, ispravlja greške ili objašnjava vašu bazu koda.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Forbindelsesfejl
|
||||
session.connection.error.workspace=Fejl ved indlæsning af arbejdsområde
|
||||
session.connection.error.unknown=Ukendt fejl
|
||||
session.connection.retry=Prøv igen
|
||||
session.connection.unsupported=Arbejdsområde understøttes ikke
|
||||
session.connection.unsupported.devcontainer=Kilo kører på din værtsmaskine og kan derfor ikke nå filerne inde i denne Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo kan ikke fortolke denne arbejdsområdesti på dit lokale filsystem.
|
||||
session.connection.unsupported.unknown=Kilo kører på din værtsmaskine og kan derfor ikke nå filerne i dette arbejdsområde.
|
||||
session.connection.unsupported.path=Arbejdsområdesti: {0}
|
||||
session.connection.unsupported.wsl=Kilo kører på din værtsmaskine og kan derfor ikke nå filerne inde i WSL.
|
||||
session.connection.unsupported.options=Mulighed 1: Åbn projektet i containeren eller WSL med JetBrains Gateway, så Kilo kører ved siden af din kode.\nMulighed 2: Åbn projektet direkte fra dit lokale filsystem, så Kilo kan få adgang til filerne.
|
||||
session.connection.warning.config=Konfigurationsadvarsler
|
||||
|
||||
session.empty.welcome=Kilo Code er en AI-kodningsassistent. Bed den om at bygge funktioner, rette fejl eller forklare din kodebase.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Verbindung fehlgeschlagen
|
||||
session.connection.error.workspace=Workspace-Laden fehlgeschlagen
|
||||
session.connection.error.unknown=Unbekannter Fehler
|
||||
session.connection.retry=Erneut versuchen
|
||||
session.connection.unsupported=Workspace nicht unterstützt
|
||||
session.connection.unsupported.devcontainer=Kilo läuft auf Ihrem Host-Rechner und kann daher nicht auf die Dateien in diesem Dev Container zugreifen.
|
||||
session.connection.unsupported.invalid=Kilo kann diesen Workspace-Pfad auf Ihrem lokalen Dateisystem nicht auflösen.
|
||||
session.connection.unsupported.unknown=Kilo läuft auf Ihrem Host-Rechner und kann daher nicht auf die Dateien dieses Workspaces zugreifen.
|
||||
session.connection.unsupported.path=Workspace-Pfad: {0}
|
||||
session.connection.unsupported.wsl=Kilo läuft auf Ihrem Host-Rechner und kann daher nicht auf die Dateien in WSL zugreifen.
|
||||
session.connection.unsupported.options=Option 1: Öffnen Sie das Projekt im Container oder in WSL mit JetBrains Gateway, damit Kilo direkt neben Ihrem Code läuft.\nOption 2: Öffnen Sie das Projekt direkt aus Ihrem lokalen Dateisystem, damit Kilo auf die Dateien zugreifen kann.
|
||||
session.connection.warning.config=Konfigurationswarnungen
|
||||
|
||||
session.empty.welcome=Kilo Code ist ein KI-Coding-Assistent. Bitten Sie ihn, Funktionen zu erstellen, Fehler zu beheben oder Ihre Codebasis zu erklären.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Error de conexión
|
||||
session.connection.error.workspace=Error al cargar el espacio de trabajo
|
||||
session.connection.error.unknown=Error desconocido
|
||||
session.connection.retry=Reintentar
|
||||
session.connection.unsupported=Espacio de trabajo no compatible
|
||||
session.connection.unsupported.devcontainer=Kilo se ejecuta en tu máquina host, por lo que no puede acceder a los archivos dentro de este Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo no puede resolver esta ruta del espacio de trabajo en tu sistema de archivos local.
|
||||
session.connection.unsupported.unknown=Kilo se ejecuta en tu máquina host, por lo que no puede acceder a los archivos de este espacio de trabajo.
|
||||
session.connection.unsupported.path=Ruta del espacio de trabajo: {0}
|
||||
session.connection.unsupported.wsl=Kilo se ejecuta en tu máquina host, por lo que no puede acceder a los archivos dentro de WSL.
|
||||
session.connection.unsupported.options=Opción 1: Abre el proyecto en el contenedor o WSL con JetBrains Gateway para que Kilo se ejecute junto a tu código.\nOpción 2: Abre el proyecto directamente desde tu sistema de archivos local para que Kilo pueda acceder a los archivos.
|
||||
session.connection.warning.config=Advertencias de configuración
|
||||
|
||||
session.empty.welcome=Kilo Code es un asistente de codificación con IA. Pida que construya funciones, corrija errores o explique su base de código.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Échec de la connexion
|
||||
session.connection.error.workspace=Échec du chargement de l'espace de travail
|
||||
session.connection.error.unknown=Erreur inconnue
|
||||
session.connection.retry=Réessayer
|
||||
session.connection.unsupported=Espace de travail non pris en charge
|
||||
session.connection.unsupported.devcontainer=Kilo s'exécute sur votre machine hôte et ne peut donc pas accéder aux fichiers de ce Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo ne parvient pas à résoudre ce chemin d'espace de travail sur votre système de fichiers local.
|
||||
session.connection.unsupported.unknown=Kilo s'exécute sur votre machine hôte et ne peut donc pas accéder aux fichiers de cet espace de travail.
|
||||
session.connection.unsupported.path=Chemin de l'espace de travail : {0}
|
||||
session.connection.unsupported.wsl=Kilo s'exécute sur votre machine hôte et ne peut donc pas accéder aux fichiers dans WSL.
|
||||
session.connection.unsupported.options=Option 1 : ouvrez le projet dans le conteneur ou WSL avec JetBrains Gateway afin que Kilo s'exécute à côté de votre code.\nOption 2 : ouvrez le projet directement depuis votre système de fichiers local afin que Kilo puisse accéder aux fichiers.
|
||||
session.connection.warning.config=Avertissements de configuration
|
||||
|
||||
session.empty.welcome=Kilo Code est un assistant de codage IA. Demandez-lui de créer des fonctionnalités, corriger des bugs ou expliquer votre base de code.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=接続に失敗しました
|
||||
session.connection.error.workspace=ワークスペースの読み込みに失敗しました
|
||||
session.connection.error.unknown=不明なエラー
|
||||
session.connection.retry=再試行
|
||||
session.connection.unsupported=ワークスペースはサポートされていません
|
||||
session.connection.unsupported.devcontainer=Kilo はホストマシン上で実行されるため、この Dev Container 内のファイルにアクセスできません。
|
||||
session.connection.unsupported.invalid=Kilo はこのワークスペースのパスをローカルファイルシステム上で解決できません。
|
||||
session.connection.unsupported.unknown=Kilo はホストマシン上で実行されるため、このワークスペースのファイルにアクセスできません。
|
||||
session.connection.unsupported.path=ワークスペースのパス: {0}
|
||||
session.connection.unsupported.wsl=Kilo はホストマシン上で実行されるため、WSL 内のファイルにアクセスできません。
|
||||
session.connection.unsupported.options=オプション1: JetBrains Gateway を使ってコンテナまたは WSL 内でプロジェクトを開き、Kilo がコードのそばで実行されるようにします。\nオプション2: プロジェクトをローカルファイルシステムから直接開き、Kilo がファイルにアクセスできるようにします。
|
||||
session.connection.warning.config=設定の警告
|
||||
|
||||
session.empty.welcome=Kilo CodeはAIコーディングアシスタントです。機能の作成、バグの修正、またはコードベースの説明を依頼できます。
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=연결 실패
|
||||
session.connection.error.workspace=워크스페이스 로딩 실패
|
||||
session.connection.error.unknown=알 수 없는 오류
|
||||
session.connection.retry=다시 시도
|
||||
session.connection.unsupported=지원되지 않는 워크스페이스
|
||||
session.connection.unsupported.devcontainer=Kilo는 호스트 머신에서 실행되므로 이 Dev Container 안의 파일에 접근할 수 없습니다.
|
||||
session.connection.unsupported.invalid=Kilo가 로컬 파일 시스템에서 이 워크스페이스 경로를 확인할 수 없습니다.
|
||||
session.connection.unsupported.unknown=Kilo는 호스트 머신에서 실행되므로 이 워크스페이스의 파일에 접근할 수 없습니다.
|
||||
session.connection.unsupported.path=워크스페이스 경로: {0}
|
||||
session.connection.unsupported.wsl=Kilo는 호스트 머신에서 실행되므로 WSL 안의 파일에 접근할 수 없습니다.
|
||||
session.connection.unsupported.options=옵션 1: JetBrains Gateway로 컨테이너 또는 WSL에서 프로젝트를 열어 Kilo가 코드 옆에서 실행되도록 합니다.\n옵션 2: 로컬 파일 시스템에서 프로젝트를 직접 열어 Kilo가 파일에 접근할 수 있도록 합니다.
|
||||
session.connection.warning.config=구성 경고
|
||||
|
||||
session.empty.welcome=Kilo Code는 AI 코딩 어시스턴트입니다. 기능 구축, 버그 수정, 코드베이스 설명을 요청하세요.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Verbinding mislukt
|
||||
session.connection.error.workspace=Werkruimte laden mislukt
|
||||
session.connection.error.unknown=Onbekende fout
|
||||
session.connection.retry=Opnieuw proberen
|
||||
session.connection.unsupported=Werkruimte niet ondersteund
|
||||
session.connection.unsupported.devcontainer=Kilo draait op je hostmachine en heeft daardoor geen toegang tot de bestanden in deze Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo kan dit werkruimtepad niet omzetten op je lokale bestandssysteem.
|
||||
session.connection.unsupported.unknown=Kilo draait op je hostmachine en heeft daardoor geen toegang tot de bestanden van deze werkruimte.
|
||||
session.connection.unsupported.path=Werkruimtepad: {0}
|
||||
session.connection.unsupported.wsl=Kilo draait op je hostmachine en heeft daardoor geen toegang tot de bestanden in WSL.
|
||||
session.connection.unsupported.options=Optie 1: Open het project in de container of WSL met JetBrains Gateway zodat Kilo naast je code draait.\nOptie 2: Open het project rechtstreeks vanuit je lokale bestandssysteem zodat Kilo bij de bestanden kan.
|
||||
session.connection.warning.config=Configuratiewaarschuwingen
|
||||
|
||||
session.empty.welcome=Kilo Code is een AI-codeerassistent. Vraag het om functies te bouwen, bugs te repareren of uw codebase uit te leggen.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Tilkoblingsfeil
|
||||
session.connection.error.workspace=Feil ved lasting av arbeidsområde
|
||||
session.connection.error.unknown=Ukjent feil
|
||||
session.connection.retry=Prøv igjen
|
||||
session.connection.unsupported=Arbeidsområde støttes ikke
|
||||
session.connection.unsupported.devcontainer=Kilo kjører på vertsmaskinen din og kan derfor ikke nå filene inne i denne Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo kan ikke tolke denne arbeidsområdestien på det lokale filsystemet.
|
||||
session.connection.unsupported.unknown=Kilo kjører på vertsmaskinen din og kan derfor ikke nå filene i dette arbeidsområdet.
|
||||
session.connection.unsupported.path=Arbeidsområdesti: {0}
|
||||
session.connection.unsupported.wsl=Kilo kjører på vertsmaskinen din og kan derfor ikke nå filene inne i WSL.
|
||||
session.connection.unsupported.options=Alternativ 1: Åpne prosjektet i containeren eller WSL med JetBrains Gateway, slik at Kilo kjører ved siden av koden din.\nAlternativ 2: Åpne prosjektet direkte fra det lokale filsystemet, slik at Kilo får tilgang til filene.
|
||||
session.connection.warning.config=Konfigurasjonsadvarsler
|
||||
|
||||
session.empty.welcome=Kilo Code er en AI-kodingsassistent. Be den om å bygge funksjoner, fikse feil eller forklare kodebasen din.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Błąd połączenia
|
||||
session.connection.error.workspace=Błąd ładowania obszaru roboczego
|
||||
session.connection.error.unknown=Nieznany błąd
|
||||
session.connection.retry=Spróbuj ponownie
|
||||
session.connection.unsupported=Obszar roboczy nieobsługiwany
|
||||
session.connection.unsupported.devcontainer=Kilo działa na Twoim komputerze hosta, więc nie ma dostępu do plików w tym Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo nie może rozpoznać tej ścieżki obszaru roboczego w lokalnym systemie plików.
|
||||
session.connection.unsupported.unknown=Kilo działa na Twoim komputerze hosta, więc nie ma dostępu do plików tego obszaru roboczego.
|
||||
session.connection.unsupported.path=Ścieżka obszaru roboczego: {0}
|
||||
session.connection.unsupported.wsl=Kilo działa na Twoim komputerze hosta, więc nie ma dostępu do plików w WSL.
|
||||
session.connection.unsupported.options=Opcja 1: Otwórz projekt w kontenerze lub WSL za pomocą JetBrains Gateway, aby Kilo działało obok Twojego kodu.\nOpcja 2: Otwórz projekt bezpośrednio z lokalnego systemu plików, aby Kilo miało dostęp do plików.
|
||||
session.connection.warning.config=Ostrzeżenia konfiguracji
|
||||
|
||||
session.empty.welcome=Kilo Code to asystent kodowania AI. Poproś go o tworzenie funkcji, naprawianie błędów lub wyjaśnianie bazy kodu.
|
||||
|
||||
+7
@@ -7,6 +7,13 @@ session.connection.error.app=Falha na conexão
|
||||
session.connection.error.workspace=Falha ao carregar o espaço de trabalho
|
||||
session.connection.error.unknown=Erro desconhecido
|
||||
session.connection.retry=Tentar novamente
|
||||
session.connection.unsupported=Espaço de trabalho sem suporte
|
||||
session.connection.unsupported.devcontainer=O Kilo é executado na sua máquina host, então não consegue acessar os arquivos dentro deste Dev Container.
|
||||
session.connection.unsupported.invalid=O Kilo não consegue resolver este caminho do espaço de trabalho no seu sistema de arquivos local.
|
||||
session.connection.unsupported.unknown=O Kilo é executado na sua máquina host, então não consegue acessar os arquivos deste espaço de trabalho.
|
||||
session.connection.unsupported.path=Caminho do espaço de trabalho: {0}
|
||||
session.connection.unsupported.wsl=O Kilo é executado na sua máquina host, então não consegue acessar os arquivos dentro do WSL.
|
||||
session.connection.unsupported.options=Opção 1: Abra o projeto no contêiner ou no WSL com o JetBrains Gateway para que o Kilo seja executado junto ao seu código.\nOpção 2: Abra o projeto diretamente do seu sistema de arquivos local para que o Kilo possa acessar os arquivos.
|
||||
session.connection.warning.config=Avisos de configuração
|
||||
|
||||
session.empty.welcome=Kilo Code é um assistente de codificação com IA. Peça que construa funcionalidades, corrija bugs ou explique sua base de código.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Ошибка подключения
|
||||
session.connection.error.workspace=Ошибка загрузки рабочей области
|
||||
session.connection.error.unknown=Неизвестная ошибка
|
||||
session.connection.retry=Повторить
|
||||
session.connection.unsupported=Рабочая область не поддерживается
|
||||
session.connection.unsupported.devcontainer=Kilo работает на вашей хост-машине и поэтому не может получить доступ к файлам внутри этого Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo не может разрешить этот путь рабочей области в локальной файловой системе.
|
||||
session.connection.unsupported.unknown=Kilo работает на вашей хост-машине и поэтому не может получить доступ к файлам этой рабочей области.
|
||||
session.connection.unsupported.path=Путь рабочей области: {0}
|
||||
session.connection.unsupported.wsl=Kilo работает на вашей хост-машине и поэтому не может получить доступ к файлам внутри WSL.
|
||||
session.connection.unsupported.options=Вариант 1: откройте проект в контейнере или WSL с помощью JetBrains Gateway, чтобы Kilo работал рядом с вашим кодом.\nВариант 2: откройте проект напрямую из локальной файловой системы, чтобы Kilo мог получить доступ к файлам.
|
||||
session.connection.warning.config=Предупреждения конфигурации
|
||||
|
||||
session.empty.welcome=Kilo Code — это AI-ассистент по программированию. Попросите его разработать функции, исправить ошибки или объяснить кодовую базу.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=การเชื่อมต่อล้มเห
|
||||
session.connection.error.workspace=โหลดพื้นที่ทำงานล้มเหลว
|
||||
session.connection.error.unknown=ข้อผิดพลาดที่ไม่ทราบ
|
||||
session.connection.retry=ลองอีกครั้ง
|
||||
session.connection.unsupported=ไม่รองรับพื้นที่ทำงาน
|
||||
session.connection.unsupported.devcontainer=Kilo ทำงานบนเครื่องโฮสต์ของคุณ จึงไม่สามารถเข้าถึงไฟล์ภายใน Dev Container นี้ได้
|
||||
session.connection.unsupported.invalid=Kilo ไม่สามารถแปลงเส้นทางพื้นที่ทำงานนี้บนระบบไฟล์ในเครื่องของคุณได้
|
||||
session.connection.unsupported.unknown=Kilo ทำงานบนเครื่องโฮสต์ของคุณ จึงไม่สามารถเข้าถึงไฟล์ของพื้นที่ทำงานนี้ได้
|
||||
session.connection.unsupported.path=เส้นทางพื้นที่ทำงาน: {0}
|
||||
session.connection.unsupported.wsl=Kilo ทำงานบนเครื่องโฮสต์ของคุณ จึงไม่สามารถเข้าถึงไฟล์ภายใน WSL ได้
|
||||
session.connection.unsupported.options=ตัวเลือกที่ 1: เปิดโปรเจกต์ในคอนเทนเนอร์หรือ WSL ด้วย JetBrains Gateway เพื่อให้ Kilo ทำงานข้างโค้ดของคุณ\nตัวเลือกที่ 2: เปิดโปรเจกต์โดยตรงจากระบบไฟล์ในเครื่องของคุณ เพื่อให้ Kilo เข้าถึงไฟล์ได้
|
||||
session.connection.warning.config=คำเตือนการกำหนดค่า
|
||||
|
||||
session.empty.welcome=Kilo Code คือผู้ช่วยเขียนโค้ด AI ขอให้สร้างฟีเจอร์แก้สันข้อผิดพลาด หรืออธิบายโค้ดเบสของคุณ
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Bağlantı hatası
|
||||
session.connection.error.workspace=Çalışma alanı yüklenemedi
|
||||
session.connection.error.unknown=Bilinmeyen hata
|
||||
session.connection.retry=Tekrar dene
|
||||
session.connection.unsupported=Çalışma alanı desteklenmiyor
|
||||
session.connection.unsupported.devcontainer=Kilo, ana makinenizde çalışır ve bu nedenle bu Dev Container içindeki dosyalara erişemez.
|
||||
session.connection.unsupported.invalid=Kilo, bu çalışma alanı yolunu yerel dosya sisteminizde çözümleyemiyor.
|
||||
session.connection.unsupported.unknown=Kilo, ana makinenizde çalışır ve bu nedenle bu çalışma alanının dosyalarına erişemez.
|
||||
session.connection.unsupported.path=Çalışma alanı yolu: {0}
|
||||
session.connection.unsupported.wsl=Kilo, ana makinenizde çalışır ve bu nedenle WSL içindeki dosyalara erişemez.
|
||||
session.connection.unsupported.options=Seçenek 1: Projeyi JetBrains Gateway ile container veya WSL içinde açın, böylece Kilo kodunuzun yanında çalışır.\nSeçenek 2: Projeyi doğrudan yerel dosya sisteminizden açın, böylece Kilo dosyalara erişebilir.
|
||||
session.connection.warning.config=Yapılandırma uyarıları
|
||||
|
||||
session.empty.welcome=Kilo Code, bir yapay zeka kodlama asistanıdır. Özellik oluşturmasını, hata düzeltirlmesi veya kod tabanınızı açıklamasını isteyin.
|
||||
|
||||
@@ -7,6 +7,13 @@ session.connection.error.app=Помилка з'єднання
|
||||
session.connection.error.workspace=Помилка завантаження робочого простору
|
||||
session.connection.error.unknown=Невідома помилка
|
||||
session.connection.retry=Спробувати знову
|
||||
session.connection.unsupported=Робочий простір не підтримується
|
||||
session.connection.unsupported.devcontainer=Kilo працює на вашій хост-машині, тому не може отримати доступ до файлів усередині цього Dev Container.
|
||||
session.connection.unsupported.invalid=Kilo не може розв'язати цей шлях робочого простору у локальній файловій системі.
|
||||
session.connection.unsupported.unknown=Kilo працює на вашій хост-машині, тому не може отримати доступ до файлів цього робочого простору.
|
||||
session.connection.unsupported.path=Шлях робочого простору: {0}
|
||||
session.connection.unsupported.wsl=Kilo працює на вашій хост-машині, тому не може отримати доступ до файлів усередині WSL.
|
||||
session.connection.unsupported.options=Варіант 1: відкрийте проєкт у контейнері або WSL за допомогою JetBrains Gateway, щоб Kilo працював поруч із вашим кодом.\nВаріант 2: відкрийте проєкт безпосередньо з локальної файлової системи, щоб Kilo міг отримати доступ до файлів.
|
||||
session.connection.warning.config=Попередження конфігурації
|
||||
|
||||
session.empty.welcome=Kilo Code — це AI-асистент для програмування. Попросіть його створити функції, виправити помилки або пояснити ваш код.
|
||||
|
||||
+7
@@ -7,6 +7,13 @@ session.connection.error.app=连接失败
|
||||
session.connection.error.workspace=工作区加载失败
|
||||
session.connection.error.unknown=未知错误
|
||||
session.connection.retry=重试
|
||||
session.connection.unsupported=不支持的工作区
|
||||
session.connection.unsupported.devcontainer=Kilo 在你的宿主机上运行,因此无法访问此 Dev Container 内的文件。
|
||||
session.connection.unsupported.invalid=Kilo 无法在本地文件系统上解析此工作区路径。
|
||||
session.connection.unsupported.unknown=Kilo 在你的宿主机上运行,因此无法访问此工作区的文件。
|
||||
session.connection.unsupported.path=工作区路径:{0}
|
||||
session.connection.unsupported.wsl=Kilo 在你的宿主机上运行,因此无法访问 WSL 内的文件。
|
||||
session.connection.unsupported.options=选项 1:使用 JetBrains Gateway 在容器或 WSL 中打开项目,让 Kilo 与你的代码一起运行。\n选项 2:直接从本地文件系统打开项目,让 Kilo 能够访问这些文件。
|
||||
session.connection.warning.config=配置警告
|
||||
|
||||
session.empty.welcome=Kilo Code 是一个 AI 编程助手。可请它构建功能、修复错误或解释您的代码库。
|
||||
|
||||
+7
@@ -7,6 +7,13 @@ session.connection.error.app=連線失敗
|
||||
session.connection.error.workspace=工作區載入失敗
|
||||
session.connection.error.unknown=未知錯誤
|
||||
session.connection.retry=重試
|
||||
session.connection.unsupported=不支援的工作區
|
||||
session.connection.unsupported.devcontainer=Kilo 在你的主機上執行,因此無法存取此 Dev Container 內的檔案。
|
||||
session.connection.unsupported.invalid=Kilo 無法在本機檔案系統上解析此工作區路徑。
|
||||
session.connection.unsupported.unknown=Kilo 在你的主機上執行,因此無法存取此工作區的檔案。
|
||||
session.connection.unsupported.path=工作區路徑:{0}
|
||||
session.connection.unsupported.wsl=Kilo 在你的主機上執行,因此無法存取 WSL 內的檔案。
|
||||
session.connection.unsupported.options=選項 1:使用 JetBrains Gateway 在容器或 WSL 中開啟專案,讓 Kilo 與你的程式碼一起執行。\n選項 2:直接從本機檔案系統開啟專案,讓 Kilo 能夠存取這些檔案。
|
||||
session.connection.warning.config=設定警告
|
||||
|
||||
session.empty.welcome=Kilo Code 是 AI 程式輔助。可請它建置功能、修復錯誤或解釋您的程式程式庫。
|
||||
|
||||
+25
@@ -275,6 +275,29 @@ class SessionUiLayoutTest : SessionUiTestBase() {
|
||||
assertEquals(promptPoint(root, prompt).y - SessionUiStyle.View.contentGap(), connection.y + connection.height)
|
||||
}
|
||||
|
||||
fun `test expanded connection panel is capped to transcript height`() {
|
||||
ui.setSize(800, 260)
|
||||
layout()
|
||||
val root = find<SessionRootPanel>(ui)
|
||||
val connection = find<ConnectionPanel>(ui)
|
||||
val prompt = find<PromptPanel>(ui)
|
||||
|
||||
connection.onEvent(SessionControllerEvent.ConnectionChanged.ShowError(
|
||||
"CLI startup failed",
|
||||
lines(60),
|
||||
))
|
||||
layout()
|
||||
connection.clickSummary()
|
||||
layout()
|
||||
val pane = connection.components.filterIsInstance<JBScrollPane>().single()
|
||||
pane.doLayout()
|
||||
|
||||
assertTrue(connection.detailsVisible())
|
||||
assertEquals(0, connection.y)
|
||||
assertEquals(promptPoint(root, prompt).y - SessionUiStyle.View.contentGap(), connection.y + connection.height)
|
||||
assertTrue(pane.viewport.extentSize.height < pane.viewport.view.preferredSize.height)
|
||||
}
|
||||
|
||||
fun `test connection panel is unaffected by active question view`() {
|
||||
ui = newUi(id = "ses_test")
|
||||
settle()
|
||||
@@ -775,6 +798,8 @@ class SessionUiLayoutTest : SessionUiTestBase() {
|
||||
private fun promptPoint(root: SessionRootPanel, prompt: PromptPanel) =
|
||||
SwingUtilities.convertPoint(prompt.parent, prompt.x, prompt.y, root.overlay)
|
||||
|
||||
private fun lines(count: Int) = (1..count).joinToString("\n") { "line $it" }
|
||||
|
||||
private class Row(override val sessionViewKind: SessionView.Kind) : JPanel(), SessionView {
|
||||
override fun getPreferredSize() = Dimension(100, 10)
|
||||
}
|
||||
|
||||
+55
@@ -138,6 +138,61 @@ class ConnectionDelayTest : SessionControllerTestBase() {
|
||||
assertEquals("providers: bad provider json", event.detail)
|
||||
}
|
||||
|
||||
fun `test persistent unsupported workspace shows standard workspace error`() {
|
||||
appRpc.state.value = KiloAppStateDto(KiloAppStatusDto.READY)
|
||||
projectRpc.state.value = workspaceReady()
|
||||
val m = controller(displayMs = 50)
|
||||
val events = collect(m)
|
||||
flush()
|
||||
events.clear()
|
||||
|
||||
projectRpc.state.value = KiloWorkspaceStateDto(
|
||||
status = KiloWorkspaceStatusDto.UNSUPPORTED,
|
||||
error = "wsl_virtual_filesystem",
|
||||
)
|
||||
pause(20)
|
||||
assertFalse(events.any { it is SessionControllerEvent.ConnectionChanged.ShowError })
|
||||
|
||||
pause(80)
|
||||
|
||||
val event = events.filterIsInstance<SessionControllerEvent.ConnectionChanged.ShowError>().single()
|
||||
assertEquals("Workspace not supported", event.summary)
|
||||
assertEquals(
|
||||
"Workspace path: /test\n\n" +
|
||||
"Kilo runs on your host machine, so it can't reach the files inside WSL.\n\n" +
|
||||
"Option 1: Open the project in the container or WSL with JetBrains Gateway so Kilo runs next to your code.\n" +
|
||||
"Option 2: Open the project directly from your local filesystem so Kilo can reach the files.",
|
||||
event.detail,
|
||||
)
|
||||
assertEquals("workspace", event.source)
|
||||
assertFalse(events.any { it is SessionControllerEvent.ConnectionChanged.ShowConnecting })
|
||||
}
|
||||
|
||||
fun `test unsupported invalid path includes the workspace path`() {
|
||||
appRpc.state.value = KiloAppStateDto(KiloAppStatusDto.READY)
|
||||
projectRpc.state.value = workspaceReady()
|
||||
val m = controller(displayMs = 50)
|
||||
val events = collect(m)
|
||||
flush()
|
||||
events.clear()
|
||||
|
||||
projectRpc.state.value = KiloWorkspaceStateDto(
|
||||
status = KiloWorkspaceStatusDto.UNSUPPORTED,
|
||||
error = "invalid_virtual_path",
|
||||
)
|
||||
pause(80)
|
||||
|
||||
val event = events.filterIsInstance<SessionControllerEvent.ConnectionChanged.ShowError>().single()
|
||||
assertEquals("Workspace not supported", event.summary)
|
||||
assertEquals(
|
||||
"Workspace path: /test\n\n" +
|
||||
"Kilo can't resolve this workspace path on your local filesystem.\n\n" +
|
||||
"Option 1: Open the project in the container or WSL with JetBrains Gateway so Kilo runs next to your code.\n" +
|
||||
"Option 2: Open the project directly from your local filesystem so Kilo can reach the files.",
|
||||
event.detail,
|
||||
)
|
||||
}
|
||||
|
||||
fun `test ready hides visible delayed connection banner immediately`() {
|
||||
appRpc.state.value = KiloAppStateDto(KiloAppStatusDto.READY)
|
||||
projectRpc.state.value = workspaceReady()
|
||||
|
||||
+28
-3
@@ -137,16 +137,41 @@ class ConnectionPanelTest : SessionControllerTestBase() {
|
||||
assertTrue(panel.detailsVisible())
|
||||
}
|
||||
|
||||
fun `test expanded details height is capped at ten lines`() {
|
||||
fun `test expanded details preferred height fits full text`() {
|
||||
edt {
|
||||
panel.onEvent(SessionControllerEvent.ConnectionChanged.ShowError("CLI startup failed", lines(30)))
|
||||
panel.onEvent(SessionControllerEvent.ConnectionChanged.ShowError("CLI startup failed", lines(10)))
|
||||
panel.size = Dimension(480, 1000)
|
||||
}
|
||||
|
||||
edt { panel.clickSummary() }
|
||||
val ten = panel.preferredSize.height
|
||||
|
||||
edt {
|
||||
panel.onEvent(SessionControllerEvent.ConnectionChanged.ShowError("CLI startup failed", lines(30)))
|
||||
panel.clickSummary()
|
||||
}
|
||||
|
||||
assertTrue(panel.detailsVisible())
|
||||
assertTrue(panel.preferredSize.height <= panel.maxExpandedHeight())
|
||||
assertTrue(panel.preferredSize.height > ten)
|
||||
}
|
||||
|
||||
fun `test expanded details grow for a wrapped single line`() {
|
||||
val sentence = (1..40).joinToString(" ") { "word$it" }
|
||||
edt {
|
||||
panel.onEvent(SessionControllerEvent.ConnectionChanged.ShowError("CLI startup failed", sentence))
|
||||
panel.size = Dimension(240, 1000)
|
||||
panel.clickSummary()
|
||||
}
|
||||
|
||||
val fontHeight = fontHeight()
|
||||
assertTrue(panel.detailsVisible())
|
||||
// A single logical line that wraps must contribute more than one visual row of height.
|
||||
assertTrue(panel.preferredSize.height > fontHeight * 2)
|
||||
}
|
||||
|
||||
private fun fontHeight(): Int {
|
||||
val details = panel.components.filterIsInstance<JBScrollPane>().single().viewport.view
|
||||
return details.getFontMetrics(details.font).height
|
||||
}
|
||||
|
||||
fun `test raw app and workspace events do not render panel`() {
|
||||
|
||||
Reference in New Issue
Block a user