take a look

This commit is contained in:
Chris Wanstrath 2026-01-27 16:58:04 -08:00
parent aaf6ce8361
commit eef3df7534
5 changed files with 58 additions and 13 deletions

View File

@ -9,6 +9,13 @@
[x] watch each app and restart it on update
[x] watches for and adds/removes apps
## apps
[ ] truism
[ ] big clock
[ ] shrimp repl(?)
[ ] dungeon party
## cli
[ ] `toes --help`
@ -21,6 +28,7 @@
## webui
[ ] list projects
[x] list projects
[ ] start/stop/restart project
[ ] todo.txt
[ ] ...

View File

@ -15,7 +15,7 @@
"typescript": "^5.9.2"
},
"dependencies": {
"hype": "git+https://git.nose.space/defunkt/hype",
"forge": "git+https://git.nose.space/defunkt/forge"
"forge": "git+https://git.nose.space/defunkt/forge",
"hype": "git+https://git.nose.space/defunkt/hype"
}
}

View File

@ -16,17 +16,17 @@
},
},
"packages": {
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
"@types/bun": ["@types/bun@1.3.7", "", { "dependencies": { "bun-types": "1.3.7" } }, "sha512-lmNuMda+Z9b7tmhA0tohwy8ZWFSnmQm1UDWXtH5r9F7wZCfkeO3Jx7wKQ1EOiKq43yHts7ky6r8SDJQWRNupkA=="],
"@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
"bun-types": ["bun-types@1.3.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-qyschsA03Qz+gou+apt6HNl6HnI+sJJLL4wLDke4iugsE6584CMupOtTY1n+2YC9nGVrEKUlTs99jjRLKgWnjQ=="],
"forge": ["forge@git+https://git.nose.space/defunkt/forge#9b6e1e91ec77d7e03589cac256d97fb9cd942184", { "peerDependencies": { "typescript": "^5" } }, "9b6e1e91ec77d7e03589cac256d97fb9cd942184"],
"hono": ["hono@4.11.7", "", {}, "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw=="],
"hype": ["hype@git+https://git.nose.space/defunkt/hype#52086f4eb94cc36ecd9470d9a101ff01002687c8", { "dependencies": { "hono": "^4.10.4", "kleur": "^4.1.5" }, "peerDependencies": { "typescript": "^5" } }, "52086f4eb94cc36ecd9470d9a101ff01002687c8"],
"hype": ["hype@git+https://git.nose.space/defunkt/hype#7b9cade936c4897539d2ca14299d90f80deb6ebe", { "dependencies": { "hono": "^4.10.4", "kleur": "^4.1.5" }, "peerDependencies": { "typescript": "^5" } }, "7b9cade936c4897539d2ca14299d90f80deb6ebe"],
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],

View File

@ -1,8 +1,40 @@
import { define, Styles } from 'forge'
import { runningApps } from '../server/apps'
const Apps = define('Apps', {
margin: '0 auto',
width: 750,
paddingTop: 20,
})
const color = '#00c0c9'
const hoverColor = 'magenta'
const Link = define({
base: 'a',
color,
textDecoration: 'none',
borderBottom: `1px solid ${color}`,
selectors: {
'&:hover': {
color: hoverColor,
cursor: 'pointer'
}
}
})
const Timestamp = define({
fontSize: 18
})
export default () => (
<>
<Apps>
<Styles />
<h1>🐾 Running Apps</h1>
{runningApps().map(app => <h2><a href={`http://localhost:${app.port}`}>{app.port}: {app.name}</a></h2>)}
</>
{runningApps().map(app => (
<h2>
<Link href={`http://localhost:${app.port}`}>{app.port}: {app.name}</Link>
<Timestamp>Started: {new Date(app.started).toLocaleString()}</Timestamp>
</h2>
))}
</Apps>
)

View File

@ -7,6 +7,7 @@ const APPS_DIR = join(process.env.DATA_DIR ?? '.', 'apps')
type RunningApp = {
name: string
port: number
started: number
proc: Subprocess
}
@ -25,6 +26,7 @@ export const appNames = () => {
return readdirSync(APPS_DIR, { withFileTypes: true })
.filter(e => e.isDirectory())
.map(e => e.name)
.filter(isApp)
.sort()
}
@ -33,7 +35,6 @@ const getPort = () => NEXT_PORT++
export const runApps = () => {
for (const dir of appNames()) {
if (!isApp(dir)) continue
const port = getPort()
runApp(dir, port)
}
@ -86,7 +87,12 @@ const runApp = async (dir: string, port: number) => {
stderr: 'pipe',
})
_runningApps.set(dir, { name: dir, port, proc })
_runningApps.set(dir, {
name: dir,
port,
proc,
started: Date.now()
})
const streamOutput = async (stream: ReadableStream<Uint8Array> | null, isErr: boolean) => {
if (!stream) return
@ -116,9 +122,8 @@ const runApp = async (dir: string, port: number) => {
})
}
export const runningApps = () =>
export const runningApps = (): RunningApp[] =>
Array.from(_runningApps.values())
.map(({ name, port }) => ({ name, port }))
.sort((a, b) => a.port - b.port)
const stopApp = (dir: string) => {