Kit Langton 3 месяцев назад
Родитель
Сommit
59b976b954

+ 0 - 7
bun.lock

@@ -418,7 +418,6 @@
         "bonjour-service": "1.3.0",
         "bonjour-service": "1.3.0",
         "bun-pty": "0.4.8",
         "bun-pty": "0.4.8",
         "chokidar": "4.0.3",
         "chokidar": "4.0.3",
-        "cli-sound": "1.1.3",
         "clipboardy": "4.0.0",
         "clipboardy": "4.0.0",
         "cross-spawn": "catalog:",
         "cross-spawn": "catalog:",
         "decimal.js": "10.5.0",
         "decimal.js": "10.5.0",
@@ -2811,8 +2810,6 @@
 
 
     "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
     "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
 
 
-    "cli-sound": ["cli-sound@1.1.3", "", { "dependencies": { "find-exec": "^1.0.3" }, "bin": { "cli-sound": "dist/esm/cli.js" } }, "sha512-dpdF3KS3wjo1fobKG5iU9KyKqzQWAqueymHzZ9epus/dZ40487gAvS6aXFeBul+GiQAQYUTAtUWgQvw6Jftbyg=="],
-
     "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="],
     "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="],
 
 
     "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
     "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
@@ -3237,8 +3234,6 @@
 
 
     "find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="],
     "find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="],
 
 
-    "find-exec": ["find-exec@1.0.3", "", { "dependencies": { "shell-quote": "^1.8.1" } }, "sha512-gnG38zW90mS8hm5smNcrBnakPEt+cGJoiMkJwCU0IYnEb0H2NQk0NIljhNW+48oniCriFek/PH6QXbwsJo/qug=="],
-
     "find-my-way": ["find-my-way@9.5.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ=="],
     "find-my-way": ["find-my-way@9.5.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ=="],
 
 
     "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="],
     "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="],
@@ -4567,8 +4562,6 @@
 
 
     "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
     "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
 
 
-    "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
-
     "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="],
     "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="],
 
 
     "shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="],
     "shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="],

+ 0 - 1
packages/opencode/package.json

@@ -129,7 +129,6 @@
     "bonjour-service": "1.3.0",
     "bonjour-service": "1.3.0",
     "bun-pty": "0.4.8",
     "bun-pty": "0.4.8",
     "chokidar": "4.0.3",
     "chokidar": "4.0.3",
-    "cli-sound": "1.1.3",
     "clipboardy": "4.0.0",
     "clipboardy": "4.0.0",
     "cross-spawn": "catalog:",
     "cross-spawn": "catalog:",
     "decimal.js": "10.5.0",
     "decimal.js": "10.5.0",

BIN
packages/opencode/src/cli/cmd/tui/asset/charge.wav


BIN
packages/opencode/src/cli/cmd/tui/asset/pulse-a.wav


BIN
packages/opencode/src/cli/cmd/tui/asset/pulse-b.wav


BIN
packages/opencode/src/cli/cmd/tui/asset/pulse-c.wav


+ 0 - 11
packages/opencode/src/cli/cmd/tui/component/logo.tsx

@@ -2,7 +2,6 @@ import { BoxRenderable, MouseButton, MouseEvent, RGBA, TextAttributes } from "@o
 import { useRenderer } from "@opentui/solid"
 import { useRenderer } from "@opentui/solid"
 import { For, createMemo, createSignal, onCleanup, onMount, type JSX } from "solid-js"
 import { For, createMemo, createSignal, onCleanup, onMount, type JSX } from "solid-js"
 import { useTheme, tint } from "@tui/context/theme"
 import { useTheme, tint } from "@tui/context/theme"
