mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-01 15:32:11 +08:00
refactor(vscode): align sounds with opencode attention
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Offer opt-in attention sounds when sessions finish, error, or need input across the sidebar, editor tabs, and Agent Manager.
|
||||
Offer opt-in OpenCode attention sounds when sessions finish, error, or need input across the sidebar, editor tabs, and Agent Manager.
|
||||
|
||||
@@ -302,6 +302,7 @@
|
||||
"@kilocode/kilo-i18n": "workspace:*",
|
||||
"@kilocode/kilo-indexing": "workspace:*",
|
||||
"@kilocode/kilo-ui": "workspace:*",
|
||||
"@kilocode/plugin": "workspace:*",
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@pierre/diffs": "catalog:",
|
||||
|
||||
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.
@@ -942,182 +942,10 @@
|
||||
"default": false,
|
||||
"description": "Run browser automation in headless mode (no visible window). When disabled, you can watch the agent interact with the browser."
|
||||
},
|
||||
"kilo-code.new.sounds.agentEnabled": {
|
||||
"kilo-code.new.attention.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Play a sound when an agent completes a task"
|
||||
},
|
||||
"kilo-code.new.sounds.permissionsEnabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Play a sound when a permission or question needs input"
|
||||
},
|
||||
"kilo-code.new.sounds.errorsEnabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Play a sound when a session errors"
|
||||
},
|
||||
"kilo-code.new.sounds.agent": {
|
||||
"type": "string",
|
||||
"default": "system",
|
||||
"enum": [
|
||||
"system",
|
||||
"default",
|
||||
"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 an agent completes"
|
||||
},
|
||||
"kilo-code.new.sounds.permissions": {
|
||||
"type": "string",
|
||||
"default": "system",
|
||||
"enum": [
|
||||
"system",
|
||||
"default",
|
||||
"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 a permission or question needs input"
|
||||
},
|
||||
"kilo-code.new.sounds.errors": {
|
||||
"type": "string",
|
||||
"default": "system",
|
||||
"enum": [
|
||||
"system",
|
||||
"default",
|
||||
"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 a session errors"
|
||||
"description": "Play OpenCode attention sounds when sessions complete, error, or need input"
|
||||
},
|
||||
"kilo-code.new.showTaskTimeline": {
|
||||
"type": "boolean",
|
||||
@@ -1199,6 +1027,7 @@
|
||||
"@kilocode/kilo-i18n": "workspace:*",
|
||||
"@kilocode/kilo-indexing": "workspace:*",
|
||||
"@kilocode/kilo-ui": "workspace:*",
|
||||
"@kilocode/plugin": "workspace:*",
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@pierre/diffs": "catalog:",
|
||||
|
||||
@@ -1066,7 +1066,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
this.sendNotificationSettings()
|
||||
break
|
||||
case "testNotification":
|
||||
previewSound(message.settingType, message.sound)
|
||||
previewSound()
|
||||
break
|
||||
case "requestTimelineSetting":
|
||||
this.sendTimelineSetting()
|
||||
@@ -2293,18 +2293,13 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
this.connectionService.notifyNotificationDismissed(notificationId)
|
||||
}
|
||||
|
||||
/** Read sound settings from VS Code config and push to webview. */
|
||||
/** Read attention settings from VS Code config and push to webview. */
|
||||
private sendNotificationSettings(): void {
|
||||
const sounds = vscode.workspace.getConfiguration("kilo-code.new.sounds")
|
||||
const attention = vscode.workspace.getConfiguration("kilo-code.new.attention")
|
||||
this.postMessage({
|
||||
type: "notificationSettingsLoaded",
|
||||
settings: {
|
||||
soundAgentEnabled: sounds.get<boolean>("agentEnabled", false),
|
||||
soundPermissionsEnabled: sounds.get<boolean>("permissionsEnabled", false),
|
||||
soundErrorsEnabled: sounds.get<boolean>("errorsEnabled", false),
|
||||
soundAgent: sounds.get<string>("agent", "system"),
|
||||
soundPermissions: sounds.get<string>("permissions", "system"),
|
||||
soundErrors: sounds.get<string>("errors", "system"),
|
||||
attentionEnabled: attention.get<boolean>("enabled", false),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
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" }>
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
export { AttentionService, previewSound, type AttentionSetting } from "./service"
|
||||
export { AttentionService, previewSound } from "./service"
|
||||
|
||||
@@ -1,56 +1,120 @@
|
||||
import * as vscode from "vscode"
|
||||
import type { TuiAttentionSoundName } from "@kilocode/plugin/tui"
|
||||
import type { SSEPayload } from "../cli-backend/sdk-sse-adapter"
|
||||
import type { KiloConnectionService } from "../cli-backend/connection-service"
|
||||
import { AttentionTracker, toAttentionSignal, type AttentionKind, type AttentionNotice } from "./attention"
|
||||
import { playSound, resolveSoundID } from "./sound"
|
||||
import { playSound } from "./sound"
|
||||
|
||||
export type AttentionSetting = "agent" | "permissions" | "errors"
|
||||
type Sync = Extract<SSEPayload, { type: "sync" }>
|
||||
type Question = Extract<SSEPayload, { type: "question.asked" | "question.replied" | "question.rejected" }>
|
||||
type Permission = Extract<SSEPayload, { type: "permission.asked" | "permission.replied" }>
|
||||
type Status = Extract<SSEPayload, { type: "session.status" }>
|
||||
type Error = Extract<SSEPayload, { type: "session.error" }>
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
export function previewSound(kind: AttentionSetting, value: string) {
|
||||
const id = resolveSoundID(value, fallback(kind))
|
||||
if (id) void playSound(id)
|
||||
export function previewSound() {
|
||||
void playSound("default")
|
||||
}
|
||||
|
||||
export class AttentionService implements vscode.Disposable {
|
||||
private readonly tracker = new 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 parents = new Map<string, string | undefined>()
|
||||
private readonly unsubscribeEvent: () => void
|
||||
private readonly unsubscribeState: () => void
|
||||
|
||||
constructor(connection: KiloConnectionService) {
|
||||
this.unsubscribeEvent = connection.onEvent((event) => {
|
||||
const signal = toAttentionSignal(event)
|
||||
if (!signal) return
|
||||
const notice = this.tracker.handle(signal)
|
||||
if (notice) this.notify(notice)
|
||||
})
|
||||
this.unsubscribeEvent = connection.onEvent((event) => this.handle(event))
|
||||
this.unsubscribeState = connection.onStateChange((state) => {
|
||||
if (state === "error" || state === "disconnected") this.tracker.reset()
|
||||
if (state === "error" || state === "disconnected") this.reset()
|
||||
})
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.unsubscribeEvent()
|
||||
this.unsubscribeState()
|
||||
this.tracker.dispose()
|
||||
this.reset()
|
||||
this.parents.clear()
|
||||
}
|
||||
|
||||
private notify(notice: AttentionNotice) {
|
||||
const key = setting(notice.kind)
|
||||
const sounds = vscode.workspace.getConfiguration("kilo-code.new.sounds")
|
||||
if (!sounds.get<boolean>(`${key}Enabled`, false)) return
|
||||
const value = sounds.get<string>(key, "system")
|
||||
const id = resolveSoundID(value, notice.kind)
|
||||
if (id) void playSound(id)
|
||||
private handle(event: SSEPayload) {
|
||||
if (event.type === "sync") return this.sync(event)
|
||||
if (event.type === "question.asked" || event.type === "question.replied" || event.type === "question.rejected") {
|
||||
return this.question(event)
|
||||
}
|
||||
if (event.type === "permission.asked" || event.type === "permission.replied") return this.permission(event)
|
||||
if (event.type === "session.status") return this.status(event)
|
||||
if (event.type === "session.error") return this.error(event)
|
||||
}
|
||||
|
||||
private sync(event: Sync) {
|
||||
if (event.name === "session.created.1") {
|
||||
this.parents.set(event.data.sessionID, event.data.info.parentID)
|
||||
return
|
||||
}
|
||||
if (event.name === "session.updated.1") {
|
||||
if (event.data.info.parentID !== undefined) {
|
||||
this.parents.set(event.data.sessionID, event.data.info.parentID ?? undefined)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (event.name !== "session.deleted.1") return
|
||||
this.parents.delete(event.data.sessionID)
|
||||
this.active.delete(event.data.sessionID)
|
||||
this.errored.delete(event.data.sessionID)
|
||||
}
|
||||
|
||||
private question(event: Question) {
|
||||
if (event.type !== "question.asked") {
|
||||
this.questions.delete(event.properties.requestID)
|
||||
return
|
||||
}
|
||||
if (this.questions.has(event.properties.id)) return
|
||||
this.questions.add(event.properties.id)
|
||||
this.notify("question")
|
||||
}
|
||||
|
||||
private permission(event: Permission) {
|
||||
if (event.type !== "permission.asked") {
|
||||
this.permissions.delete(event.properties.requestID)
|
||||
return
|
||||
}
|
||||
if (this.permissions.has(event.properties.id)) return
|
||||
this.permissions.add(event.properties.id)
|
||||
this.notify("permission")
|
||||
}
|
||||
|
||||
private status(event: Status) {
|
||||
const sessionID = event.properties.sessionID
|
||||
if (event.properties.status.type === "busy" || event.properties.status.type === "retry") {
|
||||
this.active.add(sessionID)
|
||||
this.errored.delete(sessionID)
|
||||
return
|
||||
}
|
||||
if (event.properties.status.type !== "idle") return
|
||||
if (!this.active.has(sessionID)) return
|
||||
this.active.delete(sessionID)
|
||||
if (this.errored.delete(sessionID)) return
|
||||
this.notify(this.parents.get(sessionID) ? "subagent_done" : "done")
|
||||
}
|
||||
|
||||
private error(event: Error) {
|
||||
const sessionID = event.properties.sessionID
|
||||
if (!sessionID || !this.active.has(sessionID)) return
|
||||
this.errored.add(sessionID)
|
||||
this.notify("error")
|
||||
}
|
||||
|
||||
private notify(sound: TuiAttentionSoundName) {
|
||||
const config = vscode.workspace.getConfiguration("kilo-code.new.attention")
|
||||
if (!config.get<boolean>("enabled", false)) return
|
||||
void playSound(sound)
|
||||
}
|
||||
|
||||
private reset() {
|
||||
this.active.clear()
|
||||
this.errored.clear()
|
||||
this.questions.clear()
|
||||
this.permissions.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +1,22 @@
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import type { TuiAttentionSoundName } from "@kilocode/plugin/tui"
|
||||
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",
|
||||
const files: Record<TuiAttentionSoundName, string> = {
|
||||
default: "bip-bop-01",
|
||||
question: "bip-bop-03",
|
||||
permission: "staplebops-06",
|
||||
error: "nope-03",
|
||||
done: "bip-bop-01",
|
||||
subagent_done: "yup-01",
|
||||
}
|
||||
|
||||
const root = path.join(__dirname, "../audio-wav")
|
||||
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(
|
||||
@@ -89,26 +31,7 @@ async function run(commands: Array<{ cmd: string; args: string[]; env?: NodeJS.P
|
||||
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 }> {
|
||||
function commands(file: string): Array<{ cmd: string; args: string[]; env?: NodeJS.ProcessEnv }> {
|
||||
if (process.platform === "darwin") {
|
||||
return [
|
||||
{ cmd: "afplay", args: [file] },
|
||||
@@ -139,26 +62,22 @@ function fileCommands(file: string): Array<{ cmd: string; args: string[]; env?:
|
||||
return []
|
||||
}
|
||||
|
||||
async function perform(id: SoundID, dir: string) {
|
||||
const play = async () => {
|
||||
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))
|
||||
async function perform(name: TuiAttentionSoundName, dir: string) {
|
||||
const file = path.resolve(dir, `${files[name]}.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
|
||||
}
|
||||
const ok = await play()
|
||||
if (ok) console.debug("[Kilo New] notification sound played", { id })
|
||||
const ok = await run(commands(file))
|
||||
if (ok) console.debug("[Kilo New] notification sound played", { name })
|
||||
return ok
|
||||
}
|
||||
|
||||
export async function playSound(id: SoundID, dir = root) {
|
||||
export async function playSound(name: TuiAttentionSoundName, dir = root) {
|
||||
if (queued >= limit) return false
|
||||
queued += 1
|
||||
const task = chain.catch(() => false).then(() => perform(id, dir))
|
||||
const task = chain.catch(() => false).then(() => perform(name, dir))
|
||||
chain = task.finally(() => {
|
||||
queued -= 1
|
||||
})
|
||||
|
||||
@@ -1,130 +1,119 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import {
|
||||
AttentionTracker,
|
||||
sessionErrorMessage,
|
||||
type AttentionNotice,
|
||||
type AttentionSignal,
|
||||
} from "../../src/services/attention/attention"
|
||||
import { resolveSoundID } from "../../src/services/attention/sound"
|
||||
import type { TuiAttentionSoundName } from "@kilocode/plugin/tui"
|
||||
import { AttentionService } from "../../src/services/attention/service"
|
||||
import type { KiloConnectionService } from "../../src/services/cli-backend/connection-service"
|
||||
import type { SSEPayload } from "../../src/services/cli-backend/sdk-sse-adapter"
|
||||
|
||||
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)
|
||||
function setup() {
|
||||
const sounds: TuiAttentionSoundName[] = []
|
||||
const events: Array<(event: SSEPayload) => void> = []
|
||||
const states: Array<(state: "connecting" | "connected" | "disconnected" | "error") => void> = []
|
||||
const connection = {
|
||||
onEvent: (handler: (event: SSEPayload) => void) => {
|
||||
events.push(handler)
|
||||
return () => undefined
|
||||
},
|
||||
onStateChange: (handler: (state: "connecting" | "connected" | "disconnected" | "error") => void) => {
|
||||
states.push(handler)
|
||||
return () => undefined
|
||||
},
|
||||
} as unknown as KiloConnectionService
|
||||
const service = new AttentionService(connection)
|
||||
;(service as unknown as { notify: (sound: TuiAttentionSoundName) => void }).notify = (sound) => sounds.push(sound)
|
||||
return {
|
||||
sounds,
|
||||
event: (event: SSEPayload) => events[0]?.(event),
|
||||
state: (state: "connecting" | "connected" | "disconnected" | "error") => states[0]?.(state),
|
||||
service,
|
||||
}
|
||||
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" },
|
||||
])
|
||||
function event(value: unknown) {
|
||||
return value as SSEPayload
|
||||
}
|
||||
|
||||
expect(notices).toEqual([
|
||||
{
|
||||
sessionID: "s1",
|
||||
kind: "done",
|
||||
title: "Fix the bug",
|
||||
message: "Session done",
|
||||
subagent: false,
|
||||
},
|
||||
])
|
||||
describe("AttentionService", () => {
|
||||
it("plays the upstream completion sound once after active becomes idle", () => {
|
||||
const test = setup()
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "busy" } } }))
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "idle" } } }))
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "idle" } } }))
|
||||
|
||||
expect(test.sounds).toEqual(["done"])
|
||||
test.service.dispose()
|
||||
})
|
||||
|
||||
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" },
|
||||
])
|
||||
it("uses the upstream subagent completion sound", () => {
|
||||
const test = setup()
|
||||
test.event(
|
||||
event({
|
||||
type: "sync",
|
||||
name: "session.created.1",
|
||||
data: { sessionID: "child", info: { parentID: "parent" } },
|
||||
}),
|
||||
)
|
||||
test.event(
|
||||
event({ type: "sync", name: "session.updated.1", data: { sessionID: "child", info: { title: "work" } } }),
|
||||
)
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "child", status: { type: "retry" } } }))
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "child", status: { type: "idle" } } }))
|
||||
|
||||
expect(notices[0]).toMatchObject({ kind: "subagent_done", subagent: true })
|
||||
expect(test.sounds).toEqual(["subagent_done"])
|
||||
test.service.dispose()
|
||||
})
|
||||
|
||||
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 },
|
||||
])
|
||||
it("deduplicates question and permission requests", () => {
|
||||
const test = setup()
|
||||
test.event(event({ type: "question.asked", properties: { id: "q1", sessionID: "s1" } }))
|
||||
test.event(event({ type: "question.asked", properties: { id: "q1", sessionID: "s1" } }))
|
||||
test.event(event({ type: "question.replied", properties: { requestID: "q1", sessionID: "s1" } }))
|
||||
test.event(event({ type: "question.asked", properties: { id: "q1", sessionID: "s1" } }))
|
||||
test.event(event({ type: "permission.asked", properties: { id: "p1", sessionID: "s1" } }))
|
||||
test.event(event({ type: "permission.asked", properties: { id: "p1", sessionID: "s1" } }))
|
||||
|
||||
expect(notices.map((notice) => notice.kind)).toEqual(["question", "question", "permission"])
|
||||
expect(test.sounds).toEqual(["question", "question", "permission"])
|
||||
test.service.dispose()
|
||||
})
|
||||
|
||||
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" },
|
||||
])
|
||||
it("plays the error sound and suppresses the following completion", () => {
|
||||
const test = setup()
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "busy" } } }))
|
||||
test.event(event({ type: "session.error", properties: { sessionID: "s1", error: { name: "ApiError" } } }))
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "idle" } } }))
|
||||
|
||||
expect(notices).toEqual([
|
||||
{
|
||||
sessionID: "s1",
|
||||
kind: "error",
|
||||
title: undefined,
|
||||
message: "Session error",
|
||||
subagent: false,
|
||||
},
|
||||
])
|
||||
expect(test.sounds).toEqual(["error"])
|
||||
test.service.dispose()
|
||||
})
|
||||
|
||||
it("clears active transitions when the connection resets", () => {
|
||||
const tracker = new AttentionTracker()
|
||||
tracker.handle({ type: "status", sessionID: "s1", status: "active" })
|
||||
tracker.reset()
|
||||
it("clears transitions when the backend disconnects", () => {
|
||||
const test = setup()
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "busy" } } }))
|
||||
test.state("disconnected")
|
||||
test.event(event({ type: "session.status", properties: { sessionID: "s1", status: { type: "idle" } } }))
|
||||
|
||||
expect(tracker.handle({ type: "status", sessionID: "s1", status: "idle" })).toBeUndefined()
|
||||
expect(test.sounds).toEqual([])
|
||||
test.service.dispose()
|
||||
})
|
||||
})
|
||||
|
||||
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("sound defaults", () => {
|
||||
it("keeps every sound category opt-in", async () => {
|
||||
describe("attention defaults", () => {
|
||||
it("keeps OpenCode attention sounds opt-in", async () => {
|
||||
const manifest = (await Bun.file(new URL("../../package.json", import.meta.url)).json()) as {
|
||||
contributes: { configuration: { properties: Record<string, { default?: unknown; enum?: unknown[] }> } }
|
||||
contributes: { configuration: { properties: Record<string, { default?: unknown }> } }
|
||||
}
|
||||
const properties = manifest.contributes.configuration.properties
|
||||
|
||||
expect(properties["kilo-code.new.notifications.agent"]).toBeUndefined()
|
||||
expect(properties["kilo-code.new.notifications.permissions"]).toBeUndefined()
|
||||
expect(properties["kilo-code.new.notifications.errors"]).toBeUndefined()
|
||||
expect(properties["kilo-code.new.sounds.agentEnabled"]?.default).toBe(false)
|
||||
expect(properties["kilo-code.new.sounds.permissionsEnabled"]?.default).toBe(false)
|
||||
expect(properties["kilo-code.new.sounds.errorsEnabled"]?.default).toBe(false)
|
||||
expect(properties["kilo-code.new.sounds.agent"]?.enum).not.toContain("none")
|
||||
})
|
||||
})
|
||||
|
||||
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")
|
||||
expect(properties["kilo-code.new.attention.enabled"]?.default).toBe(false)
|
||||
expect(properties["kilo-code.new.sounds.agentEnabled"]).toBeUndefined()
|
||||
expect(properties["kilo-code.new.sounds.permissionsEnabled"]).toBeUndefined()
|
||||
expect(properties["kilo-code.new.sounds.errorsEnabled"]).toBeUndefined()
|
||||
})
|
||||
|
||||
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()
|
||||
it("packages the upstream default sound set", async () => {
|
||||
const names = ["bip-bop-01", "bip-bop-03", "staplebops-06", "nope-03", "yup-01"]
|
||||
const exists = await Promise.all(
|
||||
names.map((name) => Bun.file(new URL(`../../audio-wav/${name}.wav`, import.meta.url)).exists()),
|
||||
)
|
||||
expect(exists).toEqual([true, true, true, true, true])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,166 +1,54 @@
|
||||
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"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import type { ExtensionMessage } from "../../types/messages"
|
||||
import SettingsRow from "./SettingsRow"
|
||||
|
||||
interface SoundOption {
|
||||
value: string
|
||||
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" },
|
||||
...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 = () => {
|
||||
const vscode = useVSCode()
|
||||
const language = useLanguage()
|
||||
|
||||
const [agentSoundEnabled, setAgentSoundEnabled] = createSignal(false)
|
||||
const [permSoundEnabled, setPermSoundEnabled] = createSignal(false)
|
||||
const [errorSoundEnabled, setErrorSoundEnabled] = createSignal(false)
|
||||
const [agentSound, setAgentSound] = createSignal("system")
|
||||
const [permSound, setPermSound] = createSignal("system")
|
||||
const [errorSound, setErrorSound] = createSignal("system")
|
||||
const [enabled, setEnabled] = createSignal(false)
|
||||
|
||||
const unsubscribe = vscode.onMessage((message: ExtensionMessage) => {
|
||||
if (message.type !== "notificationSettingsLoaded") return
|
||||
const settings = message.settings
|
||||
setAgentSoundEnabled(settings.soundAgentEnabled)
|
||||
setPermSoundEnabled(settings.soundPermissionsEnabled)
|
||||
setErrorSoundEnabled(settings.soundErrorsEnabled)
|
||||
setAgentSound(SOUND_OPTIONS.some((option) => option.value === settings.soundAgent) ? settings.soundAgent : "system")
|
||||
setPermSound(
|
||||
SOUND_OPTIONS.some((option) => option.value === settings.soundPermissions) ? settings.soundPermissions : "system",
|
||||
)
|
||||
setErrorSound(
|
||||
SOUND_OPTIONS.some((option) => option.value === settings.soundErrors) ? settings.soundErrors : "system",
|
||||
)
|
||||
setEnabled(message.settings.attentionEnabled)
|
||||
})
|
||||
|
||||
onCleanup(unsubscribe)
|
||||
vscode.postMessage({ type: "requestNotificationSettings" })
|
||||
|
||||
const save = (key: string, value: unknown) => {
|
||||
vscode.postMessage({ type: "updateSetting", key, value })
|
||||
}
|
||||
|
||||
const test = (settingType: "agent" | "permissions" | "errors", sound: string) => {
|
||||
vscode.postMessage({ type: "testNotification", settingType, sound })
|
||||
}
|
||||
|
||||
const picker = (
|
||||
enabled: () => boolean,
|
||||
setEnabled: (value: boolean) => void,
|
||||
value: () => string,
|
||||
set: (value: string) => void,
|
||||
key: string,
|
||||
kind: "agent" | "permissions" | "errors",
|
||||
label: string,
|
||||
) => (
|
||||
<div style={{ display: "flex", gap: "8px", "align-items": "center", "flex-wrap": "wrap" }}>
|
||||
<Switch
|
||||
checked={enabled()}
|
||||
onChange={(checked) => {
|
||||
setEnabled(checked)
|
||||
save(`sounds.${key}Enabled`, checked)
|
||||
if (checked) save(`sounds.${key}`, value())
|
||||
}}
|
||||
hideLabel
|
||||
>
|
||||
{label}
|
||||
</Switch>
|
||||
<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(`sounds.${key}`, option.value)
|
||||
}}
|
||||
disabled={!enabled()}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
triggerVariant="settings"
|
||||
/>
|
||||
<Button variant="ghost" size="small" disabled={!enabled()} onClick={() => test(kind, value())}>
|
||||
{language.t("settings.notifications.testSound")}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.agentSound.title")}
|
||||
description={language.t("settings.notifications.agentSound.description")}
|
||||
>
|
||||
{picker(
|
||||
agentSoundEnabled,
|
||||
setAgentSoundEnabled,
|
||||
agentSound,
|
||||
setAgentSound,
|
||||
"agent",
|
||||
"agent",
|
||||
language.t("settings.notifications.agentSound.title"),
|
||||
)}
|
||||
</SettingsRow>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.permSound.title")}
|
||||
description={language.t("settings.notifications.permSound.description")}
|
||||
>
|
||||
{picker(
|
||||
permSoundEnabled,
|
||||
setPermSoundEnabled,
|
||||
permSound,
|
||||
setPermSound,
|
||||
"permissions",
|
||||
"permissions",
|
||||
language.t("settings.notifications.permSound.title"),
|
||||
)}
|
||||
</SettingsRow>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.errorSound.title")}
|
||||
description={language.t("settings.notifications.errorSound.description")}
|
||||
>
|
||||
{picker(
|
||||
errorSoundEnabled,
|
||||
setErrorSoundEnabled,
|
||||
errorSound,
|
||||
setErrorSound,
|
||||
"errors",
|
||||
"errors",
|
||||
language.t("settings.notifications.errorSound.title"),
|
||||
)}
|
||||
</SettingsRow>
|
||||
</Card>
|
||||
</div>
|
||||
<Card>
|
||||
<SettingsRow
|
||||
title={language.t("settings.notifications.enable.title")}
|
||||
description={language.t("settings.notifications.enable.description")}
|
||||
last
|
||||
>
|
||||
<div style={{ display: "flex", gap: "8px", "align-items": "center" }}>
|
||||
<Switch
|
||||
checked={enabled()}
|
||||
onChange={(checked) => {
|
||||
setEnabled(checked)
|
||||
vscode.postMessage({ type: "updateSetting", key: "attention.enabled", value: checked })
|
||||
}}
|
||||
hideLabel
|
||||
>
|
||||
{language.t("settings.notifications.enable.title")}
|
||||
</Switch>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="small"
|
||||
disabled={!enabled()}
|
||||
onClick={() => vscode.postMessage({ type: "testNotification" })}
|
||||
>
|
||||
{language.t("settings.notifications.testSound")}
|
||||
</Button>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ const Settings: Component<SettingsProps> = (props) => {
|
||||
<AutocompleteTab onNavigateToModels={() => onTabChange("models")} />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="notifications">
|
||||
<h3>{language.t("settings.notifications.sounds")}</h3>
|
||||
<h3>{language.t("settings.notifications.title")}</h3>
|
||||
<NotificationsTab />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="context">
|
||||
|
||||
+11
-3
@@ -1218,7 +1218,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "تمكين الإكمال التلقائي للدردشة",
|
||||
"settings.autocomplete.chatAutocomplete.description": "عرض اقتراحات الإكمال التلقائي في مربع الدردشة",
|
||||
"settings.autocomplete.modelsHint": "لاختيار النموذج المستخدم للإكمال التلقائي، راجع إعدادات النماذج.",
|
||||
"settings.notifications.sounds": "إشعارات صوتية",
|
||||
"settings.notifications.agent.title": "إكمال الوكيل",
|
||||
"settings.notifications.agent.description": "إظهار إشعار عند إكمال الوكيل لمهمة",
|
||||
"settings.notifications.permissions.title": "طلبات الأذونات",
|
||||
"settings.notifications.permissions.description": "إظهار إشعار عند طلبات الأذونات",
|
||||
"settings.notifications.errors.title": "أخطاء",
|
||||
"settings.notifications.errors.description": "إظهار إشعار عند الأخطاء",
|
||||
"settings.notifications.sounds": "أصوات",
|
||||
"settings.notifications.enable.title": "تمكين الإشعارات الصوتية",
|
||||
"settings.notifications.enable.description":
|
||||
"تشغيل أصوات تنبيه OpenCode عند اكتمال الجلسات أو حدوث خطأ أو الحاجة إلى ردّك",
|
||||
"settings.notifications.testSound": "اختبار",
|
||||
"settings.notifications.agentSound.title": "صوت إكمال الوكيل",
|
||||
"settings.notifications.agentSound.description": "الصوت عند إكمال الوكيل",
|
||||
"settings.notifications.permSound.title": "صوت طلب الأذونات",
|
||||
@@ -1227,8 +1237,6 @@ 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": "يدوي",
|
||||
|
||||
+11
-3
@@ -1246,7 +1246,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Mostrar sugestões de autocompletar no campo de chat",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Para escolher qual modelo é usado para autocompletar, veja as configurações de Modelos.",
|
||||
"settings.notifications.sounds": "Notificações sonoras",
|
||||
"settings.notifications.agent.title": "Conclusão do agente",
|
||||
"settings.notifications.agent.description": "Mostrar notificação quando o agente conclui uma tarefa",
|
||||
"settings.notifications.permissions.title": "Solicitações de permissão",
|
||||
"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.sounds": "Sons",
|
||||
"settings.notifications.enable.title": "Ativar notificações sonoras",
|
||||
"settings.notifications.enable.description":
|
||||
"Reproduzir os sons de alerta do OpenCode quando as sessões forem concluídas, ocorrer um erro ou sua interação for necessária",
|
||||
"settings.notifications.testSound": "Testar",
|
||||
"settings.notifications.agentSound.title": "Som de conclusão do agente",
|
||||
"settings.notifications.agentSound.description": "Som ao concluir o agente",
|
||||
"settings.notifications.permSound.title": "Som de solicitação de permissão",
|
||||
@@ -1255,8 +1265,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1247,7 +1247,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Prikaži prijedloge automatskog dovršavanja u polju chata",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Da odaberete koji se model koristi za automatsko dovršavanje, pogledajte postavke Modela.",
|
||||
"settings.notifications.sounds": "Zvučna obavještenja",
|
||||
"settings.notifications.agent.title": "Završetak agenta",
|
||||
"settings.notifications.agent.description": "Prikaži obavijest kada agent završi zadatak",
|
||||
"settings.notifications.permissions.title": "Zahtjevi za dozvolu",
|
||||
"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.sounds": "Zvukovi",
|
||||
"settings.notifications.enable.title": "Omogući zvučne obavijesti",
|
||||
"settings.notifications.enable.description":
|
||||
"Reproduciraj OpenCode zvukove upozorenja kada se sesije završe, dođe do greške ili je potreban vaš odgovor",
|
||||
"settings.notifications.testSound": "Testiraj",
|
||||
"settings.notifications.agentSound.title": "Zvuk završetka agenta",
|
||||
"settings.notifications.agentSound.description": "Zvuk pri završetku agenta",
|
||||
"settings.notifications.permSound.title": "Zvuk zahtjeva za dozvolu",
|
||||
@@ -1256,8 +1266,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1240,7 +1240,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Vis autofuldførelsesforslag i chatfeltet",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"For at vælge hvilken model der bruges til autofuldførelse, se Modelindstillinger.",
|
||||
"settings.notifications.sounds": "Lydnotifikationer",
|
||||
"settings.notifications.agent.title": "Agentafslutning",
|
||||
"settings.notifications.agent.description": "Vis notifikation, når agenten fuldfører en opgave",
|
||||
"settings.notifications.permissions.title": "Tilladelsesanmodninger",
|
||||
"settings.notifications.permissions.description": "Vis notifikation ved tilladelsesanmodninger",
|
||||
"settings.notifications.errors.title": "Fejl",
|
||||
"settings.notifications.errors.description": "Vis notifikation ved fejl",
|
||||
"settings.notifications.sounds": "Lyde",
|
||||
"settings.notifications.enable.title": "Aktivér lydnotifikationer",
|
||||
"settings.notifications.enable.description":
|
||||
"Afspil notifikationslyde fra OpenCode, når sessioner afsluttes, der opstår en fejl, eller der er brug for input fra dig",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.notifications.agentSound.title": "Agentafslutningslyd",
|
||||
"settings.notifications.agentSound.description": "Lyd ved agentafslutning",
|
||||
"settings.notifications.permSound.title": "Tilladelsesanmodningslyd",
|
||||
@@ -1249,8 +1259,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1261,7 +1261,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Autovervollständigungsvorschläge im Chat-Textfeld anzeigen",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Um zu wählen, welches Modell für die Autovervollständigung verwendet wird, siehe Modelleinstellungen.",
|
||||
"settings.notifications.sounds": "Tonbenachrichtigungen",
|
||||
"settings.notifications.agent.title": "Agent-Abschluss",
|
||||
"settings.notifications.agent.description": "Benachrichtigung anzeigen, wenn der Agent eine Aufgabe abschließt",
|
||||
"settings.notifications.permissions.title": "Berechtigungsanfragen",
|
||||
"settings.notifications.permissions.description": "Benachrichtigung bei Berechtigungsanfragen anzeigen",
|
||||
"settings.notifications.errors.title": "Fehler",
|
||||
"settings.notifications.errors.description": "Benachrichtigung bei Fehlern anzeigen",
|
||||
"settings.notifications.sounds": "Töne",
|
||||
"settings.notifications.enable.title": "Tonbenachrichtigungen aktivieren",
|
||||
"settings.notifications.enable.description":
|
||||
"OpenCode-Hinweistöne wiedergeben, wenn Sitzungen abgeschlossen werden, ein Fehler auftritt oder Ihre Eingabe erforderlich ist",
|
||||
"settings.notifications.testSound": "Testen",
|
||||
"settings.notifications.agentSound.title": "Agent-Abschlusston",
|
||||
"settings.notifications.agentSound.description": "Ton bei Agent-Abschluss abspielen",
|
||||
"settings.notifications.permSound.title": "Berechtigungsanfrageton",
|
||||
@@ -1270,8 +1280,6 @@ 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",
|
||||
|
||||
@@ -1226,7 +1226,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Show autocomplete suggestions in the chat textarea",
|
||||
"settings.autocomplete.modelsHint": "To choose which model is used for autocompletions, see the Models settings.",
|
||||
|
||||
"settings.notifications.sounds": "Sound Notifications",
|
||||
"settings.notifications.agent.title": "Agent Completion",
|
||||
"settings.notifications.agent.description": "Show notification when agent completes a task",
|
||||
"settings.notifications.permissions.title": "Permission Requests",
|
||||
"settings.notifications.permissions.description": "Show notification on permission requests",
|
||||
"settings.notifications.errors.title": "Errors",
|
||||
"settings.notifications.errors.description": "Show notification on errors",
|
||||
"settings.notifications.sounds": "Sounds",
|
||||
"settings.notifications.enable.title": "Enable Sound Notifications",
|
||||
"settings.notifications.enable.description":
|
||||
"Play OpenCode attention sounds when sessions complete, encounter an error, or need your input",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.notifications.agentSound.title": "Agent Completion Sound",
|
||||
"settings.notifications.agentSound.description": "Sound to play when agent completes",
|
||||
"settings.notifications.permSound.title": "Permission Request Sound",
|
||||
@@ -1235,8 +1245,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1253,7 +1253,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Mostrar sugerencias de autocompletado en el chat",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Para elegir qué modelo se usa para el autocompletado, consulta la configuración de Modelos.",
|
||||
"settings.notifications.sounds": "Notificaciones sonoras",
|
||||
"settings.notifications.agent.title": "Finalización del agente",
|
||||
"settings.notifications.agent.description": "Mostrar notificación cuando el agente completa una tarea",
|
||||
"settings.notifications.permissions.title": "Solicitudes de permiso",
|
||||
"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.sounds": "Sonidos",
|
||||
"settings.notifications.enable.title": "Activar las notificaciones sonoras",
|
||||
"settings.notifications.enable.description":
|
||||
"Reproducir sonidos de aviso de OpenCode cuando las sesiones finalicen, se produzca un error o se requiera tu intervención",
|
||||
"settings.notifications.testSound": "Probar",
|
||||
"settings.notifications.agentSound.title": "Sonido de finalización del agente",
|
||||
"settings.notifications.agentSound.description": "Sonido a reproducir cuando el agente finaliza",
|
||||
"settings.notifications.permSound.title": "Sonido de solicitud de permiso",
|
||||
@@ -1262,8 +1272,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1265,7 +1265,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Afficher les suggestions d'autocomplétion dans le chat",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Pour choisir le modèle utilisé pour l'autocomplétion, consultez les paramètres des Modèles.",
|
||||
"settings.notifications.sounds": "Notifications sonores",
|
||||
"settings.notifications.agent.title": "Achèvement de l'agent",
|
||||
"settings.notifications.agent.description": "Afficher une notification lorsque l'agent termine une tâche",
|
||||
"settings.notifications.permissions.title": "Demandes d'autorisation",
|
||||
"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.sounds": "Sons",
|
||||
"settings.notifications.enable.title": "Activer les notifications sonores",
|
||||
"settings.notifications.enable.description":
|
||||
"Lire les sons d’alerte d’OpenCode lorsque les sessions se terminent, rencontrent une erreur ou nécessitent votre intervention",
|
||||
"settings.notifications.testSound": "Tester",
|
||||
"settings.notifications.agentSound.title": "Son d'achèvement de l'agent",
|
||||
"settings.notifications.agentSound.description": "Son à jouer lorsque l'agent termine",
|
||||
"settings.notifications.permSound.title": "Son de demande d'autorisation",
|
||||
@@ -1274,8 +1284,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1086,7 +1086,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "Abilita autocompletamento textarea chat",
|
||||
"settings.autocomplete.chatAutocomplete.description":
|
||||
"Mostra suggerimenti di autocompletamento nella textarea della chat",
|
||||
"settings.notifications.sounds": "Notifiche sonore",
|
||||
"settings.notifications.agent.title": "Completamento agente",
|
||||
"settings.notifications.agent.description": "Mostra una notifica quando l'agente completa un task",
|
||||
"settings.notifications.permissions.title": "Richieste autorizzazione",
|
||||
"settings.notifications.permissions.description": "Mostra una notifica per le richieste di autorizzazione",
|
||||
"settings.notifications.errors.title": "Errori",
|
||||
"settings.notifications.errors.description": "Mostra una notifica per gli errori",
|
||||
"settings.notifications.sounds": "Suoni",
|
||||
"settings.notifications.enable.title": "Abilita le notifiche sonore",
|
||||
"settings.notifications.enable.description":
|
||||
"Riproduci i suoni di avviso di OpenCode quando le sessioni si concludono, si verifica un errore o è richiesto il tuo intervento",
|
||||
"settings.notifications.testSound": "Prova",
|
||||
"settings.notifications.agentSound.title": "Suono completamento agente",
|
||||
"settings.notifications.agentSound.description": "Suono da riprodurre quando l'agente completa un task",
|
||||
"settings.notifications.permSound.title": "Suono richiesta autorizzazione",
|
||||
@@ -1095,8 +1105,6 @@ export const dict = {
|
||||
"settings.notifications.errorSound.description": "Suono da riprodurre per gli errori",
|
||||
"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",
|
||||
|
||||
+11
-3
@@ -1235,7 +1235,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "チャットの自動補完を有効にする",
|
||||
"settings.autocomplete.chatAutocomplete.description": "チャットテキストエリアに自動補完の提案を表示",
|
||||
"settings.autocomplete.modelsHint": "オートコンプリートに使用するモデルを選択するには、モデル設定をご覧ください。",
|
||||
"settings.notifications.sounds": "サウンド通知",
|
||||
"settings.notifications.agent.title": "エージェント完了",
|
||||
"settings.notifications.agent.description": "エージェントがタスクを完了したら通知を表示",
|
||||
"settings.notifications.permissions.title": "権限リクエスト",
|
||||
"settings.notifications.permissions.description": "権限リクエスト時に通知を表示",
|
||||
"settings.notifications.errors.title": "エラー",
|
||||
"settings.notifications.errors.description": "エラー発生時に通知を表示",
|
||||
"settings.notifications.sounds": "サウンド",
|
||||
"settings.notifications.enable.title": "サウンド通知を有効にする",
|
||||
"settings.notifications.enable.description":
|
||||
"セッションが完了したとき、エラーが発生したとき、またはユーザー入力が必要なときに OpenCode の通知音を再生します",
|
||||
"settings.notifications.testSound": "テスト",
|
||||
"settings.notifications.agentSound.title": "エージェント完了サウンド",
|
||||
"settings.notifications.agentSound.description": "エージェント完了時に再生するサウンド",
|
||||
"settings.notifications.permSound.title": "権限リクエストサウンド",
|
||||
@@ -1244,8 +1254,6 @@ 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": "手動",
|
||||
|
||||
+11
-3
@@ -1229,7 +1229,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "채팅 텍스트 영역 자동완성 활성화",
|
||||
"settings.autocomplete.chatAutocomplete.description": "채팅 텍스트 영역에서 자동완성 제안 표시",
|
||||
"settings.autocomplete.modelsHint": "자동 완성에 사용되는 모델을 선택하려면 모델 설정을 참조하세요.",
|
||||
"settings.notifications.sounds": "소리 알림",
|
||||
"settings.notifications.agent.title": "에이전트 완료",
|
||||
"settings.notifications.agent.description": "에이전트가 작업을 완료하면 알림 표시",
|
||||
"settings.notifications.permissions.title": "권한 요청",
|
||||
"settings.notifications.permissions.description": "권한 요청 시 알림 표시",
|
||||
"settings.notifications.errors.title": "오류",
|
||||
"settings.notifications.errors.description": "오류 발생 시 알림 표시",
|
||||
"settings.notifications.sounds": "소리",
|
||||
"settings.notifications.enable.title": "소리 알림 활성화",
|
||||
"settings.notifications.enable.description":
|
||||
"세션이 완료되거나 오류가 발생하거나 사용자 입력이 필요할 때 OpenCode 알림음을 재생합니다",
|
||||
"settings.notifications.testSound": "테스트",
|
||||
"settings.notifications.agentSound.title": "에이전트 완료 소리",
|
||||
"settings.notifications.agentSound.description": "에이전트 완료 시 재생할 소리",
|
||||
"settings.notifications.permSound.title": "권한 요청 소리",
|
||||
@@ -1238,8 +1248,6 @@ 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": "수동",
|
||||
|
||||
+11
-3
@@ -1241,7 +1241,17 @@ export const dict = {
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Om te kiezen welk model wordt gebruikt voor automatisch aanvullen, zie de Modellen-instellingen.",
|
||||
|
||||
"settings.notifications.sounds": "Geluidsmeldingen",
|
||||
"settings.notifications.agent.title": "Agent Voltooiing",
|
||||
"settings.notifications.agent.description": "Toon melding wanneer agent een taak voltooit",
|
||||
"settings.notifications.permissions.title": "Toestemmingsverzoeken",
|
||||
"settings.notifications.permissions.description": "Toon melding bij toestemmingsverzoeken",
|
||||
"settings.notifications.errors.title": "Fouten",
|
||||
"settings.notifications.errors.description": "Toon melding bij fouten",
|
||||
"settings.notifications.sounds": "Geluiden",
|
||||
"settings.notifications.enable.title": "Geluidsmeldingen inschakelen",
|
||||
"settings.notifications.enable.description":
|
||||
"Waarschuwingsgeluiden van OpenCode afspelen wanneer sessies worden voltooid, er een fout optreedt of uw invoer vereist is",
|
||||
"settings.notifications.testSound": "Testen",
|
||||
"settings.notifications.agentSound.title": "Agent Voltooiingsgeluid",
|
||||
"settings.notifications.agentSound.description": "Geluid om af te spelen wanneer agent voltooit",
|
||||
"settings.notifications.permSound.title": "Toestemmingsverzoek Geluid",
|
||||
@@ -1250,8 +1260,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1206,7 +1206,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Vis autofullføringsforslag i chatfeltet",
|
||||
"settings.autocomplete.modelsHint":
|
||||
"For å velge hvilken modell som brukes til autofullføring, se Modellinnstillinger.",
|
||||
"settings.notifications.sounds": "Lydvarsler",
|
||||
"settings.notifications.agent.title": "Agentfullføring",
|
||||
"settings.notifications.agent.description": "Vis varsling når agenten fullfører en oppgave",
|
||||
"settings.notifications.permissions.title": "Tillatelsesforespørsler",
|
||||
"settings.notifications.permissions.description": "Vis varsling ved tillatelsesforespørsler",
|
||||
"settings.notifications.errors.title": "Feil",
|
||||
"settings.notifications.errors.description": "Vis varsling ved feil",
|
||||
"settings.notifications.sounds": "Lyder",
|
||||
"settings.notifications.enable.title": "Aktiver lydvarsler",
|
||||
"settings.notifications.enable.description":
|
||||
"Spill av varsellyder fra OpenCode når økter fullføres, det oppstår en feil eller det trengs innspill fra deg",
|
||||
"settings.notifications.testSound": "Test",
|
||||
"settings.notifications.agentSound.title": "Agentfullføringslyd",
|
||||
"settings.notifications.agentSound.description": "Lyd ved agentfullføring",
|
||||
"settings.notifications.permSound.title": "Tillatelsesforespørselslyd",
|
||||
@@ -1215,8 +1225,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1205,7 +1205,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "Włącz autouzupełnianie czatu",
|
||||
"settings.autocomplete.chatAutocomplete.description": "Pokaż sugestie autouzupełniania w polu czatu",
|
||||
"settings.autocomplete.modelsHint": "Aby wybrać model używany do autouzupełniania, zobacz Ustawienia modeli.",
|
||||
"settings.notifications.sounds": "Powiadomienia dźwiękowe",
|
||||
"settings.notifications.agent.title": "Zakończenie agenta",
|
||||
"settings.notifications.agent.description": "Pokaż powiadomienie po zakończeniu zadania przez agenta",
|
||||
"settings.notifications.permissions.title": "Żądania uprawnień",
|
||||
"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.sounds": "Dźwięki",
|
||||
"settings.notifications.enable.title": "Włącz powiadomienia dźwiękowe",
|
||||
"settings.notifications.enable.description":
|
||||
"Odtwarzaj dźwięki alertów OpenCode, gdy sesje się zakończą, wystąpi błąd lub będzie potrzebna Twoja odpowiedź",
|
||||
"settings.notifications.testSound": "Testuj",
|
||||
"settings.notifications.agentSound.title": "Dźwięk zakończenia agenta",
|
||||
"settings.notifications.agentSound.description": "Dźwięk odtwarzany po zakończeniu agenta",
|
||||
"settings.notifications.permSound.title": "Dźwięk żądania uprawnień",
|
||||
@@ -1214,8 +1224,6 @@ 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",
|
||||
|
||||
+11
-3
@@ -1243,7 +1243,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "Включить автодополнение чата",
|
||||
"settings.autocomplete.chatAutocomplete.description": "Показывать предложения автодополнения в поле чата",
|
||||
"settings.autocomplete.modelsHint": "Чтобы выбрать модель для автодополнения, см. настройки Моделей.",
|
||||
"settings.notifications.sounds": "Звуковые уведомления",
|
||||
"settings.notifications.agent.title": "Завершение агента",
|
||||
"settings.notifications.agent.description": "Показать уведомление при завершении задачи агентом",
|
||||
"settings.notifications.permissions.title": "Запросы разрешений",
|
||||
"settings.notifications.permissions.description": "Показать уведомление при запросах разрешений",
|
||||
"settings.notifications.errors.title": "Ошибки",
|
||||
"settings.notifications.errors.description": "Показать уведомление при ошибках",
|
||||
"settings.notifications.sounds": "Звуки",
|
||||
"settings.notifications.enable.title": "Включить звуковые уведомления",
|
||||
"settings.notifications.enable.description":
|
||||
"Воспроизводить звуки оповещения OpenCode при завершении сеансов, возникновении ошибки или необходимости вашего участия",
|
||||
"settings.notifications.testSound": "Тест",
|
||||
"settings.notifications.agentSound.title": "Звук завершения агента",
|
||||
"settings.notifications.agentSound.description": "Звук при завершении агента",
|
||||
"settings.notifications.permSound.title": "Звук запроса разрешений",
|
||||
@@ -1252,8 +1262,6 @@ 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": "Вручную",
|
||||
|
||||
+11
-3
@@ -1226,7 +1226,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "เปิดใช้งานเติมอัตโนมัติแชท",
|
||||
"settings.autocomplete.chatAutocomplete.description": "แสดงข้อเสนอแนะเติมอัตโนมัติในช่องแชท",
|
||||
"settings.autocomplete.modelsHint": "เลือกโมเดลที่ใช้สำหรับการเติมอัตโนมัติได้ที่การตั้งค่าโมเดล",
|
||||
"settings.notifications.sounds": "การแจ้งเตือนด้วยเสียง",
|
||||
"settings.notifications.agent.title": "เอเจนต์เสร็จสิ้น",
|
||||
"settings.notifications.agent.description": "แสดงการแจ้งเตือนเมื่อเอเจนต์ทำงานเสร็จ",
|
||||
"settings.notifications.permissions.title": "คำขออนุญาต",
|
||||
"settings.notifications.permissions.description": "แสดงการแจ้งเตือนเมื่อมีคำขออนุญาต",
|
||||
"settings.notifications.errors.title": "ข้อผิดพลาด",
|
||||
"settings.notifications.errors.description": "แสดงการแจ้งเตือนเมื่อเกิดข้อผิดพลาด",
|
||||
"settings.notifications.sounds": "เสียง",
|
||||
"settings.notifications.enable.title": "เปิดใช้การแจ้งเตือนด้วยเสียง",
|
||||
"settings.notifications.enable.description":
|
||||
"เล่นเสียงแจ้งเตือนของ OpenCode เมื่อเซสชันเสร็จสิ้น เกิดข้อผิดพลาด หรือต้องการให้คุณป้อนข้อมูล",
|
||||
"settings.notifications.testSound": "ทดสอบ",
|
||||
"settings.notifications.agentSound.title": "เสียงเอเจนต์เสร็จสิ้น",
|
||||
"settings.notifications.agentSound.description": "เสียงเมื่อเอเจนต์ทำงานเสร็จ",
|
||||
"settings.notifications.permSound.title": "เสียงคำขออนุญาต",
|
||||
@@ -1235,8 +1245,6 @@ 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": "ด้วยตนเอง",
|
||||
|
||||
+11
-3
@@ -1234,7 +1234,17 @@ export const dict = {
|
||||
"settings.autocomplete.modelsHint":
|
||||
"Otomatik tamamlama için kullanılacak modeli seçmek için Modeller ayarlarına bakın.",
|
||||
|
||||
"settings.notifications.sounds": "Sesli Bildirimler",
|
||||
"settings.notifications.agent.title": "Ajan Tamamlanması",
|
||||
"settings.notifications.agent.description": "Ajan bir görevi tamamladığında bildirim göster",
|
||||
"settings.notifications.permissions.title": "İzin İstekleri",
|
||||
"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.sounds": "Sesler",
|
||||
"settings.notifications.enable.title": "Sesli bildirimleri etkinleştir",
|
||||
"settings.notifications.enable.description":
|
||||
"Oturumlar tamamlandığında, bir hata oluştuğunda veya sizden giriş beklendiğinde OpenCode uyarı seslerini çal",
|
||||
"settings.notifications.testSound": "Test et",
|
||||
"settings.notifications.agentSound.title": "Ajan Tamamlanma Sesi",
|
||||
"settings.notifications.agentSound.description": "Ajan tamamlandığında çalınacak ses",
|
||||
"settings.notifications.permSound.title": "İzin İsteği Sesi",
|
||||
@@ -1243,8 +1253,6 @@ 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ğı",
|
||||
|
||||
+11
-3
@@ -1234,7 +1234,17 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.description": "Показувати підказки автодоповнення в полі введення чату",
|
||||
"settings.autocomplete.modelsHint": "Щоб вибрати модель для автодоповнення, див. Налаштування моделей.",
|
||||
|
||||
"settings.notifications.sounds": "Звукові сповіщення",
|
||||
"settings.notifications.agent.title": "Завершення агента",
|
||||
"settings.notifications.agent.description": "Показувати сповіщення, коли агент завершить завдання",
|
||||
"settings.notifications.permissions.title": "Запити дозволів",
|
||||
"settings.notifications.permissions.description": "Показувати сповіщення при запитах дозволів",
|
||||
"settings.notifications.errors.title": "Помилки",
|
||||
"settings.notifications.errors.description": "Показувати сповіщення при виникненні помилок",
|
||||
"settings.notifications.sounds": "Звуки",
|
||||
"settings.notifications.enable.title": "Увімкнути звукові сповіщення",
|
||||
"settings.notifications.enable.description":
|
||||
"Відтворювати звуки сповіщень OpenCode, коли сеанси завершуються, виникає помилка або потрібна ваша відповідь",
|
||||
"settings.notifications.testSound": "Тест",
|
||||
"settings.notifications.agentSound.title": "Звук завершення агента",
|
||||
"settings.notifications.agentSound.description": "Звук, що відтворюється після завершення агента",
|
||||
"settings.notifications.permSound.title": "Звук запиту дозволу",
|
||||
@@ -1243,8 +1253,6 @@ 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": "Як поводиться публікація сесій",
|
||||
|
||||
+10
-3
@@ -1208,7 +1208,16 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "启用聊天文本框自动补全",
|
||||
"settings.autocomplete.chatAutocomplete.description": "在聊天文本框中显示自动补全建议",
|
||||
"settings.autocomplete.modelsHint": "若要选择用于自动补全的模型,请参阅模型设置。",
|
||||
"settings.notifications.sounds": "声音通知",
|
||||
"settings.notifications.agent.title": "智能体完成",
|
||||
"settings.notifications.agent.description": "智能体完成任务时显示通知",
|
||||
"settings.notifications.permissions.title": "权限请求",
|
||||
"settings.notifications.permissions.description": "权限请求时显示通知",
|
||||
"settings.notifications.errors.title": "错误",
|
||||
"settings.notifications.errors.description": "发生错误时显示通知",
|
||||
"settings.notifications.sounds": "声音",
|
||||
"settings.notifications.enable.title": "启用声音通知",
|
||||
"settings.notifications.enable.description": "在会话完成、发生错误或需要你输入时播放 OpenCode 提示音",
|
||||
"settings.notifications.testSound": "测试",
|
||||
"settings.notifications.agentSound.title": "智能体完成提示音",
|
||||
"settings.notifications.agentSound.description": "智能体完成时播放的声音",
|
||||
"settings.notifications.permSound.title": "权限请求提示音",
|
||||
@@ -1217,8 +1226,6 @@ 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": "手动",
|
||||
|
||||
+10
-3
@@ -1176,7 +1176,16 @@ export const dict = {
|
||||
"settings.autocomplete.chatAutocomplete.title": "啟用聊天文字方塊自動補全",
|
||||
"settings.autocomplete.chatAutocomplete.description": "在聊天文字方塊中顯示自動補全建議",
|
||||
"settings.autocomplete.modelsHint": "若要選擇用於自動補全的模型,請參閱模型設定。",
|
||||
"settings.notifications.sounds": "聲音通知",
|
||||
"settings.notifications.agent.title": "Agent 完成",
|
||||
"settings.notifications.agent.description": "Agent 完成任務時顯示通知",
|
||||
"settings.notifications.permissions.title": "權限請求",
|
||||
"settings.notifications.permissions.description": "權限請求時顯示通知",
|
||||
"settings.notifications.errors.title": "錯誤",
|
||||
"settings.notifications.errors.description": "發生錯誤時顯示通知",
|
||||
"settings.notifications.sounds": "聲音",
|
||||
"settings.notifications.enable.title": "啟用聲音通知",
|
||||
"settings.notifications.enable.description": "在工作階段完成、發生錯誤或需要你輸入時播放 OpenCode 提示音",
|
||||
"settings.notifications.testSound": "測試",
|
||||
"settings.notifications.agentSound.title": "Agent 完成提示音",
|
||||
"settings.notifications.agentSound.description": "Agent 完成時播放的聲音",
|
||||
"settings.notifications.permSound.title": "權限請求提示音",
|
||||
@@ -1185,8 +1194,6 @@ 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": "手動",
|
||||
|
||||
@@ -486,12 +486,7 @@ export interface GlobalConfigLoadedMessage {
|
||||
export interface NotificationSettingsLoadedMessage {
|
||||
type: "notificationSettingsLoaded"
|
||||
settings: {
|
||||
soundAgentEnabled: boolean
|
||||
soundPermissionsEnabled: boolean
|
||||
soundErrorsEnabled: boolean
|
||||
soundAgent: string
|
||||
soundPermissions: string
|
||||
soundErrors: string
|
||||
attentionEnabled: boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -435,8 +435,6 @@ export interface RequestNotificationSettingsMessage {
|
||||
|
||||
export interface TestNotificationMessage {
|
||||
type: "testNotification"
|
||||
settingType: "agent" | "permissions" | "errors"
|
||||
sound: string
|
||||
}
|
||||
|
||||
export interface ResetAllSettingsRequest {
|
||||
|
||||
Reference in New Issue
Block a user