Просмотр исходного кода

Standardize code style to no semicolons and remove unused @types/node dependency

🤖 Generated with opencode
Co-Authored-By: opencode <[email protected]>
Dax Raad 8 месяцев назад
Родитель
Сommit
6df19f1828
4 измененных файлов с 217 добавлено и 215 удалено
  1. 0 1
      bun.lock
  2. 1 2
      packages/opencode/package.json
  3. 171 168
      packages/opencode/src/session/session.ts
  4. 45 44
      packages/opencode/src/share/share.ts

+ 0 - 1
bun.lock

@@ -43,7 +43,6 @@
         "@tsconfig/bun": "1.0.7",
         "@types/bun": "latest",
         "@types/jsdom": "21.1.7",
-        "@types/node": "catalog:",
         "@types/turndown": "5.0.5",
         "typescript": "catalog:",
       },

+ 1 - 2
packages/opencode/package.json

@@ -16,8 +16,7 @@
     "@types/bun": "latest",
     "@types/jsdom": "21.1.7",
     "@types/turndown": "5.0.5",
-    "typescript": "catalog:",
-    "@types/node": "catalog:"
+    "typescript": "catalog:"
   },
   "dependencies": {
     "@flystorage/file-storage": "1.1.0",

+ 171 - 168
packages/opencode/src/session/session.ts

@@ -1,31 +1,31 @@
-import path from "path";
-import { App } from "../app/app";
-import { Identifier } from "../id/id";
-import { LLM } from "../llm/llm";
-import { Storage } from "../storage/storage";
-import { Log } from "../util/log";
+import path from "path"
+import { App } from "../app/app"
+import { Identifier } from "../id/id"
+import { LLM } from "../llm/llm"
+import { Storage } from "../storage/storage"
+import { Log } from "../util/log"
 import {
   convertToModelMessages,
   generateText,
   stepCountIs,
   streamText,
   type LanguageModelUsage,
-} from "ai";
-import { z } from "zod";
-import * as tools from "../tool";
-import { Decimal } from "decimal.js";
+} from "ai"
+import { z } from "zod"
+import * as tools from "../tool"
+import { Decimal } from "decimal.js"
 
-import PROMPT_ANTHROPIC from "./prompt/anthropic.txt";
-import PROMPT_TITLE from "./prompt/title.txt";
-import PROMPT_SUMMARIZE from "./prompt/summarize.txt";
+import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
+import PROMPT_TITLE from "./prompt/title.txt"
+import PROMPT_SUMMARIZE from "./prompt/summarize.txt"
 
-import { Share } from "../share/share";
-import { Message } from "./message";
-import { Bus } from "../bus";
-import type { Provider } from "../provider/provider";
+import { Share } from "../share/share"
+import { Message } from "./message"
+import { Bus } from "../bus"
+import type { Provider } from "../provider/provider"
 
 export namespace Session {
-  const log = Log.create({ service: "session" });
+  const log = Log.create({ service: "session" })
 
   export const Info = z
     .object({
@@ -44,8 +44,8 @@ export namespace Session {
     })
     .openapi({
       ref: "session.info",
-    });
-  export type Info = z.output<typeof Info>;
+    })
+  export type Info = z.output<typeof Info>
 
   export const Event = {
     Updated: Bus.event(
@@ -54,17 +54,17 @@ export namespace Session {
         info: Info,
       }),
     ),
