Ground Bean Bro in displayed temperatures, stream replies, and add activity calendar
Test and deploy / test-and-deploy (push) Successful in 1m19s

This commit is contained in:
snowspeeder committed 2026-09-07 06:38:16 -04:00
1 parent a72aec9f86
commit d96ed22de1
16 files changed
+551 -484

No files matched your search

+35 -8
View File
@@ -345,7 +345,7 @@ export function createApp({
app.get("/", async (req, res, next) => {
try {
// Returning users should not be left on the marketing page after signing in.
if (await session(req)) return res.status(302).location("/app").end();
if (await session(req)) return res.status(302).location("/home").end();
res.set("Cache-Control", "no-store, private");
res.sendFile(path.join(root, "public", "landing.html"));
} catch (error) {
@@ -355,7 +355,7 @@ export function createApp({
for (const route of ["/login", "/signup", "/forgot"]) {
app.get(route, async (req, res, next) => {
try {
if (await session(req)) return res.status(302).location("/app").end();
if (await session(req)) return res.status(302).location("/home").end();
res.set("Cache-Control", "no-store, private");
res.sendFile(path.join(root, "public", `${route.slice(1)}.html`));
} catch (error) {
@@ -365,7 +365,7 @@ export function createApp({
}
app.get("/reset", async (req, res, next) => {
try {
if (await session(req)) return res.status(302).location("/app").end();
if (await session(req)) return res.status(302).location("/home").end();
res.set("Cache-Control", "no-store, private");
res.sendFile(path.join(root, "public", "reset.html"));
} catch (error) {
@@ -374,7 +374,7 @@ export function createApp({
});
app.get("/setup", async (req, res, next) => {
try {
if (await session(req)) return res.status(302).location("/app").end();
if (await session(req)) return res.status(302).location("/home").end();
const exists = await db.query("SELECT 1 FROM users WHERE email=$1", [
ADMIN_EMAIL,
]);
@@ -433,9 +433,10 @@ export function createApp({
next(error);
}
});
app.get("/coffees", requireAuth, (req, res) => res.redirect("/home"));
for (const [route, file] of [
["/plans", "plans.html"],
["/home", "workspace.html"], ["/coffees", "workspace.html"],
["/home", "workspace.html"],
["/beans", "beans.html"],
["/brews", "brews.html"],
["/gear", "gear.html"],
@@ -1494,6 +1495,14 @@ export function createApp({
}
});
app.post("/api/plan-chat", requireAuth, csrf, async (req, res, next) => {
const streaming = req.get("accept")?.includes("text/event-stream");
const controller = new AbortController();
let heartbeat;
const emit = (event, data) => {
if (!res.destroyed && !res.writableEnded)
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
};
const disconnect = () => controller.abort();
try {
if (!req.body.plan || typeof req.body.plan !== "object" || Array.isArray(req.body.plan))
return res.status(400).json({ ok: false, code: "bad_plan" });
@@ -1506,14 +1515,32 @@ export function createApp({
const workspace = await workspaceFor(db,req.user.id);
const coffee = workspace.coffees.find(c=>c.key===coffeeKey(req.body.plan));
const evidence = coffee ? {name:coffee.name,roasts:coffee.roasts.slice(0,12),cuppings:coffee.cuppings.slice(0,12),experiments:coffee.plans.map(p=>({id:p.id,experiment:p.experiment})).slice(0,12)} : null;
const result = await runPlanChat({ plan: req.body.plan, messages, evidence, preferredModel: await llmModelSetting() });
const preferredModel = await llmModelSetting();
if (streaming) {
res.set({"Content-Type":"text/event-stream", "Cache-Control":"no-cache, no-transform", "X-Accel-Buffering":"no"});
res.flushHeaders();
res.on("close", disconnect);
heartbeat = setInterval(() => { if (!res.destroyed) res.write(": heartbeat\n\n"); }, 15000);
}
const result = await runPlanChat({
plan: req.body.plan, messages, evidence, preferredModel,
signal: controller.signal,
onText: streaming ? (text) => emit("reply", {text}) : undefined,
});
result.suggestions = cleanSuggestions(result.suggestions).map(s=>({...s,evidenceRoastIds:s.evidenceRoastIds.filter(id=>evidence?.roasts.some(r=>r.id===id))}));
res.json({ ok: true, ...result });
if (streaming) { emit("done", {ok:true, ...result}); res.end(); }
else res.json({ ok: true, ...result });
} catch (err) {
const code = err.code ?? "chat_failed";
res
if (res.headersSent) {
emit("error", {ok:false, code, error:err.message});
res.end();
} else res
.status(code === "no_model" ? 503 : 422)
.json({ ok: false, code, error: err.message });
} finally {
clearInterval(heartbeat);
res.off("close", disconnect);
}
});