( options: StartOpencodeSessionOptions, )
| 111 | * flattened transcript. |
| 112 | */ |
| 113 | export async function startOpencodeSession( |
| 114 | options: StartOpencodeSessionOptions, |
| 115 | ): Promise<OpencodeSessionHandle> { |
| 116 | const { directory } = options |
| 117 | // Spread into a `query` object only when set; omitting lets opencode use the |
| 118 | // server's launch cwd (correct for every provider — see `directory` docs). |
| 119 | const dirQuery = directory !== undefined ? { directory } : {} |
| 120 | |
| 121 | let client: OpencodeClient |
| 122 | let ownedServer: { close: () => void } | undefined |
| 123 | |
| 124 | if (options.baseUrl !== undefined) { |
| 125 | client = createOpencodeClient({ |
| 126 | baseUrl: options.baseUrl, |
| 127 | ...(options.headers !== undefined && { headers: options.headers }), |
| 128 | ...(directory !== undefined && { directory }), |
| 129 | }) |
| 130 | } else { |
| 131 | const config = buildConfig(options) |
| 132 | const result = await createOpencode({ |
| 133 | ...(options.hostname !== undefined && { hostname: options.hostname }), |
| 134 | ...(options.port !== undefined && { port: options.port }), |
| 135 | ...(Object.keys(config).length > 0 && { config }), |
| 136 | }) |
| 137 | client = result.client |
| 138 | ownedServer = result.server |
| 139 | } |
| 140 | |
| 141 | // Mutated from several closures (the subscription loop, dispose, teardown); |
| 142 | // a holder object keeps reads typed as `boolean` rather than being |
| 143 | // flow-narrowed to a literal across those boundaries. |
| 144 | const lifecycle = { disposed: false } |
| 145 | |
| 146 | const teardown = async (): Promise<void> => { |
| 147 | if (lifecycle.disposed) return |
| 148 | lifecycle.disposed = true |
| 149 | ownedServer?.close() |
| 150 | await Promise.resolve() |
| 151 | } |
| 152 | |
| 153 | try { |
| 154 | // Resolve the session before subscribing so the event filter has an id. |
| 155 | let sessionId: string | undefined |
| 156 | let resumed = false |
| 157 | if (options.resumeSessionId !== undefined) { |
| 158 | const existing = await client.session.get({ |
| 159 | path: { id: options.resumeSessionId }, |
| 160 | query: dirQuery, |
| 161 | }) |
| 162 | if (existing.data) { |
| 163 | sessionId = options.resumeSessionId |
| 164 | resumed = true |
| 165 | } |
| 166 | } |
| 167 | if (sessionId === undefined) { |
| 168 | const created = await client.session.create({ |
| 169 | query: dirQuery, |
| 170 | body: {}, |
no test coverage detected