-  };
+  }
 
   const state = App.state("session", () => {
-    const sessions = new Map<string, Info>();
-    const messages = new Map<string, Message.Info[]>();
+    const sessions = new Map<string, Info>()
+    const messages = new Map<string, Message.Info[]>()
 
     return {
       sessions,
       messages,
-    };
-  });
+    }
+  })
 
   export async function create() {
     const result: Info = {
@@ -74,107 +74,110 @@ export namespace Session {
         created: Date.now(),
         updated: Date.now(),
       },
-    };
-    log.info("created", result);
-    state().sessions.set(result.id, result);
-    await Storage.writeJSON("session/info/" + result.id, result);
+    }
+    log.info("created", result)
+    state().sessions.set(result.id, result)
+    await Storage.writeJSON("session/info/" + result.id, result)
     share(result.id).then((share) => {
       update(result.id, (draft) => {
-        draft.share = share;
-      });
-    });
+        draft.share = share
+      })
+    })
     Bus.publish(Event.Updated, {
       info: result,
-    });
-    return result;
+    })
+    return result
   }
 
   export async function get(id: string) {
-    const result = state().sessions.get(id);
+    const result = state().sessions.get(id)
     if (result) {
-      return result;
+      return result
     }
-    const read = await Storage.readJSON<Info>("session/info/" + id);
-    state().sessions.set(id, read);
-    return read as Info;
+    const read = await Storage.readJSON<Info>("session/info/" + id)
+    state().sessions.set(id, read)
+    return read as Info
   }
 
   export async function share(id: string) {
-    const session = await get(id);
-    if (session.share) return session.share;
-    const share = await Share.create(id);
+    const session = await get(id)
+    if (session.share) return session.share
+    const share = await Share.create(id)
     await update(id, (draft) => {
-      draft.share = share;
-    });
-    return share;
+      draft.share = share
+    })
+    for (const msg of await messages(id)) {
+      await Share.sync("session/message/" + id + "/" + msg.id, msg)
+    }
+    return share
   }
 
   export async function update(id: string, editor: (session: Info) => void) {
-    const { sessions } = state();
-    const session = await get(id);
-    if (!session) return;
-    editor(session);
-    session.time.updated = Date.now();
-    sessions.set(id, session);
-    await Storage.writeJSON("session/info/" + id, session);
+    const { sessions } = state()
+    const session = await get(id)
+    if (!session) return
+    editor(session)
+    session.time.updated = Date.now()
+    sessions.set(id, session)
+    await Storage.writeJSON("session/info/" + id, session)
     Bus.publish(Event.Updated, {
       info: session,
-    });
-    return session;
+    })
+    return session
   }
 
   export async function messages(sessionID: string) {
-    const result = [] as Message.Info[];
-    const list = Storage.list("session/message/" + sessionID);
+    const result = [] as Message.Info[]
+    const list = Storage.list("session/message/" + sessionID)
     for await (const p of list) {
-      const read = await Storage.readJSON<Message.Info>(p).catch(() => {});
-      if (!read) continue;
-      result.push(read);
+      const read = await Storage.readJSON<Message.Info>(p).catch(() => {})
+      if (!read) continue
+      result.push(read)
     }
-    result.sort((a, b) => (a.id > b.id ? 1 : -1));
-    return result;
+    result.sort((a, b) => (a.id > b.id ? 1 : -1))
+    return result
   }
 
   export async function* list() {
     for await (const item of Storage.list("session/info")) {
-      const sessionID = path.basename(item, ".json");
-      yield get(sessionID);
+      const sessionID = path.basename(item, ".json")
+      yield get(sessionID)
     }
   }
 
   export function abort(sessionID: string) {
-    const controller = pending.get(sessionID);
-    if (!controller) return false;
-    controller.abort();
-    pending.delete(sessionID);
-    return true;
+    const controller = pending.get(sessionID)
+    if (!controller) return false
+    controller.abort()
+    pending.delete(sessionID)
+    return true
   }
 
   async function updateMessage(msg: Message.Info) {
     await Storage.writeJSON(
       "session/message/" + msg.metadata.sessionID + "/" + msg.id,
       msg,
-    );
+    )
     Bus.publish(Message.Event.Updated, {
       info: msg,
-    });
+    })
   }
 
   export async function chat(input: {
-    sessionID: string;
-    providerID: string;
-    modelID: string;
-    parts: Message.Part[];
+    sessionID: string
+    providerID: string
+    modelID: string
+    parts: Message.Part[]
   }) {
-    const l = log.clone().tag("session", input.sessionID);
-    l.info("chatting");
-    const model = await LLM.findModel(input.providerID, input.modelID);
-    let msgs = await messages(input.sessionID);
-    const previous = msgs.at(-1);
+    const l = log.clone().tag("session", input.sessionID)
+    l.info("chatting")
+    const model = await LLM.findModel(input.providerID, input.modelID)
+    let msgs = await messages(input.sessionID)
+    const previous = msgs.at(-1)
     if (previous?.metadata.assistant) {
       const tokens =
         previous.metadata.assistant.tokens.input +
-        previous.metadata.assistant.tokens.output;
+        previous.metadata.assistant.tokens.output
       if (
         tokens >
         (model.info.contextWindow - (model.info.maxOutputTokens ?? 0)) * 0.9
@@ -183,22 +186,22 @@ export namespace Session {
           sessionID: input.sessionID,
           providerID: input.providerID,
           modelID: input.modelID,
-        });
-        return chat(input);
+        })
+        return chat(input)
       }
     }
 
