This commit is contained in:
Chris Wanstrath 2025-09-21 12:37:21 -07:00
parent 0de8b07e29
commit 8f7fc5d36b
9 changed files with 31 additions and 24 deletions

View File

@ -1,10 +1,10 @@
import { apps } from "@/webapp"
import { Thread } from "@/shell"
import { getState } from "@/state"
export default function (project: string) {
const state = Thread.getStore()
const state = getState()
if (apps().includes(project) && state) {
if (state && apps().includes(project)) {
state.project = project
}

View File

@ -1,10 +1,10 @@
import { readdirSync } from "fs"
import { NOSE_WWW } from "@/config"
import { Thread } from "@/shell"
import { getState } from "@/state"
import { appPath } from "@/webapp"
export default function () {
const state = Thread.getStore()
const state = getState()
if (!state) return { error: "no state" }
const project = state.project

View File

@ -1,7 +1,7 @@
import { Thread } from "@/shell"
import { getState } from "@/state"
export default function () {
const state = Thread.getStore()
const state = getState()
if (!state) return { error: "no state" }
return state?.project || "none"

View File

@ -1,8 +1,8 @@
import { apps } from "@/webapp"
import { Thread } from "@/shell"
import { getState } from "@/state"
export default function () {
const state = Thread.getStore()
const state = getState()
if (!state) return { error: "no state" }
return { html: apps().map(app => app === state.project ? `<b class="cyan">${app}</b>` : app).join(" ") }

View File

@ -1,8 +1,8 @@
import { Glob } from "bun"
import { watch } from "fs"
import { NOSE_SYS_BIN, NOSE_BIN } from "./config"
import { sendAll } from "./websocket"
import { expectDir } from "./utils"
import { NOSE_SYS_BIN, NOSE_BIN } from "./config"
const sysCmdWatcher = watch(NOSE_SYS_BIN, async (event, filename) =>
sendAll({ type: "commands", data: await commands() })

View File

@ -9,7 +9,7 @@ import { transpile, isFile, tilde } from "./utils"
import { apps, serveApp, publishDNS } from "./webapp"
import { runCommand } from "./shell"
import { commands } from "./commands"
import { send, addWebsocket, removeWebsocket, closeWebsockets, websockets } from "./websocket"
import { send, addWebsocket, removeWebsocket, closeWebsockets } from "./websocket"
import { Layout } from "./components/layout"
import { Terminal } from "./components/terminal"

View File

@ -2,20 +2,11 @@
// runs commands and such.
import type { CommandResult, CommandOutput } from "./shared/types"
import type { State } from "./state"
import { join } from "path"
import { NOSE_SYS_BIN, NOSE_BIN } from "./config"
import { isFile } from "./utils"
import { AsyncLocalStorage } from "async_hooks"
// Ensure "Thread" lives between bun's hot reloads
const g = globalThis as typeof globalThis & { __thread?: AsyncLocalStorage<State> }
export const Thread = g.__thread ??= new AsyncLocalStorage<State>()
type State = {
id?: string
session?: string
project?: string
}
import { ALS } from "./state"
const sessions: Map<string, State> = new Map()
@ -31,7 +22,7 @@ export async function runCommand(session: string, id: string, input: string): Pr
const state = getState(session, id)
try {
[status, output] = await Thread.run(state, async () => await exec(cmd, args))
[status, output] = await ALS.run(state, async () => await exec(cmd, args))
} catch (err) {
status = "error"
output = errorMessage(err)

15
src/state.ts Normal file
View File

@ -0,0 +1,15 @@
import { AsyncLocalStorage } from "async_hooks"
export type State = {
id?: string
session?: string
project?: string
}
// Ensure "ALS" lives between bun's hot reloads
const g = globalThis as typeof globalThis & { __thread?: AsyncLocalStorage<State> }
export const ALS = g.__thread ??= new AsyncLocalStorage<State>()
export function getState(): State | undefined {
return ALS.getStore()
}

View File

@ -1,8 +1,9 @@
import { type Context, Hono } from "hono"
import type { Child } from "hono/jsx"
import { type Context, Hono } from "hono"
import { renderToString } from "hono/jsx/dom/server"
import { join, dirname } from "path"
import { readdirSync, watch } from "fs"
import { NOSE_WWW } from "./config"
import { expectDir, isFile } from "./utils"