Skip to content
Draft
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
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
READ ~/Code/agent-scripts/AGENTS.MD BEFORE ANYTHING (skip if file missing).

Anton owns this project. Say hi when you start!
Any changes made should update the Unreleased section in CHANGELOG.md.
Only user-facing changes should update the Unreleased section in CHANGELOG.md.
Internal notes, planning docs, repo instructions, and similar housekeeping changes do not need changelog entries.
If a changelog entry is later fixed by a follow-up change, merge the follow-up into the original entry instead of adding a new bullet.
Any code or docs change should be followed immediately by a fresh build so local testing uses current artifacts.
Keep the local `devservers` binary in `$PATH` and any `pnpm link` usage pointed at the latest repo build output so CLI testing always exercises the newest changes.
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

## Unreleased

### Changed
- Success notifications in the UI now dismiss automatically after five seconds, while actionable error notifications remain until dismissed manually.
- Refreshed the compact service dashboard with `@24letters/ui`, accessible forms and confirmations, responsive navigation, and clearer service actions and log connection states.
- CLI mutations verify daemon identity and canonical config paths. HTTP failures no longer trigger implicit daemon startup or restart, and requests have bounded deadlines and validated responses.
- Catalog reads no longer unregister missing projects or stop their services. Project removal is explicit, and invalid compose reloads retain the last valid service catalog.

### Fixed
- Serialized config updates, port reservations, and lifecycle cascades to prevent lost updates, duplicate allocations, and overlapping start/stop operations. Daemons acquire storage ownership locks to prevent competing writers.
- Project registration validates before saving, and project removal only targets its own services. Interrupted service startup cleans up partially initialized panes.
- Log streams reject unknown services, bound polling and buffering, and stop work on disconnect. Stale port detection cannot update a replacement service, and daemon shutdown cancels its own work while preserving service panes.

## 0.6.0 - 2026-07-15

### Added
Expand Down
15 changes: 15 additions & 0 deletions IDEAS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Ideas

## Fully Managed Environment Variable Onboarding

When a project is fully all-in on `devservers`, onboarding can become fully guided.
When the user first tries to start the project, `devservers` can ask for any missing
`.env` variables or secrets in a wizard-style flow.

In the command line, this could use a prompt style similar to `create-t3-app`,
asking the user questions about the required environment variables. In the UI, the
experience can be richer: the app can ask for the variables, store them, and keep
them managed from then on.

The user then never has to worry about the contents of `.env.local`, `.env`, or
similar files. Environment variables are always fully managed by `devservers`.
89 changes: 24 additions & 65 deletions apps/ui/README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,32 @@
# React + TypeScript + Vite
# Devservers UI

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
React dashboard for the Devservers daemon. Built with Vite, Tailwind CSS v4, and the
[`@24letters/ui`](https://github.com/atimmer/ui) component library (Base UI primitives,
Phosphor icons, Inter and Newsreader fonts).

Currently, two official plugins are available:
## Structure

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
- `src/App.tsx` composes the shell, dialogs, and confirmation flow.
- `src/hooks/` owns data flow: `use-services` polls the daemon with cancellation,
`use-selection` persists the main-pane target, `use-service-actions` runs lifecycle
actions with cascade confirmation, and `use-log-stream` keeps the log websocket alive
with reconnects.
- `src/components/` holds presentational pieces; `components/dialogs/` holds the add,
edit, project, and compose-definition dialogs.
- `src/lib/status.ts` maps service statuses to the `--status-*` tokens defined in
`src/index.css`. `src/lib/notify.ts` wraps Sonner toasts: successes dismiss after five
seconds, errors stay until dismissed.
- `src/api.ts`, `src/dashboard.ts`, and `src/logs.ts` are transport and pure helpers.

## React Compiler
## Development

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
Do not run `pnpm dev` directly; the dev server is managed by the `devservers` CLI.
Point the UI at a different daemon or mock with `VITE_DAEMON_URL`.

## Expanding the ESLint configuration
Keyboard: `/` focuses the service filter, `Cmd+B` toggles the sidebar.

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```sh
pnpm typecheck
pnpm lint
pnpm build
```
7 changes: 4 additions & 3 deletions apps/ui/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<!doctype html>
<html lang="en">
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ui</title>
<meta name="color-scheme" content="dark" />
<title>Devservers</title>
</head>
<body>
<div id="root"></div>
Expand Down
12 changes: 6 additions & 6 deletions apps/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,26 @@
},
"dependencies": {
"@24letters/devservers-shared": "workspace:*",
"@radix-ui/react-dialog": "^1.1.15",
"@24letters/ui": "0.1.1",
"@phosphor-icons/react": "2.1.10",
"@xterm/addon-fit": "^0.11.0",
"@xterm/xterm": "^6.0.0",
"react": "^19.2.7",
"react-dom": "^19.2.7"
"react-dom": "^19.2.7",
"sonner": "2.0.7"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@tailwindcss/vite": "^4.1.18",
"@tailwindcss/vite": "^4.3.3",
"@types/node": "^24.10.1",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^5.1.1",
"autoprefixer": "^10.4.23",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.18",
"tailwindcss": "^4.3.3",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
"vite": "^7.2.4"
Expand Down
5 changes: 5 additions & 0 deletions apps/ui/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion apps/ui/public/vite.svg

This file was deleted.

Loading
Loading