@@ -15,6 +15,7 @@ import { existsSync } from "fs"
1515import { git } from "../util/git"
1616import { Glob } from "../util/glob"
1717import { which } from "../util/which"
18+ import { ProjectID } from "./schema"
1819
1920export namespace Project {
2021 const log = Log . create ( { service : "project" } )
@@ -33,7 +34,7 @@ export namespace Project {
3334
3435 export const Info = z
3536 . object ( {
36- id : z . string ( ) ,
37+ id : ProjectID . zod ,
3738 worktree : z . string ( ) ,
3839 vcs : z . literal ( "git" ) . optional ( ) ,
3940 name : z . string ( ) . optional ( ) ,
@@ -73,7 +74,7 @@ export namespace Project {
7374 ? { url : row . icon_url ?? undefined , color : row . icon_color ?? undefined }
7475 : undefined
7576 return {
76- id : row . id ,
77+ id : ProjectID . make ( row . id ) ,
7778 worktree : row . worktree ,
7879 vcs : row . vcs ? Info . shape . vcs . parse ( row . vcs ) : undefined ,
7980 name : row . name ?? undefined ,
@@ -91,6 +92,7 @@ export namespace Project {
9192 function readCachedId ( dir : string ) {
9293 return Filesystem . readText ( path . join ( dir , "opencode" ) )
9394 . then ( ( x ) => x . trim ( ) )
95+ . then ( ProjectID . make )
9496 . catch ( ( ) => undefined )
9597 }
9698
@@ -111,7 +113,7 @@ export namespace Project {
111113
112114 if ( ! gitBinary ) {
113115 return {
114- id : id ?? " global" ,
116+ id : id ?? ProjectID . global ,
115117 worktree : sandbox ,
116118 sandbox,
117119 vcs : Info . shape . vcs . parse ( Flag . OPENCODE_FAKE_VCS ) ,
@@ -130,7 +132,7 @@ export namespace Project {
130132
131133 if ( ! worktree ) {
132134 return {
133- id : id ?? " global" ,
135+ id : id ?? ProjectID . global ,
134136 worktree : sandbox ,
135137 sandbox,
136138 vcs : Info . shape . vcs . parse ( Flag . OPENCODE_FAKE_VCS ) ,
@@ -160,22 +162,22 @@ export namespace Project {
160162
161163 if ( ! roots ) {
162164 return {
163- id : " global" ,
165+ id : ProjectID . global ,
164166 worktree : sandbox ,
165167 sandbox,
166168 vcs : Info . shape . vcs . parse ( Flag . OPENCODE_FAKE_VCS ) ,
167169 }
168170 }
169171
170- id = roots [ 0 ]
172+ id = roots [ 0 ] ? ProjectID . make ( roots [ 0 ] ) : undefined
171173 if ( id ) {
172174 await Filesystem . write ( path . join ( dotgit , "opencode" ) , id ) . catch ( ( ) => undefined )
173175 }
174176 }
175177
176178 if ( ! id ) {
177179 return {
178- id : " global" ,
180+ id : ProjectID . global ,
179181 worktree : sandbox ,
180182 sandbox,
181183 vcs : "git" ,
@@ -208,7 +210,7 @@ export namespace Project {
208210 }
209211
210212 return {
211- id : " global" ,
213+ id : ProjectID . global ,
212214 worktree : "/" ,
213215 sandbox : "/" ,
214216 vcs : Info . shape . vcs . parse ( Flag . OPENCODE_FAKE_VCS ) ,
@@ -228,7 +230,7 @@ export namespace Project {
228230 updated : Date . now ( ) ,
229231 } ,
230232 }
231- if ( data . id !== " global" ) {
233+ if ( data . id !== ProjectID . global ) {
232234 await migrateFromGlobal ( data . id , data . worktree )
233235 }
234236 return fresh
@@ -308,12 +310,12 @@ export namespace Project {
308310 return
309311 }
310312
311- async function migrateFromGlobal ( id : string , worktree : string ) {
312- const row = Database . use ( ( db ) => db . select ( ) . from ( ProjectTable ) . where ( eq ( ProjectTable . id , " global" ) ) . get ( ) )
313+ async function migrateFromGlobal ( id : ProjectID , worktree : string ) {
314+ const row = Database . use ( ( db ) => db . select ( ) . from ( ProjectTable ) . where ( eq ( ProjectTable . id , ProjectID . global ) ) . get ( ) )
313315 if ( ! row ) return
314316
315317 const sessions = Database . use ( ( db ) =>
316- db . select ( ) . from ( SessionTable ) . where ( eq ( SessionTable . project_id , " global" ) ) . all ( ) ,
318+ db . select ( ) . from ( SessionTable ) . where ( eq ( SessionTable . project_id , ProjectID . global ) ) . all ( ) ,
317319 )
318320 if ( sessions . length === 0 ) return
319321
@@ -323,14 +325,14 @@ export namespace Project {
323325 // Skip sessions that belong to a different directory
324326 if ( row . directory && row . directory !== worktree ) return
325327
326- log . info ( "migrating session" , { sessionID : row . id , from : " global" , to : id } )
328+ log . info ( "migrating session" , { sessionID : row . id , from : ProjectID . global , to : id } )
327329 Database . use ( ( db ) => db . update ( SessionTable ) . set ( { project_id : id } ) . where ( eq ( SessionTable . id , row . id ) ) . run ( ) )
328330 } ) . catch ( ( error ) => {
329331 log . error ( "failed to migrate sessions from global to project" , { error, projectId : id } )
330332 } )
331333 }
332334
333- export function setInitialized ( id : string ) {
335+ export function setInitialized ( id : ProjectID ) {
334336 Database . use ( ( db ) =>
335337 db
336338 . update ( ProjectTable )
@@ -352,7 +354,7 @@ export namespace Project {
352354 )
353355 }
354356
355- export function get ( id : string ) : Info | undefined {
357+ export function get ( id : ProjectID ) : Info | undefined {
356358 const row = Database . use ( ( db ) => db . select ( ) . from ( ProjectTable ) . where ( eq ( ProjectTable . id , id ) ) . get ( ) )
357359 if ( ! row ) return undefined
358360 return fromRow ( row )
@@ -375,12 +377,13 @@ export namespace Project {
375377
376378 export const update = fn (
377379 z . object ( {
378- projectID : z . string ( ) ,
380+ projectID : ProjectID . zod ,
379381 name : z . string ( ) . optional ( ) ,
380382 icon : Info . shape . icon . optional ( ) ,
381383 commands : Info . shape . commands . optional ( ) ,
382384 } ) ,
383385 async ( input ) => {
386+ const id = ProjectID . make ( input . projectID )
384387 const result = Database . use ( ( db ) =>
385388 db
386389 . update ( ProjectTable )
@@ -391,7 +394,7 @@ export namespace Project {
391394 commands : input . commands ,
392395 time_updated : Date . now ( ) ,
393396 } )
394- . where ( eq ( ProjectTable . id , input . projectID ) )
397+ . where ( eq ( ProjectTable . id , id ) )
395398 . returning ( )
396399 . get ( ) ,
397400 )
@@ -407,7 +410,7 @@ export namespace Project {
407410 } ,
408411 )
409412
410- export async function sandboxes ( id : string ) {
413+ export async function sandboxes ( id : ProjectID ) {
411414 const row = Database . use ( ( db ) => db . select ( ) . from ( ProjectTable ) . where ( eq ( ProjectTable . id , id ) ) . get ( ) )
412415 if ( ! row ) return [ ]
413416 const data = fromRow ( row )
@@ -419,7 +422,7 @@ export namespace Project {
419422 return valid
420423 }
421424
422- export async function addSandbox ( id : string , directory : string ) {
425+ export async function addSandbox ( id : ProjectID , directory : string ) {
423426 const row = Database . use ( ( db ) => db . select ( ) . from ( ProjectTable ) . where ( eq ( ProjectTable . id , id ) ) . get ( ) )
424427 if ( ! row ) throw new Error ( `Project not found: ${ id } ` )
425428 const sandboxes = [ ...row . sandboxes ]
@@ -443,7 +446,7 @@ export namespace Project {
443446 return data
444447 }
445448
446- export async function removeSandbox ( id : string , directory : string ) {
449+ export async function removeSandbox ( id : ProjectID , directory : string ) {
447450 const row = Database . use ( ( db ) => db . select ( ) . from ( ProjectTable ) . where ( eq ( ProjectTable . id , id ) ) . get ( ) )
448451 if ( ! row ) throw new Error ( `Project not found: ${ id } ` )
449452 const sandboxes = row . sandboxes . filter ( ( s ) => s !== directory )
0 commit comments