1- import { Config } from '@oclif/core' ;
21import open from 'open' ;
2+ import * as fs from 'node:fs/promises' ;
3+ import { tmpdir } from 'node:os' ;
4+ import os from 'node:os' ;
5+ import path from 'node:path' ;
36
47import { DashboardApiClient } from '../api/dashboard/index.js' ;
58import { config } from '../config.js' ;
69import { LoginHelper } from '../connect/login-helper.js' ;
710import { Reporter } from '../ui/reporters/reporter.js' ;
11+ import { OsUtils } from '../utils/os-utils.js' ;
12+ import { spawn } from '../utils/spawn.js' ;
813import { ConnectOrchestrator } from './connect.js' ;
9- import { LoginOrchestrator } from './login.js' ;
14+
15+ const DESKTOP_APP_PATHS = {
16+ darwin : '/Applications/Codify.app' ,
17+ linux : '/usr/bin/codify' ,
18+ } ;
19+
20+ const DOWNLOAD_URLS : Record < string , Record < string , string > > = {
21+ darwin : {
22+ arm64 : 'https://releases-desktop.codifycli.com/channels/stable/Codify_aarch64.dmg' ,
23+ x64 : 'https://releases-desktop.codifycli.com/channels/stable/Codify_x64.dmg' ,
24+ } ,
25+ linux_deb : {
26+ arm64 : 'https://releases-desktop.codifycli.com/channels/stable/Codify_arm64.deb' ,
27+ x64 : 'https://releases-desktop.codifycli.com/channels/stable/Codify_amd64.deb' ,
28+ } ,
29+ linux_rpm : {
30+ aarch64 : 'https://releases-desktop.codifycli.com/channels/stable/Codify_aarch64.rpm' ,
31+ x64 : 'https://releases-desktop.codifycli.com/channels/stable/Codify_x86_64.rpm' ,
32+ } ,
33+ } ;
34+
35+ async function getDesktopAppPath ( ) : Promise < string | null > {
36+ const appPath = OsUtils . isMacOS ( )
37+ ? DESKTOP_APP_PATHS . darwin
38+ : OsUtils . isLinux ( )
39+ ? DESKTOP_APP_PATHS . linux
40+ : null ;
41+
42+ if ( ! appPath ) return null ;
43+
44+ try {
45+ await fs . access ( appPath ) ;
46+ return appPath ;
47+ } catch {
48+ return null ;
49+ }
50+ }
51+
52+ function getDownloadUrl ( ) : { url : string ; platform : 'darwin' | 'linux_deb' | 'linux_rpm' } | null {
53+ const arch = os . arch ( ) ;
54+
55+ if ( OsUtils . isMacOS ( ) ) {
56+ return {
57+ url : DOWNLOAD_URLS . darwin [ arch ] ?? DOWNLOAD_URLS . darwin [ 'x64' ] ,
58+ platform : 'darwin' ,
59+ } ;
60+ }
61+
62+ if ( OsUtils . isLinux ( ) ) {
63+ const platform = OsUtils . isDebianBased ( ) ? 'linux_deb' : 'linux_rpm' ;
64+ return {
65+ url : DOWNLOAD_URLS [ platform ] [ arch ] ?? DOWNLOAD_URLS [ platform ] [ 'x64' ] ,
66+ platform,
67+ } ;
68+ }
69+
70+ return null ;
71+ }
72+
73+ async function installDesktopApp ( reporter : Reporter , url : string , platform : 'darwin' | 'linux_deb' | 'linux_rpm' ) : Promise < void > {
74+ const ext = url . split ( '.' ) . pop ( ) ! ;
75+ const tmpFile = path . join ( tmpdir ( ) , `codify-desktop.${ ext } ` ) ;
76+
77+ console . log ( 'Downloading Codify desktop app...' ) ;
78+ await spawn ( `curl -L -o ${ tmpFile } ${ url } ` ) ;
79+
80+ if ( platform === 'darwin' ) {
81+ const mountPoint = path . join ( tmpdir ( ) , 'codify-dmg-mount' ) ;
82+ try {
83+ console . log ( 'Installing Codify desktop app...' ) ;
84+ await spawn ( `hdiutil attach ${ tmpFile } -mountpoint ${ mountPoint } -nobrowse -quiet` ) ;
85+ await spawn ( `cp -R ${ mountPoint } /Codify.app /Applications/Codify.app` ) ;
86+ } finally {
87+ await spawn ( `hdiutil detach ${ mountPoint } -quiet` ) . catch ( ( ) => { } ) ;
88+ await fs . unlink ( tmpFile ) . catch ( ( ) => { } ) ;
89+ }
90+ } else {
91+ const password = await reporter . promptSudo ( 'codify-installer' , {
92+ command : platform === 'linux_deb' ? `dpkg -i ${ tmpFile } ` : `rpm -i ${ tmpFile } ` ,
93+ options : { requiresRoot : true } ,
94+ } ) ;
95+
96+ if ( password == null ) {
97+ console . log ( 'Installation cancelled.' ) ;
98+ return ;
99+ }
100+
101+ try {
102+ console . log ( 'Installing Codify desktop app...' ) ;
103+ const cmd = platform === 'linux_deb' ? `dpkg -i ${ tmpFile } ` : `rpm -i ${ tmpFile } ` ;
104+ await spawn ( cmd , { requiresRoot : true } , undefined , password ) ;
105+ } finally {
106+ await fs . unlink ( tmpFile ) . catch ( ( ) => { } ) ;
107+ }
108+ }
109+
110+ console . log ( 'Codify desktop app installed successfully.' ) ;
111+ }
10112
11113export class EditOrchestrator {
12114
13115 static async run ( rootCommand : string , reporter : Reporter ) {
14- const login = LoginHelper . get ( ) ?. isLoggedIn ;
15- if ( ! login ) {
16- console . log ( 'User is not logged in. Attempting to log in...' )
17- await LoginOrchestrator . run ( ) ;
116+ const desktopPath = await getDesktopAppPath ( ) ;
117+
118+ if ( desktopPath ) {
119+ await open ( desktopPath ) ;
120+ return ;
121+ }
122+
123+ const download = getDownloadUrl ( ) ;
124+ if ( download ) {
125+ const shouldInstall = await reporter . promptConfirmation (
126+ 'Codify desktop app is not installed. Would you like to download and install it?'
127+ ) ;
128+
129+ await reporter . hide ( ) ;
130+
131+ if ( shouldInstall ) {
132+ await installDesktopApp ( reporter , download . url , download . platform ) ;
133+ const installedPath = await getDesktopAppPath ( ) ;
134+ if ( installedPath ) {
135+ await open ( installedPath ) ;
136+ }
137+ return ;
138+ }
18139 }
19140
141+ await EditOrchestrator . openDashboard ( rootCommand , reporter ) ;
142+ }
143+
144+ private static async openDashboard ( rootCommand : string , reporter : Reporter ) {
145+ const isLoggedIn = LoginHelper . get ( ) ?. isLoggedIn ;
146+
20147 let defaultDocumentId : null | string = null ;
21- try {
22- defaultDocumentId = await DashboardApiClient . getDefaultDocumentId ( ) ;
23- } catch {
24- console . warn ( 'Mismatch accounts between local and dashboard. Cannot open default document' )
148+ if ( isLoggedIn ) {
149+ try {
150+ defaultDocumentId = await DashboardApiClient . getDefaultDocumentId ( ) ;
151+ } catch {
152+ // ignore — just open homepage
153+ }
25154 }
26155
27156 const url = defaultDocumentId
@@ -31,11 +160,11 @@ export class EditOrchestrator {
31160 await ConnectOrchestrator . run ( rootCommand , reporter , false , ( code ) => {
32161 open ( `${ url } ?connection_code=${ code } ` ) ;
33162 console . log (
34- `Opening default Codify file :
163+ `Opening Codify dashboard :
35164${ url } ?connection_code=${ code }
36165
37166Starting connection. If unsuccessful, manually enter the code:
38- ${ code } `)
167+ ${ code } `) ;
39168 } ) ;
40169 }
41170}
0 commit comments