diff --git a/src/cli/index.ts b/src/cli/index.ts index 826312f..19e7455 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -40,7 +40,7 @@ async function get(url: string): Promise { } } -async function getManifest(appName: string): Promise<{ exists: boolean; manifest?: Manifest } | null> { +async function getManifest(appName: string): Promise<{ exists: boolean, manifest?: Manifest } | null> { try { const res = await fetch(makeUrl(`/api/sync/apps/${appName}/manifest`)) if (res.status === 404) return { exists: false } @@ -276,7 +276,7 @@ async function getApp(name: string) { console.log(color.green(`✓ Downloaded ${name}`)) } -function getAppPackage(): { name?: string; scripts?: { toes?: string } } | null { +function getAppPackage(): { name?: string, scripts?: { toes?: string } } | null { try { return JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf-8')) } catch { @@ -579,7 +579,7 @@ async function syncApp() { for (const line of lines) { if (!line.startsWith('data: ')) continue - const event = JSON.parse(line.slice(6)) as { type: 'change' | 'delete'; path: string; hash?: string } + const event = JSON.parse(line.slice(6)) as { type: 'change' | 'delete', path: string, hash?: string } if (event.type === 'change') { // Skip if we already have this version (handles echo from our own changes) @@ -621,6 +621,37 @@ async function prompt(message: string): Promise { }) } +async function renameApp(arg: string | undefined, newName: string) { + const name = resolveAppName(arg) + if (!name) return + + const result = await getManifest(name) + if (result === null) return + if (!result.exists) { + console.error(`App not found on server: ${name}`) + return + } + + const expected = `sudo rename ${name} ${newName}` + console.log(`This will rename ${color.bold(name)} to ${color.bold(newName)}.`) + const answer = await prompt(`Type "${expected}" to confirm: `) + + if (answer !== expected) { + console.log('Aborted.') + return + } + + const response = await post<{ ok: boolean, error?: string, name?: string }>(`/api/apps/${name}/rename`, { name: newName }) + if (!response) return + + if (!response.ok) { + console.error(color.red(`Error: ${response.error}`)) + return + } + + console.log(color.green(`✓ Renamed ${name} to ${response.name}`)) +} + async function rmApp(arg?: string) { const name = resolveAppName(arg) if (!name) return @@ -752,4 +783,11 @@ program .argument('[name]', 'app name (uses current directory if omitted)') .action(rmApp) +program + .command('rename') + .description('Rename an app') + .argument('[name]', 'app name (uses current directory if omitted)') + .argument('', 'new app name') + .action(renameApp) + program.parse() \ No newline at end of file diff --git a/src/client/index.tsx b/src/client/index.tsx index f5a9719..b67b0a8 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -623,7 +623,7 @@ async function doRenameApp(input: HTMLInputElement) { }) const text = await res.text() - let data: { ok?: boolean; error?: string; name?: string } + let data: { ok?: boolean, error?: string, name?: string } try { data = JSON.parse(text) } catch {