mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-29 03:44:06 +08:00
feat(vscode): add attention notifications
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Notify when sessions finish, error, or need input across the sidebar, editor tabs, and Agent Manager, with configurable system or bundled attention sounds.
|
||||
@@ -25,3 +25,6 @@ AGENTS.md
|
||||
|
||||
# Include bin/ directory for CLI binary (production)
|
||||
!bin/**
|
||||
|
||||
# Include WAV assets used by extension-host notification playback
|
||||
!audio-wav/**
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -945,44 +945,187 @@
|
||||
"kilo-code.new.notifications.agent": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show notification when agent completes a task"
|
||||
"description": "Show a notification when an agent completes a task"
|
||||
},
|
||||
"kilo-code.new.notifications.permissions": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show notification on permission requests"
|
||||
"description": "Show a notification when a permission or question needs input"
|
||||
},
|
||||
"kilo-code.new.notifications.errors": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show notification on errors"
|
||||
"description": "Show a notification when a session errors"
|
||||
},
|
||||
"kilo-code.new.sounds.playWhenFocused": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Play attention sounds when the affected session is focused"
|
||||
},
|
||||
"kilo-code.new.sounds.agent": {
|
||||
"type": "string",
|
||||
"default": "default",
|
||||
"default": "system",
|
||||
"enum": [
|
||||
"system",
|
||||
"default",
|
||||
"none"
|
||||
"none",
|
||||
"alert-01",
|
||||
"alert-02",
|
||||
"alert-03",
|
||||
"alert-04",
|
||||
"alert-05",
|
||||
"alert-06",
|
||||
"alert-07",
|
||||
"alert-08",
|
||||
"alert-09",
|
||||
"alert-10",
|
||||
"bip-bop-01",
|
||||
"bip-bop-02",
|
||||
"bip-bop-03",
|
||||
"bip-bop-04",
|
||||
"bip-bop-05",
|
||||
"bip-bop-06",
|
||||
"bip-bop-07",
|
||||
"bip-bop-08",
|
||||
"bip-bop-09",
|
||||
"bip-bop-10",
|
||||
"staplebops-01",
|
||||
"staplebops-02",
|
||||
"staplebops-03",
|
||||
"staplebops-04",
|
||||
"staplebops-05",
|
||||
"staplebops-06",
|
||||
"staplebops-07",
|
||||
"nope-01",
|
||||
"nope-02",
|
||||
"nope-03",
|
||||
"nope-04",
|
||||
"nope-05",
|
||||
"nope-06",
|
||||
"nope-07",
|
||||
"nope-08",
|
||||
"nope-09",
|
||||
"nope-10",
|
||||
"nope-11",
|
||||
"nope-12",
|
||||
"yup-01",
|
||||
"yup-02",
|
||||
"yup-03",
|
||||
"yup-04",
|
||||
"yup-05",
|
||||
"yup-06"
|
||||
],
|
||||
"description": "Sound to play when agent completes"
|
||||
"description": "Sound to play when an agent completes"
|
||||
},
|
||||
"kilo-code.new.sounds.permissions": {
|
||||
"type": "string",
|
||||
"default": "default",
|
||||
"default": "system",
|
||||
"enum": [
|
||||
"system",
|
||||
"default",
|
||||
"none"
|
||||
"none",
|
||||
"alert-01",
|
||||
"alert-02",
|
||||
"alert-03",
|
||||
"alert-04",
|
||||
"alert-05",
|
||||
"alert-06",
|
||||
"alert-07",
|
||||
"alert-08",
|
||||
"alert-09",
|
||||
"alert-10",
|
||||
"bip-bop-01",
|
||||
"bip-bop-02",
|
||||
"bip-bop-03",
|
||||
"bip-bop-04",
|
||||
"bip-bop-05",
|
||||
"bip-bop-06",
|
||||
"bip-bop-07",
|
||||
"bip-bop-08",
|
||||
"bip-bop-09",
|
||||
"bip-bop-10",
|
||||
"staplebops-01",
|
||||
"staplebops-02",
|
||||
"staplebops-03",
|
||||
"staplebops-04",
|
||||
"staplebops-05",
|
||||
"staplebops-06",
|
||||
"staplebops-07",
|
||||
"nope-01",
|
||||
"nope-02",
|
||||
"nope-03",
|
||||
"nope-04",
|
||||
"nope-05",
|
||||
"nope-06",
|
||||
"nope-07",
|
||||
"nope-08",
|
||||
"nope-09",
|
||||
"nope-10",
|
||||
"nope-11",
|
||||
"nope-12",
|
||||
"yup-01",
|
||||
"yup-02",
|
||||
"yup-03",
|
||||
"yup-04",
|
||||
"yup-05",
|
||||
"yup-06"
|
||||
],
|
||||
"description": "Sound to play on permission requests"
|
||||
"description": "Sound to play when a permission or question needs input"
|
||||
},
|
||||
"kilo-code.new.sounds.errors": {
|
||||
"type": "string",
|
||||
"default": "default",
|
||||
"default": "system",
|
||||
"enum": [
|
||||
"system",
|
||||
"default",
|
||||
"none"
|
||||
"none",
|
||||
"alert-01",
|
||||
"alert-02",
|
||||
"alert-03",
|
||||
"alert-04",
|
||||
"alert-05",
|
||||
"alert-06",
|
||||
"alert-07",
|
||||
"alert-08",
|
||||
"alert-09",
|
||||
"alert-10",
|
||||
"bip-bop-01",
|
||||
"bip-bop-02",
|
||||
"bip-bop-03",
|
||||
"bip-bop-04",
|
||||
"bip-bop-05",
|
||||
"bip-bop-06",
|
||||
"bip-bop-07",
|
||||
"bip-bop-08",
|
||||
"bip-bop-09",
|
||||
"bip-bop-10",
|
||||
"staplebops-01",
|
||||
"staplebops-02",
|
||||
"staplebops-03",
|
||||
"staplebops-04",
|
||||
"staplebops-05",
|
||||
"staplebops-06",
|
||||
"staplebops-07",
|
||||
"nope-01",
|
||||
"nope-02",
|
||||
"nope-03",
|
||||
"nope-04",
|
||||
"nope-05",
|
||||
"nope-06",
|
||||
"nope-07",
|
||||
"nope-08",
|
||||
"nope-09",
|
||||
"nope-10",
|
||||
"nope-11",
|
||||
"nope-12",
|
||||
"yup-01",
|
||||
"yup-02",
|
||||
"yup-03",
|
||||
"yup-04",
|
||||
"yup-05",
|
||||
"yup-06"
|
||||
],
|
||||
"description": "Sound to play on errors"
|
||||
"description": "Sound to play when a session errors"
|
||||
},
|
||||
"kilo-code.new.showTaskTimeline": {
|
||||
"type": "boolean",
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
Config,
|
||||
} from "@kilocode/sdk/v2/client"
|
||||
import { type KiloConnectionService, ServerStartupError } from "./services/cli-backend"
|
||||
import { previewSound } from "./services/attention"
|
||||
import type { EditorContext, IndexingStatus } from "./services/cli-backend/types"
|
||||
import { FileIgnoreController } from "./services/autocomplete/shims/FileIgnoreController"
|
||||
import { ChatTextAreaAutocomplete } from "./services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete"
|
||||
@@ -242,6 +243,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
|
||||
private webview: vscode.Webview | null = null
|
||||
private currentSession: Session | null = null
|
||||
private viewActive = true
|
||||
/** Remembers the last selected session so /new can stay in the same worktree after clearSession. */
|
||||
private contextSessionID: string | undefined
|
||||
private connectionState: "connecting" | "connected" | "disconnected" | "error" = "connecting"
|
||||
@@ -377,12 +379,23 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
private focusSession(id?: string): void {
|
||||
this.streams.focus(id)
|
||||
if (id) this.connectionService.registerFocused(this.instanceId, id)
|
||||
if (id && this.viewActive) this.connectionService.registerFocused(this.instanceId, id)
|
||||
else this.connectionService.unregisterFocused(this.instanceId)
|
||||
}
|
||||
|
||||
private setViewActive(active: boolean): void {
|
||||
this.viewActive = active
|
||||
if (!active) {
|
||||
this.connectionService.unregisterFocused(this.instanceId)
|
||||
return
|
||||
}
|
||||
const id = this.contextSessionID ?? this.currentSession?.id
|
||||
if (id) this.connectionService.registerFocused(this.instanceId, id)
|
||||
}
|
||||
|
||||
public setStreamVisibility(active: boolean): void {
|
||||
this.visibleTaskStreams.setActive(active)
|
||||
this.setViewActive(active)
|
||||
}
|
||||
|
||||
public setProjectDirectory(directory: string | null): void {
|
||||
@@ -595,9 +608,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
|
||||
this.setupWebviewMessageHandler(panel.webview)
|
||||
this.viewStateDisposable?.dispose()
|
||||
this.viewStateDisposable = this.visibleTaskStreams.bindPanel(panel, () =>
|
||||
this.focusSession(panel.active ? this.currentSession?.id : undefined),
|
||||
)
|
||||
this.viewStateDisposable = this.visibleTaskStreams.bindPanel(panel, () => {
|
||||
this.setViewActive(panel.active)
|
||||
this.focusSession(panel.active ? this.currentSession?.id : undefined)
|
||||
})
|
||||
this.setViewActive(panel.active)
|
||||
this.initializeConnection()
|
||||
}
|
||||
|
||||
@@ -1064,6 +1079,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
case "requestNotificationSettings":
|
||||
this.sendNotificationSettings()
|
||||
break
|
||||
case "testNotification":
|
||||
previewSound(message.settingType, message.sound)
|
||||
break
|
||||
case "requestTimelineSetting":
|
||||
this.sendTimelineSetting()
|
||||
break
|
||||
@@ -2301,9 +2319,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
notifyAgent: notifications.get<boolean>("agent", true),
|
||||
notifyPermissions: notifications.get<boolean>("permissions", true),
|
||||
notifyErrors: notifications.get<boolean>("errors", true),
|
||||
soundAgent: sounds.get<string>("agent", "default"),
|
||||
soundPermissions: sounds.get<string>("permissions", "default"),
|
||||
soundErrors: sounds.get<string>("errors", "default"),
|
||||
playWhenFocused: sounds.get<boolean>("playWhenFocused", false),
|
||||
soundAgent: sounds.get<string>("agent", "system"),
|
||||
soundPermissions: sounds.get<string>("permissions", "system"),
|
||||
soundErrors: sounds.get<string>("errors", "system"),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ export class AgentManagerProvider implements Disposable {
|
||||
* Updated synchronously — unlike the session provider's currentSession which depends on
|
||||
* an async `session.get` round-trip and can be stale during rapid tab switches. */
|
||||
private activeSessionId: string | undefined
|
||||
private focusedId: string | undefined
|
||||
constructor(
|
||||
private readonly host: Host,
|
||||
private readonly connectionService: KiloConnectionService,
|
||||
@@ -222,6 +223,12 @@ export class AgentManagerProvider implements Disposable {
|
||||
this.onVisibilityChange?.(ctx.visible)
|
||||
ctx.onDidChangeVisibility((visible) => {
|
||||
this.statsPoller.setVisible(visible)
|
||||
this.onVisibilityChange?.(visible)
|
||||
if (visible && this.focusedId) {
|
||||
this.connectionService.registerFocused("agent-manager", this.focusedId)
|
||||
return
|
||||
}
|
||||
this.connectionService.unregisterFocused("agent-manager")
|
||||
})
|
||||
|
||||
ctx.sessions.onFollowupAdopted((session, directory) => {
|
||||
@@ -241,6 +248,8 @@ export class AgentManagerProvider implements Disposable {
|
||||
this.prBridge.poller.stop()
|
||||
this.diffs.stop()
|
||||
this.panel = undefined
|
||||
this.connectionService.unregisterFocused("agent-manager")
|
||||
this.connectionService.registerOpen("agent-manager", [])
|
||||
this.onVisibilityChange?.(false)
|
||||
}
|
||||
ctx.sessions.dispose()
|
||||
@@ -448,7 +457,8 @@ export class AgentManagerProvider implements Disposable {
|
||||
|
||||
if (m.type === "loadMessages") {
|
||||
this.activeSessionId = m.sessionID
|
||||
this.connectionService.registerFocused("agent-manager", m.sessionID)
|
||||
this.focusedId = m.sessionID
|
||||
if (this.panel?.visible) this.connectionService.registerFocused("agent-manager", m.sessionID)
|
||||
this.terminalManager.syncOnSessionSwitch(m.sessionID)
|
||||
this.prBridge.poller.setActiveWorktreeId(this.state?.getSession(m.sessionID)?.worktreeId ?? undefined)
|
||||
return msg
|
||||
@@ -456,6 +466,7 @@ export class AgentManagerProvider implements Disposable {
|
||||
|
||||
if (m.type === "clearSession") {
|
||||
this.activeSessionId = undefined
|
||||
this.focusedId = undefined
|
||||
this.connectionService.unregisterFocused("agent-manager")
|
||||
void Promise.resolve().then(() => {
|
||||
if (!this.panel || !this.state) return
|
||||
|
||||
@@ -14,6 +14,7 @@ import { KiloConnectionService } from "./services/cli-backend"
|
||||
import { registerAutocompleteProvider } from "./services/autocomplete"
|
||||
import { ensureBackendForAutocomplete } from "./services/autocomplete/ensure-backend"
|
||||
import { AutocompleteServiceManager } from "./services/autocomplete/AutocompleteServiceManager"
|
||||
import { AttentionService } from "./services/attention"
|
||||
import { BrowserAutomationService } from "./services/browser-automation"
|
||||
import { TelemetryEventName, TelemetryProxy } from "./services/telemetry"
|
||||
import { registerCommitMessageService } from "./services/commit-message"
|
||||
@@ -48,6 +49,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Create shared connection service (one server for all webviews)
|
||||
const connectionService = new KiloConnectionService(context)
|
||||
const attention = new AttentionService(connectionService)
|
||||
let restore = context.workspaceState.get<RestoreState>(RESTORE_KEY) ?? {}
|
||||
const remember = (patch: RestoreState) => {
|
||||
const next = { ...restore, ...patch }
|
||||
@@ -517,6 +519,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
dispose: () => {
|
||||
shuttingDown = true
|
||||
unsubscribeStateChange()
|
||||
attention.dispose()
|
||||
browserAutomationService.dispose()
|
||||
provider.dispose()
|
||||
connectionService.dispose()
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import type { SSEPayload } from "../cli-backend/sdk-sse-adapter"
|
||||
|
||||
export type AttentionKind = "done" | "subagent_done" | "question" | "permission" | "error"
|
||||
|
||||
export type AttentionSignal =
|
||||
| {
|
||||
type: "session"
|
||||
sessionID: string
|
||||
title?: string | null
|
||||
parentID?: string | null
|
||||
deleted?: boolean
|
||||
}
|
||||
| { type: "status"; sessionID: string; status: "active" | "idle" }
|
||||
| { type: "question"; sessionID: string; requestID: string; open: boolean }
|
||||
| { type: "permission"; sessionID: string; requestID: string; open: boolean }
|
||||
| { type: "error"; sessionID: string; error?: unknown }
|
||||
|
||||
export type AttentionNotice = {
|
||||
sessionID: string
|
||||
kind: AttentionKind
|
||||
title?: string
|
||||
message: string
|
||||
subagent: boolean
|
||||
}
|
||||
|
||||
type Meta = {
|
||||
title?: string
|
||||
parentID?: string
|
||||
}
|
||||
|
||||
type SessionSignal = Extract<AttentionSignal, { type: "session" }>
|
||||
type StatusSignal = Extract<AttentionSignal, { type: "status" }>
|
||||
type RequestSignal = Extract<AttentionSignal, { type: "question" | "permission" }>
|
||||
type ErrorSignal = Extract<AttentionSignal, { type: "error" }>
|
||||
|
||||
type DeliveryInput = {
|
||||
appFocused: boolean
|
||||
sessionFocused: boolean
|
||||
subagent: boolean
|
||||
notifications: boolean
|
||||
sound: boolean
|
||||
playWhenFocused: boolean
|
||||
}
|
||||
|
||||
export function delivery(input: DeliveryInput) {
|
||||
return {
|
||||
notification: input.notifications && !input.appFocused && !input.subagent,
|
||||
sound: input.sound && (input.playWhenFocused || !input.appFocused || !input.sessionFocused),
|
||||
}
|
||||
}
|
||||
|
||||
export function sessionErrorMessage(error: unknown) {
|
||||
if (!error || typeof error !== "object") return "Session error"
|
||||
if ("name" in error && error.name === "MessageAbortedError") return "Session aborted"
|
||||
if (!("data" in error) || !error.data || typeof error.data !== "object") return "Session error"
|
||||
if (!("message" in error.data) || error.data.message !== "SSE read timed out") return "Session error"
|
||||
return "Model stopped responding"
|
||||
}
|
||||
|
||||
export class AttentionTracker {
|
||||
private readonly active = new Set<string>()
|
||||
private readonly errored = new Set<string>()
|
||||
private readonly questions = new Set<string>()
|
||||
private readonly permissions = new Set<string>()
|
||||
private readonly sessions = new Map<string, Meta>()
|
||||
|
||||
handle(signal: AttentionSignal): AttentionNotice | undefined {
|
||||
switch (signal.type) {
|
||||
case "session":
|
||||
return this.handleSession(signal)
|
||||
case "question":
|
||||
return this.handleRequest(signal, this.questions, "question", "Question needs input")
|
||||
case "permission":
|
||||
return this.handleRequest(signal, this.permissions, "permission", "Permission needs input")
|
||||
case "error":
|
||||
return this.handleError(signal)
|
||||
case "status":
|
||||
return this.handleStatus(signal)
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.active.clear()
|
||||
this.errored.clear()
|
||||
this.questions.clear()
|
||||
this.permissions.clear()
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.reset()
|
||||
this.sessions.clear()
|
||||
}
|
||||
|
||||
private handleSession(signal: SessionSignal): AttentionNotice | undefined {
|
||||
if (signal.deleted) {
|
||||
this.sessions.delete(signal.sessionID)
|
||||
this.active.delete(signal.sessionID)
|
||||
this.errored.delete(signal.sessionID)
|
||||
return
|
||||
}
|
||||
const current = this.sessions.get(signal.sessionID) ?? {}
|
||||
const title = signal.title === undefined ? current.title : signal.title || undefined
|
||||
const parentID = signal.parentID === undefined ? current.parentID : signal.parentID || undefined
|
||||
this.sessions.set(signal.sessionID, { title, parentID })
|
||||
}
|
||||
|
||||
private handleRequest(signal: RequestSignal, requests: Set<string>, kind: AttentionKind, message: string) {
|
||||
if (!signal.open) {
|
||||
requests.delete(signal.requestID)
|
||||
return
|
||||
}
|
||||
if (requests.has(signal.requestID)) return
|
||||
requests.add(signal.requestID)
|
||||
return this.notice(signal.sessionID, kind, message)
|
||||
}
|
||||
|
||||
private handleError(signal: ErrorSignal) {
|
||||
if (!this.active.has(signal.sessionID)) return
|
||||
this.errored.add(signal.sessionID)
|
||||
return this.notice(signal.sessionID, "error", sessionErrorMessage(signal.error))
|
||||
}
|
||||
|
||||
private handleStatus(signal: StatusSignal) {
|
||||
if (signal.status === "active") {
|
||||
this.active.add(signal.sessionID)
|
||||
this.errored.delete(signal.sessionID)
|
||||
return
|
||||
}
|
||||
if (!this.active.has(signal.sessionID)) return
|
||||
this.active.delete(signal.sessionID)
|
||||
if (this.errored.delete(signal.sessionID)) return
|
||||
const session = this.sessions.get(signal.sessionID)
|
||||
return this.notice(signal.sessionID, session?.parentID ? "subagent_done" : "done", "Session done")
|
||||
}
|
||||
|
||||
private notice(sessionID: string, kind: AttentionKind, message: string): AttentionNotice {
|
||||
const session = this.sessions.get(sessionID)
|
||||
return {
|
||||
sessionID,
|
||||
kind,
|
||||
title: session?.title,
|
||||
message,
|
||||
subagent: session?.parentID !== undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function toAttentionSignal(event: SSEPayload): AttentionSignal | undefined {
|
||||
if (event.type === "sync") {
|
||||
if (event.name === "session.created.1") {
|
||||
return {
|
||||
type: "session",
|
||||
sessionID: event.data.sessionID,
|
||||
title: event.data.info.title,
|
||||
parentID: event.data.info.parentID ?? null,
|
||||
}
|
||||
}
|
||||
if (event.name === "session.updated.1") {
|
||||
return {
|
||||
type: "session",
|
||||
sessionID: event.data.sessionID,
|
||||
title: event.data.info.title,
|
||||
parentID: event.data.info.parentID,
|
||||
}
|
||||
}
|
||||
if (event.name === "session.deleted.1") {
|
||||
return { type: "session", sessionID: event.data.sessionID, deleted: true }
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (event.type === "session.status") {
|
||||
const status = event.properties.status.type
|
||||
if (status === "busy" || status === "retry") {
|
||||
return { type: "status", sessionID: event.properties.sessionID, status: "active" }
|
||||
}
|
||||
if (status === "idle") return { type: "status", sessionID: event.properties.sessionID, status: "idle" }
|
||||
return
|
||||
}
|
||||
|
||||
if (event.type === "question.asked") {
|
||||
return {
|
||||
type: "question",
|
||||
sessionID: event.properties.sessionID,
|
||||
requestID: event.properties.id,
|
||||
open: true,
|
||||
}
|
||||
}
|
||||
if (event.type === "question.replied" || event.type === "question.rejected") {
|
||||
return {
|
||||
type: "question",
|
||||
sessionID: event.properties.sessionID,
|
||||
requestID: event.properties.requestID,
|
||||
open: false,
|
||||
}
|
||||
}
|
||||
if (event.type === "permission.asked") {
|
||||
return {
|
||||
type: "permission",
|
||||
sessionID: event.properties.sessionID,
|
||||
requestID: event.properties.id,
|
||||
open: true,
|
||||
}
|
||||
}
|
||||
if (event.type === "permission.replied") {
|
||||
return {
|
||||
type: "permission",
|
||||
sessionID: event.properties.sessionID,
|
||||
requestID: event.properties.requestID,
|
||||
open: false,
|
||||
}
|
||||
}
|
||||
if (event.type === "session.error" && event.properties.sessionID) {
|
||||
return {
|
||||
type: "error",
|
||||
sessionID: event.properties.sessionID,
|
||||
error: event.properties.error,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { AttentionService, previewSound, type AttentionSetting } from "./service"
|
||||
@@ -0,0 +1,87 @@
|
||||
import * as vscode from "vscode"
|
||||
import type { KiloConnectionService } from "../cli-backend/connection-service"
|
||||
import { AttentionTracker, delivery, toAttentionSignal, type AttentionKind, type AttentionNotice } from "./attention"
|
||||
import { playSound, resolveSoundID } from "./sound"
|
||||
|
||||
export type AttentionSetting = "agent" | "permissions" | "errors"
|
||||
|
||||
function setting(kind: AttentionKind): AttentionSetting {
|
||||
if (kind === "error") return "errors"
|
||||
if (kind === "question" || kind === "permission") return "permissions"
|
||||
return "agent"
|
||||
}
|
||||
|
||||
function fallback(kind: AttentionSetting): AttentionKind {
|
||||
if (kind === "errors") return "error"
|
||||
if (kind === "permissions") return "permission"
|
||||
return "done"
|
||||
}
|
||||
|
||||
function clean(value: string | undefined) {
|
||||
return (value ?? "Kilo session")
|
||||
.replace(/[\u0000-\u001F\u007F-\u009F]/g, "")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
.slice(0, 80)
|
||||
}
|
||||
|
||||
export function previewSound(kind: AttentionSetting, value: string) {
|
||||
const id = resolveSoundID(value, fallback(kind))
|
||||
if (id) void playSound(id)
|
||||
}
|
||||
|
||||
export class AttentionService implements vscode.Disposable {
|
||||
private readonly tracker = new AttentionTracker()
|
||||
private readonly unsubscribeEvent: () => void
|
||||
private readonly unsubscribeState: () => void
|
||||
private readonly focus: vscode.Disposable
|
||||
private appFocused = vscode.window.state.focused
|
||||
|
||||
constructor(private readonly connection: KiloConnectionService) {
|
||||
this.focus = vscode.window.onDidChangeWindowState((state) => {
|
||||
this.appFocused = state.focused
|
||||
})
|
||||
this.unsubscribeEvent = connection.onEvent((event) => {
|
||||
const signal = toAttentionSignal(event)
|
||||
if (!signal) return
|
||||
const notice = this.tracker.handle(signal)
|
||||
if (notice) this.notify(notice)
|
||||
})
|
||||
this.unsubscribeState = connection.onStateChange((state) => {
|
||||
if (state === "error" || state === "disconnected") this.tracker.reset()
|
||||
})
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.unsubscribeEvent()
|
||||
this.unsubscribeState()
|
||||
this.focus.dispose()
|
||||
this.tracker.dispose()
|
||||
}
|
||||
|
||||
private notify(notice: AttentionNotice) {
|
||||
const key = setting(notice.kind)
|
||||
const notifications = vscode.workspace.getConfiguration("kilo-code.new.notifications")
|
||||
const sounds = vscode.workspace.getConfiguration("kilo-code.new.sounds")
|
||||
const value = sounds.get<string>(key, "system")
|
||||
const id = resolveSoundID(value, notice.kind)
|
||||
const result = delivery({
|
||||
appFocused: this.appFocused,
|
||||
sessionFocused: this.connection.isSessionFocused(notice.sessionID),
|
||||
subagent: notice.subagent,
|
||||
notifications: notifications.get<boolean>(key, true),
|
||||
sound: id !== undefined,
|
||||
playWhenFocused: sounds.get<boolean>("playWhenFocused", false),
|
||||
})
|
||||
|
||||
if (result.sound && id) void playSound(id)
|
||||
if (!result.notification) return
|
||||
|
||||
const message = `${clean(notice.title)}: ${notice.message}`
|
||||
if (notice.kind === "error") {
|
||||
void vscode.window.showErrorMessage(message)
|
||||
return
|
||||
}
|
||||
void vscode.window.showInformationMessage(message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import { exec } from "../../util/process"
|
||||
import type { AttentionKind } from "./attention"
|
||||
|
||||
export const CustomSoundIDs = [
|
||||
"alert-01",
|
||||
"alert-02",
|
||||
"alert-03",
|
||||
"alert-04",
|
||||
"alert-05",
|
||||
"alert-06",
|
||||
"alert-07",
|
||||
"alert-08",
|
||||
"alert-09",
|
||||
"alert-10",
|
||||
"bip-bop-01",
|
||||
"bip-bop-02",
|
||||
"bip-bop-03",
|
||||
"bip-bop-04",
|
||||
"bip-bop-05",
|
||||
"bip-bop-06",
|
||||
"bip-bop-07",
|
||||
"bip-bop-08",
|
||||
"bip-bop-09",
|
||||
"bip-bop-10",
|
||||
"staplebops-01",
|
||||
"staplebops-02",
|
||||
"staplebops-03",
|
||||
"staplebops-04",
|
||||
"staplebops-05",
|
||||
"staplebops-06",
|
||||
"staplebops-07",
|
||||
"nope-01",
|
||||
"nope-02",
|
||||
"nope-03",
|
||||
"nope-04",
|
||||
"nope-05",
|
||||
"nope-06",
|
||||
"nope-07",
|
||||
"nope-08",
|
||||
"nope-09",
|
||||
"nope-10",
|
||||
"nope-11",
|
||||
"nope-12",
|
||||
"yup-01",
|
||||
"yup-02",
|
||||
"yup-03",
|
||||
"yup-04",
|
||||
"yup-05",
|
||||
"yup-06",
|
||||
] as const
|
||||
|
||||
export type CustomSoundID = (typeof CustomSoundIDs)[number]
|
||||
export type SoundID = "system" | CustomSoundID
|
||||
|
||||
const ids = new Set<string>(CustomSoundIDs)
|
||||
const root = path.join(__dirname, "../audio-wav")
|
||||
const defaults: Record<AttentionKind, CustomSoundID> = {
|
||||
done: "bip-bop-01",
|
||||
subagent_done: "yup-01",
|
||||
question: "bip-bop-03",
|
||||
permission: "staplebops-06",
|
||||
error: "nope-03",
|
||||
}
|
||||
|
||||
let chain = Promise.resolve(false)
|
||||
let queued = 0
|
||||
const limit = 3
|
||||
|
||||
export function resolveSoundID(value: string | undefined, kind: AttentionKind): SoundID | undefined {
|
||||
if (!value || value === "none") return
|
||||
if (value === "default") return defaults[kind]
|
||||
if (value === "system") return "system"
|
||||
if (ids.has(value)) return value as CustomSoundID
|
||||
}
|
||||
|
||||
async function run(commands: Array<{ cmd: string; args: string[]; env?: NodeJS.ProcessEnv }>) {
|
||||
for (const command of commands) {
|
||||
const ok = await exec(command.cmd, command.args, command.env ? { env: command.env } : {}).then(
|
||||
() => true,
|
||||
(error) => {
|
||||
console.debug("[Kilo New] notification sound command failed", { cmd: command.cmd, error })
|
||||
return false
|
||||
},
|
||||
)
|
||||
if (ok) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function systemCommands(): Array<{ cmd: string; args: string[] }> {
|
||||
if (process.platform === "darwin") return [{ cmd: "osascript", args: ["-e", "beep"] }]
|
||||
if (process.platform === "linux") {
|
||||
return [
|
||||
{ cmd: "canberra-gtk-play", args: ["-i", "message-new-instant"] },
|
||||
{ cmd: "paplay", args: ["/usr/share/sounds/freedesktop/stereo/message.oga"] },
|
||||
]
|
||||
}
|
||||
if (process.platform === "win32") {
|
||||
return [
|
||||
{
|
||||
cmd: "powershell",
|
||||
args: ["-NoProfile", "-NonInteractive", "-Command", "[System.Media.SystemSounds]::Exclamation.Play()"],
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
function fileCommands(file: string): Array<{ cmd: string; args: string[]; env?: NodeJS.ProcessEnv }> {
|
||||
if (process.platform === "darwin") {
|
||||
return [
|
||||
{ cmd: "afplay", args: [file] },
|
||||
{ cmd: "play", args: [file] },
|
||||
]
|
||||
}
|
||||
if (process.platform === "linux") {
|
||||
return [
|
||||
{ cmd: "aplay", args: [file] },
|
||||
{ cmd: "paplay", args: [file] },
|
||||
{ cmd: "play", args: [file] },
|
||||
]
|
||||
}
|
||||
if (process.platform === "win32") {
|
||||
return [
|
||||
{
|
||||
cmd: "powershell",
|
||||
args: [
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-Command",
|
||||
"$sound = [System.Media.SoundPlayer]::new($env:KILO_SOUND_PATH); $sound.PlaySync(); $sound.Dispose()",
|
||||
],
|
||||
env: { ...process.env, KILO_SOUND_PATH: file },
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
async function perform(id: SoundID, dir: string) {
|
||||
if (id === "system") return run(systemCommands())
|
||||
const file = path.resolve(dir, `${id}.wav`)
|
||||
if (!file.startsWith(`${path.resolve(dir)}${path.sep}`)) return false
|
||||
if (!fs.existsSync(file)) {
|
||||
console.warn("[Kilo New] notification sound is missing", { file })
|
||||
return false
|
||||
}
|
||||
return run(fileCommands(file))
|
||||
}
|
||||
|
||||
export async function playSound(id: SoundID, dir = root) {
|
||||
if (queued >= limit) return false
|
||||
queued += 1
|
||||
const task = chain.catch(() => false).then(() => perform(id, dir))
|
||||
chain = task.finally(() => {
|
||||
queued -= 1
|
||||
})
|
||||
return task
|
||||
}
|
||||
@@ -452,6 +452,14 @@ export class KiloConnectionService {
|
||||
this.flushViewed()
|
||||
}
|
||||
|
||||
/** Whether any Kilo surface currently has this session selected. */
|
||||
isSessionFocused(sessionID: string): boolean {
|
||||
for (const id of this.focused.values()) {
|
||||
if (id === sessionID) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** Debounced: send the aggregated focused + open session IDs to the server. */
|
||||
flushViewed(): void {
|
||||
if (!this.isRemoteEnabled()) return
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import {
|
||||
AttentionTracker,
|
||||
delivery,
|
||||
sessionErrorMessage,
|
||||
type AttentionNotice,
|
||||
type AttentionSignal,
|
||||
} from "../../src/services/attention/attention"
|
||||
import { resolveSoundID } from "../../src/services/attention/sound"
|
||||
|
||||
function collect(signals: AttentionSignal[]) {
|
||||
const tracker = new AttentionTracker()
|
||||
const notices: AttentionNotice[] = []
|
||||
for (const signal of signals) {
|
||||
const notice = tracker.handle(signal)
|
||||
if (notice) notices.push(notice)
|
||||
}
|
||||
return notices
|
||||
}
|
||||
|
||||
describe("AttentionTracker", () => {
|
||||
it("notifies once after an active session becomes idle", () => {
|
||||
const notices = collect([
|
||||
{ type: "session", sessionID: "s1", title: "Fix the bug", parentID: null },
|
||||
{ type: "status", sessionID: "s1", status: "active" },
|
||||
{ type: "status", sessionID: "s1", status: "idle" },
|
||||
{ type: "status", sessionID: "s1", status: "idle" },
|
||||
])
|
||||
|
||||
expect(notices).toEqual([
|
||||
{
|
||||
sessionID: "s1",
|
||||
kind: "done",
|
||||
title: "Fix the bug",
|
||||
message: "Session done",
|
||||
subagent: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("uses the subagent completion sound category", () => {
|
||||
const notices = collect([
|
||||
{ type: "session", sessionID: "child", title: "Research", parentID: "parent" },
|
||||
{ type: "status", sessionID: "child", status: "active" },
|
||||
{ type: "status", sessionID: "child", status: "idle" },
|
||||
])
|
||||
|
||||
expect(notices[0]).toMatchObject({ kind: "subagent_done", subagent: true })
|
||||
})
|
||||
|
||||
it("notifies for distinct questions and permissions while suppressing duplicate requests", () => {
|
||||
const notices = collect([
|
||||
{ type: "question", sessionID: "s1", requestID: "q1", open: true },
|
||||
{ type: "question", sessionID: "s1", requestID: "q1", open: true },
|
||||
{ type: "question", sessionID: "s1", requestID: "q1", open: false },
|
||||
{ type: "question", sessionID: "s1", requestID: "q1", open: true },
|
||||
{ type: "permission", sessionID: "s1", requestID: "p1", open: true },
|
||||
{ type: "permission", sessionID: "s1", requestID: "p1", open: true },
|
||||
])
|
||||
|
||||
expect(notices.map((notice) => notice.kind)).toEqual(["question", "question", "permission"])
|
||||
})
|
||||
|
||||
it("notifies an active session error and suppresses its following completion", () => {
|
||||
const notices = collect([
|
||||
{ type: "status", sessionID: "s1", status: "active" },
|
||||
{ type: "error", sessionID: "s1", error: { name: "ApiError" } },
|
||||
{ type: "status", sessionID: "s1", status: "idle" },
|
||||
])
|
||||
|
||||
expect(notices).toEqual([
|
||||
{
|
||||
sessionID: "s1",
|
||||
kind: "error",
|
||||
title: undefined,
|
||||
message: "Session error",
|
||||
subagent: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("clears active transitions when the connection resets", () => {
|
||||
const tracker = new AttentionTracker()
|
||||
tracker.handle({ type: "status", sessionID: "s1", status: "active" })
|
||||
tracker.reset()
|
||||
|
||||
expect(tracker.handle({ type: "status", sessionID: "s1", status: "idle" })).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("sessionErrorMessage", () => {
|
||||
it("classifies aborts and response timeouts", () => {
|
||||
expect(sessionErrorMessage({ name: "MessageAbortedError" })).toBe("Session aborted")
|
||||
expect(sessionErrorMessage({ data: { message: "SSE read timed out" } })).toBe("Model stopped responding")
|
||||
expect(sessionErrorMessage({ name: "ApiError" })).toBe("Session error")
|
||||
})
|
||||
})
|
||||
|
||||
describe("delivery", () => {
|
||||
it("shows root notifications only while VS Code is blurred", () => {
|
||||
expect(
|
||||
delivery({
|
||||
appFocused: false,
|
||||
sessionFocused: true,
|
||||
subagent: false,
|
||||
notifications: true,
|
||||
sound: true,
|
||||
playWhenFocused: false,
|
||||
}),
|
||||
).toEqual({ notification: true, sound: true })
|
||||
|
||||
expect(
|
||||
delivery({
|
||||
appFocused: true,
|
||||
sessionFocused: true,
|
||||
subagent: false,
|
||||
notifications: true,
|
||||
sound: true,
|
||||
playWhenFocused: false,
|
||||
}),
|
||||
).toEqual({ notification: false, sound: false })
|
||||
})
|
||||
|
||||
it("plays sounds for background sessions and keeps subagent notifications silent", () => {
|
||||
expect(
|
||||
delivery({
|
||||
appFocused: true,
|
||||
sessionFocused: false,
|
||||
subagent: true,
|
||||
notifications: true,
|
||||
sound: true,
|
||||
playWhenFocused: false,
|
||||
}),
|
||||
).toEqual({ notification: false, sound: true })
|
||||
})
|
||||
|
||||
it("keeps visual and sound preferences independent", () => {
|
||||
expect(
|
||||
delivery({
|
||||
appFocused: false,
|
||||
sessionFocused: false,
|
||||
subagent: false,
|
||||
notifications: false,
|
||||
sound: true,
|
||||
playWhenFocused: false,
|
||||
}),
|
||||
).toEqual({ notification: false, sound: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe("resolveSoundID", () => {
|
||||
it("uses the OpenCode attention defaults", () => {
|
||||
expect(resolveSoundID("default", "done")).toBe("bip-bop-01")
|
||||
expect(resolveSoundID("default", "question")).toBe("bip-bop-03")
|
||||
expect(resolveSoundID("default", "permission")).toBe("staplebops-06")
|
||||
expect(resolveSoundID("default", "error")).toBe("nope-03")
|
||||
expect(resolveSoundID("default", "subagent_done")).toBe("yup-01")
|
||||
})
|
||||
|
||||
it("accepts system and bundled sounds and rejects invalid values", () => {
|
||||
expect(resolveSoundID("system", "done")).toBe("system")
|
||||
expect(resolveSoundID("alert-04", "done")).toBe("alert-04")
|
||||
expect(resolveSoundID("none", "done")).toBeUndefined()
|
||||
expect(resolveSoundID("unknown", "done")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, createSignal, onCleanup } from "solid-js"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import { Switch } from "@kilocode/kilo-ui/switch"
|
||||
import { Select } from "@kilocode/kilo-ui/select"
|
||||
import { Card } from "@kilocode/kilo-ui/card"
|
||||
@@ -12,9 +13,27 @@ interface SoundOption {
|
||||
labelKey: string
|
||||
}
|
||||
|
||||
const groups = [
|
||||
{ value: "alert", key: "alert", count: 10 },
|
||||
{ value: "bip-bop", key: "bipbop", count: 10 },
|
||||
{ value: "staplebops", key: "staplebops", count: 7 },
|
||||
{ value: "nope", key: "nope", count: 12 },
|
||||
{ value: "yup", key: "yup", count: 6 },
|
||||
]
|
||||
|
||||
const SOUND_OPTIONS: SoundOption[] = [
|
||||
{ value: "system", labelKey: "settings.notifications.sound.system" },
|
||||
{ value: "default", labelKey: "settings.notifications.sound.default" },
|
||||
{ value: "none", labelKey: "settings.notifications.sound.none" },
|
||||
...groups.flatMap((group) =>
|
||||
Array.from({ length: group.count }, (_, index) => {
|
||||
const suffix = String(index + 1).padStart(2, "0")
|
||||
return {
|
||||
value: `${group.value}-${suffix}`,
|
||||
labelKey: `sound.option.${group.key}${suffix}`,
|
||||
}
|
||||
}),
|
||||
),
|
||||
]
|
||||
|
||||
const NotificationsTab: Component = () => {
|
||||
@@ -24,21 +43,21 @@ const NotificationsTab: Component = () => {
|
||||
const [agentNotify, setAgentNotify] = createSignal(true)
|
||||
const [permNotify, setPermNotify] = createSignal(true)
|
||||
const [errorNotify, setErrorNotify] = createSignal(true)
|
||||
const [agentSound, setAgentSound] = createSignal("default")
|
||||
const [permSound, setPermSound] = createSignal("default")
|
||||
const [errorSound, setErrorSound] = createSignal("default")
|
||||
const [playWhenFocused, setPlayWhenFocused] = createSignal(false)
|
||||
const [agentSound, setAgentSound] = createSignal("system")
|
||||
const [permSound, setPermSound] = createSignal("system")
|
||||
const [errorSound, setErrorSound] = createSignal("system")
|
||||
|
||||
const unsubscribe = vscode.onMessage((message: ExtensionMessage) => {
|
||||
if (message.type !== "notificationSettingsLoaded") {
|
||||
return
|
||||
}
|
||||
const s = message.settings
|
||||
setAgentNotify(s.notifyAgent)
|
||||
setPermNotify(s.notifyPermissions)
|
||||
setErrorNotify(s.notifyErrors)
|
||||
setAgentSound(s.soundAgent)
|
||||
setPermSound(s.soundPermissions)
|
||||
setErrorSound(s.soundErrors)
|
||||
if (message.type !== "notificationSettingsLoaded") return
|
||||
const settings = message.settings
|
||||
setAgentNotify(settings.notifyAgent)
|
||||
setPermNotify(settings.notifyPermissions)
|
||||
setErrorNotify(settings.notifyErrors)
|
||||
setPlayWhenFocused(settings.playWhenFocused)
|
||||
setAgentSound(settings.soundAgent)
|
||||
setPermSound(settings.soundPermissions)
|
||||
setErrorSound(settings.soundErrors)
|
||||
})
|
||||
|
||||
onCleanup(unsubscribe)
|
||||
@@ -48,6 +67,37 @@ const NotificationsTab: Component = () => {
|
||||
vscode.postMessage({ type: "updateSetting", key, value })
|
||||
}
|
||||
|
||||
const test = (settingType: "agent" | "permissions" | "errors", sound: string) => {
|
||||
vscode.postMessage({ type: "testNotification", settingType, sound })
|
||||
}
|
||||
|
||||
const picker = (
|
||||
value: () => string,
|
||||
set: (value: string) => void,
|
||||
key: string,
|
||||
kind: "agent" | "permissions" | "errors",
|
||||
) => (
|
||||
<div style={{ display: "flex", gap: "8px", "align-items": "center", "flex-wrap": "wrap" }}>
|
||||
<Select
|
||||
options={SOUND_OPTIONS}
|
||||
current={SOUND_OPTIONS.find((option) => option.value === value())}
|
||||
value={(option) => option.value}
|
||||
label={(option) => language.t(option.labelKey)}
|
||||
onSelect={(option) => {
|
||||
if (!option) return
|
||||
set(option.value)
|
||||
save(key, option.value)
|
||||
}}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
triggerVariant="settings"
|
||||
/>
|
||||
<Button variant="ghost" size="small" onClick={() => test(kind, value())}>
|
||||
{language.t("settings.notifications.testSound")}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card>
|
||||
@@ -101,66 +151,39 @@ const NotificationsTab: Component = () => {
|
||||
|
||||
<h4 style={{ "margin-top": "16px", "margin-bottom": "8px" }}>{language.t("settings.notifications.sounds")}</h4>
|
||||
<Card>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.playWhenFocused.title")}
|
||||
description={language.t("settings.notifications.playWhenFocused.description")}
|
||||
>
|
||||
<Switch
|
||||
checked={playWhenFocused()}
|
||||
onChange={(checked) => {
|
||||
setPlayWhenFocused(checked)
|
||||
save("sounds.playWhenFocused", checked)
|
||||
}}
|
||||
hideLabel
|
||||
>
|
||||
{language.t("settings.notifications.playWhenFocused.title")}
|
||||
</Switch>
|
||||
</SettingsRow>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.agentSound.title")}
|
||||
description={language.t("settings.notifications.agentSound.description")}
|
||||
>
|
||||
<Select
|
||||
options={SOUND_OPTIONS}
|
||||
current={SOUND_OPTIONS.find((o) => o.value === agentSound())}
|
||||
value={(o) => o.value}
|
||||
label={(o) => language.t(o.labelKey)}
|
||||
onSelect={(o) => {
|
||||
if (o) {
|
||||
setAgentSound(o.value)
|
||||
save("sounds.agent", o.value)
|
||||
}
|
||||
}}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
triggerVariant="settings"
|
||||
/>
|
||||
{picker(agentSound, setAgentSound, "sounds.agent", "agent")}
|
||||
</SettingsRow>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.permSound.title")}
|
||||
description={language.t("settings.notifications.permSound.description")}
|
||||
>
|
||||
<Select
|
||||
options={SOUND_OPTIONS}
|
||||
current={SOUND_OPTIONS.find((o) => o.value === permSound())}
|
||||
value={(o) => o.value}
|
||||
label={(o) => language.t(o.labelKey)}
|
||||
onSelect={(o) => {
|
||||
if (o) {
|
||||
setPermSound(o.value)
|
||||
save("sounds.permissions", o.value)
|
||||
}
|
||||
}}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
triggerVariant="settings"
|
||||
/>
|
||||
{picker(permSound, setPermSound, "sounds.permissions", "permissions")}
|
||||
</SettingsRow>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.errorSound.title")}
|
||||
description={language.t("settings.notifications.errorSound.description")}
|
||||
last
|
||||
>
|
||||
<Select
|
||||
options={SOUND_OPTIONS}
|
||||
current={SOUND_OPTIONS.find((o) => o.value === errorSound())}
|
||||
value={(o) => o.value}
|
||||
label={(o) => language.t(o.labelKey)}
|
||||
onSelect={(o) => {
|
||||
if (o) {
|
||||
setErrorSound(o.value)
|
||||
save("sounds.errors", o.value)
|
||||
}
|
||||
}}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
triggerVariant="settings"
|
||||
/>
|
||||
{picker(errorSound, setErrorSound, "sounds.errors", "errors")}
|
||||
</SettingsRow>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
+4
@@ -1224,6 +1224,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "إظهار إشعار عند طلبات الأذونات",
|
||||
"settings.notifications.errors.title": "أخطاء",
|
||||
"settings.notifications.errors.description": "إظهار إشعار عند الأخطاء",
|
||||
"settings.notifications.playWhenFocused.title": "تشغيل الأصوات عند التركيز",
|
||||
"settings.notifications.playWhenFocused.description": "السماح بأصوات الإشعار حتى عندما تكون نافذة VS Code مُركَزة",
|
||||
"settings.notifications.sounds": "أصوات",
|
||||
"settings.notifications.agentSound.title": "صوت إكمال الوكيل",
|
||||
"settings.notifications.agentSound.description": "الصوت عند إكمال الوكيل",
|
||||
@@ -1233,6 +1235,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "الصوت عند الأخطاء",
|
||||
"settings.notifications.sound.default": "افتراضي",
|
||||
"settings.notifications.sound.none": "بدون",
|
||||
"settings.notifications.sound.system": "النظام",
|
||||
"settings.notifications.testSound": "اختبار",
|
||||
"settings.experimental.share.title": "وضع المشاركة",
|
||||
"settings.experimental.share.description": "سلوك مشاركة الجلسة",
|
||||
"settings.experimental.share.manual": "يدوي",
|
||||
|
||||
+5
@@ -1252,6 +1252,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Mostrar notificação em solicitações de permissão",
|
||||
"settings.notifications.errors.title": "Erros",
|
||||
"settings.notifications.errors.description": "Mostrar notificação em erros",
|
||||
"settings.notifications.playWhenFocused.title": "Reproduzir sons quando focado",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Permitir notificações sonoras mesmo quando a janela do VS Code estiver focada",
|
||||
"settings.notifications.sounds": "Sons",
|
||||
"settings.notifications.agentSound.title": "Som de conclusão do agente",
|
||||
"settings.notifications.agentSound.description": "Som ao concluir o agente",
|
||||
@@ -1261,6 +1264,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Som em erros",
|
||||
"settings.notifications.sound.default": "Padrão",
|
||||
"settings.notifications.sound.none": "Nenhum",
|
||||
"settings.notifications.sound.system": "Sistema",
|
||||
"settings.notifications.testSound": "Teste",
|
||||
"settings.experimental.share.title": "Modo de compartilhamento",
|
||||
"settings.experimental.share.description": "Comportamento do compartilhamento de sessão",
|
||||
"settings.experimental.share.manual": "Manual",
|
||||
|
||||
+5
@@ -1253,6 +1253,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Prikaži obavijest pri zahtjevima za dozvolu",
|
||||
"settings.notifications.errors.title": "Greške",
|
||||
"settings.notifications.errors.description": "Prikaži obavijest pri greškama",
|
||||
"settings.notifications.playWhenFocused.title": "Reproduciraj zvukove prilikom fokusa",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Omogući zvučne obavijesti čak i kad je VS Code prozor fokusiran",
|
||||
"settings.notifications.sounds": "Zvukovi",
|
||||
"settings.notifications.agentSound.title": "Zvuk završetka agenta",
|
||||
"settings.notifications.agentSound.description": "Zvuk pri završetku agenta",
|
||||
@@ -1262,6 +1265,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Zvuk pri greškama",
|
||||
"settings.notifications.sound.default": "Zadano",
|
||||
"settings.notifications.sound.none": "Ništa",
|
||||
"settings.notifications.sound.system": "Sistem",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.experimental.share.title": "Način dijeljenja",
|
||||
"settings.experimental.share.description": "Ponašanje dijeljenja sesije",
|
||||
"settings.experimental.share.manual": "Ručno",
|
||||
|
||||
+4
@@ -1246,6 +1246,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Vis notifikation ved tilladelsesanmodninger",
|
||||
"settings.notifications.errors.title": "Fejl",
|
||||
"settings.notifications.errors.description": "Vis notifikation ved fejl",
|
||||
"settings.notifications.playWhenFocused.title": "Afspil lyde ved fokus",
|
||||
"settings.notifications.playWhenFocused.description": "Tillad lydnotifikationer, selvom VS Code-vinduet er i fokus",
|
||||
"settings.notifications.sounds": "Lyde",
|
||||
"settings.notifications.agentSound.title": "Agentafslutningslyd",
|
||||
"settings.notifications.agentSound.description": "Lyd ved agentafslutning",
|
||||
@@ -1255,6 +1257,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Lyd ved fejl",
|
||||
"settings.notifications.sound.default": "Standard",
|
||||
"settings.notifications.sound.none": "Ingen",
|
||||
"settings.notifications.sound.system": "System",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.experimental.share.title": "Delingstilstand",
|
||||
"settings.experimental.share.description": "Adfærd for sessionsdeling",
|
||||
"settings.experimental.share.manual": "Manuel",
|
||||
|
||||
+5
@@ -1267,6 +1267,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Benachrichtigung bei Berechtigungsanfragen anzeigen",
|
||||
"settings.notifications.errors.title": "Fehler",
|
||||
"settings.notifications.errors.description": "Benachrichtigung bei Fehlern anzeigen",
|
||||
"settings.notifications.playWhenFocused.title": "Sounds bei Fokus abspielen",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Sound-Benachrichtigungen abspielen, auch wenn das VS Code-Fenster fokussiert ist",
|
||||
"settings.notifications.sounds": "Töne",
|
||||
"settings.notifications.agentSound.title": "Agent-Abschlusston",
|
||||
"settings.notifications.agentSound.description": "Ton bei Agent-Abschluss abspielen",
|
||||
@@ -1276,6 +1279,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Ton bei Fehlern abspielen",
|
||||
"settings.notifications.sound.default": "Standard",
|
||||
"settings.notifications.sound.none": "Kein",
|
||||
"settings.notifications.sound.system": "System",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.experimental.share.title": "Freigabemodus",
|
||||
"settings.experimental.share.description": "Verhalten der Sitzungsfreigabe",
|
||||
"settings.experimental.share.manual": "Manuell",
|
||||
|
||||
@@ -1232,6 +1232,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Show notification on permission requests",
|
||||
"settings.notifications.errors.title": "Errors",
|
||||
"settings.notifications.errors.description": "Show notification on errors",
|
||||
"settings.notifications.playWhenFocused.title": "Play Sounds When Focused",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Allow sound notifications to play even when VS Code window is focused",
|
||||
"settings.notifications.sounds": "Sounds",
|
||||
"settings.notifications.agentSound.title": "Agent Completion Sound",
|
||||
"settings.notifications.agentSound.description": "Sound to play when agent completes",
|
||||
@@ -1241,6 +1244,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Sound to play on errors",
|
||||
"settings.notifications.sound.default": "Default",
|
||||
"settings.notifications.sound.none": "None",
|
||||
"settings.notifications.sound.system": "System",
|
||||
"settings.notifications.testSound": "Test",
|
||||
|
||||
"settings.experimental.share.title": "Share Mode",
|
||||
"settings.experimental.share.description": "How session sharing behaves",
|
||||
|
||||
+5
@@ -1259,6 +1259,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Mostrar notificación en solicitudes de permiso",
|
||||
"settings.notifications.errors.title": "Errores",
|
||||
"settings.notifications.errors.description": "Mostrar notificación en errores",
|
||||
"settings.notifications.playWhenFocused.title": "Reproducir sonidos cuando está enfocado",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Permitir notificaciones de sonido aun cuando la ventana de VS Code esté enfocada",
|
||||
"settings.notifications.sounds": "Sonidos",
|
||||
"settings.notifications.agentSound.title": "Sonido de finalización del agente",
|
||||
"settings.notifications.agentSound.description": "Sonido a reproducir cuando el agente finaliza",
|
||||
@@ -1268,6 +1271,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Sonido a reproducir en errores",
|
||||
"settings.notifications.sound.default": "Predeterminado",
|
||||
"settings.notifications.sound.none": "Ninguno",
|
||||
"settings.notifications.sound.system": "Sistema",
|
||||
"settings.notifications.testSound": "Prueba",
|
||||
"settings.experimental.share.title": "Modo de compartir",
|
||||
"settings.experimental.share.description": "Comportamiento de compartir sesión",
|
||||
"settings.experimental.share.manual": "Manual",
|
||||
|
||||
+5
@@ -1271,6 +1271,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Afficher une notification lors des demandes d'autorisation",
|
||||
"settings.notifications.errors.title": "Erreurs",
|
||||
"settings.notifications.errors.description": "Afficher une notification en cas d'erreur",
|
||||
"settings.notifications.playWhenFocused.title": "Jouer les sons quand VS Code est focusé",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Permettre les notifications sonores même quand la fenêtre VS Code est focusée",
|
||||
"settings.notifications.sounds": "Sons",
|
||||
"settings.notifications.agentSound.title": "Son d'achèvement de l'agent",
|
||||
"settings.notifications.agentSound.description": "Son à jouer lorsque l'agent termine",
|
||||
@@ -1280,6 +1283,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Son à jouer en cas d'erreur",
|
||||
"settings.notifications.sound.default": "Par défaut",
|
||||
"settings.notifications.sound.none": "Aucun",
|
||||
"settings.notifications.sound.system": "Système",
|
||||
"settings.notifications.testSound": "Tester",
|
||||
"settings.experimental.share.title": "Mode de partage",
|
||||
"settings.experimental.share.description": "Comportement du partage de session",
|
||||
"settings.experimental.share.manual": "Manuel",
|
||||
|
||||
+5
@@ -1099,8 +1099,13 @@ export const dict = {
|
||||
"settings.notifications.permSound.description": "Suono da riprodurre per le richieste di autorizzazione",
|
||||
"settings.notifications.errorSound.title": "Suono errore",
|
||||
"settings.notifications.errorSound.description": "Suono da riprodurre per gli errori",
|
||||
"settings.notifications.playWhenFocused.title": "Riproduci suoni quando è in focus",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Consenti notifiche audio anche quando la finestra di VS Code è in primo piano",
|
||||
"settings.notifications.sound.default": "Predefinito",
|
||||
"settings.notifications.sound.none": "Nessuno",
|
||||
"settings.notifications.sound.system": "Sistema",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.experimental.share.title": "Modalità condivisione",
|
||||
"settings.experimental.share.description": "Come si comporta la condivisione sessione",
|
||||
"settings.experimental.share.manual": "Manuale",
|
||||
|
||||
+5
@@ -1241,6 +1241,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "権限リクエスト時に通知を表示",
|
||||
"settings.notifications.errors.title": "エラー",
|
||||
"settings.notifications.errors.description": "エラー発生時に通知を表示",
|
||||
"settings.notifications.playWhenFocused.title": "フォーカス時にサウンドを再生",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"VS Codeウィンドウにフォーカスがある場合でもサウンド通知を再生できるようにする",
|
||||
"settings.notifications.sounds": "サウンド",
|
||||
"settings.notifications.agentSound.title": "エージェント完了サウンド",
|
||||
"settings.notifications.agentSound.description": "エージェント完了時に再生するサウンド",
|
||||
@@ -1250,6 +1253,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "エラー発生時に再生するサウンド",
|
||||
"settings.notifications.sound.default": "デフォルト",
|
||||
"settings.notifications.sound.none": "なし",
|
||||
"settings.notifications.sound.system": "システム",
|
||||
"settings.notifications.testSound": "テスト",
|
||||
"settings.experimental.share.title": "共有モード",
|
||||
"settings.experimental.share.description": "セッション共有の動作",
|
||||
"settings.experimental.share.manual": "手動",
|
||||
|
||||
+4
@@ -1235,6 +1235,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "권한 요청 시 알림 표시",
|
||||
"settings.notifications.errors.title": "오류",
|
||||
"settings.notifications.errors.description": "오류 발생 시 알림 표시",
|
||||
"settings.notifications.playWhenFocused.title": "포커스 시 소리 재생",
|
||||
"settings.notifications.playWhenFocused.description": "VS Code 창이 포커스되어 있어도 소리 알림 재생",
|
||||
"settings.notifications.sounds": "소리",
|
||||
"settings.notifications.agentSound.title": "에이전트 완료 소리",
|
||||
"settings.notifications.agentSound.description": "에이전트 완료 시 재생할 소리",
|
||||
@@ -1244,6 +1246,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "오류 발생 시 재생할 소리",
|
||||
"settings.notifications.sound.default": "기본값",
|
||||
"settings.notifications.sound.none": "없음",
|
||||
"settings.notifications.sound.system": "시스템",
|
||||
"settings.notifications.testSound": "테스트 소리",
|
||||
"settings.experimental.share.title": "공유 모드",
|
||||
"settings.experimental.share.description": "세션 공유 동작 방식",
|
||||
"settings.experimental.share.manual": "수동",
|
||||
|
||||
+5
@@ -1247,6 +1247,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Toon melding bij toestemmingsverzoeken",
|
||||
"settings.notifications.errors.title": "Fouten",
|
||||
"settings.notifications.errors.description": "Toon melding bij fouten",
|
||||
"settings.notifications.playWhenFocused.title": "Speel geluid bij focus",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Sta geluidsmeldingen toe zelfs als VS Code-venster focus heeft",
|
||||
"settings.notifications.sounds": "Geluiden",
|
||||
"settings.notifications.agentSound.title": "Agent Voltooiingsgeluid",
|
||||
"settings.notifications.agentSound.description": "Geluid om af te spelen wanneer agent voltooit",
|
||||
@@ -1256,6 +1259,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Geluid om af te spelen bij fouten",
|
||||
"settings.notifications.sound.default": "Standaard",
|
||||
"settings.notifications.sound.none": "Geen",
|
||||
"settings.notifications.sound.system": "Systeem",
|
||||
"settings.notifications.testSound": "Test",
|
||||
|
||||
"settings.experimental.share.title": "Deelmodus",
|
||||
"settings.experimental.share.description": "Hoe sessiedelen zich gedraagt",
|
||||
|
||||
+4
@@ -1212,6 +1212,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Vis varsling ved tillatelsesforespørsler",
|
||||
"settings.notifications.errors.title": "Feil",
|
||||
"settings.notifications.errors.description": "Vis varsling ved feil",
|
||||
"settings.notifications.playWhenFocused.title": "Spill lyd ved fokus",
|
||||
"settings.notifications.playWhenFocused.description": "Tillat lydvarsler selv om VS Code-vinduet er i fokus",
|
||||
"settings.notifications.sounds": "Lyder",
|
||||
"settings.notifications.agentSound.title": "Agentfullføringslyd",
|
||||
"settings.notifications.agentSound.description": "Lyd ved agentfullføring",
|
||||
@@ -1221,6 +1223,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Lyd ved feil",
|
||||
"settings.notifications.sound.default": "Standard",
|
||||
"settings.notifications.sound.none": "Ingen",
|
||||
"settings.notifications.sound.system": "System",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.experimental.share.title": "Delingsmodus",
|
||||
"settings.experimental.share.description": "Oppførsel for sesjonsdeling",
|
||||
"settings.experimental.share.manual": "Manuell",
|
||||
|
||||
+5
@@ -1211,6 +1211,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Pokaż powiadomienie przy żądaniach uprawnień",
|
||||
"settings.notifications.errors.title": "Błędy",
|
||||
"settings.notifications.errors.description": "Pokaż powiadomienie przy błędach",
|
||||
"settings.notifications.playWhenFocused.title": "Odtwarzaj dźwięki przy fokusu",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Pozwól na dźwięki powiadomień, nawet gdy okno VS Code jest w fokusu",
|
||||
"settings.notifications.sounds": "Dźwięki",
|
||||
"settings.notifications.agentSound.title": "Dźwięk zakończenia agenta",
|
||||
"settings.notifications.agentSound.description": "Dźwięk odtwarzany po zakończeniu agenta",
|
||||
@@ -1220,6 +1223,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Dźwięk odtwarzany przy błędach",
|
||||
"settings.notifications.sound.default": "Domyślny",
|
||||
"settings.notifications.sound.none": "Brak",
|
||||
"settings.notifications.sound.system": "System",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.experimental.share.title": "Tryb udostępniania",
|
||||
"settings.experimental.share.description": "Zachowanie udostępniania sesji",
|
||||
"settings.experimental.share.manual": "Ręczny",
|
||||
|
||||
+5
@@ -1249,6 +1249,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Показать уведомление при запросах разрешений",
|
||||
"settings.notifications.errors.title": "Ошибки",
|
||||
"settings.notifications.errors.description": "Показать уведомление при ошибках",
|
||||
"settings.notifications.playWhenFocused.title": "Воспроизводить звуки при фокусе",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Разрешить звуковые уведомления, даже когда окно VS Code находится в фокусе",
|
||||
"settings.notifications.sounds": "Звуки",
|
||||
"settings.notifications.agentSound.title": "Звук завершения агента",
|
||||
"settings.notifications.agentSound.description": "Звук при завершении агента",
|
||||
@@ -1258,6 +1261,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Звук при ошибках",
|
||||
"settings.notifications.sound.default": "По умолчанию",
|
||||
"settings.notifications.sound.none": "Нет",
|
||||
"settings.notifications.sound.system": "Система",
|
||||
"settings.notifications.testSound": "Тест",
|
||||
"settings.experimental.share.title": "Режим обмена",
|
||||
"settings.experimental.share.description": "Поведение обмена сессиями",
|
||||
"settings.experimental.share.manual": "Вручную",
|
||||
|
||||
+4
@@ -1232,6 +1232,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "แสดงการแจ้งเตือนเมื่อมีคำขออนุญาต",
|
||||
"settings.notifications.errors.title": "ข้อผิดพลาด",
|
||||
"settings.notifications.errors.description": "แสดงการแจ้งเตือนเมื่อเกิดข้อผิดพลาด",
|
||||
"settings.notifications.playWhenFocused.title": "เล่นเสียงเมื่อโฟกัส",
|
||||
"settings.notifications.playWhenFocused.description": "อนุญาตให้แจ้งเตือนด้วยเสียงแม้ว่าหน้าต่าง VS Code อยู่ในโฟกัส",
|
||||
"settings.notifications.sounds": "เสียง",
|
||||
"settings.notifications.agentSound.title": "เสียงเอเจนต์เสร็จสิ้น",
|
||||
"settings.notifications.agentSound.description": "เสียงเมื่อเอเจนต์ทำงานเสร็จ",
|
||||
@@ -1241,6 +1243,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "เสียงเมื่อเกิดข้อผิดพลาด",
|
||||
"settings.notifications.sound.default": "ค่าเริ่มต้น",
|
||||
"settings.notifications.sound.none": "ไม่มี",
|
||||
"settings.notifications.sound.system": "ระบบ",
|
||||
"settings.notifications.testSound": "ทดสอบ",
|
||||
"settings.experimental.share.title": "โหมดแชร์",
|
||||
"settings.experimental.share.description": "พฤติกรรมการแชร์เซสชัน",
|
||||
"settings.experimental.share.manual": "ด้วยตนเอง",
|
||||
|
||||
+4
@@ -1240,6 +1240,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "İzin isteklerinde bildirim göster",
|
||||
"settings.notifications.errors.title": "Hatalar",
|
||||
"settings.notifications.errors.description": "Hata oluştuğunda bildirim göster",
|
||||
"settings.notifications.playWhenFocused.title": "Odaklandığında Sesleri Çal",
|
||||
"settings.notifications.playWhenFocused.description": "VS Code penceresi odaklıyken bile ses bildirimlerine izin ver",
|
||||
"settings.notifications.sounds": "Sesler",
|
||||
"settings.notifications.agentSound.title": "Ajan Tamamlanma Sesi",
|
||||
"settings.notifications.agentSound.description": "Ajan tamamlandığında çalınacak ses",
|
||||
@@ -1249,6 +1251,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Hata oluştuğunda çalınacak ses",
|
||||
"settings.notifications.sound.default": "Varsayılan",
|
||||
"settings.notifications.sound.none": "Yok",
|
||||
"settings.notifications.sound.system": "Sistem",
|
||||
"settings.notifications.testSound": "Test",
|
||||
|
||||
"settings.experimental.share.title": "Paylaşım Modu",
|
||||
"settings.experimental.share.description": "Oturum paylaşımının nasıl davranacağı",
|
||||
|
||||
+5
@@ -1240,6 +1240,9 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "Показувати сповіщення при запитах дозволів",
|
||||
"settings.notifications.errors.title": "Помилки",
|
||||
"settings.notifications.errors.description": "Показувати сповіщення при виникненні помилок",
|
||||
"settings.notifications.playWhenFocused.title": "Відтворювати звуки при фокусі",
|
||||
"settings.notifications.playWhenFocused.description":
|
||||
"Дозволяти звукові сповіщення, навіть коли вікно VS Code знаходиться на фокусі",
|
||||
"settings.notifications.sounds": "Звуки",
|
||||
"settings.notifications.agentSound.title": "Звук завершення агента",
|
||||
"settings.notifications.agentSound.description": "Звук, що відтворюється після завершення агента",
|
||||
@@ -1249,6 +1252,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Звук, що відтворюється при виникненні помилок",
|
||||
"settings.notifications.sound.default": "За замовчуванням",
|
||||
"settings.notifications.sound.none": "Немає",
|
||||
"settings.notifications.sound.system": "Система",
|
||||
"settings.notifications.testSound": "Тест",
|
||||
|
||||
"settings.experimental.share.title": "Режим публікації",
|
||||
"settings.experimental.share.description": "Як поводиться публікація сесій",
|
||||
|
||||
+4
@@ -1214,6 +1214,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "权限请求时显示通知",
|
||||
"settings.notifications.errors.title": "错误",
|
||||
"settings.notifications.errors.description": "发生错误时显示通知",
|
||||
"settings.notifications.playWhenFocused.title": "聚焦时播放声音",
|
||||
"settings.notifications.playWhenFocused.description": "即使 VS Code 窗口处于焦点状态也播放声音通知",
|
||||
"settings.notifications.sounds": "声音",
|
||||
"settings.notifications.agentSound.title": "智能体完成提示音",
|
||||
"settings.notifications.agentSound.description": "智能体完成时播放的声音",
|
||||
@@ -1223,6 +1225,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "发生错误时播放的声音",
|
||||
"settings.notifications.sound.default": "默认",
|
||||
"settings.notifications.sound.none": "无",
|
||||
"settings.notifications.sound.system": "系统",
|
||||
"settings.notifications.testSound": "测试",
|
||||
"settings.experimental.share.title": "分享模式",
|
||||
"settings.experimental.share.description": "会话分享行为",
|
||||
"settings.experimental.share.manual": "手动",
|
||||
|
||||
+4
@@ -1182,6 +1182,8 @@ export const dict = {
|
||||
"settings.notifications.permissions.description": "權限請求時顯示通知",
|
||||
"settings.notifications.errors.title": "錯誤",
|
||||
"settings.notifications.errors.description": "發生錯誤時顯示通知",
|
||||
"settings.notifications.playWhenFocused.title": "聚焦時播放聲音",
|
||||
"settings.notifications.playWhenFocused.description": "即使 VS Code 視窗聚焦也播放聲音通知",
|
||||
"settings.notifications.sounds": "聲音",
|
||||
"settings.notifications.agentSound.title": "Agent 完成提示音",
|
||||
"settings.notifications.agentSound.description": "Agent 完成時播放的聲音",
|
||||
@@ -1191,6 +1193,8 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "發生錯誤時播放的聲音",
|
||||
"settings.notifications.sound.default": "預設",
|
||||
"settings.notifications.sound.none": "無",
|
||||
"settings.notifications.sound.system": "系統",
|
||||
"settings.notifications.testSound": "測試",
|
||||
"settings.experimental.share.title": "分享模式",
|
||||
"settings.experimental.share.description": "工作階段分享行為",
|
||||
"settings.experimental.share.manual": "手動",
|
||||
|
||||
@@ -489,6 +489,7 @@ export interface NotificationSettingsLoadedMessage {
|
||||
notifyAgent: boolean
|
||||
notifyPermissions: boolean
|
||||
notifyErrors: boolean
|
||||
playWhenFocused: boolean
|
||||
soundAgent: string
|
||||
soundPermissions: string
|
||||
soundErrors: string
|
||||
|
||||
@@ -433,6 +433,12 @@ export interface RequestNotificationSettingsMessage {
|
||||
type: "requestNotificationSettings"
|
||||
}
|
||||
|
||||
export interface TestNotificationMessage {
|
||||
type: "testNotification"
|
||||
settingType: "agent" | "permissions" | "errors"
|
||||
sound: string
|
||||
}
|
||||
|
||||
export interface ResetAllSettingsRequest {
|
||||
type: "resetAllSettings"
|
||||
}
|
||||
@@ -1133,6 +1139,7 @@ export type WebviewMessage =
|
||||
| UpdateConfigMessage
|
||||
| OpenSettingsTabRequest
|
||||
| RequestNotificationSettingsMessage
|
||||
| TestNotificationMessage
|
||||
| ResetAllSettingsRequest
|
||||
| SettingsTabChangedMessage
|
||||
| SyncSessionRequest
|
||||
|
||||
Reference in New Issue
Block a user