toes open <app>

This commit is contained in:
Chris Wanstrath 2026-01-29 11:24:09 -08:00
parent 95d4348560
commit 7763dc6314
3 changed files with 42 additions and 10 deletions

View File

@ -24,7 +24,7 @@
[x] `toes start <app>`
[x] `toes stop <app>`
[x] `toes restart <app>`
[ ] `toes open <app>`
[x] `toes open <app>`
[ ] `toes logs <app>`
[ ] `toes new`
[ ] `toes pull`

View File

@ -57,6 +57,20 @@ const restartApp = async (app: string) => {
await post(`/api/apps/${app}/restart`)
}
async function openApp(name: string) {
const app: App | undefined = await get(`/api/apps/${name}`)
if (!app) {
console.error(`App not found: ${name}`)
return
}
if (app.state !== 'running') {
console.error(`App is not running: ${name}`)
return
}
const url = `http://localhost:${app.port}`
console.log(`Opening ${url}`)
Bun.spawn(['open', url])
}
program
.name('toes')
@ -79,13 +93,18 @@ program
.argument('<name>', 'app name')
.action(stopApp)
program
.command('restart')
.description('Restart an app')
.argument('<name>', 'app name')
.action(restartApp)
program
.command('open')
.description('Open an app in browser')
.argument('<name>', 'app name')
.action(openApp)
program
.command('new')
.description('Create a new app')

View File

@ -1,7 +1,16 @@
import { allApps, initApps, onChange, startApp, stopApp, updateAppIcon } from '$apps'
import type { App as SharedApp } from '@types'
import type { App as BackendApp } from '$apps'
import { Hype } from 'hype'
// BackendApp -> SharedApp
function convert(app: BackendApp): SharedApp {
const clone = { ...app }
delete clone.proc
delete clone.logs
return clone
}
const app = new Hype({ layout: false })
// SSE endpoint for real-time app state updates
@ -47,14 +56,18 @@ app.get('/api/apps/stream', c => {
})
})
app.get('/api/apps', c => {
const apps = allApps().map(app => {
const clone = { ...app }
delete clone.proc
delete clone.logs
return clone
})
return c.json(apps)
app.get('/api/apps', c =>
c.json(allApps().map(convert))
)
app.get('/api/apps/:app', c => {
const appName = c.req.param('app')
if (!appName) return c.json({ error: 'App not found' }, 404)
const app = allApps().find(a => a.name === appName)
if (!app) return c.json({ error: 'App not found' }, 404)
return c.json(convert(app))
})
app.post('/api/apps/:app/start', c => {