-    using abort = lock(input.sessionID);
+    using abort = lock(input.sessionID)
 
     const lastSummary = msgs.findLast(
       (msg) => msg.metadata.assistant?.summary === true,
-    );
+    )
     if (lastSummary)
       msgs = msgs.filter(
         (msg) => msg.role === "system" || msg.id >= lastSummary.id,
-      );
+      )
 
-    const app = await App.use();
+    const app = await App.use()
     if (msgs.length === 0) {
       const system: Message.Info = {
         id: Identifier.ascending("message"),
@@ -216,16 +219,16 @@ export namespace Session {
           },
           tool: {},
         },
-      };
-      const contextFile = Bun.file(path.join(app.root, "CONTEXT.md"));
+      }
+      const contextFile = Bun.file(path.join(app.root, "CONTEXT.md"))
       if (await contextFile.exists()) {
-        const context = await contextFile.text();
+        const context = await contextFile.text()
         system.parts.push({
           type: "text",
           text: context,
-        });
+        })
       }
-      msgs.push(system);
+      msgs.push(system)
       generateText({
         messages: convertToModelMessages([
           {
@@ -245,10 +248,10 @@ export namespace Session {
         model: model.instance,
       }).then((result) => {
         return Session.update(input.sessionID, (draft) => {
-          draft.title = result.text;
-        });
-      });
-      await updateMessage(system);
+          draft.title = result.text
+        })
+      })
+      await updateMessage(system)
     }
     const msg: Message.Info = {
       role: "user",
@@ -261,9 +264,9 @@ export namespace Session {
         sessionID: input.sessionID,
         tool: {},
       },
-    };
-    msgs.push(msg);
-    await updateMessage(msg);
+    }
+    await updateMessage(msg)
+    msgs.push(msg)
 
     const next: Message.Info = {
       id: Identifier.ascending("message"),
@@ -286,15 +289,15 @@ export namespace Session {
         sessionID: input.sessionID,
         tool: {},
       },
-    };
-    await updateMessage(next);
+    }
+    await updateMessage(next)
     const result = streamText({
       onStepFinish: async (step) => {
-        const assistant = next.metadata!.assistant!;
-        const usage = getUsage(step.usage, model.info);
-        assistant.cost = usage.cost;
-        assistant.tokens = usage.tokens;
-        await updateMessage(next);
+        const assistant = next.metadata!.assistant!
+        const usage = getUsage(step.usage, model.info)
+        assistant.cost = usage.cost
+        assistant.tokens = usage.tokens
+        await updateMessage(next)
       },
       abortSignal: abort.signal,
       maxRetries: 6,
@@ -303,39 +306,39 @@ export namespace Session {
       temperature: 0,
       tools,
       model: model.instance,
-    });
-    let text: Message.TextPart | undefined;
-    const reader = result.toUIMessageStream().getReader();
+    })
+    let text: Message.TextPart | undefined
+    const reader = result.toUIMessageStream().getReader()
     while (true) {
       const result = await reader.read().catch((e) => {
         if (e instanceof DOMException && e.name === "AbortError") {
-          return;
+          return
         }
-        throw e;
-      });
-      if (!result) break;
-      const { done, value } = result;
-      if (done) break;
+        throw e
+      })
+      if (!result) break
+      const { done, value } = result
+      if (done) break
       l.info("part", {
         type: value.type,
-      });
+      })
       switch (value.type) {
         case "start":
-          break;
+          break
         case "start-step":
-          text = undefined;
+          text = undefined
           next.parts.push({
             type: "step-start",
-          });
-          break;
+          })
+          break
         case "text":
           if (!text) {
-            text = value;
-            next.parts.push(value);
-            break;
+            text = value
+            next.parts.push(value)
+            break
           }
