mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-19 10:02:04 +08:00
Merge branch 'main' into hide-training-models
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Prevent unnecessary repeat auto-compactions when providers report inconsistent token totals.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Support model-specific reasoning overrides for task subagents, including custom subagents with their own model and variant settings.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Preserve existing Agent Manager worktrees and use deterministic suffixes when explicit branch names collide.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Allow hosted runtimes to cap shell command duration and explain environment-enforced timeouts.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Indicate when no models are available in model-not-found errors.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Group Kilo Code commands in the VS Code command palette and clarify the Open in Tab command title.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": minor
|
||||
"@kilocode/kilo-indexing": minor
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Use embedded LanceDB as the default semantic search vector store so indexing works without a separate Qdrant server. Existing Qdrant users and Intel Mac users can select `qdrant` with `indexing.vectorStore`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Dismiss stale permission prompts when another view has already answered them.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Speed up the first Agent Manager prompt in new worktrees by seeding snapshots from the checkout's Git index.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep large chat transcripts responsive by mounting only viewport-visible conversation rows.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Accelerate initial snapshots for regular Git sessions while preserving existing changes and asynchronously storing snapshots independently from the source repository.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/kilo-ui": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Speed up large session forks by retaining final task outcomes instead of duplicating resumable subagent histories, and load completed task details only when expanded.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Refresh connected provider model lists when the models catalog updates.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/kilo-gateway": patch
|
||||
---
|
||||
|
||||
Show model free and prompt-training indicators only when their explicit catalog metadata is enabled.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep HTTP status codes beside tool error titles when error details wrap.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Prevent task subagents from asking questions that users cannot answer from the parent session.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Show the first Agent Manager Local prompt and progress indicator immediately while its session is being created.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep binary and audio files collapsed in diff reviews instead of showing empty diff panels.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Prevent duplicate CLI attention alerts and route Kilo prompts through the configurable notification system.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Stabilize code indexing workers, retry Kilo model catalog downloads, reduce progress log noise, and show indexing failures as TUI notifications instead of writing over the terminal interface.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Remove the unsupported paste-summary toggle from VS Code settings.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/kilo-gateway": patch
|
||||
---
|
||||
|
||||
Prevent streamed tool calls from executing twice and leaving answered questions disabled in VS Code.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Restore Kilo branding, fork-specific CLI commands, and CLI lifecycle initialization after upstream merges.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Remove the unsupported code search tool.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/kilo-gateway": patch
|
||||
---
|
||||
|
||||
Update the Vercel AI SDK providers for Cerebras, xAI, and OpenAI-compatible endpoints.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep permission approvals working when continuing or switching Agent Manager worktree sessions.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Route question responses to the worktree where the question was created.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Support configuring code indexing separately for global and project settings in Kilo Console, the CLI TUI, and VS Code.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Validate GitHub attachments and language server release paths before downloading or executing them.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep custom-answer selection in sync and show one submit action while entering custom text.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Preserve complete session state when applying partial session updates in VS Code.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Restore persisted sessions across development extension branches and worktrees.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Restore streamed responses in the CLI TUI and move code indexing status into the session sidebar.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-vscode": patch
|
||||
---
|
||||
|
||||
Agent Manager terminals now use `terminal.integrated.fontFamily` and `terminal.integrated.fontSize` (including Nerd Font glyphs) instead of the editor font.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Start MCP servers while Agent Manager worktree sessions initialize to reduce the delay before the first response.
|
||||
@@ -212,7 +212,7 @@ jobs:
|
||||
|
||||
for (const pr of stalePrs) {
|
||||
const issue_number = pr.number
|
||||
const closeComment = `To stay organized pull requests are automatically closed after ${PR_DAYS_INACTIVE} days of inactivity. If the pull request is still relevant please open a new one.`
|
||||
const closeComment = `To stay organized pull requests are automatically closed after ${PR_DAYS_INACTIVE} days of inactivity. If the pull request is still relevant please reopen it or create a fresh new one.`
|
||||
|
||||
if (dryRun) {
|
||||
core.info(`[dry-run] Would close PR #${issue_number} from ${pr.author?.login || 'unknown'} (last activity: ${pr.activity.date.toISOString()} via ${pr.activity.source}): ${pr.title}`)
|
||||
@@ -314,7 +314,7 @@ jobs:
|
||||
let skippedIssueCount = 0
|
||||
|
||||
for (const issue of staleIssues) {
|
||||
const closeComment = `To stay organized issues are automatically closed after ${ISSUE_DAYS_INACTIVE} days of no activity. If the issue is still relevant please open a new one.`
|
||||
const closeComment = `To stay organized issues are automatically closed after ${ISSUE_DAYS_INACTIVE} days of no activity. If the issue is still relevant please reopen it or create a fresh new one.`
|
||||
|
||||
if (dryRun) {
|
||||
core.info(`[dry-run] Would close issue #${issue.number} (last activity: ${issue.activity.toISOString()} via updated): ${issue.title}`)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@opencode-ai/core",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -96,7 +96,7 @@
|
||||
},
|
||||
"packages/http-recorder": {
|
||||
"name": "@opencode-ai/http-recorder",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@effect/platform-node": "catalog:",
|
||||
"effect": "catalog:",
|
||||
@@ -109,7 +109,7 @@
|
||||
},
|
||||
"packages/kilo-console": {
|
||||
"name": "@kilocode/kilo-console",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-web-ui": "workspace:*",
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
@@ -131,7 +131,7 @@
|
||||
},
|
||||
"packages/kilo-docs": {
|
||||
"name": "@kilocode/kilo-docs",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@docsearch/css": "^4",
|
||||
"@docsearch/js": "^4",
|
||||
@@ -161,7 +161,7 @@
|
||||
},
|
||||
"packages/kilo-gateway": {
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/anthropic": "3.0.71",
|
||||
@@ -198,7 +198,7 @@
|
||||
},
|
||||
"packages/kilo-i18n": {
|
||||
"name": "@kilocode/kilo-i18n",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
@@ -208,7 +208,7 @@
|
||||
},
|
||||
"packages/kilo-indexing": {
|
||||
"name": "@kilocode/kilo-indexing",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-bedrock-runtime": "3.1005.0",
|
||||
"@aws-sdk/credential-provider-ini": "3.972.31",
|
||||
@@ -240,11 +240,11 @@
|
||||
},
|
||||
"packages/kilo-jetbrains": {
|
||||
"name": "@kilocode/kilo-jetbrains",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
},
|
||||
"packages/kilo-telemetry": {
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
"posthog-node": "4.4.0",
|
||||
@@ -258,7 +258,7 @@
|
||||
},
|
||||
"packages/kilo-ui": {
|
||||
"name": "@kilocode/kilo-ui",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@kobalte/core": "0.13.11",
|
||||
@@ -295,7 +295,7 @@
|
||||
},
|
||||
"packages/kilo-vscode": {
|
||||
"name": "kilo-code",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.39.0",
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
@@ -361,7 +361,7 @@
|
||||
},
|
||||
"packages/kilo-web-ui": {
|
||||
"name": "@kilocode/kilo-web-ui",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-ui": "workspace:*",
|
||||
"@kobalte/core": "catalog:",
|
||||
@@ -376,7 +376,7 @@
|
||||
},
|
||||
"packages/llm": {
|
||||
"name": "@opencode-ai/llm",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@smithy/eventstream-codec": "4.2.14",
|
||||
"@smithy/util-utf8": "4.2.2",
|
||||
@@ -394,7 +394,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "@kilocode/cli",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"bin": {
|
||||
"kilo": "./bin/kilo",
|
||||
"kilocode": "./bin/kilo",
|
||||
@@ -562,7 +562,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@kilocode/plugin",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"effect": "catalog:",
|
||||
@@ -590,7 +590,7 @@
|
||||
},
|
||||
"packages/plugin-atomic-chat": {
|
||||
"name": "@kilocode/plugin-atomic-chat",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/plugin": "workspace:*",
|
||||
},
|
||||
@@ -604,7 +604,7 @@
|
||||
},
|
||||
"packages/script": {
|
||||
"name": "@opencode-ai/script",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"semver": "^7.6.3",
|
||||
},
|
||||
@@ -615,7 +615,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@kilocode/sdk",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"cross-spawn": "catalog:",
|
||||
},
|
||||
@@ -630,7 +630,7 @@
|
||||
},
|
||||
"packages/storybook": {
|
||||
"name": "@opencode-ai/storybook",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"devDependencies": {
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@solidjs/meta": "catalog:",
|
||||
@@ -653,7 +653,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@kobalte/core": "catalog:",
|
||||
|
||||
+1
-1
@@ -153,6 +153,6 @@
|
||||
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
|
||||
"mammoth@1.12.0": "patches/mammoth@1.12.0.patch"
|
||||
},
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"name": "@opencode-ai/core",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "kilo"
|
||||
name = "Kilo"
|
||||
description = "The open source coding agent."
|
||||
version = "7.3.42"
|
||||
version = "7.3.45"
|
||||
schema_version = 1
|
||||
authors = ["Anomaly"]
|
||||
repository = "https://github.com/Kilo-Org/kilocode"
|
||||
@@ -11,26 +11,26 @@ name = "Kilo"
|
||||
icon = "./icons/opencode.svg"
|
||||
|
||||
[agent_servers.opencode.targets.darwin-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.45/opencode-darwin-arm64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.darwin-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.45/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-linux-arm64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.45/opencode-linux-arm64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-linux-x64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.45/opencode-linux-x64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.windows-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.45/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"name": "@opencode-ai/http-recorder",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-console",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -52,6 +52,7 @@ export type ProjectConsoleQuery = ProjectQuery & {
|
||||
|
||||
export type ProjectConsoleSnapshot = {
|
||||
project: ProjectItem
|
||||
config: EffectiveConfig
|
||||
vcs: VcsInfo
|
||||
worktrees: string[]
|
||||
terminals: ProjectTerminalItem[]
|
||||
@@ -439,7 +440,8 @@ export async function loadProjectConsole(input: ProjectConsoleQuery): Promise<Pr
|
||||
const project = await resolved(input)
|
||||
const query = { url: input.url, dir: project.worktree }
|
||||
const sdk = client(query)
|
||||
const [vcs, worktrees] = await Promise.all([
|
||||
const [config, vcs, worktrees] = await Promise.all([
|
||||
sdk.config.overlay({ scope: "global" }),
|
||||
sdk.vcs.get({ directory: query.dir }),
|
||||
sdk.worktree.list({ directory: query.dir }),
|
||||
])
|
||||
@@ -450,6 +452,7 @@ export async function loadProjectConsole(input: ProjectConsoleQuery): Promise<Pr
|
||||
|
||||
return {
|
||||
project,
|
||||
config: demand("Config", config).effective,
|
||||
vcs: demand("VCS", vcs),
|
||||
worktrees: dirs,
|
||||
terminals: terminals.flat(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Show } from "solid-js"
|
||||
import { createUniqueId, Show } from "solid-js"
|
||||
import { Button } from "@kilocode/kilo-web-ui/button"
|
||||
import { Icon } from "@kilocode/kilo-web-ui/icon"
|
||||
|
||||
@@ -14,21 +14,31 @@ type Props = {
|
||||
}
|
||||
|
||||
export function ConfirmDialog(props: Props) {
|
||||
const id = createUniqueId()
|
||||
const title = `${id}-title`
|
||||
const message = `${id}-message`
|
||||
|
||||
return (
|
||||
<Show when={props.open}>
|
||||
<div class="confirm-scrim">
|
||||
<section class="confirm-dialog" role="alertdialog" aria-modal="true" aria-labelledby="confirm-title">
|
||||
<div class="confirm-scrim" onKeyDown={(event) => event.key === "Escape" && props.onCancel()}>
|
||||
<section
|
||||
class="confirm-dialog"
|
||||
role="alertdialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby={title}
|
||||
aria-describedby={props.message ? message : undefined}
|
||||
>
|
||||
<div class="confirm-body">
|
||||
<div class="confirm-icon" aria-hidden="true">
|
||||
<Icon name="warning" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 id="confirm-title">{props.title}</h2>
|
||||
<Show when={props.message}>{(text) => <p>{text()}</p>}</Show>
|
||||
<h2 id={title}>{props.title}</h2>
|
||||
<Show when={props.message}>{(text) => <p id={message}>{text()}</p>}</Show>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="confirm-actions">
|
||||
<Button variant="ghost" disabled={props.busy} onClick={props.onCancel}>
|
||||
<Button variant="ghost" disabled={props.busy} onClick={props.onCancel} autofocus>
|
||||
{props.cancel ?? "Cancel"}
|
||||
</Button>
|
||||
<Button variant="primary" disabled={props.busy} onClick={props.onConfirm}>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Button } from "@kilocode/kilo-web-ui/button"
|
||||
import { Input } from "@kilocode/kilo-web-ui/input"
|
||||
import { createUniqueId, Show } from "solid-js"
|
||||
|
||||
type Props = {
|
||||
open: boolean
|
||||
title: string
|
||||
message?: string
|
||||
label: string
|
||||
value: string
|
||||
placeholder?: string
|
||||
confirm?: string
|
||||
cancel?: string
|
||||
busy?: boolean
|
||||
onInput: (value: string) => void
|
||||
onCancel: () => void
|
||||
onConfirm: () => void
|
||||
}
|
||||
|
||||
export function PromptDialog(props: Props) {
|
||||
const id = createUniqueId()
|
||||
const title = `${id}-title`
|
||||
const message = `${id}-message`
|
||||
const input = `${id}-input`
|
||||
|
||||
return (
|
||||
<Show when={props.open}>
|
||||
<div class="confirm-scrim" onKeyDown={(event) => event.key === "Escape" && props.onCancel()}>
|
||||
<section
|
||||
class="confirm-dialog prompt-dialog"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby={title}
|
||||
aria-describedby={props.message ? message : undefined}
|
||||
>
|
||||
<form
|
||||
class="prompt-form"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
props.onConfirm()
|
||||
}}
|
||||
>
|
||||
<div class="prompt-body">
|
||||
<div class="prompt-copy">
|
||||
<h2 id={title}>{props.title}</h2>
|
||||
<Show when={props.message}>{(text) => <p id={message}>{text()}</p>}</Show>
|
||||
</div>
|
||||
<label class="prompt-field" for={input}>
|
||||
<span>{props.label}</span>
|
||||
<Input
|
||||
id={input}
|
||||
value={props.value}
|
||||
placeholder={props.placeholder}
|
||||
disabled={props.busy}
|
||||
autofocus
|
||||
onInput={(event) => props.onInput(event.currentTarget.value)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<footer class="confirm-actions">
|
||||
<Button type="button" variant="ghost" disabled={props.busy} onClick={props.onCancel}>
|
||||
{props.cancel ?? "Cancel"}
|
||||
</Button>
|
||||
<Button type="submit" variant="primary" disabled={props.busy}>
|
||||
{props.confirm ?? "Confirm"}
|
||||
</Button>
|
||||
</footer>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
@@ -30,13 +30,6 @@ function ConfigContent(props: { children?: JSX.Element }) {
|
||||
</Card>
|
||||
)}
|
||||
</Show>
|
||||
<Show when={ctx.saving()}>
|
||||
{(item) => (
|
||||
<Card class="banner" variant="info">
|
||||
{item()}...
|
||||
</Card>
|
||||
)}
|
||||
</Show>
|
||||
<Show when={ctx.data.error}>
|
||||
<Card class="banner" variant="error">
|
||||
<strong>Dashboard request failed</strong>
|
||||
|
||||
@@ -32,6 +32,7 @@ export function ConfigSidebar() {
|
||||
const href = (path: string) => `${path === "/" ? base() : `${base()}${path}`}${loc.search}`
|
||||
const current = (path: string) => path === active() || (path !== "/" && active().startsWith(`${path}/`))
|
||||
const group = (item: ConfigNode): item is ConfigGroup => "items" in item
|
||||
const navigation = createMemo(() => configNav.filter((item) => !project() || !group(item) || !item.globalOnly))
|
||||
|
||||
return (
|
||||
<aside class="config-sidebar" aria-label="Configuration sections">
|
||||
@@ -42,7 +43,7 @@ export function ConfigSidebar() {
|
||||
</span>
|
||||
</div>
|
||||
<nav class="config-options">
|
||||
<For each={configNav}>
|
||||
<For each={navigation()}>
|
||||
{(item) => {
|
||||
if (!group(item)) {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Show } from "solid-js"
|
||||
import { Button } from "@kilocode/kilo-web-ui/button"
|
||||
import { Card } from "@kilocode/kilo-web-ui/card"
|
||||
import { Spinner } from "@kilocode/kilo-web-ui/spinner"
|
||||
import { CustomSelect, type SelectOption } from "../../components/CustomSelect"
|
||||
import { ConfigPage } from "./ConfigPage"
|
||||
import {
|
||||
MAX_CONTEXT_SIDEBAR_WIDTH,
|
||||
MIN_CONTEXT_SIDEBAR_WIDTH,
|
||||
type ConsoleDiffStyle,
|
||||
useConsoleUiSettings,
|
||||
} from "./state/console"
|
||||
|
||||
const styles = [
|
||||
{ value: "unified", label: "Unified" },
|
||||
{ value: "split", label: "Split" },
|
||||
] satisfies SelectOption<ConsoleDiffStyle>[]
|
||||
|
||||
export function ConsoleUiRoute() {
|
||||
const state = useConsoleUiSettings()
|
||||
|
||||
return (
|
||||
<ConfigPage
|
||||
title="Console UI"
|
||||
description="Configure the local Kilo Console interface. These preferences are saved in your user config."
|
||||
actions={
|
||||
<>
|
||||
<Show when={state.configured()}>
|
||||
<Button variant="secondary" disabled={Boolean(state.ctx.saving())} onClick={state.reset}>
|
||||
Use default
|
||||
</Button>
|
||||
</Show>
|
||||
<Button
|
||||
variant="primary"
|
||||
disabled={Boolean(state.ctx.saving()) || !state.dirty()}
|
||||
aria-busy={Boolean(state.ctx.saving())}
|
||||
onClick={state.save}
|
||||
>
|
||||
<Show when={state.ctx.saving()}>
|
||||
<Spinner />
|
||||
</Show>
|
||||
Save
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div class="ui-settings">
|
||||
<Card class="ui-card" padding={0}>
|
||||
<header class="ui-card-header">
|
||||
<div>
|
||||
<h2>Project context sidebar</h2>
|
||||
<p>Set the default width used by the Context and Changes panel in project consoles.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div class="ui-form">
|
||||
<label class="ui-field">
|
||||
<span>Sidebar width</span>
|
||||
<input
|
||||
type="number"
|
||||
min={MIN_CONTEXT_SIDEBAR_WIDTH}
|
||||
max={MAX_CONTEXT_SIDEBAR_WIDTH}
|
||||
step="1"
|
||||
value={state.width()}
|
||||
onInput={(event) => state.setWidth(event.currentTarget.value)}
|
||||
/>
|
||||
<small>
|
||||
Width in pixels, between {MIN_CONTEXT_SIDEBAR_WIDTH} and {MAX_CONTEXT_SIDEBAR_WIDTH}. You can also
|
||||
resize the sidebar by dragging its left edge.
|
||||
</small>
|
||||
</label>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="ui-card" padding={0}>
|
||||
<header class="ui-card-header">
|
||||
<div>
|
||||
<h2>Diff review</h2>
|
||||
<p>Choose the default layout used when reviewing changed files in project consoles.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div class="ui-form">
|
||||
<div class="ui-field">
|
||||
<span>Diff layout</span>
|
||||
<CustomSelect
|
||||
class="console-diff-select"
|
||||
label="Diff layout"
|
||||
value={state.style()}
|
||||
options={styles}
|
||||
disabled={Boolean(state.ctx.saving())}
|
||||
onSelect={state.setStyle}
|
||||
/>
|
||||
<small>
|
||||
Unified shows changes in one column. Split shows the original and modified file side by side.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</ConfigPage>
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import type { IconProps } from "@kilocode/kilo-web-ui/icon"
|
||||
import { AgentBuilderRoute, AgentsRoute } from "./AgentsRoute"
|
||||
import { CliNotificationsRoute } from "./CliNotificationsRoute"
|
||||
import { CliUiRoute } from "./CliUiRoute"
|
||||
import { ConsoleUiRoute } from "./ConsoleUiRoute"
|
||||
import { FormattersRoute, LspRoute } from "./FormattersRoute"
|
||||
import { IndexingRoute } from "./IndexingRoute"
|
||||
import { KeybindsRoute } from "./KeybindsRoute"
|
||||
@@ -26,6 +27,7 @@ export type ConfigSection = {
|
||||
export type ConfigGroup = {
|
||||
id: string
|
||||
label: string
|
||||
globalOnly?: boolean
|
||||
items: ConfigSection[]
|
||||
}
|
||||
|
||||
@@ -130,6 +132,14 @@ export const configNav: ConfigNode[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "console",
|
||||
label: "Console",
|
||||
globalOnly: true,
|
||||
items: [
|
||||
{ path: "/console/ui", href: "/settings/console/ui", icon: "sliders", label: "UI", component: ConsoleUiRoute },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "advanced",
|
||||
label: "Advanced",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import {
|
||||
DEFAULT_CONTEXT_SIDEBAR_WIDTH,
|
||||
MAX_CONTEXT_SIDEBAR_WIDTH,
|
||||
MIN_CONTEXT_SIDEBAR_WIDTH,
|
||||
normalizeConsoleDiffStyle,
|
||||
normalizeContextSidebarWidth,
|
||||
parseContextSidebarWidth,
|
||||
} from "./console"
|
||||
|
||||
describe("console UI config state", () => {
|
||||
test("defaults the diff layout to unified", () => {
|
||||
expect(normalizeConsoleDiffStyle(undefined)).toBe("unified")
|
||||
expect(normalizeConsoleDiffStyle("unified")).toBe("unified")
|
||||
expect(normalizeConsoleDiffStyle("split")).toBe("split")
|
||||
expect(normalizeConsoleDiffStyle("side-by-side")).toBe("unified")
|
||||
})
|
||||
|
||||
test("normalizes missing and out-of-range widths", () => {
|
||||
expect(normalizeContextSidebarWidth(undefined)).toBe(DEFAULT_CONTEXT_SIDEBAR_WIDTH)
|
||||
expect(normalizeContextSidebarWidth(Number.NaN)).toBe(DEFAULT_CONTEXT_SIDEBAR_WIDTH)
|
||||
expect(normalizeContextSidebarWidth(100)).toBe(MIN_CONTEXT_SIDEBAR_WIDTH)
|
||||
expect(normalizeContextSidebarWidth(900)).toBe(MAX_CONTEXT_SIDEBAR_WIDTH)
|
||||
expect(normalizeContextSidebarWidth(411.6)).toBe(412)
|
||||
})
|
||||
|
||||
test("accepts only integer widths within the supported range", () => {
|
||||
expect(parseContextSidebarWidth("352")).toBe(352)
|
||||
expect(parseContextSidebarWidth(String(MIN_CONTEXT_SIDEBAR_WIDTH))).toBe(MIN_CONTEXT_SIDEBAR_WIDTH)
|
||||
expect(parseContextSidebarWidth(String(MAX_CONTEXT_SIDEBAR_WIDTH))).toBe(MAX_CONTEXT_SIDEBAR_WIDTH)
|
||||
expect(parseContextSidebarWidth("249")).toBeUndefined()
|
||||
expect(parseContextSidebarWidth("801")).toBeUndefined()
|
||||
expect(parseContextSidebarWidth("352.5")).toBeUndefined()
|
||||
expect(parseContextSidebarWidth("wide")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
import { createEffect, createSignal } from "solid-js"
|
||||
import { useConfig } from "../../../context/config"
|
||||
|
||||
export const DEFAULT_CONTEXT_SIDEBAR_WIDTH = 300
|
||||
export const MIN_CONTEXT_SIDEBAR_WIDTH = 250
|
||||
export const MAX_CONTEXT_SIDEBAR_WIDTH = 800
|
||||
export const DEFAULT_CONSOLE_DIFF_STYLE = "unified" as const
|
||||
export type ConsoleDiffStyle = "unified" | "split"
|
||||
|
||||
export function normalizeConsoleDiffStyle(value: unknown): ConsoleDiffStyle {
|
||||
return value === "split" ? "split" : DEFAULT_CONSOLE_DIFF_STYLE
|
||||
}
|
||||
|
||||
export function normalizeContextSidebarWidth(value: unknown) {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_CONTEXT_SIDEBAR_WIDTH
|
||||
return Math.min(MAX_CONTEXT_SIDEBAR_WIDTH, Math.max(MIN_CONTEXT_SIDEBAR_WIDTH, Math.round(value)))
|
||||
}
|
||||
|
||||
export function parseContextSidebarWidth(value: string) {
|
||||
const width = Number(value)
|
||||
if (!Number.isInteger(width)) return undefined
|
||||
if (width < MIN_CONTEXT_SIDEBAR_WIDTH || width > MAX_CONTEXT_SIDEBAR_WIDTH) return undefined
|
||||
return width
|
||||
}
|
||||
|
||||
export function useConsoleUiSettings() {
|
||||
const ctx = useConfig()
|
||||
const [width, setWidth] = createSignal(String(DEFAULT_CONTEXT_SIDEBAR_WIDTH))
|
||||
const [style, setStyle] = createSignal<ConsoleDiffStyle>(DEFAULT_CONSOLE_DIFF_STYLE)
|
||||
const [dirty, setDirty] = createSignal(false)
|
||||
|
||||
createEffect(() => {
|
||||
if (dirty()) return
|
||||
const config = ctx.data()?.effective.console
|
||||
setWidth(String(normalizeContextSidebarWidth(config?.context_sidebar_width)))
|
||||
setStyle(normalizeConsoleDiffStyle(config?.diff_style))
|
||||
})
|
||||
|
||||
function save() {
|
||||
const value = parseContextSidebarWidth(width())
|
||||
if (value === undefined) {
|
||||
ctx.fail(`Enter a sidebar width between ${MIN_CONTEXT_SIDEBAR_WIDTH} and ${MAX_CONTEXT_SIDEBAR_WIDTH} pixels.`)
|
||||
return
|
||||
}
|
||||
ctx.patch({ console: { context_sidebar_width: value, diff_style: style() } })
|
||||
setWidth(String(value))
|
||||
setDirty(false)
|
||||
}
|
||||
|
||||
function reset() {
|
||||
ctx.unset([
|
||||
["console", "context_sidebar_width"],
|
||||
["console", "diff_style"],
|
||||
])
|
||||
setWidth(String(DEFAULT_CONTEXT_SIDEBAR_WIDTH))
|
||||
setStyle(DEFAULT_CONSOLE_DIFF_STYLE)
|
||||
setDirty(false)
|
||||
}
|
||||
|
||||
return {
|
||||
ctx,
|
||||
width,
|
||||
setWidth: (value: string) => {
|
||||
setWidth(value)
|
||||
setDirty(true)
|
||||
},
|
||||
style,
|
||||
setStyle: (value: string) => {
|
||||
setStyle(normalizeConsoleDiffStyle(value))
|
||||
setDirty(true)
|
||||
},
|
||||
dirty,
|
||||
configured: () => {
|
||||
const config = ctx.data()?.effective.console
|
||||
return config?.context_sidebar_width !== undefined || config?.diff_style !== undefined
|
||||
},
|
||||
save,
|
||||
reset,
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,17 @@
|
||||
import { A, useLocation, useParams } from "@solidjs/router"
|
||||
import { createEffect, createMemo, createResource, createSignal, For, onCleanup, Show } from "solid-js"
|
||||
import { createEffect, createMemo, createResource, createSignal, For, on, onCleanup, Show } from "solid-js"
|
||||
import { Badge } from "@kilocode/kilo-web-ui/badge"
|
||||
import { Button } from "@kilocode/kilo-web-ui/button"
|
||||
import { Card } from "@kilocode/kilo-web-ui/card"
|
||||
import { Icon } from "@kilocode/kilo-web-ui/icon"
|
||||
import { ResizeHandle } from "@kilocode/kilo-web-ui/resize-handle"
|
||||
import { Spinner } from "@kilocode/kilo-web-ui/spinner"
|
||||
import { File } from "@opencode-ai/ui/file"
|
||||
import { FileComponentProvider } from "@opencode-ai/ui/context/file"
|
||||
import { SessionReview, type SessionReviewDiffStyle } from "@opencode-ai/ui/session-review"
|
||||
import { ConfirmDialog } from "../../components/ConfirmDialog"
|
||||
import { LoadingScreen } from "../../components/LoadingScreen"
|
||||
import { PromptDialog } from "../../components/PromptDialog"
|
||||
import {
|
||||
createProjectPty,
|
||||
createProjectWorktree,
|
||||
@@ -12,6 +21,7 @@ import {
|
||||
loadProjectConsole,
|
||||
loadProjectDiff,
|
||||
loadProjectDiffFile,
|
||||
patchConfig,
|
||||
removeProjectPty,
|
||||
removeProjectWorktree,
|
||||
resetProjectWorktree,
|
||||
@@ -21,6 +31,7 @@ import {
|
||||
viewProjectSessions,
|
||||
type ProjectConsoleEvent,
|
||||
type ProjectConsoleQuery,
|
||||
type ProjectDiffItem,
|
||||
type ProjectTerminalItem,
|
||||
type Query,
|
||||
} from "../../client"
|
||||
@@ -30,6 +41,14 @@ import {
|
||||
clearUnread as storeClearUnread,
|
||||
sessionHasUnread,
|
||||
} from "../../shared/terminal-status"
|
||||
import {
|
||||
DEFAULT_CONSOLE_DIFF_STYLE,
|
||||
DEFAULT_CONTEXT_SIDEBAR_WIDTH,
|
||||
MAX_CONTEXT_SIDEBAR_WIDTH,
|
||||
MIN_CONTEXT_SIDEBAR_WIDTH,
|
||||
normalizeConsoleDiffStyle,
|
||||
normalizeContextSidebarWidth,
|
||||
} from "../config/state/console"
|
||||
import { GhosttyTerminal } from "./terminal/GhosttyTerminal"
|
||||
|
||||
const ui = new Set(["3017", "3018"])
|
||||
@@ -41,6 +60,13 @@ type Context = {
|
||||
kind: "local" | "worktree"
|
||||
}
|
||||
|
||||
type Editor = { kind: "create"; value: string } | { kind: "rename"; item: Context; value: string }
|
||||
|
||||
type Pending = {
|
||||
kind: "delete" | "reset"
|
||||
item: Context
|
||||
}
|
||||
|
||||
function discoverable(search: URLSearchParams) {
|
||||
if (search.get("server")) return false
|
||||
return ui.has(window.location.port)
|
||||
@@ -125,13 +151,21 @@ export function ProjectConsoleRoute() {
|
||||
const [selected, setSelected] = createSignal(window.localStorage.getItem(`kilo.console.${params.project}.dir`) ?? "")
|
||||
const [active, setActive] = createSignal(window.localStorage.getItem(`kilo.console.${params.project}.pty`) ?? "")
|
||||
const [local, setLocal] = createSignal<ProjectTerminalItem[]>([])
|
||||
const [file, setFile] = createSignal<string | undefined>()
|
||||
const [openFiles, setOpenFiles] = createSignal<string[]>([])
|
||||
const [details, setDetails] = createSignal<Record<string, ProjectDiffItem>>({})
|
||||
const [infoWidth, setInfoWidth] = createSignal(DEFAULT_CONTEXT_SIDEBAR_WIDTH)
|
||||
const [viewport, setViewport] = createSignal(window.innerWidth)
|
||||
const [diffStyle, setDiffStyle] = createSignal<SessionReviewDiffStyle>(DEFAULT_CONSOLE_DIFF_STYLE)
|
||||
const [saving, setSaving] = createSignal<string | undefined>()
|
||||
const [failure, setFailure] = createSignal<string | undefined>()
|
||||
const [unread, setUnread] = createSignal(new Set<string>())
|
||||
const [closing, setClosing] = createSignal(new Set<string>())
|
||||
const [labelRev, setLabelRev] = createSignal(0)
|
||||
const [editor, setEditor] = createSignal<Editor | undefined>()
|
||||
const [pending, setPending] = createSignal<Pending | undefined>()
|
||||
const events = { timer: undefined as number | undefined }
|
||||
const resize = { timer: undefined as number | undefined, pending: false }
|
||||
const detailPending = new Set<string>()
|
||||
const project = () => params.project ?? ""
|
||||
const query = createMemo<ProjectConsoleQuery | undefined>(() => {
|
||||
const target = clean(url()) || fallback()
|
||||
@@ -139,6 +173,7 @@ export function ProjectConsoleRoute() {
|
||||
return { url: target, dir: "", project: project() }
|
||||
})
|
||||
const [snap, { refetch }] = createResource(query, loadProjectConsole)
|
||||
const visibleInfoWidth = createMemo(() => Math.min(infoWidth(), maxInfoWidth()))
|
||||
|
||||
const contexts = createMemo<Context[]>(() => {
|
||||
const data = snap()
|
||||
@@ -185,11 +220,13 @@ export function ProjectConsoleRoute() {
|
||||
return { input: item, dir: item.dir }
|
||||
})
|
||||
const [diffs] = createResource(diffKey, (item) => loadProjectDiff(item.input, item.dir))
|
||||
const detailKey = createMemo(() => {
|
||||
const item = target()
|
||||
const path = file()
|
||||
if (!item || !path) return undefined
|
||||
return { input: item, dir: item.dir, file: path }
|
||||
// Diff summary items carry no content (patch/before/after empty); overlay full file
|
||||
// diffs as they load so the review renders syntax-highlighted changes per file.
|
||||
const reviewDiffs = createMemo<ProjectDiffItem[]>(() => {
|
||||
const map = details()
|
||||
return (diffs() ?? [])
|
||||
.filter((item): item is ProjectDiffItem & { file: string } => typeof item.file === "string")
|
||||
.map((item) => map[item.file] ?? item)
|
||||
})
|
||||
const terminal = createMemo(() => {
|
||||
const item = activeTerminal()
|
||||
@@ -205,7 +242,6 @@ export function ProjectConsoleRoute() {
|
||||
return items
|
||||
})
|
||||
const terminalKeys = createMemo(() => Array.from(terminalMap().keys()))
|
||||
const [detail] = createResource(detailKey, (item) => loadProjectDiffFile(item.input, item.dir, item.file))
|
||||
const settings = createMemo(() => {
|
||||
const q = search().toString()
|
||||
return `/projects/${encodeURIComponent(project())}/settings${q ? `?${q}` : ""}`
|
||||
@@ -300,18 +336,67 @@ export function ProjectConsoleRoute() {
|
||||
setSelected(item.dir)
|
||||
const pty = terminalsFor(item.dir)[0]
|
||||
setActive(pty?.id ?? "")
|
||||
setFile(undefined)
|
||||
remember(item.dir, pty?.id)
|
||||
}
|
||||
|
||||
function selectTerminal(item: ProjectTerminalItem) {
|
||||
setSelected(item.directory)
|
||||
setActive(item.id)
|
||||
setFile(undefined)
|
||||
clearUnread(item)
|
||||
remember(item.directory, item.id)
|
||||
}
|
||||
|
||||
function fetchDetail(path: string) {
|
||||
const base = target()
|
||||
if (!base) return
|
||||
if (details()[path] || detailPending.has(path)) return
|
||||
detailPending.add(path)
|
||||
void loadProjectDiffFile(base, base.dir, path)
|
||||
.then((item) => {
|
||||
if (item && item.file) setDetails((prev) => ({ ...prev, [item.file!]: item }))
|
||||
})
|
||||
.catch((err) => console.warn("Worktree diff file:", err))
|
||||
.finally(() => detailPending.delete(path))
|
||||
}
|
||||
|
||||
function openReviewFiles(next: string[]) {
|
||||
setOpenFiles(next)
|
||||
for (const path of next) fetchDetail(path)
|
||||
}
|
||||
|
||||
function changeDiffStyle(style: SessionReviewDiffStyle) {
|
||||
setDiffStyle(style)
|
||||
const base = query()
|
||||
if (!base) return
|
||||
void patchConfig({ url: base.url, dir: "", scope: "global" }, { console: { diff_style: style } }).catch((err) =>
|
||||
console.warn(`Console diff style: ${errMsg(err)}`),
|
||||
)
|
||||
}
|
||||
|
||||
function resizeInfo(value: number) {
|
||||
const width = normalizeContextSidebarWidth(value)
|
||||
setInfoWidth(width)
|
||||
resize.pending = true
|
||||
if (resize.timer) window.clearTimeout(resize.timer)
|
||||
resize.timer = window.setTimeout(() => {
|
||||
resize.timer = undefined
|
||||
const base = query()
|
||||
if (!base) {
|
||||
resize.pending = false
|
||||
return
|
||||
}
|
||||
void patchConfig({ url: base.url, dir: "", scope: "global" }, { console: { context_sidebar_width: width } })
|
||||
.catch((err) => console.warn(`Console sidebar width: ${errMsg(err)}`))
|
||||
.finally(() => {
|
||||
resize.pending = false
|
||||
})
|
||||
}, 350)
|
||||
}
|
||||
|
||||
function maxInfoWidth() {
|
||||
return Math.max(MIN_CONTEXT_SIDEBAR_WIDTH, Math.min(MAX_CONTEXT_SIDEBAR_WIDTH, viewport() - 604))
|
||||
}
|
||||
|
||||
function run(label: string, job: () => Promise<unknown>) {
|
||||
setSaving(label)
|
||||
setFailure(undefined)
|
||||
@@ -322,10 +407,26 @@ export function ProjectConsoleRoute() {
|
||||
}
|
||||
|
||||
function addWorktree() {
|
||||
if (!projectInput()) return
|
||||
setEditor({ kind: "create", value: "" })
|
||||
}
|
||||
|
||||
function submitEditor() {
|
||||
const state = editor()
|
||||
if (!state) return
|
||||
if (state.kind === "rename") {
|
||||
const value = state.value.trim()
|
||||
if (value) window.localStorage.setItem(labelKey(state.item.dir), value)
|
||||
if (!value) window.localStorage.removeItem(labelKey(state.item.dir))
|
||||
setLabelRev((revision) => revision + 1)
|
||||
setEditor(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
const input = projectInput()
|
||||
const data = snap()
|
||||
if (!input || !data) return
|
||||
const name = window.prompt("Worktree name") ?? undefined
|
||||
if (!input) return
|
||||
const name = state.value.trim() || undefined
|
||||
setEditor(undefined)
|
||||
run("Creating worktree", async () => {
|
||||
const next = await createProjectWorktree(input, name)
|
||||
setSelected(next.directory)
|
||||
@@ -395,27 +496,12 @@ export function ProjectConsoleRoute() {
|
||||
|
||||
function renameWorktree(item: Context) {
|
||||
if (item.kind === "local") return
|
||||
const input = window.prompt("Worktree label", displayLabel(item))
|
||||
if (input === null) return
|
||||
const next = input.trim()
|
||||
if (next) window.localStorage.setItem(labelKey(item.dir), next)
|
||||
else window.localStorage.removeItem(labelKey(item.dir))
|
||||
setLabelRev((value) => value + 1)
|
||||
setEditor({ kind: "rename", item, value: displayLabel(item) })
|
||||
}
|
||||
|
||||
function removeWorktree(item: Context) {
|
||||
const input = projectInput()
|
||||
if (!input || item.kind === "local") return
|
||||
if (!window.confirm(`Remove worktree ${displayLabel(item)}?`)) return
|
||||
run("Removing worktree", async () => {
|
||||
await removeProjectWorktree(input, item.dir)
|
||||
window.localStorage.removeItem(labelKey(item.dir))
|
||||
setLabelRev((value) => value + 1)
|
||||
if (selected() === item.dir) {
|
||||
setSelected(input.dir)
|
||||
remember(input.dir)
|
||||
}
|
||||
})
|
||||
if (!projectInput() || item.kind === "local") return
|
||||
setPending({ kind: "delete", item })
|
||||
}
|
||||
|
||||
function removeSelected() {
|
||||
@@ -425,18 +511,88 @@ export function ProjectConsoleRoute() {
|
||||
}
|
||||
|
||||
function resetSelected() {
|
||||
const input = projectInput()
|
||||
const item = current()
|
||||
if (!input || !item || item.kind === "local") return
|
||||
if (!window.confirm(`Reset worktree ${displayLabel(item)}?`)) return
|
||||
run("Resetting worktree", async () => resetProjectWorktree(input, item.dir))
|
||||
if (!projectInput() || !item || item.kind === "local") return
|
||||
setPending({ kind: "reset", item })
|
||||
}
|
||||
|
||||
function confirmWorktree() {
|
||||
const state = pending()
|
||||
const input = projectInput()
|
||||
if (!state || !input) return
|
||||
setPending(undefined)
|
||||
if (state.kind === "reset") {
|
||||
run("Resetting worktree", async () => resetProjectWorktree(input, state.item.dir))
|
||||
return
|
||||
}
|
||||
|
||||
run("Removing worktree", async () => {
|
||||
await removeProjectWorktree(input, state.item.dir)
|
||||
window.localStorage.removeItem(labelKey(state.item.dir))
|
||||
setLabelRev((revision) => revision + 1)
|
||||
if (selected() === state.item.dir) {
|
||||
setSelected(input.dir)
|
||||
remember(input.dir)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateEditor(value: string) {
|
||||
setEditor((state) => {
|
||||
if (!state) return state
|
||||
return { ...state, value }
|
||||
})
|
||||
}
|
||||
|
||||
function editorTitle() {
|
||||
const state = editor()
|
||||
if (!state || state.kind === "create") return "Create worktree"
|
||||
return `Rename ${displayLabel(state.item)}`
|
||||
}
|
||||
|
||||
function editorMessage() {
|
||||
if (editor()?.kind === "rename") return "Leave the name blank to restore the generated worktree name."
|
||||
return "Choose a recognizable name, or leave it blank to generate one automatically."
|
||||
}
|
||||
|
||||
function pendingTitle() {
|
||||
const state = pending()
|
||||
if (!state) return ""
|
||||
const action = state.kind === "reset" ? "Reset" : "Delete"
|
||||
return `${action} worktree ${displayLabel(state.item)}?`
|
||||
}
|
||||
|
||||
function pendingMessage() {
|
||||
if (pending()?.kind === "reset") return "This discards all uncommitted changes in the worktree."
|
||||
return "This removes the worktree directory and its files from the project."
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const data = snap()
|
||||
if (!data) return
|
||||
if (!resize.pending) setInfoWidth(normalizeContextSidebarWidth(data.config.console?.context_sidebar_width))
|
||||
setDiffStyle(normalizeConsoleDiffStyle(data.config.console?.diff_style))
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const next = search().get("server")
|
||||
if (next && next !== url()) setUrl(next)
|
||||
})
|
||||
|
||||
// Reset review state when the selected worktree changes so one worktree's
|
||||
// file contents never leak into another.
|
||||
createEffect(
|
||||
on(
|
||||
() => target()?.dir,
|
||||
() => {
|
||||
setOpenFiles([])
|
||||
setDetails({})
|
||||
detailPending.clear()
|
||||
},
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(() => {
|
||||
if (!discoverable(search())) return
|
||||
void resolveServer().then((value) => {
|
||||
@@ -507,8 +663,13 @@ export function ProjectConsoleRoute() {
|
||||
onCleanup(stop)
|
||||
})
|
||||
|
||||
const updateViewport = () => setViewport(window.innerWidth)
|
||||
window.addEventListener("resize", updateViewport)
|
||||
|
||||
onCleanup(() => {
|
||||
if (events.timer) window.clearTimeout(events.timer)
|
||||
if (resize.timer) window.clearTimeout(resize.timer)
|
||||
window.removeEventListener("resize", updateViewport)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
@@ -525,7 +686,7 @@ export function ProjectConsoleRoute() {
|
||||
})
|
||||
|
||||
return (
|
||||
<section class="project-console">
|
||||
<section class="project-console" style={`--project-info-width: ${visibleInfoWidth()}px`}>
|
||||
<aside class="project-console-sidebar" aria-label="Project console sections">
|
||||
<div class="project-console-title">
|
||||
<span class="project-console-heading">
|
||||
@@ -734,52 +895,87 @@ export function ProjectConsoleRoute() {
|
||||
</main>
|
||||
|
||||
<aside class="project-console-info" aria-label="Project details">
|
||||
<div class="project-info-card">
|
||||
<div class="project-panel-heading">Context</div>
|
||||
<strong>{currentLabel()}</strong>
|
||||
<code>{current()?.dir ?? snap()?.project.worktree ?? project()}</code>
|
||||
<ResizeHandle
|
||||
direction="horizontal"
|
||||
edge="start"
|
||||
size={visibleInfoWidth()}
|
||||
min={MIN_CONTEXT_SIDEBAR_WIDTH}
|
||||
max={maxInfoWidth()}
|
||||
aria-label="Resize project context sidebar"
|
||||
onResize={resizeInfo}
|
||||
/>
|
||||
<div class="project-info-card project-info-context">
|
||||
<div class="project-info-context-head">
|
||||
<span class="project-panel-heading">Context</span>
|
||||
<Badge variant="outline">{current()?.kind === "worktree" ? "Worktree" : "Local"}</Badge>
|
||||
</div>
|
||||
<strong class="project-info-title">{currentLabel()}</strong>
|
||||
<code class="project-info-path" title={current()?.dir}>
|
||||
{current()?.dir ?? snap()?.project.worktree ?? project()}
|
||||
</code>
|
||||
<Show when={current()?.kind === "worktree"}>
|
||||
<div class="project-info-actions">
|
||||
<button type="button" onClick={resetSelected} disabled={!!saving()}>
|
||||
<Button variant="secondary" size="small" onClick={resetSelected} disabled={!!saving()}>
|
||||
Reset
|
||||
</button>
|
||||
<button type="button" onClick={removeSelected} disabled={!!saving()}>
|
||||
Remove
|
||||
</button>
|
||||
</Button>
|
||||
<Button variant="destructive" size="small" onClick={removeSelected} disabled={!!saving()}>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<div class="project-info-card grow">
|
||||
<div class="project-panel-heading">Changes</div>
|
||||
<Show when={diffs.loading && !diffs()}>
|
||||
<p class="empty">Loading diff...</p>
|
||||
<div class="project-info-review">
|
||||
<Show
|
||||
when={!diffs.error}
|
||||
fallback={<div class="project-review-state project-review-state-error">{errMsg(diffs.error)}</div>}
|
||||
>
|
||||
<Show
|
||||
when={!(diffs.loading && !diffs())}
|
||||
fallback={
|
||||
<div class="project-review-state">
|
||||
<Spinner />
|
||||
<span>Loading changes…</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<FileComponentProvider component={File}>
|
||||
<SessionReview
|
||||
diffs={reviewDiffs()}
|
||||
title={<span>Changes</span>}
|
||||
diffStyle={diffStyle()}
|
||||
onDiffStyleChange={changeDiffStyle}
|
||||
open={openFiles()}
|
||||
onOpenChange={openReviewFiles}
|
||||
empty={<div class="project-review-empty">No changes detected.</div>}
|
||||
/>
|
||||
</FileComponentProvider>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={diffs.error}>
|
||||
<p class="empty">{errMsg(diffs.error)}</p>
|
||||
</Show>
|
||||
<Show when={!diffs.loading && (diffs() ?? []).length === 0 && !diffs.error}>
|
||||
<p class="empty">No changes detected.</p>
|
||||
</Show>
|
||||
<div class="project-diff-list">
|
||||
<For each={diffs() ?? []}>
|
||||
{(item) => (
|
||||
<button
|
||||
type="button"
|
||||
class="project-diff-row"
|
||||
classList={{ active: file() === item.file }}
|
||||
onClick={() => setFile(item.file)}
|
||||
>
|
||||
<span>{item.file}</span>
|
||||
<small>
|
||||
+{item.additions} -{item.deletions}
|
||||
</small>
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<Show when={detail()}>{(item) => <pre class="project-diff-detail">{item()?.patch ?? ""}</pre>}</Show>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<PromptDialog
|
||||
open={Boolean(editor())}
|
||||
title={editorTitle()}
|
||||
message={editorMessage()}
|
||||
label="Worktree name"
|
||||
value={editor()?.value ?? ""}
|
||||
placeholder="feature-name"
|
||||
confirm={editor()?.kind === "rename" ? "Save" : "Create"}
|
||||
busy={Boolean(saving())}
|
||||
onInput={updateEditor}
|
||||
onCancel={() => setEditor(undefined)}
|
||||
onConfirm={submitEditor}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
open={Boolean(pending())}
|
||||
title={pendingTitle()}
|
||||
message={pendingMessage()}
|
||||
confirm={pending()?.kind === "reset" ? "Reset" : "Delete"}
|
||||
busy={Boolean(saving())}
|
||||
onCancel={() => setPending(undefined)}
|
||||
onConfirm={confirmWorktree}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,20 @@
|
||||
background: var(--card);
|
||||
}
|
||||
|
||||
.kilo-console .ui-card:has(.console-diff-select[open]) {
|
||||
position: relative;
|
||||
z-index: 40;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.kilo-console .console-diff-select[open] {
|
||||
z-index: 41;
|
||||
}
|
||||
|
||||
.kilo-console .console-diff-select .models-select-menu {
|
||||
z-index: 42;
|
||||
}
|
||||
|
||||
.kilo-console .ui-card-header,
|
||||
.kilo-console .ui-card-footer {
|
||||
display: flex;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
.kilo-console .project-console {
|
||||
display: grid;
|
||||
grid-template-columns: 13.75rem minmax(24rem, 1fr) minmax(16rem, 22rem);
|
||||
grid-template-columns:
|
||||
13.75rem minmax(24rem, 1fr)
|
||||
clamp(250px, var(--project-info-width, 300px), min(800px, calc(100vw - 37.75rem)));
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
@@ -280,8 +282,7 @@
|
||||
|
||||
.kilo-console .project-context span,
|
||||
.kilo-console .project-terminal-row span,
|
||||
.kilo-console .project-settings-link span,
|
||||
.kilo-console .project-diff-row span {
|
||||
.kilo-console .project-settings-link span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -340,14 +341,6 @@
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
|
||||
.kilo-console .project-diff-row small {
|
||||
overflow: hidden;
|
||||
color: var(--muted-foreground);
|
||||
font-size: 0.6875rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.kilo-console .project-sidebar-bottom {
|
||||
flex: 0 0 auto;
|
||||
border-top: 1px solid var(--border);
|
||||
@@ -460,27 +453,40 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-left: 1px solid var(--border);
|
||||
background: var(--background);
|
||||
padding: clamp(1rem, 2.4vw, 2rem) clamp(0.875rem, 1.8vw, 1.25rem);
|
||||
padding: 0.875rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-console-info > [data-component="resize-handle"]::after {
|
||||
background: var(--ring);
|
||||
}
|
||||
|
||||
.kilo-console .project-info-card {
|
||||
display: grid;
|
||||
gap: 0.625rem;
|
||||
min-height: 0;
|
||||
gap: 0.5rem;
|
||||
flex: 0 0 auto;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: color-mix(in oklab, var(--muted) 30%, transparent);
|
||||
background: var(--card);
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-card.grow {
|
||||
overflow: auto;
|
||||
.kilo-console .project-info-context-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-card strong {
|
||||
.kilo-console .project-info-context-head .project-panel-heading {
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-title {
|
||||
overflow: hidden;
|
||||
color: var(--foreground);
|
||||
font-size: 0.875rem;
|
||||
@@ -489,7 +495,7 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-card code {
|
||||
.kilo-console .project-info-path {
|
||||
overflow: hidden;
|
||||
color: var(--muted-foreground);
|
||||
font-family: var(--font-family-mono, monospace);
|
||||
@@ -502,64 +508,81 @@
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.125rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-actions button,
|
||||
.kilo-console .project-diff-row {
|
||||
.kilo-console .project-info-actions [data-component="button"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Rich review panel — fills remaining height; SessionReview scrolls internally. */
|
||||
.kilo-console .project-info-review {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--input-base);
|
||||
color: var(--foreground);
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
padding: 0.5rem 0.625rem;
|
||||
text-align: left;
|
||||
background: var(--card);
|
||||
}
|
||||
|
||||
.kilo-console .project-info-actions button:hover,
|
||||
.kilo-console .project-info-actions button:focus-visible,
|
||||
.kilo-console .project-diff-row:hover,
|
||||
.kilo-console .project-diff-row:focus-visible,
|
||||
.kilo-console .project-diff-row.active {
|
||||
border-color: var(--ring);
|
||||
outline: 0;
|
||||
.kilo-console .project-info-review [data-component="session-review"] {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-actions button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.kilo-console .project-diff-list {
|
||||
display: grid;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-diff-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 0.125rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-diff-row.active {
|
||||
background: color-mix(in oklab, var(--muted) 55%, transparent);
|
||||
}
|
||||
|
||||
.kilo-console .project-diff-detail {
|
||||
overflow: auto;
|
||||
max-height: 18rem;
|
||||
margin: 0.5rem 0 0;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--background-base);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-family-mono, monospace);
|
||||
font-size: 0.6875rem;
|
||||
line-height: 1.4;
|
||||
.kilo-console .project-info-review [data-slot="session-review-header"] {
|
||||
box-sizing: border-box;
|
||||
height: auto;
|
||||
min-height: 2.5rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-review [data-slot="session-review-title"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
min-height: 1.25rem;
|
||||
color: var(--text-weaker);
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: 0.625rem;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.kilo-console .project-info-review [data-slot="session-review-actions"] > [data-component="button"] {
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
height: 1.5rem;
|
||||
gap: 0.25rem;
|
||||
padding: 0 0.375rem;
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-review-state,
|
||||
.kilo-console .project-review-empty {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
min-height: 0;
|
||||
color: var(--muted-foreground);
|
||||
font-size: 0.75rem;
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.kilo-console .project-review-state-error {
|
||||
color: var(--destructive, #ef4444);
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.kilo-console .project-console {
|
||||
grid-template-columns: 13.75rem minmax(0, 1fr);
|
||||
|
||||
@@ -408,7 +408,7 @@
|
||||
}
|
||||
|
||||
.kilo-console .confirm-dialog {
|
||||
width: min(48rem, 100%);
|
||||
width: min(28rem, 100%);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border-radius: var(--radius-lg);
|
||||
@@ -435,16 +435,21 @@
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.kilo-console .confirm-body h2 {
|
||||
.kilo-console .confirm-body h2,
|
||||
.kilo-console .prompt-copy h2 {
|
||||
margin: 0;
|
||||
color: var(--text-strong);
|
||||
font-size: clamp(1.15rem, 2vw, 1.35rem);
|
||||
line-height: 1.35;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.kilo-console .confirm-body p {
|
||||
.kilo-console .confirm-body p,
|
||||
.kilo-console .prompt-copy p {
|
||||
margin: 0.5rem 0 0;
|
||||
color: var(--text-weak);
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.625;
|
||||
}
|
||||
|
||||
.kilo-console .confirm-actions {
|
||||
@@ -455,3 +460,25 @@
|
||||
background: color-mix(in srgb, var(--background-base) 65%, transparent);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.kilo-console .prompt-form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.kilo-console .prompt-body {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.kilo-console .prompt-field {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
color: var(--text-strong);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.kilo-console .prompt-field input {
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-docs",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --webpack --port 3002",
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fc50e7ce14bc197134d5fdf38ac92087940906f7b627e2507c082a5be0527d31
|
||||
size 17378
|
||||
oid sha256:129ea4c06998d8418bdb8edc8e61e094849835edb3f40cf6e1ddc34568168e61
|
||||
size 52396
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3838b7760984c6c822078de1bdb74067839775d29ab8a0435626d0afff8cbb30
|
||||
size 24826
|
||||
oid sha256:1bd31cd4e01c2e2a5ed579bce1b542368e7a11fc878d375a93fb238ba4f82469
|
||||
size 53288
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f5e9dd9a8b232e960fbc1925a2447a7634b2db241f6fe9b9ba8527665a5ca4c4
|
||||
size 14248
|
||||
oid sha256:47b7b7bfb4a6b5631d8fdb808c1b3a9eb631b6f96911ddf15880f0c2fee4f7e0
|
||||
size 38558
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fbaee116f80051c31aa2b17eacca856c173c843b66c015ad8129aba83b4d29ad
|
||||
size 27563
|
||||
oid sha256:16c736bff5fba46d9e7d88e852ad70f96e37ad000280b03cb393da9c970e2ae9
|
||||
size 1415
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fbaee116f80051c31aa2b17eacca856c173c843b66c015ad8129aba83b4d29ad
|
||||
size 27563
|
||||
oid sha256:288e4d74c5e74773cea45e3b7cb428903ace337f9d27a3506c9ba193fe291b86
|
||||
size 3041
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2ae8197b9d63cf977fa5112a1b02eb48bc22a1577b4dee15abd475805f0db5b0
|
||||
size 11769
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b70543ee69296913543f8de0f1b1d4787fb6be8a9e410423073b0a84a6da6305
|
||||
size 21290
|
||||
oid sha256:fe0ed476823eb03bc50fec4e9cdb656552aab3b07ee6ed3c30265ed41f0bfda0
|
||||
size 21344
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:001db2cec148c97a321076e45ec4478beced1bd18f0f4347927419d7194d6a43
|
||||
size 31986
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e3f86dabc39700b3a86508c1e6499a546eeabf720832b62c9ce12f2d97378ebd
|
||||
size 34649
|
||||
@@ -61,6 +61,8 @@
|
||||
<!-- packages/opencode/src/provider/transform.ts -->
|
||||
- <https://git-scm.com>
|
||||
<!-- packages/kilo-vscode/src/agent-manager/WorktreeManager.ts -->
|
||||
- <https://github.com>
|
||||
<!-- packages/opencode/src/kilocode/security/github.ts -->
|
||||
- <https://github.com/apps/kiloconnect>
|
||||
<!-- packages/opencode/src/cli/cmd/github.ts -->
|
||||
- <https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/utils/overflow.ts>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-i18n",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Kilo-specific i18n translations and overrides",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-indexing",
|
||||
"version": "7.3.42",
|
||||
"version": "7.3.45",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Standalone indexing engine and host helpers for Kilo Code",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 7.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#11165](https://github.com/Kilo-Org/kilocode/pull/11165) [`bf67155`](https://github.com/Kilo-Org/kilocode/commit/bf6715594bae4a1160abb7cfdfdedaba4b8358ec) - Enhance draft prompts from the JetBrains chat composer using the configured small model.
|
||||
|
||||
## 7.3.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+44
@@ -19,10 +19,18 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
/**
|
||||
* Chat orchestrator that handles message sending, history loading,
|
||||
@@ -39,6 +47,7 @@ class KiloBackendChatManager(
|
||||
) {
|
||||
companion object {
|
||||
private val JSON_TYPE = "application/json".toMediaType()
|
||||
private const val ENHANCE_TIMEOUT_MINUTES = 2L
|
||||
|
||||
private val CHAT_EVENTS = setOf(
|
||||
"message.updated",
|
||||
@@ -107,6 +116,28 @@ class KiloBackendChatManager(
|
||||
|
||||
// ------ prompt ------
|
||||
|
||||
suspend fun enhancePrompt(dir: String, text: String): String {
|
||||
val http = requireClient()
|
||||
val url = requireBase()
|
||||
val body = KiloCliDataParser.buildEnhancePromptJson(text)
|
||||
val request = Request.Builder()
|
||||
.url("$url/enhance-prompt?directory=${encode(dir)}")
|
||||
.post(body.toRequestBody(JSON_TYPE))
|
||||
.build()
|
||||
val call = http.newCall(request)
|
||||
call.timeout().timeout(ENHANCE_TIMEOUT_MINUTES, TimeUnit.MINUTES)
|
||||
|
||||
return call.await().use { response ->
|
||||
val raw = response.body?.string().orEmpty()
|
||||
if (!response.isSuccessful) {
|
||||
log.warn("enhance prompt failed: HTTP ${response.code}")
|
||||
raw.takeIf { it.isNotBlank() }?.let { log.debug { "kind=enhancePrompt error=${ChatLogSummary.body(it)}" } }
|
||||
throw RuntimeException("Enhance prompt failed: HTTP ${response.code}")
|
||||
}
|
||||
KiloCliDataParser.parseEnhancedPrompt(raw)
|
||||
}
|
||||
}
|
||||
|
||||
fun prompt(id: String, dir: String, prompt: PromptDto) {
|
||||
val meta = if (log.isDebugEnabled) {
|
||||
"${ChatLogSummary.dir(dir)} ${ChatLogSummary.prompt(prompt)}"
|
||||
@@ -324,6 +355,19 @@ class KiloBackendChatManager(
|
||||
private fun requireBase(): String =
|
||||
base ?: throw IllegalStateException("Chat manager not started")
|
||||
|
||||
private suspend fun Call.await(): Response = suspendCancellableCoroutine { cont ->
|
||||
cont.invokeOnCancellation { cancel() }
|
||||
enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
if (!cont.isCancelled) cont.resumeWithException(e)
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
cont.resume(response) { _, value, _ -> value.close() }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun encode(value: String): String =
|
||||
java.net.URLEncoder.encode(value, "UTF-8")
|
||||
}
|
||||
|
||||
+7
@@ -365,6 +365,13 @@ object KiloCliDataParser {
|
||||
// JSON serialization (DTO → JSON for outgoing requests)
|
||||
// ================================================================
|
||||
|
||||
fun parseEnhancedPrompt(raw: String): String =
|
||||
tryParseObject(raw)?.str("text")
|
||||
?: throw IllegalArgumentException("Enhance prompt response is missing text")
|
||||
|
||||
fun buildEnhancePromptJson(text: String): String =
|
||||
"""{"text":${escape(text)}}"""
|
||||
|
||||
/**
|
||||
* Build the JSON body for `POST /session/{id}/prompt_async`.
|
||||
*/
|
||||
|
||||
+3
@@ -100,6 +100,9 @@ class KiloSessionRpcApiImpl : KiloSessionRpcApi {
|
||||
|
||||
// ------ chat ------
|
||||
|
||||
override suspend fun enhancePrompt(directory: String, text: String): String =
|
||||
ready { chat.enhancePrompt(directory, text) }
|
||||
|
||||
override suspend fun prompt(id: String, directory: String, prompt: PromptDto) {
|
||||
app.requireReady()
|
||||
LOG.info("prompt RPC: session=$id, dir=$directory, parts=${prompt.parts.size}")
|
||||
|
||||
+51
@@ -6,12 +6,17 @@ import ai.kilocode.rpc.dto.ModelSelectionDto
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@@ -39,4 +44,50 @@ class KiloBackendChatManagerTest {
|
||||
assertTrue(mock.lastSummarizePath!!.startsWith("/session/ses_abc/summarize?directory="))
|
||||
assertEquals("""{"providerID":"anthropic","modelID":"claude-4"}""", mock.lastSummarizeBody)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `enhance prompt posts scoped request and returns rewritten text`() = runBlocking {
|
||||
val port = mock.start()
|
||||
val chat = KiloBackendChatManager(scope, TestLog())
|
||||
chat.start(OkHttpClient(), port, MutableSharedFlow())
|
||||
mock.enhanced = """{"text":"Use a focused implementation plan"}"""
|
||||
|
||||
val result = chat.enhancePrompt("/test/project", "make a plan")
|
||||
|
||||
assertEquals("Use a focused implementation plan", result)
|
||||
assertEquals(1, mock.requestCount("/enhance-prompt"))
|
||||
assertTrue(mock.lastEnhancePath!!.startsWith("/enhance-prompt?directory="))
|
||||
assertEquals("""{"text":"make a plan"}""", mock.lastEnhanceBody)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `enhance prompt hides provider response details`() = runBlocking {
|
||||
val port = mock.start()
|
||||
val chat = KiloBackendChatManager(scope, TestLog())
|
||||
chat.start(OkHttpClient(), port, MutableSharedFlow())
|
||||
mock.enhanceStatus = 500
|
||||
mock.enhanced = """{"error":"provider unavailable"}"""
|
||||
|
||||
val error = assertFailsWith<RuntimeException> {
|
||||
chat.enhancePrompt("/test/project", "make a plan")
|
||||
}
|
||||
|
||||
assertEquals("Enhance prompt failed: HTTP 500", error.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `enhance prompt cancels the HTTP request with its coroutine`() = runBlocking {
|
||||
val port = mock.start()
|
||||
val chat = KiloBackendChatManager(scope, TestLog())
|
||||
chat.start(OkHttpClient(), port, MutableSharedFlow())
|
||||
val gate = CountDownLatch(1)
|
||||
mock.responseGate = gate
|
||||
val request = async(Dispatchers.Default) { chat.enhancePrompt("/test/project", "make a plan") }
|
||||
assertTrue(mock.awaitRequestCount("/enhance-prompt", 1))
|
||||
|
||||
request.cancelAndJoin()
|
||||
gate.countDown()
|
||||
|
||||
assertTrue(request.isCancelled)
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -82,6 +82,10 @@ class MockCliServer : AutoCloseable {
|
||||
@Volatile var summarizeStatus = 200
|
||||
@Volatile var lastSummarizePath: String? = null
|
||||
@Volatile var lastSummarizeBody: String? = null
|
||||
@Volatile var enhanced = """{"text":"Enhanced prompt"}"""
|
||||
@Volatile var enhanceStatus = 200
|
||||
@Volatile var lastEnhancePath: String? = null
|
||||
@Volatile var lastEnhanceBody: String? = null
|
||||
@Volatile var sessionRenameStatus = 200
|
||||
@Volatile var sessionRenameResponse = """{"id":"ses_test","slug":"test","projectID":"prj_test","directory":"/test","title":"Renamed","version":"1.0.0","time":{"created":1000,"updated":2000}}"""
|
||||
@Volatile var lastSessionRenamePath: String? = null
|
||||
@@ -325,6 +329,11 @@ class MockCliServer : AutoCloseable {
|
||||
lastSummarizeBody = body
|
||||
respond(output, summarizeStatus, summarizeResponse)
|
||||
}
|
||||
bare == "/enhance-prompt" && method == "POST" -> {
|
||||
lastEnhancePath = path
|
||||
lastEnhanceBody = body
|
||||
respond(output, enhanceStatus, enhanced)
|
||||
}
|
||||
else -> respond(output, 404, """{"error":"Not found"}""")
|
||||
}
|
||||
} catch (_: SocketException) {
|
||||
|
||||
+5
@@ -3,6 +3,7 @@ package ai.kilocode.client
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationGroupManager
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
|
||||
object KiloNotifications {
|
||||
@@ -10,6 +11,10 @@ object KiloNotifications {
|
||||
|
||||
fun error(title: String, content: String? = null) {
|
||||
val project = ProjectManager.getInstance().openProjects.firstOrNull { !it.isDefault }
|
||||
error(project, title, content)
|
||||
}
|
||||
|
||||
fun error(project: Project?, title: String, content: String? = null) {
|
||||
val notification = NotificationGroupManager.getInstance()
|
||||
.getNotificationGroup(GROUP)
|
||||
?.createNotification(title, content ?: "", NotificationType.ERROR)
|
||||
|
||||
+3
@@ -155,6 +155,9 @@ class KiloSessionService internal constructor(
|
||||
|
||||
// ------ Chat ops (explicit session ID) ------
|
||||
|
||||
suspend fun enhancePrompt(dir: String, text: String): String =
|
||||
call { enhancePrompt(dir, text) }
|
||||
|
||||
/** Send a prompt to a session. */
|
||||
suspend fun prompt(id: String, dir: String, dto: PromptDto) {
|
||||
val meta = if (LOG.isDebugEnabled) {
|
||||
|
||||
+1
@@ -308,6 +308,7 @@ class SessionUi(
|
||||
project = project,
|
||||
onSend = { text -> sendPrompt(text) },
|
||||
onAbort = { controller.abort() },
|
||||
onEnhance = controller::enhancePrompt,
|
||||
)
|
||||
|
||||
sessionContent.add(header, BorderLayout.NORTH)
|
||||
|
||||
+40
-1
@@ -51,6 +51,7 @@ import ai.kilocode.log.ChatLogSummary
|
||||
import ai.kilocode.log.KiloLog
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
@@ -124,6 +125,8 @@ class SessionController(
|
||||
) { sid ?: ref?.key ?: "pending" }
|
||||
|
||||
private var disposed = false
|
||||
private var enhancement = 0L
|
||||
private val enhancements = mutableMapOf<Long, (Result<String>) -> Unit>()
|
||||
private var partType: String? = null
|
||||
private var tool: String? = null
|
||||
private var eventJob: Job? = null
|
||||
@@ -195,6 +198,37 @@ class SessionController(
|
||||
updates.requestFlush(true)
|
||||
}
|
||||
|
||||
fun enhancePrompt(text: String, complete: (Result<String>) -> Unit) {
|
||||
assertEdt()
|
||||
if (disposed) {
|
||||
complete(Result.failure(CancellationException("Session controller disposed")))
|
||||
return
|
||||
}
|
||||
val id = ++enhancement
|
||||
enhancements[id] = complete
|
||||
capture("Prompt Enhance Clicked", mapOf("textLength" to bucket(text)))
|
||||
cs.launch {
|
||||
val result = try {
|
||||
Result.success(sessions.enhancePrompt(directory, text))
|
||||
} catch (e: CancellationException) {
|
||||
Result.failure(e)
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
edt {
|
||||
val callback = enhancements.remove(id) ?: return@edt
|
||||
result.onSuccess {
|
||||
capture("Prompt Enhanced", mapOf("textLength" to bucket(text)))
|
||||
}.onFailure { e ->
|
||||
if (e !is CancellationException) {
|
||||
capture("Session Error", mapOf("context" to "enhance-prompt", "errorClass" to e::class.java.name))
|
||||
}
|
||||
}
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun prompt(text: String) {
|
||||
assertEdt()
|
||||
val start = sid ?: ref?.key ?: "pending"
|
||||
@@ -1716,13 +1750,18 @@ class SessionController(
|
||||
|
||||
override fun dispose() {
|
||||
runEdt {
|
||||
if (disposed) return@runEdt
|
||||
disposed = true
|
||||
connectionDelay.dispose()
|
||||
cancelSubscriptions()
|
||||
drainJob?.cancel()
|
||||
drainJob = null
|
||||
val callbacks = enhancements.values.toList()
|
||||
enhancements.clear()
|
||||
cs.cancel()
|
||||
val result = Result.failure<String>(CancellationException("Session controller disposed"))
|
||||
callbacks.forEach { it(result) }
|
||||
}
|
||||
cs.cancel()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
+72
@@ -1,5 +1,6 @@
|
||||
package ai.kilocode.client.session.ui.prompt
|
||||
|
||||
import ai.kilocode.client.KiloNotifications
|
||||
import ai.kilocode.client.actions.SendPromptAction
|
||||
import ai.kilocode.client.actions.StopSessionAction
|
||||
import ai.kilocode.client.plugin.KiloBundle
|
||||
@@ -33,6 +34,7 @@ import com.intellij.openapi.keymap.KeymapManagerListener
|
||||
import com.intellij.openapi.keymap.KeymapUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.IconLoader
|
||||
import com.intellij.ui.AnimatedIcon
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import com.intellij.xml.util.XmlStringUtil
|
||||
import com.intellij.util.ui.JBValue
|
||||
@@ -41,6 +43,7 @@ import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
import com.intellij.util.messages.MessageBusConnection
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Cursor
|
||||
import java.awt.Graphics
|
||||
@@ -65,6 +68,7 @@ class PromptPanel(
|
||||
private val project: Project,
|
||||
private val onSend: (String) -> Unit,
|
||||
private val onAbort: () -> Unit,
|
||||
private val onEnhance: (String, (Result<String>) -> Unit) -> Unit,
|
||||
) : BorderLayoutPanel(), SessionEditorStyleTarget, SendPromptContext {
|
||||
|
||||
companion object {
|
||||
@@ -73,6 +77,7 @@ class PromptPanel(
|
||||
private val STOP_ICON: Icon = IconLoader.getIcon("/icons/stop.svg", PromptPanel::class.java)
|
||||
private val SHIELD_ICON: Icon = IconLoader.getIcon("/icons/shield.svg", PromptPanel::class.java)
|
||||
private val SHIELD_FILLED_ICON: Icon = IconLoader.getIcon("/icons/shield-filled.svg", PromptPanel::class.java)
|
||||
private val WAND_ICON: Icon = IconLoader.getIcon("/icons/wand-sparkles.svg", PromptPanel::class.java)
|
||||
}
|
||||
|
||||
val mode = ModePicker()
|
||||
@@ -146,9 +151,19 @@ class PromptPanel(
|
||||
addActionListener { onAutoApproveToggle(!autoApprove) }
|
||||
}
|
||||
|
||||
private val enhancingIcon = AnimatedIcon.Default()
|
||||
private val enhance = HoverIcon().apply {
|
||||
icon = WAND_ICON
|
||||
toolTipText = KiloBundle.message("prompt.action.enhance")
|
||||
accessibleContext.accessibleName = KiloBundle.message("prompt.action.enhance")
|
||||
addActionListener { enhance() }
|
||||
}
|
||||
|
||||
@Volatile
|
||||
private var busy = false
|
||||
private var ready = false
|
||||
private var enhancing = false
|
||||
private var request = 0L
|
||||
|
||||
override val isSendEnabled: Boolean
|
||||
get() = ready && !busy && text().isNotEmpty()
|
||||
@@ -171,6 +186,7 @@ class PromptPanel(
|
||||
editor.text = ""
|
||||
editor.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(e: DocumentEvent) {
|
||||
invalidateEnhancement()
|
||||
syncEditorHeight()
|
||||
onChange()
|
||||
}
|
||||
@@ -192,21 +208,26 @@ class PromptPanel(
|
||||
bar.add(Box.createHorizontalGlue())
|
||||
bar.add(auto)
|
||||
bar.add(Box.createHorizontalStrut(JBUI.scale(SessionUiStyle.View.Prompt.CONTROL_GAP)))
|
||||
bar.add(enhance)
|
||||
bar.add(Box.createHorizontalStrut(JBUI.scale(SessionUiStyle.View.Prompt.CONTROL_GAP)))
|
||||
bar.add(button)
|
||||
shell.add(bar, BorderLayout.SOUTH)
|
||||
add(shell, BorderLayout.CENTER)
|
||||
syncTooltip()
|
||||
syncAutoApprove()
|
||||
syncEnhance()
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
fun setReady(value: Boolean) {
|
||||
ready = value
|
||||
if (!value) invalidateEnhancement() else syncEnhance()
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
fun setBusy(value: Boolean) {
|
||||
busy = value
|
||||
if (value) invalidateEnhancement() else syncEnhance()
|
||||
button.icon = if (value) STOP_ICON else SEND_ICON
|
||||
syncTooltip()
|
||||
}
|
||||
@@ -283,6 +304,57 @@ class PromptPanel(
|
||||
super.removeNotify()
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private fun enhance() {
|
||||
if (!enhance.isEnabled) return
|
||||
val source = editor.text
|
||||
if (source.isBlank()) {
|
||||
editor.text = KiloBundle.message("prompt.action.enhance.description")
|
||||
focus()
|
||||
return
|
||||
}
|
||||
val id = ++request
|
||||
enhancing = true
|
||||
syncEnhance()
|
||||
onEnhance(source.trim()) { result -> completeEnhancement(id, source, result) }
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private fun completeEnhancement(id: Long, source: String, result: Result<String>) {
|
||||
if (id != request || editor.text != source) return
|
||||
enhancing = false
|
||||
syncEnhance()
|
||||
result.onSuccess {
|
||||
editor.text = it
|
||||
focus()
|
||||
}.onFailure {
|
||||
if (it is CancellationException) return@onFailure
|
||||
KiloNotifications.error(
|
||||
project,
|
||||
KiloBundle.message("prompt.action.enhance.failed"),
|
||||
KiloBundle.message("prompt.action.enhance.failed.description"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private fun invalidateEnhancement() {
|
||||
request++
|
||||
enhancing = false
|
||||
syncEnhance()
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private fun syncEnhance() {
|
||||
enhance.isEnabled = ready && !busy && !enhancing
|
||||
enhance.icon = if (enhancing) enhancingIcon else WAND_ICON
|
||||
enhance.toolTipText = if (enhancing) {
|
||||
KiloBundle.message("prompt.action.enhance.loading")
|
||||
} else {
|
||||
KiloBundle.message("prompt.action.enhance")
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private fun submit(src: String) {
|
||||
if (!isSendEnabled) return
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 21L14 10M15 4V2M15 16V14M8 9H10M20 9H22M17.8 11.8L19 13M17.8 6.2L19 5M12.2 6.2L11 5" stroke="#6C707E" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 287 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 21L14 10M15 4V2M15 16V14M8 9H10M20 9H22M17.8 11.8L19 13M17.8 6.2L19 5M12.2 6.2L11 5" stroke="#CED0D6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 287 B |
@@ -135,6 +135,11 @@ prompt.placeholder.with.newline=Type a message... ({0} for new line)
|
||||
prompt.button.send=Send
|
||||
prompt.button.stop=Stop
|
||||
prompt.button.send.tooltip.stop=To stop, press {0}
|
||||
prompt.action.enhance=Enhance prompt
|
||||
prompt.action.enhance.loading=Enhancing prompt...
|
||||
prompt.action.enhance.description=The 'Enhance Prompt' button helps improve your prompt by providing additional context, clarification, or rephrasing. Try typing a prompt in here and clicking the button again to see how it works.
|
||||
prompt.action.enhance.failed=Failed to enhance prompt
|
||||
prompt.action.enhance.failed.description=The configured small model could not enhance this prompt.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -207,7 +212,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=The lightweight model used for prompt enhancement, title generation, and other quick tasks.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=تحسين الطلب
|
||||
prompt.action.enhance.loading=جارٍ تحسين الطلب...
|
||||
prompt.action.enhance.description=يساعد زر 'تحسين الطلب' في تحسين طلبك بإضافة سياق أو توضيحات أو إعادة صياغة. جرّب كتابة طلب هنا، ثم انقر على الزر مرة أخرى لترى كيف يعمل.
|
||||
prompt.action.enhance.failed=فشل تحسين الطلب
|
||||
prompt.action.enhance.failed.description=تعذّر على النموذج الصغير الذي تم إعداده تحسين هذا الطلب.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=النموذج الخفيف المستخدم لتحسين الطلبات وإنشاء العناوين وغيرها من المهام السريعة.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=Poboljšaj upit
|
||||
prompt.action.enhance.loading=Poboljšavanje upita...
|
||||
prompt.action.enhance.description=Dugme 'Poboljšaj upit' pomaže vam da poboljšate upit dodavanjem dodatnog konteksta, pojašnjenja ili preformulacije. Unesite upit ovdje i ponovo kliknite na dugme da vidite kako funkcioniše.
|
||||
prompt.action.enhance.failed=Poboljšavanje upita nije uspjelo
|
||||
prompt.action.enhance.failed.description=Konfigurisani mali model nije uspio poboljšati ovaj upit.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Lagani model koji se koristi za poboljšavanje upita, generisanje naslova i druge brze zadatke.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=Forbedr prompt
|
||||
prompt.action.enhance.loading=Forbedrer prompt...
|
||||
prompt.action.enhance.description=Knappen 'Forbedr prompt' hjælper med at forbedre din prompt ved at tilføje ekstra kontekst, præciseringer eller omformuleringer. Prøv at skrive en prompt her og klikke på knappen igen for at se, hvordan det fungerer.
|
||||
prompt.action.enhance.failed=Kunne ikke forbedre prompten
|
||||
prompt.action.enhance.failed.description=Den konfigurerede lille model kunne ikke forbedre denne prompt.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Den lette model, der bruges til at forbedre prompts, generere titler og udføre andre hurtige opgaver.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -213,6 +213,11 @@ prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
prompt.action.autoApprove.disabled.tooltip=Auto-approve is disabled. Click to approve permission prompts automatically.
|
||||
prompt.action.enhance=Prompt verbessern
|
||||
prompt.action.enhance.loading=Prompt wird verbessert...
|
||||
prompt.action.enhance.description=Die Schaltfläche „Prompt verbessern“ hilft Ihnen, Ihren Prompt durch zusätzlichen Kontext, Klarstellungen oder Umformulierungen zu verbessern. Geben Sie hier einen Prompt ein und klicken Sie erneut auf die Schaltfläche, um zu sehen, wie sie funktioniert.
|
||||
prompt.action.enhance.failed=Prompt konnte nicht verbessert werden
|
||||
prompt.action.enhance.failed.description=Das konfigurierte kleine Modell konnte diesen Prompt nicht verbessern.
|
||||
model.picker.dataCollected=Daten können für das Training verwendet werden
|
||||
model.picker.dataCollected.current=Das aktuell ausgewählte Modell kann für das Training verwendet werden
|
||||
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Das leichtgewichtige Modell, das zur Verbesserung von Prompts, zur Titelgenerierung und für andere schnelle Aufgaben verwendet wird.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -213,6 +213,11 @@ prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
prompt.action.autoApprove.disabled.tooltip=Auto-approve is disabled. Click to approve permission prompts automatically.
|
||||
prompt.action.enhance=Mejorar mensaje
|
||||
prompt.action.enhance.loading=Mejorando mensaje...
|
||||
prompt.action.enhance.description=El botón «Mejorar mensaje» ayuda a mejorar el mensaje aportando contexto adicional, aclaraciones o una reformulación. Escribe un mensaje aquí y vuelve a hacer clic en el botón para ver cómo funciona.
|
||||
prompt.action.enhance.failed=No se pudo mejorar el mensaje
|
||||
prompt.action.enhance.failed.description=El modelo pequeño configurado no pudo mejorar este mensaje.
|
||||
model.picker.dataCollected=Los datos pueden usarse para entrenamiento
|
||||
model.picker.dataCollected.current=El modelo seleccionado actualmente puede usarse para entrenamiento
|
||||
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=El modelo ligero que se utiliza para mejorar mensajes, generar títulos y realizar otras tareas rápidas.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -213,6 +213,11 @@ prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
prompt.action.autoApprove.disabled.tooltip=Auto-approve is disabled. Click to approve permission prompts automatically.
|
||||
prompt.action.enhance=Améliorer l'invite
|
||||
prompt.action.enhance.loading=Amélioration de l'invite...
|
||||
prompt.action.enhance.description=Le bouton « Améliorer l'invite » permet d'améliorer votre invite en ajoutant du contexte, des précisions ou en la reformulant. Saisissez une invite ici, puis cliquez à nouveau sur le bouton pour voir comment il fonctionne.
|
||||
prompt.action.enhance.failed=Impossible d'améliorer l'invite
|
||||
prompt.action.enhance.failed.description=Le petit modèle configuré n'a pas pu améliorer cette invite.
|
||||
model.picker.dataCollected=Les données peuvent être utilisées pour l’entraînement
|
||||
model.picker.dataCollected.current=Le modèle actuellement sélectionné peut être utilisé pour l’entraînement
|
||||
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Le modèle léger utilisé pour améliorer les invites, générer des titres et effectuer d'autres tâches rapides.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=プロンプトを改善
|
||||
prompt.action.enhance.loading=プロンプトを改善中…
|
||||
prompt.action.enhance.description='プロンプトを改善'ボタンを使うと、コンテキストの追加、内容の明確化、言い換えによってプロンプトを改善できます。ここにプロンプトを入力し、もう一度ボタンをクリックして動作を確認してみてください。
|
||||
prompt.action.enhance.failed=プロンプトの改善に失敗しました
|
||||
prompt.action.enhance.failed.description=設定された小型モデルでは、このプロンプトを改善できませんでした。
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=プロンプトの改善やタイトル生成など、短時間で処理できるタスクに使用する軽量モデルです。
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=프롬프트 개선
|
||||
prompt.action.enhance.loading=프롬프트 개선 중…
|
||||
prompt.action.enhance.description='프롬프트 개선' 버튼을 사용하면 컨텍스트를 추가하거나 내용을 명확히 하고 표현을 다듬어 프롬프트를 개선할 수 있습니다. 여기에 프롬프트를 입력한 다음 버튼을 다시 클릭해 작동 방식을 확인해 보세요.
|
||||
prompt.action.enhance.failed=프롬프트 개선 실패
|
||||
prompt.action.enhance.failed.description=설정된 소형 모델이 이 프롬프트를 개선하지 못했습니다.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=프롬프트 개선, 제목 생성 및 빠르게 처리할 수 있는 기타 작업에 사용되는 경량 모델입니다.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=Prompt verbeteren
|
||||
prompt.action.enhance.loading=Prompt wordt verbeterd…
|
||||
prompt.action.enhance.description=Met de knop 'Prompt verbeteren' kunt u uw prompt verbeteren door extra context toe te voegen, de inhoud te verduidelijken of de tekst anders te formuleren. Typ hier een prompt en klik nogmaals op de knop om te zien hoe het werkt.
|
||||
prompt.action.enhance.failed=Prompt verbeteren is mislukt
|
||||
prompt.action.enhance.failed.description=Het geconfigureerde kleine model kon deze prompt niet verbeteren.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Het lichtgewichtmodel dat wordt gebruikt om prompts te verbeteren, titels te genereren en andere snelle taken uit te voeren.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -74,6 +74,11 @@ prompt.placeholder.with.newline=Skriv en melding… ({0} for ny linje)
|
||||
prompt.button.send=Send
|
||||
prompt.button.stop=Stopp
|
||||
prompt.button.send.tooltip.stop=Trykk {0} for å stoppe
|
||||
prompt.action.enhance=Forbedre forespørsel
|
||||
prompt.action.enhance.loading=Forbedrer forespørselen...
|
||||
prompt.action.enhance.description=Knappen 'Forbedre forespørsel' hjelper deg med å forbedre forespørselen ved å legge til mer kontekst, presiseringer eller omformuleringer. Skriv inn en forespørsel her, og klikk på knappen igjen for å se hvordan det fungerer.
|
||||
prompt.action.enhance.failed=Kunne ikke forbedre forespørselen
|
||||
prompt.action.enhance.failed.description=Den konfigurerte lille modellen kunne ikke forbedre denne forespørselen.
|
||||
mode.picker.tooltip=Velg modus
|
||||
mode.picker.deprecated=utdatert
|
||||
model.picker.tooltip=Velg modell
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Lettvektsmodellen som brukes til å forbedre forespørsler, generere titler og utføre andre raske oppgaver.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -74,6 +74,11 @@ prompt.placeholder.with.newline=Wpisz wiadomość… ({0} nowa linia)
|
||||
prompt.button.send=Wyślij
|
||||
prompt.button.stop=Zatrzymaj
|
||||
prompt.button.send.tooltip.stop=Aby zatrzymać, naciśnij {0}
|
||||
prompt.action.enhance=Ulepsz prompt
|
||||
prompt.action.enhance.loading=Ulepszanie promptu...
|
||||
prompt.action.enhance.description=Przycisk 'Ulepsz prompt' pomaga dopracować prompt, dodając kontekst, wyjaśnienia lub zmieniając jego sformułowanie. Spróbuj wpisać tutaj prompt i ponownie kliknąć przycisk, aby zobaczyć, jak to działa.
|
||||
prompt.action.enhance.failed=Nie udało się ulepszyć promptu
|
||||
prompt.action.enhance.failed.description=Skonfigurowany mały model nie mógł ulepszyć tego promptu.
|
||||
mode.picker.tooltip=Wybierz tryb
|
||||
mode.picker.deprecated=przestarzały
|
||||
model.picker.tooltip=Wybierz model
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Lekki model używany do ulepszania promptów, generowania tytułów i wykonywania innych szybkich zadań.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -74,6 +74,11 @@ prompt.placeholder.with.newline=Digite uma mensagem… ({0} para nova linha)
|
||||
prompt.button.send=Enviar
|
||||
prompt.button.stop=Parar
|
||||
prompt.button.send.tooltip.stop=Para parar, pressione {0}
|
||||
prompt.action.enhance=Melhorar prompt
|
||||
prompt.action.enhance.loading=Melhorando o prompt...
|
||||
prompt.action.enhance.description=O botão 'Melhorar prompt' ajuda a aprimorar seu prompt, fornecendo mais contexto, esclarecimentos ou reformulações. Digite um prompt aqui e clique novamente no botão para ver como funciona.
|
||||
prompt.action.enhance.failed=Falha ao melhorar o prompt
|
||||
prompt.action.enhance.failed.description=O modelo leve configurado não conseguiu melhorar este prompt.
|
||||
mode.picker.tooltip=Selecionar modo
|
||||
mode.picker.deprecated=obsoleto
|
||||
model.picker.tooltip=Selecionar modelo
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=O modelo leve usado para aprimorar prompts, gerar títulos e realizar outras tarefas rápidas.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -74,6 +74,11 @@ prompt.placeholder.with.newline=Введите сообщение… ({0} — н
|
||||
prompt.button.send=Отправить
|
||||
prompt.button.stop=Остановить
|
||||
prompt.button.send.tooltip.stop=Для остановки нажмите {0}
|
||||
prompt.action.enhance=Улучшить промпт
|
||||
prompt.action.enhance.loading=Улучшаем промпт…
|
||||
prompt.action.enhance.description=Кнопка 'Улучшить промпт' помогает улучшить ваш промпт, добавляя контекст, уточнения или переформулировки. Введите промпт и снова нажмите кнопку, чтобы увидеть, как это работает.
|
||||
prompt.action.enhance.failed=Не удалось улучшить промпт
|
||||
prompt.action.enhance.failed.description=Настроенная малая модель не смогла улучшить этот промпт.
|
||||
mode.picker.tooltip=Выбрать режим
|
||||
mode.picker.deprecated=устаревший
|
||||
model.picker.tooltip=Выбрать модель
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Лёгкая модель, используемая для улучшения промптов, создания заголовков и других быстрых задач.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -74,6 +74,11 @@ prompt.placeholder.with.newline=พิมพ์ข้อความ… ({0} ส
|
||||
prompt.button.send=ส่ง
|
||||
prompt.button.stop=หยุด
|
||||
prompt.button.send.tooltip.stop=กด {0} เพื่อหยุด
|
||||
prompt.action.enhance=ปรับปรุงพรอมต์
|
||||
prompt.action.enhance.loading=กำลังปรับปรุงพรอมต์…
|
||||
prompt.action.enhance.description=ปุ่ม 'ปรับปรุงพรอมต์' ช่วยปรับปรุงพรอมต์ของคุณโดยเพิ่มบริบท ทำให้ชัดเจนขึ้น หรือเรียบเรียงใหม่ ลองพิมพ์พรอมต์ที่นี่แล้วคลิกปุ่มอีกครั้งเพื่อดูว่าทำงานอย่างไร
|
||||
prompt.action.enhance.failed=ปรับปรุงพรอมต์ไม่สำเร็จ
|
||||
prompt.action.enhance.failed.description=โมเดลขนาดเล็กที่กำหนดค่าไว้ไม่สามารถปรับปรุงพรอมต์นี้ได้
|
||||
mode.picker.tooltip=เลือกโหมด
|
||||
mode.picker.deprecated=ล้าสมัย
|
||||
model.picker.tooltip=เลือกโมเดล
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=โมเดลน้ำหนักเบาที่ใช้สำหรับปรับปรุงพรอมต์ สร้างชื่อเรื่อง และทำงานด่วนอื่นๆ
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -74,6 +74,11 @@ prompt.placeholder.with.newline=Bir mesaj yazın… ({0} yeni satır için)
|
||||
prompt.button.send=Gönder
|
||||
prompt.button.stop=Durdur
|
||||
prompt.button.send.tooltip.stop=Durdurmak için {0} basın
|
||||
prompt.action.enhance=İstemi iyileştir
|
||||
prompt.action.enhance.loading=İstem iyileştiriliyor…
|
||||
prompt.action.enhance.description='İstemi İyileştir' düğmesi, ek bağlam, açıklama veya farklı bir ifade sunarak isteminizi iyileştirmenize yardımcı olur. Nasıl çalıştığını görmek için buraya bir istem yazıp düğmeye tekrar tıklayın.
|
||||
prompt.action.enhance.failed=İstem iyileştirilemedi
|
||||
prompt.action.enhance.failed.description=Yapılandırılan küçük model bu istemi iyileştiremedi.
|
||||
mode.picker.tooltip=Mod seç
|
||||
mode.picker.deprecated=geçersiz
|
||||
model.picker.tooltip=Model seç
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=İstem iyileştirme, başlık oluşturma ve diğer hızlı görevler için kullanılan hafif model.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=Покращити запит
|
||||
prompt.action.enhance.loading=Покращення запиту...
|
||||
prompt.action.enhance.description=Кнопка 'Покращити запит' допомагає вдосконалити ваш запит, надаючи додатковий контекст, уточнення або перефразування. Введіть запит тут і натисніть кнопку ще раз, щоб побачити, як це працює.
|
||||
prompt.action.enhance.failed=Не вдалося покращити запит
|
||||
prompt.action.enhance.failed.description=Налаштована мала модель не змогла покращити цей запит.
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=Легка модель, що використовується для покращення запитів, генерування заголовків та інших швидких завдань.
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ session.login.required.dismiss=Dismiss
|
||||
|
||||
session.header.todos.toggle=Toggle to-dos
|
||||
|
||||
prompt.action.enhance=优化提示词
|
||||
prompt.action.enhance.loading=正在优化提示词...
|
||||
prompt.action.enhance.description=“优化提示词”按钮可通过补充上下文、澄清内容或重新措辞来改进您的提示词。请在此输入提示词,然后再次点击该按钮,即可查看效果。
|
||||
prompt.action.enhance.failed=提示词优化失败
|
||||
prompt.action.enhance.failed.description=已配置的小模型无法优化此提示词。
|
||||
prompt.action.autoApprove.enable=Enable auto-approve
|
||||
prompt.action.autoApprove.disable=Disable auto-approve
|
||||
prompt.action.autoApprove.enabled.tooltip=Auto-approve is enabled. Permission prompts will be approved automatically.
|
||||
@@ -232,7 +237,7 @@ settings.login.action=Open User Profile
|
||||
settings.models.defaultModel.title=Default Model
|
||||
settings.models.defaultModel.description=The model Kilo uses when no mode-specific model is configured.
|
||||
settings.models.smallModel.title=Small Model
|
||||
settings.models.smallModel.description=The lightweight model used for tasks such as title generation.
|
||||
settings.models.smallModel.description=用于优化提示词、生成标题和执行其他快速任务的轻量级模型。
|
||||
settings.models.subagentModel.title=Subagent Model
|
||||
settings.models.subagentModel.description=The default model for task-tool subagents. If unset, subagents inherit the calling mode model.
|
||||
settings.models.subagentVariant.title=Reasoning Effort
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user