11import type { Session as SDKSession , Message , Part } from "@opencode-ai/sdk/v2"
22import { Session } from "@/session/session"
33import { MessageV2 } from "../../session/message-v2"
4- import { effectCmd } from "../effect-cmd"
4+ import { CliError , effectCmd } from "../effect-cmd"
55import { Database } from "@/storage/db"
66import { SessionTable , MessageTable , PartTable } from "../../session/session.sql"
77import { InstanceRef } from "@/effect/instance-ref"
@@ -88,11 +88,12 @@ export const ImportCommand = effectCmd({
8888 demandOption : true ,
8989 } ) ,
9090 handler : Effect . fn ( "Cli.import" ) ( function * ( args ) {
91+ // effectCmd always provides InstanceRef via InstanceStore.Service.provide; this is an invariant.
9192 const ctx = yield * InstanceRef
92- if ( ! ctx ) return
93+ if ( ! ctx ) return yield * Effect . die ( "InstanceRef not provided" )
9394 const store = yield * InstanceStore . Service
94- // Match legacy bootstrap() finally — dispose runs disposers + emits
95- // server.instance.disposed even on early- return / error paths .
95+ // Ensure store. dispose runs disposers and emits server.instance.disposed
96+ // on every exit path: success, early return, typed failure, defect, interrupt .
9697 return yield * runImport ( args . file , ctx . project . id ) . pipe ( Effect . ensuring ( store . dispose ( ctx ) ) )
9798 } ) ,
9899} )
@@ -117,11 +118,20 @@ const runImport = Effect.fn("Cli.import.body")(function* (file: string, projectI
117118 const req = yield * Effect . orDie ( share . request ( ) )
118119 const headers = shouldAttachShareAuthHeaders ( file , req . baseUrl ) ? req . headers : { }
119120
121+ const tryFetch = ( url : string ) =>
122+ Effect . tryPromise ( {
123+ try : ( ) => fetch ( url , { headers } ) ,
124+ catch : ( e ) =>
125+ new CliError ( {
126+ message : `Failed to fetch share data: ${ e instanceof Error ? e . message : String ( e ) } ` ,
127+ } ) ,
128+ } )
129+
120130 const dataPath = req . api . data ( slug )
121- let response = yield * Effect . promise ( ( ) => fetch ( `${ baseUrl } ${ dataPath } ` , { headers } ) )
131+ let response = yield * tryFetch ( `${ baseUrl } ${ dataPath } ` )
122132
123133 if ( ! response . ok && dataPath !== `/api/share/${ slug } /data` ) {
124- response = yield * Effect . promise ( ( ) => fetch ( `${ baseUrl } /api/share/${ slug } /data` , { headers } ) )
134+ response = yield * tryFetch ( `${ baseUrl } /api/share/${ slug } /data` )
125135 }
126136
127137 if ( ! response . ok ) {
@@ -130,7 +140,10 @@ const runImport = Effect.fn("Cli.import.body")(function* (file: string, projectI
130140 return
131141 }
132142
133- const shareData = ( yield * Effect . promise ( ( ) => response . json ( ) ) ) as ShareData [ ]
143+ const shareData = yield * Effect . tryPromise ( {
144+ try : ( ) => response . json ( ) as Promise < ShareData [ ] > ,
145+ catch : ( ) => new CliError ( { message : "Share data was not valid JSON" } ) ,
146+ } )
134147 const transformed = transformShareData ( shareData )
135148
136149 if ( ! transformed ) {
0 commit comments