From 8f7fc5d36b5c446d3d988fb099596a010ef0b9b6 Mon Sep 17 00:00:00 2001
From: Chris Wanstrath <2+defunkt@users.noreply.github.com>
Date: Sun, 21 Sep 2025 12:37:21 -0700
Subject: [PATCH] getState
---
nose/bin/load.ts | 6 +++---
nose/bin/ls.ts | 4 ++--
nose/bin/project.ts | 4 ++--
nose/bin/projects.ts | 4 ++--
src/commands.ts | 2 +-
src/server.tsx | 2 +-
src/shell.ts | 15 +++------------
src/state.ts | 15 +++++++++++++++
src/webapp.ts | 3 ++-
9 files changed, 31 insertions(+), 24 deletions(-)
create mode 100644 src/state.ts
diff --git a/nose/bin/load.ts b/nose/bin/load.ts
index 41ecad7..908eac8 100644
--- a/nose/bin/load.ts
+++ b/nose/bin/load.ts
@@ -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
}
diff --git a/nose/bin/ls.ts b/nose/bin/ls.ts
index e017c42..ea98b79 100644
--- a/nose/bin/ls.ts
+++ b/nose/bin/ls.ts
@@ -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
diff --git a/nose/bin/project.ts b/nose/bin/project.ts
index 4997fb1..b1da363 100644
--- a/nose/bin/project.ts
+++ b/nose/bin/project.ts
@@ -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"
diff --git a/nose/bin/projects.ts b/nose/bin/projects.ts
index 179bd7d..ddb0604 100644
--- a/nose/bin/projects.ts
+++ b/nose/bin/projects.ts
@@ -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 ? `${app}` : app).join(" ") }
diff --git a/src/commands.ts b/src/commands.ts
index 7237fe2..b4423af 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -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() })
diff --git a/src/server.tsx b/src/server.tsx
index 4ba0bfe..081cc08 100644
--- a/src/server.tsx
+++ b/src/server.tsx
@@ -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"
diff --git a/src/shell.ts b/src/shell.ts
index 0e7f9e9..ad036c0 100644
--- a/src/shell.ts
+++ b/src/shell.ts
@@ -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 }
-export const Thread = g.__thread ??= new AsyncLocalStorage()
-
-type State = {
- id?: string
- session?: string
- project?: string
-}
+import { ALS } from "./state"
const sessions: Map = 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)
diff --git a/src/state.ts b/src/state.ts
new file mode 100644
index 0000000..4f3c9fd
--- /dev/null
+++ b/src/state.ts
@@ -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 }
+export const ALS = g.__thread ??= new AsyncLocalStorage()
+
+export function getState(): State | undefined {
+ return ALS.getStore()
+}
\ No newline at end of file
diff --git a/src/webapp.ts b/src/webapp.ts
index 5796f0c..ca16cfb 100644
--- a/src/webapp.ts
+++ b/src/webapp.ts
@@ -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"