Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ the run is registered and the driver continues detached, so a loop outlives the
request — and the tab — that started it:

```
loop_start {projectSlug, goal, profile?, intervalMs?, sessionId?, maxIterations?}
loop_start {projectSlug, goal, profile?, intervalMs?, sessionId?}
loop_stop {loopId} · loop_status {loopId} · loop_runs {}
```

Expand All @@ -460,9 +460,9 @@ loop_stop {loopId} · loop_status {loopId} · loop_runs {}
- `Aaa` completion defers entirely to
`loop_report::validate_completion_readiness` — the same gate a model calling
`loop_report_update` must clear, so the loop cannot finish itself by a route
the report would have rejected. Measured: with no report on disk, three DONEs
in a row were refused and the run hit its cap, where `standard` completed in
two iterations.
the report would have rejected. Measured: with no passing report on disk,
three DONEs in a row are refused and the run remains live until Stop, while
`standard` completes in two iterations.
- Progress rides the SSE bus as `loop.iteration`, `loop.done_refused`,
`loop.completed`, `loop.finished`.
- **The panel rejoins a run it did not start.** On mount it asks `loop_runs`
Expand Down
3 changes: 3 additions & 0 deletions client/build-electron/entitlements.mac.plist
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
refused without this. -->
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- Electron's V8 JIT needs an explicit hardened-runtime grant on macOS. -->
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<!-- Core listens on 127.0.0.1 and the browser panel loads the open web. -->
Expand Down
27 changes: 25 additions & 2 deletions client/e2e/features.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,31 @@ import { expect, test } from "@playwright/test";
const PNG_1PX =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=";

const openTab = (page: import("@playwright/test").Page, name: string) =>
page.getByRole("tab", { name, exact: true }).click();
const TAB_LABELS: Record<string, string> = {
play: "Play",
code: "Code",
art: "Assets",
build: "Build",
scene: "Scene",
test: "Test",
terminal: "Terminal",
browser: "Browser",
reports: "Reports",
};

async function openTab(page: import("@playwright/test").Page, name: string): Promise<void> {
const tab = page.getByRole("tab", { name, exact: true });
if ((await tab.count()) === 0) {
const picker = page.getByRole("button", { name: `Show ${TAB_LABELS[name]}` });
if ((await picker.count()) > 0) {
await picker.click();
} else {
await page.getByRole("button", { name: "Add view" }).click();
await page.getByRole("menuitem", { name: TAB_LABELS[name], exact: true }).click();
}
}
await tab.click();
}

