TOES_URL and TOES_HOST support

This commit is contained in:
Chris Wanstrath 2026-01-30 16:51:36 -08:00
parent bde7a2c287
commit 1da7e77f00
6 changed files with 86 additions and 23 deletions

View File

@ -17,6 +17,19 @@ Plug it in, turn it on, and forget about the cloud.
- https://toes.local web UI for managing your projects. - https://toes.local web UI for managing your projects.
- Per-branch staging environments for Claude. - Per-branch staging environments for Claude.
## cli configuration
by default, the CLI connects to `localhost:3000` in dev and `toes.local:80` in production.
```bash
toes config # show current host
TOES_URL=http://192.168.1.50:3000 toes list # full URL
TOES_HOST=mypi.local toes list # hostname (port 80)
TOES_HOST=mypi.local PORT=3000 toes list # hostname + port
```
set `NODE_ENV=production` to default to `toes.local:80`.
## fun stuff ## fun stuff
- textOS (TODO, more?) - textOS (TODO, more?)

View File

@ -1,5 +1,6 @@
export { logApp } from './logs' export { logApp } from './logs'
export { export {
configShow,
infoApp, infoApp,
listApps, listApps,
newApp, newApp,

View File

@ -1,5 +1,5 @@
import type { LogLine } from '@types' import type { LogLine } from '@types'
import { get, makeUrl } from '../http' import { get, handleError, makeUrl } from '../http'
import { resolveAppName } from '../name' import { resolveAppName } from '../name'
export const printLog = (line: LogLine) => export const printLog = (line: LogLine) =>
@ -29,6 +29,7 @@ export async function logApp(arg: string | undefined, options: { follow?: boolea
} }
export async function tailLogs(name: string) { export async function tailLogs(name: string) {
try {
const url = makeUrl(`/api/apps/${name}/logs/stream`) const url = makeUrl(`/api/apps/${name}/logs/stream`)
const res = await fetch(url) const res = await fetch(url)
if (!res.ok) { if (!res.ok) {
@ -56,4 +57,7 @@ export async function tailLogs(name: string) {
} }
} }
} }
} catch (error) {
handleError(error)
}
} }

View File

@ -3,7 +3,7 @@ import { generateTemplates, type TemplateType } from '%templates'
import color from 'kleur' import color from 'kleur'
import { existsSync, mkdirSync, writeFileSync } from 'fs' import { existsSync, mkdirSync, writeFileSync } from 'fs'
import { basename, join } from 'path' import { basename, join } from 'path'
import { del, get, getManifest, post } from '../http' import { del, get, getManifest, HOST, post } from '../http'
import { confirm, prompt } from '../prompts' import { confirm, prompt } from '../prompts'
import { resolveAppName } from '../name' import { resolveAppName } from '../name'
import { pushApp } from './sync' import { pushApp } from './sync'
@ -15,6 +15,33 @@ export const STATE_ICONS: Record<string, string> = {
invalid: color.red('◌'), invalid: color.red('◌'),
} }
export async function configShow() {
console.log(`Host: ${color.bold(HOST)}`)
const source = process.env.TOES_URL
? 'TOES_URL'
: process.env.TOES_HOST
? 'TOES_HOST' + (process.env.PORT ? ' + PORT' : '')
: process.env.NODE_ENV === 'production'
? 'default (production)'
: 'default (development)'
console.log(`Source: ${color.gray(source)}`)
if (process.env.TOES_URL) {
console.log(` TOES_URL=${process.env.TOES_URL}`)
}
if (process.env.TOES_HOST) {
console.log(` TOES_HOST=${process.env.TOES_HOST}`)
}
if (process.env.PORT) {
console.log(` PORT=${process.env.PORT}`)
}
if (process.env.NODE_ENV) {
console.log(` NODE_ENV=${process.env.NODE_ENV}`)
}
}
export async function infoApp(arg?: string) { export async function infoApp(arg?: string) {
const name = resolveAppName(arg) const name = resolveAppName(arg)
if (!name) return if (!name) return

View File

@ -1,6 +1,17 @@
import type { Manifest } from '@types' import type { Manifest } from '@types'
export const HOST = `http://localhost:${process.env.PORT ?? 3000}` function getDefaultHost(): string {
if (process.env.NODE_ENV === 'production') {
return `http://toes.local:${process.env.PORT ?? 80}`
}
return `http://localhost:${process.env.PORT ?? 3000}`
}
const defaultPort = process.env.NODE_ENV === 'production' ? 80 : 3000
export const HOST = process.env.TOES_URL
?? (process.env.TOES_HOST ? `http://${process.env.TOES_HOST}:${process.env.PORT ?? defaultPort}` : undefined)
?? getDefaultHost()
export function makeUrl(path: string): string { export function makeUrl(path: string): string {
return `${HOST}${path}` return `${HOST}${path}`
@ -9,6 +20,7 @@ export function makeUrl(path: string): string {
export function handleError(error: unknown): void { export function handleError(error: unknown): void {
if (error instanceof Error && 'code' in error && error.code === 'ConnectionRefused') { if (error instanceof Error && 'code' in error && error.code === 'ConnectionRefused') {
console.error(`🐾 Can't connect to toes server at ${HOST}`) console.error(`🐾 Can't connect to toes server at ${HOST}`)
console.error(` Set TOES_URL or TOES_HOST to connect to a different host`)
return return
} }
console.error(error) console.error(error)

View File

@ -3,6 +3,7 @@ import { readFileSync } from 'fs'
import color from 'kleur' import color from 'kleur'
import { import {
configShow,
diffApp, diffApp,
getApp, getApp,
infoApp, infoApp,
@ -45,6 +46,11 @@ program
.command('version', { hidden: true }) .command('version', { hidden: true })
.action(() => console.log(program.version())) .action(() => console.log(program.version()))
program
.command('config')
.description('Show current host configuration')
.action(configShow)
program program
.command('info') .command('info')
.description('Show info for an app') .description('Show info for an app')