-import * as Sound from "@tui/util/sound"
 import { go, logo } from "@/cli/logo"
 import { go, logo } from "@/cli/logo"
 
 
 export type LogoShape = {
 export type LogoShape = {
@@ -563,7 +562,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
   const [now, setNow] = createSignal(0)
   const [now, setNow] = createSignal(0)
   let box: BoxRenderable | undefined
   let box: BoxRenderable | undefined
   let timer: ReturnType<typeof setInterval> | undefined
   let timer: ReturnType<typeof setInterval> | undefined
-  let hum = false
 
 
   const stop = () => {
   const stop = () => {
     if (!timer) return
     if (!timer) return
@@ -575,10 +573,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
     const t = performance.now()
     const t = performance.now()
     setNow(t)
     setNow(t)
     const item = hold()
     const item = hold()
-    if (item && !hum && t - item.at >= HOLD) {
-      hum = true
-      Sound.start()
-    }
     if (item && t - item.at >= CHARGE) {
     if (item && t - item.at >= CHARGE) {
       burst(item.x, item.y)
       burst(item.x, item.y)
     }
     }
@@ -605,8 +599,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
 
 
   onCleanup(() => {
   onCleanup(() => {
     stop()
     stop()
-    hum = false
-    Sound.dispose()
   })
   })
 
 
   onMount(() => {
   onMount(() => {
@@ -626,14 +618,12 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
     setNow(t)
     setNow(t)
     if (!last) setRelease(undefined)
     if (!last) setRelease(undefined)
     setHold({ x, y, at: t, glyph: select(x, y, ctx) })
     setHold({ x, y, at: t, glyph: select(x, y, ctx) })
-    hum = false
     start()
     start()
   }
   }
 
 
   const burst = (x: number, y: number) => {
   const burst = (x: number, y: number) => {
     const item = hold()
     const item = hold()
     if (!item) return
     if (!item) return
-    hum = false
     const t = performance.now()
     const t = performance.now()
     const age = t - item.at
     const age = t - item.at
     const rise = ramp(age, HOLD, CHARGE)
     const rise = ramp(age, HOLD, CHARGE)
@@ -655,7 +645,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } =
     ])
     ])
     setNow(t)
     setNow(t)
     start()
     start()
-    Sound.pulse(lerp(0.8, 1, level))
   }
   }
 
 
   const frame = createMemo(() => {
   const frame = createMemo(() => {

+ 0 - 156
packages/opencode/src/cli/cmd/tui/util/sound.ts

@@ -1,156 +0,0 @@
-import { Player } from "cli-sound"
-import { mkdirSync } from "node:fs"
-import { tmpdir } from "node:os"
-import { basename, join } from "node:path"
-import { Process } from "@/util/process"
-import { which } from "@/util/which"
-import pulseA from "../asset/pulse-a.wav" with { type: "file" }
-import pulseB from "../asset/pulse-b.wav" with { type: "file" }
-import pulseC from "../asset/pulse-c.wav" with { type: "file" }
-import charge from "../asset/charge.wav" with { type: "file" }
-
-const FILE = [pulseA, pulseB, pulseC]
-
-const HUM = charge
-const DIR = join(tmpdir(), "opencode-sfx")
-
-const LIST = [
-  "ffplay",
-  "mpv",
-  "mpg123",
-  "mpg321",
-  "mplayer",
-  "afplay",
-  "play",
-  "omxplayer",
-  "aplay",
-  "cmdmp3",
-  "cvlc",
-  "powershell.exe",
-] as const
-
-type Kind = (typeof LIST)[number]
-
-function args(kind: Kind, file: string, volume: number) {
-  if (kind === "ffplay") return [kind, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file]
-  if (kind === "mpv")
-    return [kind, "--no-video", "--audio-display=no", "--volume", String(Math.round(volume * 100)), file]
-  if (kind === "mpg123" || kind === "mpg321") return [kind, "-g", String(Math.round(volume * 100)), file]
-  if (kind === "mplayer") return [kind, "-vo", "null", "-volume", String(Math.round(volume * 100)), file]
-  if (kind === "afplay" || kind === "omxplayer" || kind === "aplay" || kind === "cmdmp3") return [kind, file]
-  if (kind === "play") return [kind, "-v", String(volume), file]
-  if (kind === "cvlc") return [kind, `--gain=${volume}`, "--play-and-exit", file]
-  return [kind, "-c", `(New-Object Media.SoundPlayer '${file.replace(/'/g, "''")}').PlaySync()`]
-}
-
-let item: Player | null | undefined
-let kind: Kind | null | undefined
-let proc: Process.Child | undefined
-let tail: ReturnType<typeof setTimeout> | undefined
-let cache: Promise<{ hum: string; pulse: string[] }> | undefined
-let seq = 0
-let shot = 0
-
-function load() {
-  if (item !== undefined) return item
-  try {
-    item = new Player({ volume: 0.35 })
-  } catch {
-    item = null
-  }
-  return item
-}
-
-async function file(path: string) {
-  mkdirSync(DIR, { recursive: true })
-  const next = join(DIR, basename(path))
-  const out = Bun.file(next)
-  if (await out.exists()) return next
-  await Bun.write(out, Bun.file(path))
-  return next
-}
-
-function asset() {
-  cache ??= Promise.all([file(HUM), Promise.all(FILE.map(file))]).then(([hum, pulse]) => ({ hum, pulse }))
-  return cache
-}
-
-function pick() {
-  if (kind !== undefined) return kind
-  kind = LIST.find((item) => which(item)) ?? null
-  return kind
-}
-
-function run(file: string, volume: number) {
-  const kind = pick()
-  if (!kind) return
-  return Process.spawn(args(kind, file, volume), {
-    stdin: "ignore",
-    stdout: "ignore",
-    stderr: "ignore",
-  })
-}
-
-function clear() {
-  if (!tail) return
-  clearTimeout(tail)
-  tail = undefined
-}
-
-function play(file: string, volume: number) {
-  const item = load()
-  if (!item) return run(file, volume)?.exited
-  return item.play(file, { volume }).catch(() => run(file, volume)?.exited)
-}
-
-export function start() {
-  stop()
-  const id = ++seq
-  void asset().then(({ hum }) => {
-    if (id !== seq) return
-    const next = run(hum, 0.24)
-    if (!next) return
-    proc = next
-    void next.exited.then(
-      () => {
-        if (id !== seq) return
-        if (proc === next) proc = undefined
-      },
-      () => {
-        if (id !== seq) return
-        if (proc === next) proc = undefined
-      },
-    )
-  })
-}
-
-export function stop(delay = 0) {
-  seq++
-  clear()
-  if (!proc) return
-  const next = proc
-  if (delay <= 0) {
-    proc = undefined
-    void Process.stop(next).catch(() => undefined)
-    return
-  }
-  tail = setTimeout(() => {
-    tail = undefined
-    if (proc === next) proc = undefined
-    void Process.stop(next).catch(() => undefined)
-  }, delay)
-}
-
-export function pulse(scale = 1) {
-  stop(140)
-  const index = shot++ % FILE.length
-  void asset()
-    .then(({ pulse }) => play(pulse[index], 0.26 + 0.14 * scale))
-    .catch(() => undefined)
-}
-
-export function dispose() {
-  stop()
-}
-
-export * as Sound from "./sound"