diff --git a/.gitignore b/.gitignore index 4923d39..e5dc11d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules +.venv .DS_Store dbs .env diff --git a/bliss-cli/live-editor/artifact-editor.eta b/bliss-cli/live-editor/artifact-editor.eta new file mode 100644 index 0000000..7e5c1a8 --- /dev/null +++ b/bliss-cli/live-editor/artifact-editor.eta @@ -0,0 +1,57 @@ +
+
+ <% if (it.kind === 'route') { %><%= it.artifact.verb %> <%= it.artifact.path %><% } else { %><%= it.artifact.name %><% } %> + <%= it.kind %> +
+
+ <% if (it.kind === 'route' && it.artifact.verb !== 'GET') { %> +

Saving does not replay this <%= it.artifact.verb %> route.

+ <% } %> + +
<%= it.kind === 'route' ? it.artifact.handler : it.artifact.content %>
+ <% if (it.kind === 'template') { %> +
+ Rendering test +
<%= it.artifact.test_object || '' %>
+ +
+ <% } %> + +
+
+ diff --git a/bliss-cli/live-editor/inspector.js b/bliss-cli/live-editor/inspector.js new file mode 100644 index 0000000..b4f228d --- /dev/null +++ b/bliss-cli/live-editor/inspector.js @@ -0,0 +1,3 @@ +function handler(req, res) { + res.render("inspector/slideout", {}); +} diff --git a/bliss-cli/live-editor/install.js b/bliss-cli/live-editor/install.js new file mode 100644 index 0000000..9ca0487 --- /dev/null +++ b/bliss-cli/live-editor/install.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node + +// Install/update the live editor using Bliss's public CLI workflow. This file +// intentionally does not open the Bliss database directly. +const { spawnSync } = require("node:child_process"); +const path = require("node:path"); + +const repo = path.resolve(__dirname, "../.."); +const cli = path.join(repo, "bliss-cli/bliss"); + +function bliss(...args) { + const result = spawnSync(process.execPath, [cli, ...args], { + cwd: repo, + env: process.env, + encoding: "utf8", + }); + if (result.status !== 0) throw new Error(result.stderr || result.stdout); + return result.stdout.trim(); +} + +function json(...args) { + return JSON.parse(bliss(...args)); +} + +const structures = json("structures"); +let structure = structures.find((item) => item.name === "__bliss_live_editor"); +if (!structure) { + const created = json("create-structure", "__bliss_live_editor"); + structure = { id: created.id }; +} + +const structureId = String(structure.id); +bliss("update-settings", structureId, "--route-prefix", "/_bliss"); +let state = json("structure", structureId); +if (!state.dbs.some((db) => String(db.id) === "0" && db.alias === "bliss")) { + bliss("attach-db", structureId, "0", "bliss"); +} + +const templates = [ + ["inspector/slideout", "slideout.eta"], + ["inspector/route_editor", "route-editor.eta"], + ["inspector/template_editor", "template-editor.eta"], + ["inspector/artifact_editor", "artifact-editor.eta"], +]; +for (const [name, filename] of templates) { + let template = state.templates.find((item) => item.name === name); + if (!template) { + template = json("create-template", structureId, name); + } + bliss( + "update-template", + structureId, + String(template.id), + "--content-file", + path.join(__dirname, filename), + ); +} + +const routes = [ + ["/inspector", "inspector.js"], + ["/editor/route/:id", "route-editor.js"], + ["/editor/template/:id", "template-editor.js"], +]; +for (const [routePath, filename] of routes) { + let route = state.routes.find( + (item) => item.verb === "GET" && item.path === routePath, + ); + if (!route) { + route = json("create-route", structureId, "GET", routePath); + } + bliss( + "update-route", + structureId, + String(route.id), + "--handler-file", + path.join(__dirname, filename), + ); +} + +console.log(`live editor installed as Structure ${structureId}`); diff --git a/bliss-cli/live-editor/route-editor.eta b/bliss-cli/live-editor/route-editor.eta new file mode 100644 index 0000000..212859e --- /dev/null +++ b/bliss-cli/live-editor/route-editor.eta @@ -0,0 +1,28 @@ +
+
<%= it.sourceRoute.verb %> <%= it.sourceRoute.path %>
+ <% if (it.sourceRoute.verb !== "GET") { %> +
Rerunning this <%= it.sourceRoute.verb %> request can repeat writes or external side effects. Bliss will not rerun it automatically.
+ <% } %> +
<%= it.sourceRoute.handler %>
+ +
+ diff --git a/bliss-cli/live-editor/route-editor.js b/bliss-cli/live-editor/route-editor.js new file mode 100644 index 0000000..85e2cb9 --- /dev/null +++ b/bliss-cli/live-editor/route-editor.js @@ -0,0 +1,7 @@ +function handler(req, res) { + const sql = require("db")("bliss").sql; + const kind = "route"; + const artifact = sql.prepare("SELECT * FROM routes WHERE id = ?").get(req.params.id); + if (!artifact) return res.status(404).send("Route not found"); + res.render("inspector/artifact_editor", { kind, artifact }); +} diff --git a/bliss-cli/live-editor/slideout.eta b/bliss-cli/live-editor/slideout.eta new file mode 100644 index 0000000..e3fe878 --- /dev/null +++ b/bliss-cli/live-editor/slideout.eta @@ -0,0 +1,200 @@ + + diff --git a/bliss-cli/live-editor/template-editor.eta b/bliss-cli/live-editor/template-editor.eta new file mode 100644 index 0000000..f2aa49d --- /dev/null +++ b/bliss-cli/live-editor/template-editor.eta @@ -0,0 +1,25 @@ +
+
<%= it.sourceTemplate.name %>
+
<%= it.sourceTemplate.content %>
+ +
+ diff --git a/bliss-cli/live-editor/template-editor.js b/bliss-cli/live-editor/template-editor.js new file mode 100644 index 0000000..00843a1 --- /dev/null +++ b/bliss-cli/live-editor/template-editor.js @@ -0,0 +1,7 @@ +function handler(req, res) { + const sql = require("db")("bliss").sql; + const kind = "template"; + const artifact = sql.prepare("SELECT * FROM templates WHERE id = ?").get(req.params.id); + if (!artifact) return res.status(404).send("Template not found"); + res.render("inspector/artifact_editor", { kind, artifact }); +} diff --git a/chat-rearchitecture.md b/chat-rearchitecture.md new file mode 100644 index 0000000..ffb64aa --- /dev/null +++ b/chat-rearchitecture.md @@ -0,0 +1,558 @@ +# Chat Rearchitecture — "AIM 2005" edition + +> Living design doc **and** build log. Section 1–8 is the plan; Section 10 is the +> running notes I update as I build. Keep it honest: record what actually +> happened, not what was supposed to. + +--- + +## 0. Prime directive (read this first) + +**We are building fun interfaces at the expense of security and safety.** This is +a hypermedia playground, not a hardened product. Concretely: + +- **Messages may contain arbitrary HTML/JS and we render it unescaped, forever.** + `<%~ it.content %>` (Eta raw) stays. A message can ` +