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
1 change: 1 addition & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
package-manager-cache: false

- name: Restore node_modules cache
if: runner.os != 'Windows'
id: nm-cache-e2e
uses: actions/cache@v5
with:
Expand Down
2 changes: 2 additions & 0 deletions dashboard/src/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export const cloneDefaultSettings = (): DashboardSettings => ({
dbAutoVacuumOnStartup: DEFAULT_DASHBOARD_SETTINGS.dbAutoVacuumOnStartup,
dbPruningEnabled: DEFAULT_DASHBOARD_SETTINGS.dbPruningEnabled,
dbRetentionDays: DEFAULT_DASHBOARD_SETTINGS.dbRetentionDays,
restartSprintPolicy: DEFAULT_DASHBOARD_SETTINGS.restartSprintPolicy,
restartInvocationPolicy: DEFAULT_DASHBOARD_SETTINGS.restartInvocationPolicy,
appearance: { ...DEFAULT_DASHBOARD_SETTINGS.appearance },
automationLevel: DEFAULT_DASHBOARD_SETTINGS.automationLevel,
automationInterventions: { ...DEFAULT_DASHBOARD_SETTINGS.automationInterventions },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ import { NumberInput, Row, Toggle, TextInput, PillChoiceGroup } from "../Setting
import { LocalFilePickerField } from "../LocalFilePickerField.js";
import type { ProjectSettings } from "../../../../../../src/contracts/settings-scope-types.js";
import { SectionCard, getBadge as getBadgeHelper, getFieldBadge as getFieldBadgeHelper } from "./SharedPanelComponents.js";
import { Bot, Cog, Database, FolderOpen, Sparkles } from "lucide-preact";
import { Bot, Cog, Database, FolderOpen, RotateCcw, Sparkles } from "lucide-preact";
import { openOnboarding } from "../../../lib/onboarding-control.js";
import { useProjectData } from "../../../context/project-data.js";

const toRestartSprintPolicy = (value: string) => (
value === "pause" || value === "cancel" ? value : "continue"
);

const toRestartInvocationPolicy = (value: string) => (
value === "cancel" || value === "restart" ? value : "continue"
);

const ProjectContextCard: FunctionComponent<{
projectName: string;
Expand Down Expand Up @@ -333,6 +340,43 @@ export const SettingsGeneralPanel: FunctionComponent<{ state: SettingsPageState
</Row>
</SectionCard>

<SectionCard title="Restart Behavior" watermark="RST" icon={<RotateCcw strokeWidth={2.4} />}>
<Row label="After app restart" description="Choose what Code UX does with sprint runs that were active when the runtime stopped.">
<PillChoiceGroup
value={systemSettings?.runtime.restartSprintPolicy ?? "continue"}
onChange={(value) => updateSystem((current) => ({
...current,
runtime: {
...current.runtime,
restartSprintPolicy: toRestartSprintPolicy(value),
},
}))}
options={[
{ value: "continue", label: "Continue", hint: "Resume active sprint watch loops." },
{ value: "pause", label: "Pause", hint: "Hold active sprints for manual resume." },
{ value: "cancel", label: "Cancel", hint: "Stop active sprint runs on startup." },
]}
/>
</Row>
<Row label="Interrupted invocations" description="When sprints continue after restart, choose how interrupted provider, QA, and task invocations are reconciled." last>
<PillChoiceGroup
value={systemSettings?.runtime.restartInvocationPolicy ?? "continue"}
onChange={(value) => updateSystem((current) => ({
...current,
runtime: {
...current.runtime,
restartInvocationPolicy: toRestartInvocationPolicy(value),
},
}))}
options={[
{ value: "continue", label: "Continue", hint: "Keep live provider runtimes attached when possible." },
{ value: "cancel", label: "Cancel", hint: "Mark interrupted work cancelled." },
{ value: "restart", label: "Restart", hint: "Retry interrupted work from preserved state." },
]}
/>
</Row>
</SectionCard>

<SectionCard title="Database Settings" watermark="DBM" icon={<Database strokeWidth={2.4} />}>
<Row label="Automatic pruning" description="Automatically prune completed task runs, VM activities, attention items, and realtime events on startup.">
<Toggle aria-label="Toggle setting" value={systemSettings?.runtime.dbPruningEnabled ?? true}
Expand Down
9 changes: 9 additions & 0 deletions dashboard/src/v2/lib/settings-search-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ const BASE_CATEGORY_TERMS: Record<CategoryId, string[]> = {
"console log",
"debug log",
"retention",
"restart",
"restart behavior",
"after app restart",
"continue sprints",
"pause sprints",
"cancel sprints",
"interrupted invocation",
"restart invocation",
"cancel invocation",
],
appearance: [
"theme",
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/system-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This project is a Model Context Protocol (MCP) server with an integrated dashboa
- Instantiate repositories, services, handlers, orchestrator.
- Register MCP request handlers via `src/server/mcp-request-router.ts`.
- Start dashboard HTTP server.
- Start MCP stdio transport.
- Start MCP stdio transport only for an attached MCP pipe/socket or explicit `CODE_UX_ENABLE_MCP_STDIO=1`; daemon stdin such as `/dev/null` keeps stdio disabled.
- Serve cached dashboard live activity and git status via `src/server/activity-cache-service.ts`.
- Dashboard dependency composition lives in `src/app/dependency-factory/dashboard-factory.ts`. When two dashboard services must be constructed before both concrete instances exist, the factory uses `LateBoundDependency<T>` from `src/shared/late-bound-dependency.ts` and links it synchronously before returning dependencies. Consumers resolve these holders at action time so missing links fail with an explicit late-bound dependency error instead of placeholder objects or private-field mutation.

Expand Down
3 changes: 2 additions & 1 deletion docs/development/testing-and-quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Root E2E specs should prepare normal app state through `tests/e2e/helpers/prepar
- Use `completeOnboarding`, `ensureSelectedProject`, `createDraftSprint`, and `createTaskInSprint` for setup instead of hand-writing setup requests in each spec.
- Use unique fixture keys and generated names from the helper utilities so parallel workers and retries do not collide.
- Prefer role-based locators, accessible names, landmarks, and stable `data-testid` roots over CSS shape or timing assertions.
- For live-updating menus or dropdowns, keep helper clicks idempotent: reopen the menu and retry if a located item detaches between visibility and click, while still asserting the accessible action is visible before each attempt.
- Build paths with Node `os`, `path`, and `fs` APIs so fixtures remain portable on Windows, macOS, and Linux.
- For credential-free project setup coverage, drive the visible Add Project UI and disable the Project Setup Agent option before submitting so the test does not call provider orchestration, Docker provider startup, worker dispatch, or sprint execution endpoints.
- Clean up created sprints and tasks with `deleteTask`, `deleteSprint`, or `cleanupSprintFixture` in `afterEach` when a spec mutates persistent app state.
Expand All @@ -99,7 +100,7 @@ Root E2E specs should prepare normal app state through `tests/e2e/helpers/prepar

The Playwright workflow is `.github/workflows/playwright.yml`. It runs on pushes and pull requests targeting `main` or `dev`, keeping release and publish workflows separate from validation.

The workflow matrix covers `ubuntu-latest`, `macos-latest`, and `windows-latest`. It installs dependencies with pnpm 10.33.0 on Node 22, builds the server and dashboard before Playwright starts `node dist/index.js`, caches browser binaries under `.cache/ms-playwright`, installs Linux Chromium system dependencies only on Linux runners, and runs the same `pnpm run test:e2e` script used locally. It uploads `test-results/` and `playwright-report/` as the `playwright-artifacts` workflow artifact for seven days, with empty uploads ignored so successful runs do not fail if no failure artifacts were produced.
The workflow matrix covers `ubuntu-latest`, `macos-latest`, and `windows-latest`. It installs dependencies with pnpm 10.33.0 on Node 22, builds the server and dashboard before Playwright starts `node dist/index.js`, caches browser binaries under `.cache/ms-playwright`, installs Linux Chromium system dependencies only on Linux runners, and runs the same `pnpm run test:e2e` script used locally. Linux and macOS restore a `node_modules` cache for speed; Windows intentionally skips that cache and performs a clean pnpm install so pnpm's nested package links are regenerated instead of reusing a stale symlink tree. It uploads `test-results/` and `playwright-report/` as the `playwright-artifacts` workflow artifact for seven days, with empty uploads ignored so successful runs do not fail if no failure artifacts were produced.

This lane is credential-free. It validates the compiled dashboard and server, including project setup coverage through `tests/e2e/project-setup-release.spec.ts`, without provider keys, Docker provider startup, project setup automation, sprint orchestration, or real project state.

Expand Down
4 changes: 2 additions & 2 deletions docs/mcp/runtime-and-dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Startup sequence:
6. `src/server/code-ux-server.ts` starts dashboard server.
- Dashboard API routes (such as project, sprint, task, conversation, and planning endpoints) are broken out into modular route files for maintainability.
- Route wrappers and body request parsers are maintained as separate server-layer boundaries.
7. `src/server/code-ux-server.ts` connects MCP stdio transport.
7. `src/server/code-ux-server.ts` connects MCP stdio transport only when stdin is an MCP pipe/socket or `CODE_UX_ENABLE_MCP_STDIO=1` is set. TTY stdin and daemon-style character-device stdin such as `/dev/null` leave stdio disabled so the dashboard/backend stays alive without an attached client.
8. `src/server/code-ux-server.ts` optionally starts the MCP HTTP transport with the same project-manager tool surface.
9. `src/server/code-ux-server.ts` starts runtime intervals and schedules deferred startup work.

Expand Down Expand Up @@ -131,5 +131,5 @@ On `SIGINT`, `SIGTERM`, or `SIGHUP`, and when the Electron shell quits:
- Server requests every registered active dispatch to stop through its normal abort hook.
- Server scans running Docker containers for `code-ux.*` labels and kills any remaining Code UX-managed containers directly.
- Server preserves Docker workspace/runtime volumes and leaves shutdown-interrupted Docker-backed task rows retryable. Startup recovery closes the interrupted local CLI invocation/dispatch/QA telemetry as `cancelled`, not `failed`, and can resume from the same workspace volume when that retry mode is enabled.
- Server closes MCP stdio and HTTP transports. The dashboard and MCP HTTP listeners track open sockets and destroy them during shutdown, including upgraded dashboard WebSocket sockets, so an open browser tab does not hold the process in the HTTP close path.
- Server closes any active MCP stdio transport and the MCP HTTP transport. The dashboard and MCP HTTP listeners track open sockets and destroy them during shutdown, including upgraded dashboard WebSocket sockets, so an open browser tab does not hold the process in the HTTP close path.
- Process exits cleanly.
Loading
Loading