fix: event-loop freezes, plugin-install boot crash, tmux attach/scrollbar, Codex transcripts

- GET /api/workflows: one LEAD() window pass in a read worker (read-pool.js,
  workflow-stats.js); idx_events_session restored, idx_events_tool added
- compat-sqlite gains function/pluck/readonly so a plugin install without a
  better-sqlite3 build boots again; antigravity-usage uses db.js's Database
- install-hooks adds no checkout hooks while the agenthub plugin is enabled
  (events were doubled)
- terminal attach runs the live tmux server's own binary; the pane scrollbar
  gets a visible 2-column style, and claude panes start with
  CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 so tmux keeps history to scroll
- Codex sessions' conversation in GET /api/sessions/:id/transcript
- Codex/Antigravity sessions claimed by their workspace without hooks
- UI-audit follow-ups, docs and OpenAPI
This commit is contained in:
2026-10-05 17:01:05 +07:00
parent 442f133930
commit 198fbb7980
78 changed files with 2716 additions and 873 deletions
@@ -148,6 +148,33 @@ describe("antigravity usage", () => {
assert.equal(agy.firstFileUri(msg(pb(1, msg(pb(2, "file:///a%20b/c"))))), "/a b/c");
});
it("decodes a blob given as a plain Uint8Array, as node:sqlite returns one", () => {
const u8 = (b) => new Uint8Array(b);
const u = agy.generationUsage(
u8(generation({ model: "gemini-3.8-flash", input: 5, output: 1 }))
);
assert.equal(u.model, "gemini-3.8-flash");
assert.equal(agy.firstFileUri(u8(msg(pb(1, msg(pb(2, "file:///a%20b/c")))))), "/a b/c");
});
it("opens agy's files with the driver db.js chose, read-only (node:sqlite when better-sqlite3 has no build)", () => {
const { Database: Chosen } = require("../db");
assert.equal(typeof Chosen, "function");
const Compat = require("../compat-sqlite");
const file = conversation("33333333-3333-4333-8333-333333333333", {
gens: [{ model: "gemini-3.1-pro", input: 1, output: 2 }],
});
const conn = new Compat(file, { readonly: true, fileMustExist: true });
assert.equal(conn.prepare("SELECT count(*) AS n FROM gen_metadata").get().n, 1);
assert.throws(() => conn.exec("DELETE FROM gen_metadata"), /readonly|read-only/i);
conn.close();
assert.throws(
() => new Compat(path.join(CONV, "missing.db"), { readonly: true, fileMustExist: true }),
/does not exist|unable to open/i
);
assert.equal(fs.existsSync(path.join(CONV, "missing.db")), false);
});
it("creates the session with its name, cwd, model and per-model tokens", async () => {
conversation(ID, {
cwd: "/work/my app",