fix(ui): recover sessions and dashboards after prolonged outages (#115654)

* fix(ui): recover long-running sessions and dashboards

* fix(ui): expose browser-safe gateway timers

* refactor(ui): keep browser timer surface minimal

* refactor(gateway): extract pending request state

* fix(ci): refresh browser runtime and format baseline

* fix(ci): exclude generated plugin outputs from targeted lint

* fix(ui): bound long-running connection and pane lifecycles

* refactor(ui): split long-running lifecycle regression coverage

* fix(ui): bound long-running media and lint ownership

* fix(security): preserve explicit workspace disable denylist

* fix(ci): preserve plugin manifest fallback lint
This commit is contained in:
Peter Steinberger
2026-07-29 10:09:51 -04:00
committed by GitHub
parent 1ab48a71df
commit fde4658bf6
32 changed files with 1297 additions and 166 deletions
@@ -0,0 +1,50 @@
import { describe, expect, it } from "vitest";
import { detectChangedLanes } from "../../scripts/changed-lanes.mjs";
import { createChangedCheckPlan } from "../../scripts/check-changed.mjs";
describe("generated extension asset lint planning", () => {
it("still lints extension tests alongside a generated browser asset", () => {
const generatedAsset = "extensions/browser/chrome-extension/modules/copilot-runtime.js";
const extensionTest = "extensions/browser/chrome-extension/modules/copilot-gateway.test.ts";
const result = detectChangedLanes([generatedAsset, extensionTest]);
const plan = createChangedCheckPlan(result, { env: { PATH: "/usr/bin" } });
expect(result.lanes.extensionTests).toBe(true);
expect(plan.commands).toContainEqual(
expect.objectContaining({
name: "lint extension changed file",
args: [
"scripts/run-oxlint.mjs",
"--tsconfig",
"config/tsconfig/oxlint.extensions.json",
extensionTest,
],
}),
);
expect(
plan.commands
.filter((command) => command.args[0] === "scripts/run-oxlint.mjs")
.flatMap((command) => command.args),
).not.toContain(generatedAsset);
});
it("keeps fallback extension lint for a manifest beside a generated browser asset", () => {
const generatedAsset = "extensions/browser/chrome-extension/modules/copilot-runtime.js";
const manifest = "extensions/browser/openclaw.plugin.json";
const result = detectChangedLanes([generatedAsset, manifest]);
const plan = createChangedCheckPlan(result, { env: { PATH: "/usr/bin" } });
expect(result.lanes.extensions).toBe(true);
expect(plan.commands).toContainEqual(
expect.objectContaining({
name: "lint extensions",
args: ["lint:extensions"],
}),
);
expect(
plan.commands
.filter((command) => command.args[0] === "scripts/run-oxlint.mjs")
.flatMap((command) => command.args),
).not.toContain(generatedAsset);
});
});
+42
View File
@@ -804,6 +804,48 @@ describe("scripts/changed-lanes", () => {
}
});
it("keeps manifest-declared generated browser assets out of targeted extension lint", () => {
const generatedAsset = "extensions/browser/chrome-extension/modules/copilot-runtime.js";
const result = detectChangedLanes([
generatedAsset,
"packages/gateway-client/src/protocol-client.ts",
]);
const plan = createChangedCheckPlan(result, { env: { PATH: "/usr/bin" } });
expect(result.lanes.extensions).toBe(true);
expect(plan.commands.map((command) => command.args[0])).toContain("tsgo:extensions");
expect(plan.commands.map((command) => command.args[0])).not.toContain("lint:extensions");
expect(
plan.commands
.filter((command) => command.args[0] === "scripts/run-oxlint.mjs")
.flatMap((command) => command.args),
).not.toContain(generatedAsset);
});
it("still lints extension source alongside its generated browser asset", () => {
const generatedAsset = "extensions/browser/chrome-extension/modules/copilot-runtime.js";
const source = "extensions/browser/scripts/copilot-runtime-entry.ts";
const result = detectChangedLanes([generatedAsset, source]);
const plan = createChangedCheckPlan(result, { env: { PATH: "/usr/bin" } });
expect(plan.commands).toContainEqual(
expect.objectContaining({
name: "lint extension changed file",
args: [
"scripts/run-oxlint.mjs",
"--tsconfig",
"config/tsconfig/oxlint.extensions.json",
source,
],
}),
);
expect(
plan.commands
.filter((command) => command.args[0] === "scripts/run-oxlint.mjs")
.flatMap((command) => command.args),
).not.toContain(generatedAsset);
});
it.each([
{
owner: "core",