From b562863fcc7ff760130fa487d2f00054a9e8d93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernat=20Peric=C3=A0s?= Date: Mon, 27 Oct 2025 13:18:23 +0100 Subject: [PATCH] feat: add `session.started` event that triggers when a new session is created (#3413) --- packages/opencode/src/session/index.ts | 9 +++ .../opencode/test/session/session.test.ts | 71 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 packages/opencode/test/session/session.test.ts diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index ee4cc704..b4785c53 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -78,6 +78,12 @@ export namespace Session { export type ShareInfo = z.output export const Event = { + Started: Bus.event( + "session.started", + z.object({ + info: Info, + }), + ), Updated: Bus.event( "session.updated", z.object({ @@ -167,6 +173,9 @@ export namespace Session { } log.info("created", result) await Storage.write(["session", Instance.project.id, result.id], result) + Bus.publish(Event.Started, { + info: result, + }) const cfg = await Config.get() if (!result.parentID && (Flag.OPENCODE_AUTO_SHARE || cfg.share === "auto")) share(result.id) diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts new file mode 100644 index 00000000..573c9e59 --- /dev/null +++ b/packages/opencode/test/session/session.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, test } from "bun:test" +import path from "path" +import { Session } from "../../src/session" +import { Bus } from "../../src/bus" +import { Log } from "../../src/util/log" +import { Instance } from "../../src/project/instance" + +const projectRoot = path.join(__dirname, "../..") +Log.init({ print: false }) + +describe("session.started event", () => { + test("should emit session.started event when session is created", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + let eventReceived = false + let receivedInfo: Session.Info | undefined + + const unsub = Bus.subscribe(Session.Event.Started, (event) => { + eventReceived = true + receivedInfo = event.properties.info as Session.Info + }) + + const session = await Session.create({}) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + unsub() + + expect(eventReceived).toBe(true) + expect(receivedInfo).toBeDefined() + expect(receivedInfo?.id).toBe(session.id) + expect(receivedInfo?.projectID).toBe(session.projectID) + expect(receivedInfo?.directory).toBe(session.directory) + expect(receivedInfo?.title).toBe(session.title) + + await Session.remove(session.id) + }, + }) + }) + + test("session.started event should be emitted before session.updated", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const events: string[] = [] + + const unsubStarted = Bus.subscribe(Session.Event.Started, () => { + events.push("started") + }) + + const unsubUpdated = Bus.subscribe(Session.Event.Updated, () => { + events.push("updated") + }) + + const session = await Session.create({}) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + unsubStarted() + unsubUpdated() + + expect(events).toContain("started") + expect(events).toContain("updated") + expect(events.indexOf("started")).toBeLessThan(events.indexOf("updated")) + + await Session.remove(session.id) + }, + }) + }) +})