-          text.text += value.text;
-          break;
+          text.text += value.text
+          break
 
         case "tool-call":
           next.parts.push({
@@ -346,60 +349,60 @@ export namespace Session {
               // hack until zod v4
               args: value.args as any,
             },
-          });
-          break;
+          })
+          break
 
         case "tool-result":
           const match = next.parts.find(
             (p) =>
               p.type === "tool-invocation" &&
               p.toolInvocation.toolCallId === value.toolCallId,
-          );
+          )
           if (match && match.type === "tool-invocation") {
-            const { output, metadata } = value.result as any;
-            next.metadata!.tool[value.toolCallId] = metadata;
+            const { output, metadata } = value.result as any
+            next.metadata!.tool[value.toolCallId] = metadata
             match.toolInvocation = {
               ...match.toolInvocation,
               state: "result",
               result: output,
-            };
+            }
           }
-          break;
+          break
 
         case "finish":
-          break;
+          break
         case "finish-step":
-          break;
+          break
         case "error":
-          log.error("error", value);
-          break;
+          log.error("error", value)
+          break
 
         default:
           l.info("unhandled", {
             type: value.type,
-          });
+          })
       }
-      await updateMessage(next);
+      await updateMessage(next)
     }
-    next.metadata!.time.completed = Date.now();
-    await updateMessage(next);
-    return next;
+    next.metadata!.time.completed = Date.now()
+    await updateMessage(next)
+    return next
   }
 
   export async function summarize(input: {
-    sessionID: string;
-    providerID: string;
-    modelID: string;
+    sessionID: string
+    providerID: string
+    modelID: string
   }) {
-    using abort = lock(input.sessionID);
-    const msgs = await messages(input.sessionID);
+    using abort = lock(input.sessionID)
+    const msgs = await messages(input.sessionID)
     const lastSummary = msgs.findLast(
       (msg) => msg.metadata.assistant?.summary === true,
-    )?.id;
+    )?.id
     const filtered = msgs.filter(
       (msg) => msg.role !== "system" && (!lastSummary || msg.id >= lastSummary),
-    );
-    const model = await LLM.findModel(input.providerID, input.modelID);
+    )
+    const model = await LLM.findModel(input.providerID, input.modelID)
     const next: Message.Info = {
       id: Identifier.ascending("message"),
       role: "assistant",
@@ -422,8 +425,8 @@ export namespace Session {
           created: Date.now(),
         },
       },
-    };
-    await updateMessage(next);
+    }
+    await updateMessage(next)
     const result = await generateText({
       abortSignal: abort.signal,
       model: model.instance,
@@ -448,31 +451,31 @@ export namespace Session {
           ],
         },
       ]),
-    });
+    })
     next.parts.push({
       type: "text",
       text: result.text,
-    });
-    const assistant = next.metadata!.assistant!;
-    const usage = getUsage(result.usage, model.info);
-    assistant.cost = usage.cost;
-    assistant.tokens = usage.tokens;
-    await updateMessage(next);
+    })
+    const assistant = next.metadata!.assistant!
+    const usage = getUsage(result.usage, model.info)
+    assistant.cost = usage.cost
+    assistant.tokens = usage.tokens
+    await updateMessage(next)
   }
 
