status-light.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import type { Plugin } from "@opencode-ai/plugin"
  2. import { join } from "path"
  3. import { homedir } from "os"
  4. interface Config {
  5. serviceUrl?: string
  6. }
  7. async function loadConfig(directory: string): Promise<Config> {
  8. // 1. 尝试项目级配置
  9. try {
  10. const projectConfig = Bun.file(join(directory, ".opencode", "status-light.json"))
  11. if (await projectConfig.exists()) {
  12. return await projectConfig.json()
  13. }
  14. } catch {}
  15. // 2. 尝试全局配置
  16. try {
  17. const globalConfig = Bun.file(join(homedir(), ".config", "opencode", "status-light.json"))
  18. if (await globalConfig.exists()) {
  19. return await globalConfig.json()
  20. }
  21. } catch {}
  22. return {}
  23. }
  24. export const StatusLightPlugin: Plugin = async ({ directory }) => {
  25. const config = await loadConfig(directory)
  26. const serviceUrl = process.env.STATUS_LIGHT_URL || config.serviceUrl || "http://localhost:8080"
  27. async function sendStatus(code: string) {
  28. try {
  29. await fetch(`${serviceUrl}/api/event`, {
  30. method: "POST",
  31. headers: { "Content-Type": "application/json" },
  32. body: JSON.stringify({ code, timestamp: new Date().toISOString() }),
  33. })
  34. } catch {
  35. // 静默失败,不影响 OpenCode
  36. }
  37. }
  38. return {
  39. event: async ({ event }) => {
  40. let code = ""
  41. switch (event.type) {
  42. case "session.idle":
  43. code = "idle"
  44. break
  45. case "session.status":
  46. code = event.properties?.status?.type || ""
  47. break
  48. case "message.part.updated": {
  49. const part = event.properties?.part
  50. if (part?.type === "tool") {
  51. code = part.state?.status || "using_tool"
  52. } else if (part?.type === "reasoning") {
  53. code = "reasoning"
  54. }
  55. break
  56. }
  57. case "permission.asked":
  58. code = "permission"
  59. break
  60. case "session.error":
  61. code = "error"
  62. break
  63. }
  64. if (code) {
  65. await sendStatus(code)
  66. }
  67. },
  68. }
  69. }