async function callRpc(
page: import("@playwright/test").Page,
Expand Down
1 change: 0 additions & 1 deletion client/e2e/loop-gate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ test.describe("loop completion gate", () => {
profile: String(body.params?.profile ?? "standard"),
status: "running",
iteration: 0,
maxIterations: 100,
startedAtMs: Date.now(),
},
},
Expand Down
1 change: 1 addition & 0 deletions client/e2e/one-prompt-live.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ test.describe("one-prompt live production proof @live", () => {
expect(persisted.tests.length).toBeGreaterThan(baseline.tests.length);

const reportsTab = page.getByRole("tab", { name: "reports", exact: true });
if ((await reportsTab.count()) === 0) await page.getByRole("button", { name: "Show Reports" }).click();
await reportsTab.click();
const reportsPanel = page.locator("#workspace-panel-reports");
await expect(reportsPanel.getByText(goal, { exact: true })).toBeVisible({ timeout: 30_000 });
Expand Down
1 change: 1 addition & 0 deletions client/e2e/reports.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ test.describe("Reports workspace", () => {
await projectButton.click();

const reportsTab = page.getByRole("tab", { name: "reports", exact: true });
if ((await reportsTab.count()) === 0) await page.getByRole("button", { name: "Show Reports" }).click();
await expect(reportsTab).toBeVisible();
await reportsTab.click();
await expect(reportsTab).toHaveAttribute("aria-selected", "true");
Expand Down
12 changes: 7 additions & 5 deletions client/e2e/smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ test("editor boots with the CaliCode workspace shell", async ({ page }) => {
await page.goto("/");
await expect(page.getByLabel("Agent prompt")).toBeVisible();
await expect(page.locator("canvas").first()).toBeVisible();
for (const name of ["play", "code", "art", "scene", "test"]) {
await expect(page.getByRole("tab", { name, exact: true })).toBeVisible();
}
await expect(page.locator("[data-empty-workspace]")).toBeVisible();
await expect(page.getByRole("tab")).toHaveCount(0);
await page.getByRole("button", { name: "Show Play" }).click();
await expect(page.getByRole("tab", { name: "play", exact: true })).toBeVisible();
});

test("play transport runs PIE and captures frames", async ({ page }) => {
await page.goto("/");
await page.getByRole("tab", { name: "play", exact: true }).click();
await page.getByRole("button", { name: "Show Play" }).click();

await page.getByRole("button", { name: "PLAY", exact: true }).click();
await expect(page.getByRole("button", { name: "PAUSE", exact: true })).toBeVisible({ timeout: 10_000 });
Expand All @@ -22,6 +23,7 @@ test("play transport runs PIE and captures frames", async ({ page }) => {

test("live bar exposes build, fps, and a console", async ({ page }) => {
await page.goto("/");
await page.getByRole("button", { name: "Show Play" }).click();
await expect(page.getByText("FPS", { exact: false }).first()).toBeVisible();

// The log lives in the bottom dock now, behind the panel toggle.
Expand All @@ -34,7 +36,7 @@ test("live bar exposes build, fps, and a console", async ({ page }) => {

test("tweak pins open a live inspector over the viewport", async ({ page }) => {
await page.goto("/");
await page.getByRole("tab", { name: "play", exact: true }).click();
await page.getByRole("button", { name: "Show Play" }).click();

const pin = page.getByRole("button", { name: "RUNTIME", exact: true });
await expect(pin).toHaveAttribute("aria-pressed", "false");
Expand Down
23 changes: 22 additions & 1 deletion client/e2e/visual.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,35 @@ async function settle(page: Page): Promise<void> {
const MAX_DIFF_PIXELS = 150;

const TABS = ["play", "code", "art", "scene", "test"] as const;
const TAB_PICKER_LABELS: Record<(typeof TABS)[number], string> = {
play: "Play",
code: "Code",
art: "Assets",
scene: "Scene",
test: "Test",
};

async function openWorkspaceTab(page: Page, tab: (typeof TABS)[number]): Promise<void> {
const existing = page.getByRole("tab", { name: tab, exact: true });
if ((await existing.count()) === 0) {
const picker = page.getByRole("button", { name: `Show ${TAB_PICKER_LABELS[tab]}` });
if ((await picker.count()) > 0) {
await picker.click();
} else {
await page.getByRole("button", { name: "Add view" }).click();
await page.getByRole("menuitem", { name: TAB_PICKER_LABELS[tab], exact: true }).click();
}
}
await page.getByRole("tab", { name: tab, exact: true }).click();
}

test.describe("workspace surfaces @visual", () => {
for (const tab of TABS) {
test(`${tab} tab`, async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 900 });
await page.goto("/");
await settle(page);
await page.getByRole("tab", { name: tab, exact: true }).click();
await openWorkspaceTab(page, tab);
await settle(page);

await expect(page).toHaveScreenshot(`tab-${tab}.png`, {
Expand Down
Binary file modified client/e2e/visual.spec.ts-snapshots/console-expanded-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/console-expanded-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/layout-tablet-768-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/layout-tablet-768-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-art-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-art-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-code-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-code-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-play-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-play-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-scene-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-scene-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-test-darwin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/e2e/visual.spec.ts-snapshots/tab-test-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 25 additions & 1 deletion client/e2e/workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,31 @@ const slugify = (value: string) =>
const uniqueLabel = (prefix: string, testInfo: TestInfo) =>
`${prefix} ${testInfo.workerIndex}-${testInfo.repeatEachIndex}-${Math.random().toString(36).slice(2, 8)}`;

const openTab = (page: Page, name: string) => page.getByRole("tab", { name, exact: true }).click();
const TAB_LABELS: Record<string, string> = {
play: "Play",
code: "Code",
art: "Assets",
build: "Build",
scene: "Scene",
test: "Test",
terminal: "Terminal",
browser: "Browser",
reports: "Reports",
};

async function openTab(page: Page, name: string): Promise<void> {
const tab = page.getByRole("tab", { name, exact: true });
if ((await tab.count()) === 0) {
const picker = page.getByRole("button", { name: `Show ${TAB_LABELS[name]}` });
if ((await picker.count()) > 0) {
await picker.click();
} else {
await page.getByRole("button", { name: "Add view" }).click();
await page.getByRole("menuitem", { name: TAB_LABELS[name], exact: true }).click();
}
}
await tab.click();
}

async function callRpc(page: Page, method: string, params: Record<string, unknown>): Promise<any> {
return page.evaluate(
Expand Down
4 changes: 3 additions & 1 deletion client/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,9 @@ function registerIpc(panel: BrowserPanel): void {
});
return result.canceled ? null : (result.filePaths[0] ?? null);
});
ipcMain.handle(IPC.panelBounds, (_event, bounds: PanelBounds) => {
// Bounds are high-frequency, fire-and-forget layout updates from the
// renderer (`ipcRenderer.send`), not request/response calls.
ipcMain.on(IPC.panelBounds, (_event, bounds: PanelBounds) => {
panel.setBounds(bounds);
});
ipcMain.handle(IPC.panelTarget, () => panel.targetId());
Expand Down
Loading
Loading