-  const pending = new Map<string, AbortController>();
+  const pending = new Map<string, AbortController>()
   function lock(sessionID: string) {
-    log.info("locking", { sessionID });
-    if (pending.has(sessionID)) throw new BusyError(sessionID);
-    const controller = new AbortController();
-    pending.set(sessionID, controller);
+    log.info("locking", { sessionID })
+    if (pending.has(sessionID)) throw new BusyError(sessionID)
+    const controller = new AbortController()
+    pending.set(sessionID, controller)
     return {
       signal: controller.signal,
       [Symbol.dispose]() {
-        log.info("unlocking", { sessionID });
-        pending.delete(sessionID);
+        log.info("unlocking", { sessionID })
+        pending.delete(sessionID)
       },
-    };
+    }
   }
 
   function getUsage(usage: LanguageModelUsage, model: Provider.Model) {
@@ -480,19 +483,19 @@ export namespace Session {
       input: usage.inputTokens ?? 0,
       output: usage.outputTokens ?? 0,
       reasoning: usage.reasoningTokens ?? 0,
-    };
+    }
     return {
       cost: new Decimal(0)
         .add(new Decimal(tokens.input).mul(model.cost.input))
         .add(new Decimal(tokens.output).mul(model.cost.output))
         .toNumber(),
       tokens,
-    };
+    }
   }
 
   export class BusyError extends Error {
     constructor(public readonly sessionID: string) {
-      super(`Session ${sessionID} is busy`);
+      super(`Session ${sessionID} is busy`)
     }
   }
 }

+ 45 - 44
packages/opencode/src/share/share.ts

@@ -1,60 +1,61 @@
-import { App } from "../app/app";
-import { Bus } from "../bus";
-import { Session } from "../session/session";
-import { Storage } from "../storage/storage";
-import { Log } from "../util/log";
+import { App } from "../app/app"
+import { Bus } from "../bus"
+import { Session } from "../session/session"
+import { Storage } from "../storage/storage"
+import { Log } from "../util/log"
 
 export namespace Share {
-  const log = Log.create({ service: "share" });
+  const log = Log.create({ service: "share" })
 
-  let queue: Promise<void> = Promise.resolve();
-  const pending = new Map<string, any>();
+  let queue: Promise<void> = Promise.resolve()
+  const pending = new Map<string, any>()
 
   const state = App.state("share", async () => {
     Bus.subscribe(Storage.Event.Write, async (payload) => {
-      const [root, ...splits] = payload.properties.key.split("/");
-      if (root !== "session") return;
-      const [, sessionID] = splits;
-      const session = await Session.get(sessionID);
-      if (!session.share) return;
-      const { secret } = session.share;
-
-      const key = payload.properties.key;
-      pending.set(key, payload.properties.content);
+      await sync(payload.properties.key, payload.properties.content)
+    })
+  })
 
-      queue = queue
-        .then(async () => {
-          const content = pending.get(key);
-          if (content === undefined) return;
-          pending.delete(key);
+  export async function sync(key: string, content: any) {
+    const [root, ...splits] = key.split("/")
+    if (root !== "session") return
+    const [, sessionID] = splits
+    const session = await Session.get(sessionID)
+    if (!session.share) return
+    const { secret } = session.share
+    pending.set(key, content)
+    queue = queue
+      .then(async () => {
+        const content = pending.get(key)
+        if (content === undefined) return
+        pending.delete(key)
 
-          return fetch(`${URL}/share_sync`, {
-            method: "POST",
-            body: JSON.stringify({
-              sessionID: sessionID,
-              secret,
-              key: key,
-              content,
-            }),
-          });
+        return fetch(`${URL}/share_sync`, {
+          method: "POST",
+          body: JSON.stringify({
+            sessionID: sessionID,
+            secret,
+            key: key,
+            content,
+          }),
         })
-        .then((x) => {
-          if (x) {
-            log.info("synced", {
-              key: key,
-              status: x.status,
-            });
-          }
-        });
-    });
-  });
+      })
+      .then((x) => {
+        if (x) {
+          log.info("synced", {
+            key: key,
+            status: x.status,
+          })
+        }
+      })
+  }
 
   export async function init() {
-    await state();
+    await state()
   }
 
   export const URL =
-    process.env["OPENCODE_API"] ?? "https://api.dev.opencode.ai";
+    process.env["OPENCODE_API"] ?? "https://api.dev.opencode.ai"
 
   export async function create(sessionID: string) {
     return fetch(`${URL}/share_create`, {
@@ -62,6 +63,6 @@ export namespace Share {
       body: JSON.stringify({ sessionID: sessionID }),
     })
       .then((x) => x.json())
-      .then((x) => x as { url: string; secret: string });
+      .then((x) => x as { url: string; secret: string })
   }
 }