diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 83ab2d4..4400655 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,4 +48,4 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: dist
- path: packages/*/dist/
+ path: dist/
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c0e4247..cf54cd4 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -26,7 +26,7 @@ jobs:
- run: npm run build
- name: Publish to npm
- run: npm publish -w packages/cli --access public
+ run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 41a5648..2105107 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,5 @@ coverage/
# Temporary
tmp/
.tmp/
+
+CLAUDE.local.md
diff --git a/.prettierignore b/.prettierignore
index 1137375..9983913 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -2,4 +2,4 @@ node_modules/
dist/
coverage/
*.db
-packages/web/public/
+public/
diff --git a/README.md b/README.md
index b96138c..cee1772 100644
--- a/README.md
+++ b/README.md
@@ -1,147 +1,165 @@
-# Clux
+
+
+
-> **v0.2.0 — This project is under active development.** APIs, commands, and features may change without notice.
+Clux
-A tmux session multiplexer with a web dashboard and CLI. Clux lets you create, manage, and monitor multiple tmux sessions from the browser or command line. Run any command — LLM coding agents, dev servers, build scripts, or anything else. It supports inter-pane messaging, session tagging, and real-time output monitoring out of the box.
+
+ A tmux session multiplexer for running parallel coding agents, with a web dashboard and CLI.
+
-## Features
+
+
+
+
+
-- Web dashboard with WebSocket live updates
-- Real-time monitoring of pane output
-- Create and manage tmux sessions running any command
-- Send input and capture output from any pane without attaching
-- Relay messages between panes
-- Tag, search, and describe sessions with persistent metadata (SQLite)
-- Export sessions to Markdown
-
-## Prerequisites
-
-- Node.js >= 18
-- tmux
+Clux wraps tmux into a programmable session manager designed for running multiple Claude Code instances (or any command) in parallel. It pairs a full-featured CLI with a browser dashboard that streams live terminal output over WebSocket. Sessions are enriched with tags, descriptions, and statistics, all persisted in SQLite so nothing is lost between restarts. Built-in inter-pane messaging lets your agents coordinate without manual copy-paste.
## Installation
```bash
-git clone && cd clux
-npm install
-npm run build
+npm install -g @clux-cli/cli
```
-## Web Dashboard
+Requires **Node.js 18+** and **tmux**.
-The web package provides a browser UI backed by Express and WebSocket with live session state, pane output, and session management.
+
+Install from source
```bash
-npm run dev:web
+git clone https://github.com/devhelp/clux.git && cd clux
+npm install
+npm run build
```
-The dashboard runs at `http://127.0.0.1:3456` by default. Configure via environment variables (see `.env.example`).
+This compiles TypeScript and bundles the CLI. You can then run it directly with `node dist/index.js` or link it globally with `npm link`.
-## CLI
+
-After building, you can also manage sessions from the command line:
-
-```bash
-node packages/cli/dist/index.js --help
-```
+## Quick Start
-Or create an alias:
+Start a Claude session in your current project directory:
```bash
-alias clux="node $(pwd)/packages/cli/dist/index.js"
+clux claude
```
-### Quick Start
+The session name is auto-generated from your directory path. If a session for this directory already exists, clux switches you into it instead of creating a duplicate.
-Create a session with an LLM agent:
+Open the web dashboard in another terminal to see all sessions at a glance:
```bash
-clux create my-project --command claude --path ~/projects/my-app
+clux web
```
-List running sessions:
+The dashboard is available at `http://127.0.0.1:3456` and shows live terminal output, session metadata, and management controls.
-```bash
-clux ls
-```
-
-Send a prompt to a running session:
+You can also manage sessions without attaching to them:
```bash
-clux send my-project "refactor the auth module"
+clux ls # list all sessions
+clux send my-session "run the tests" # send a command to a pane
+clux capture my-session --lines 100 # grab recent output
```
-Capture the current output:
+## Claude Sessions
+
+The `clux claude` command is a shortcut purpose-built for Claude Code workflows. It creates a tmux session running `claude`, tags it with `claude` and `ai`, and immediately attaches. The session name is derived from the working directory — path segments are abbreviated to keep names readable (e.g. `/home/user/projects/clux` becomes `claude_h-u-projects-clux`).
```bash
-clux capture my-project --lines 100
+clux claude # auto-name from current directory
+clux claude my-agent # explicit name
+clux claude --path ~/other/repo # different working directory
+clux claude --detach # create without attaching
+clux claude --danger # run with --dangerously-skip-permissions
```
-Attach to a session interactively:
+The command is idempotent: if a session with the resolved name already exists, clux switches to it rather than failing.
-```bash
-clux attach my-project
-```
+## CLI Commands
-### Commands
+Every command supports `--help` for detailed usage.
| Command | Description |
|---------|-------------|
-| `create ` | Create a new session. Supports `--command`, `--path`, `--layout` |
-| `list` / `ls` | List all sessions. Filter with `--tag` or `--search` |
-| `info ` | Detailed session info |
-| `attach ` | Attach to a session (Ctrl+B D to detach) |
-| `kill ` | Kill a session |
-| `send ` | Send text to a pane. Use `--pane` to target a specific pane |
-| `capture ` | Capture pane output. `--all` for full scrollback, `-o` to write to file |
-| `monitor ` | Watch pane output in real-time |
-| `relay ` | Relay messages between panes (`--from`, `--to`, `--message` or `--capture`) |
-| `add-window ` | Add a new window to a session |
-| `rename-window ` | Rename a window |
-| `export ` | Export session to Markdown |
-| `tag ` | Add or remove (`-r`) tags |
+| `create ` | Create a session. `--command`, `--path`, `--layout`, `--description`, `--tags` |
+| `claude [name]` | Create or switch to a Claude session. `--path`, `--detach`, `--danger` |
+| `list` / `ls` | List sessions. `--tag`, `--search` |
+| `info ` | Detailed session info (windows, panes, metadata, stats) |
+| `attach ` | Attach interactively. Ctrl+B D to detach |
+| `kill ` | Terminate a session |
+| `send ` | Send text to a pane. `--pane`, `--no-enter` |
+| `capture ` | Capture pane output. `--lines`, `--all`, `--output` |
+| `monitor ` | Watch pane output live. `--pane`, `--interval` |
+| `relay ` | Relay between panes. `--from`, `--to`, `--message` or `--capture` |
+| `export ` | Export session to Markdown. `--output` |
+| `tag ` | Add tags. `-r` to remove |
| `describe ` | Set session description |
-| `stats [name]` | Session statistics (commands sent, duration) |
+| `stats [name]` | Session statistics |
+| `add-window ` | Add a window. `--command` |
+| `rename-window ` | Rename a window |
+| `web` | Start the web dashboard. `--port`, `--host` |
-## Project Structure
+The `relay` command enables inter-agent coordination. You can capture the output of one pane and pipe it as input to another — useful when one agent produces context that a second agent needs to act on. Use `--capture` to grab recent output from the source pane, or `--message` to send a literal string.
-```
-clux/
- packages/
- core/ # Session management, tmux wrapper, metadata store
- cli/ # Commander-based CLI (@clux-cli/cli)
- web/ # Express + WebSocket dashboard (@clux-cli/web)
+```bash
+clux relay my-session --from 0.0 --to 0.1 --capture 50
+clux relay my-session --from 0.0 --to 0.1 --message "refactor complete, review the diff"
```
-This is an npm workspaces monorepo. The `core` package is a shared dependency used by both `cli` and `web`.
+## Web Dashboard
-## Development
+Launch the dashboard with `clux web`. It runs at `http://127.0.0.1:3456` by default. For LAN access, bind to all interfaces with `--host 0.0.0.0`.
-```bash
-# Build everything
-npm run build
+The dashboard connects via WebSocket and renders live terminal output using xterm.js. The sidebar lists all active sessions with real-time status — sessions running Claude are detected automatically via process inspection and flagged with a distinct badge, no manual tagging required.
+
+From the browser you can create new sessions, switch between panes using tabs, send commands, relay messages between panes (with a preview of captured output before sending), export sessions to Markdown, and terminate sessions. The interface uses a dark theme built on Radix color tokens and is fully responsive, collapsing to a slide-in sidebar on mobile screens.
+
+Under the hood, the dashboard leverages tmux control mode for sub-16ms push latency when available, falling back to polling if control mode is not supported.
+
+## REST API
-# Build individual packages
-npm run build:core
-npm run build:cli
-npm run build:web
+The web server exposes a REST API for programmatic access and automation.
-# Run the web dashboard in dev mode
-npm run dev:web
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| GET | `/api/sessions` | List all sessions |
+| GET | `/api/sessions/:name` | Get session details |
+| POST | `/api/sessions` | Create session |
+| DELETE | `/api/sessions/:name` | Kill session |
+| POST | `/api/sessions/:name/send` | Send text to a pane |
+| GET | `/api/sessions/:name/capture/:paneId` | Capture pane output (`?lines=N`) |
+| GET | `/api/sessions/:name/export` | Export session as Markdown |
+| POST | `/api/sessions/:name/relay` | Relay between panes |
+| POST | `/api/sessions/:name/windows` | Add a window |
+| DELETE | `/api/sessions/:name/panes/:paneId` | Kill a pane |
+| PATCH | `/api/sessions/:name/windows/:index` | Rename a window |
+| GET | `/api/settings` | Server configuration |
-# Run tests
-npm test
-npm run test:watch
-npm run test:coverage
+Clients can also connect via WebSocket on the same host and port. Messages are JSON-encoded — use `subscribe` to stream live pane output, `send` to push text to a pane, and `input` to forward raw terminal keystrokes.
-# Lint and format
-npm run lint
-npm run lint:fix
-npm run format
-npm run format:check
+## Architecture
-# Clean build artifacts
-npm run clean
+The codebase is a single TypeScript package organized into three logical modules under `src/`: `core/` (tmux session management, SQLite metadata store, terminal parser, process detection), `cli/` (Commander-based commands), and `web/` (Express + WebSocket dashboard). TypeScript compiles to `dist/`, then esbuild bundles everything into a single `dist/index.js` for distribution. Session metadata is stored in SQLite at `~/.clux/sessions.db` with WAL mode enabled.
+
+## Configuration
+
+The web dashboard binds to `127.0.0.1:3456` by default. Override with CLI flags (`clux web --port 8080 --host 0.0.0.0`) or environment variables (`PORT`, `HOST`). All sessions are created with a 50,000-line scrollback buffer. Supported pane layouts: `tiled`, `even-horizontal`, `even-vertical`, `main-horizontal`, `main-vertical`.
+
+## Development
+
+For contributors working on clux itself:
+
+```bash
+git clone https://github.com/devhelp/clux.git && cd clux
+npm install
+npm run build # compile TypeScript + esbuild bundle
+npm run dev:web # compile and run web dashboard locally
+npm test # run tests (vitest)
+npm run test:coverage # tests with coverage
+npm run lint # eslint
+npm run format:check # prettier check
```
## License
diff --git a/esbuild.mjs b/esbuild.mjs
new file mode 100644
index 0000000..2106761
--- /dev/null
+++ b/esbuild.mjs
@@ -0,0 +1,22 @@
+import * as esbuild from 'esbuild';
+import path from 'path';
+import fs from 'fs';
+import { fileURLToPath } from 'url';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+await esbuild.build({
+ entryPoints: [path.join(__dirname, 'dist/index.js')],
+ bundle: true,
+ platform: 'node',
+ target: 'node18',
+ outfile: path.join(__dirname, 'dist/index.js'),
+ allowOverwrite: true,
+ external: ['better-sqlite3'],
+});
+
+fs.cpSync(
+ path.join(__dirname, 'public'),
+ path.join(__dirname, 'dist/public'),
+ { recursive: true },
+);
diff --git a/package-lock.json b/package-lock.json
index 92613f1..996dedf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,28 +1,37 @@
{
- "name": "clux",
- "version": "0.4.0",
+ "name": "@clux-cli/cli",
+ "version": "0.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "clux",
- "version": "0.4.0",
+ "name": "@clux-cli/cli",
+ "version": "0.5.0",
"license": "MIT",
- "workspaces": [
- "packages/core",
- "packages/cli",
- "packages/web"
- ],
"dependencies": {
- "@clux-cli/cli": "^0.3.0",
- "better-sqlite3": "^12.6.2"
+ "better-sqlite3": "^12.6.2",
+ "chalk": "^4.1.2",
+ "cli-table3": "^0.6.5",
+ "commander": "^13.0.0",
+ "express": "^4.21.0",
+ "ora": "^5.4.1",
+ "ws": "^8.18.0"
+ },
+ "bin": {
+ "clux": "dist/index.js"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
+ "@types/better-sqlite3": "^7.6.13",
+ "@types/express": "^5.0.0",
+ "@types/node": "^22.0.0",
+ "@types/ws": "^8.5.0",
"@vitest/coverage-v8": "^4.0.18",
+ "esbuild": "^0.27.4",
"eslint": "^10.0.2",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.1",
+ "typescript": "^5.7.0",
"typescript-eslint": "^8.56.1",
"vitest": "^4.0.18"
},
@@ -80,18 +89,6 @@
"node": ">=18"
}
},
- "node_modules/@clux-cli/cli": {
- "resolved": "packages/cli",
- "link": true
- },
- "node_modules/@clux-cli/core": {
- "resolved": "packages/core",
- "link": true
- },
- "node_modules/@clux-cli/web": {
- "resolved": "packages/web",
- "link": true
- },
"node_modules/@colors/colors": {
"version": "1.5.0",
"license": "MIT",
@@ -170,6 +167,8 @@
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
+ "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
"cpu": [
"arm64"
],
@@ -372,8 +371,6 @@
},
"node_modules/@esbuild/linux-x64": {
"version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz",
- "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==",
"cpu": [
"x64"
],
@@ -767,6 +764,8 @@
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
+ "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
"cpu": [
"arm64"
],
@@ -975,8 +974,6 @@
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
- "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
"cpu": [
"x64"
],
@@ -989,8 +986,6 @@
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
- "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
"cpu": [
"x64"
],
@@ -2528,7 +2523,10 @@
},
"node_modules/fsevents": {
"version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
+ "hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
@@ -4098,56 +4096,6 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
- },
- "packages/cli": {
- "name": "@clux-cli/cli",
- "version": "0.4.0",
- "license": "MIT",
- "dependencies": {
- "better-sqlite3": "^12.6.2",
- "chalk": "^4.1.2",
- "cli-table3": "^0.6.5",
- "commander": "^13.0.0",
- "express": "^4.21.0",
- "ora": "^5.4.1",
- "ws": "^8.18.0"
- },
- "bin": {
- "clux": "dist/index.js"
- },
- "devDependencies": {
- "@types/node": "^22.0.0",
- "esbuild": "^0.27.4",
- "typescript": "^5.7.0"
- }
- },
- "packages/core": {
- "name": "@clux-cli/core",
- "version": "0.4.0",
- "license": "MIT",
- "dependencies": {
- "better-sqlite3": "^12.6.2"
- },
- "devDependencies": {
- "@types/better-sqlite3": "^7.6.13",
- "typescript": "^5.7.0"
- }
- },
- "packages/web": {
- "name": "@clux-cli/web",
- "version": "0.4.0",
- "license": "MIT",
- "dependencies": {
- "@clux-cli/core": "*",
- "express": "^4.21.0",
- "ws": "^8.18.0"
- },
- "devDependencies": {
- "@types/express": "^5.0.0",
- "@types/node": "^22.0.0",
- "@types/ws": "^8.5.0",
- "typescript": "^5.7.0"
- }
}
}
}
diff --git a/package.json b/package.json
index e5bbd06..26e29d1 100644
--- a/package.json
+++ b/package.json
@@ -1,26 +1,28 @@
{
- "name": "clux",
+ "name": "@clux-cli/cli",
"version": "0.5.0",
- "private": true,
"license": "MIT",
"description": "Clux — tmux session multiplexer with web dashboard and CLI.",
- "workspaces": [
- "packages/core",
- "packages/cli",
- "packages/web"
+ "main": "dist/index.js",
+ "bin": {
+ "clux": "dist/index.js"
+ },
+ "files": [
+ "dist"
],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/devhelp/clux.git"
+ },
"scripts": {
- "build": "npm run build:core && npm run build:web && npm run build:cli",
- "build:core": "npm run build -w packages/core",
- "build:cli": "npm run build -w packages/cli",
- "build:web": "npm run build -w packages/web",
- "dev:web": "npm run dev -w packages/web",
- "cli": "node packages/cli/dist/index.js",
- "clean": "rm -rf packages/*/dist",
- "lint": "eslint 'packages/*/src/**/*.ts'",
- "lint:fix": "eslint 'packages/*/src/**/*.ts' --fix",
- "format": "prettier --write 'packages/*/src/**/*.ts'",
- "format:check": "prettier --check 'packages/*/src/**/*.ts'",
+ "build": "tsc && node esbuild.mjs",
+ "dev:web": "tsc && cp -r public dist/web/public && node dist/web/server.js",
+ "cli": "node dist/index.js",
+ "clean": "rm -rf dist",
+ "lint": "eslint 'src/**/*.ts'",
+ "lint:fix": "eslint 'src/**/*.ts' --fix",
+ "format": "prettier --write 'src/**/*.ts'",
+ "format:check": "prettier --check 'src/**/*.ts'",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
@@ -29,15 +31,26 @@
"node": ">=18.0.0"
},
"dependencies": {
- "@clux-cli/cli": "^0.3.0",
- "better-sqlite3": "^12.6.2"
+ "better-sqlite3": "^12.6.2",
+ "commander": "^13.0.0",
+ "chalk": "^4.1.2",
+ "cli-table3": "^0.6.5",
+ "ora": "^5.4.1",
+ "express": "^4.21.0",
+ "ws": "^8.18.0"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
+ "@types/better-sqlite3": "^7.6.13",
+ "@types/express": "^5.0.0",
+ "@types/node": "^22.0.0",
+ "@types/ws": "^8.5.0",
"@vitest/coverage-v8": "^4.0.18",
+ "esbuild": "^0.27.4",
"eslint": "^10.0.2",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.1",
+ "typescript": "^5.7.0",
"typescript-eslint": "^8.56.1",
"vitest": "^4.0.18"
}
diff --git a/packages/cli/esbuild.mjs b/packages/cli/esbuild.mjs
deleted file mode 100644
index 2f460d3..0000000
--- a/packages/cli/esbuild.mjs
+++ /dev/null
@@ -1,39 +0,0 @@
-import * as esbuild from 'esbuild';
-import path from 'path';
-import fs from 'fs';
-import { fileURLToPath } from 'url';
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-
-const workspaceResolve = {
- name: 'workspace-resolve',
- setup(build) {
- build.onResolve({ filter: /^@clux-cli\// }, (args) => {
- if (args.path === '@clux-cli/core') {
- return { path: path.resolve(__dirname, '../core/dist/index.js') };
- }
- if (
- args.path === '@clux-cli/web' ||
- args.path === '@clux-cli/web/dist/server'
- ) {
- return { path: path.resolve(__dirname, '../web/dist/server.js') };
- }
- });
- },
-};
-
-await esbuild.build({
- entryPoints: [path.join(__dirname, 'dist/index.js')],
- bundle: true,
- platform: 'node',
- target: 'node18',
- outfile: path.join(__dirname, 'dist/index.js'),
- allowOverwrite: true,
- external: ['better-sqlite3'],
- plugins: [workspaceResolve],
-});
-
-// Copy web public assets into CLI dist so they're available at runtime
-const srcPublic = path.resolve(__dirname, '../web/dist/public');
-const destPublic = path.resolve(__dirname, 'dist/public');
-fs.cpSync(srcPublic, destPublic, { recursive: true });
diff --git a/packages/cli/package.json b/packages/cli/package.json
deleted file mode 100644
index 2526ce1..0000000
--- a/packages/cli/package.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "name": "@clux-cli/cli",
- "version": "0.5.0",
- "license": "MIT",
- "main": "dist/index.js",
- "bin": {
- "clux": "dist/index.js"
- },
- "files": [
- "dist"
- ],
- "repository": {
- "type": "git",
- "url": "https://github.com/michalsikora/clux.git",
- "directory": "packages/cli"
- },
- "scripts": {
- "build": "tsc && node esbuild.mjs",
- "watch": "tsc --watch",
- "start": "node dist/index.js"
- },
- "dependencies": {
- "better-sqlite3": "^12.6.2",
- "commander": "^13.0.0",
- "chalk": "^4.1.2",
- "cli-table3": "^0.6.5",
- "ora": "^5.4.1",
- "express": "^4.21.0",
- "ws": "^8.18.0"
- },
- "devDependencies": {
- "@types/node": "^22.0.0",
- "esbuild": "^0.27.4",
- "typescript": "^5.7.0"
- }
-}
diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json
deleted file mode 100644
index 8f24167..0000000
--- a/packages/cli/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": "../../tsconfig.base.json",
- "compilerOptions": {
- "outDir": "./dist",
- "rootDir": "./src"
- },
- "include": ["src/**/*"]
-}
diff --git a/packages/core/package.json b/packages/core/package.json
deleted file mode 100644
index 3dcec55..0000000
--- a/packages/core/package.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "@clux-cli/core",
- "version": "0.5.0",
- "private": true,
- "license": "MIT",
- "main": "dist/index.js",
- "types": "dist/index.d.ts",
- "files": ["dist"],
- "repository": {
- "type": "git",
- "url": "https://github.com/michalsikora/clux.git",
- "directory": "packages/core"
- },
- "scripts": {
- "build": "tsc",
- "watch": "tsc --watch"
- },
- "devDependencies": {
- "@types/better-sqlite3": "^7.6.13",
- "typescript": "^5.7.0"
- },
- "dependencies": {
- "better-sqlite3": "^12.6.2"
- }
-}
diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json
deleted file mode 100644
index 8f24167..0000000
--- a/packages/core/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": "../../tsconfig.base.json",
- "compilerOptions": {
- "outDir": "./dist",
- "rootDir": "./src"
- },
- "include": ["src/**/*"]
-}
diff --git a/packages/web/package.json b/packages/web/package.json
deleted file mode 100644
index ad66289..0000000
--- a/packages/web/package.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "name": "@clux-cli/web",
- "version": "0.5.0",
- "private": true,
- "license": "MIT",
- "main": "dist/server.js",
- "files": ["dist"],
- "repository": {
- "type": "git",
- "url": "https://github.com/michalsikora/clux.git",
- "directory": "packages/web"
- },
- "scripts": {
- "build": "tsc && cp -r public dist/public",
- "dev": "node dist/server.js",
- "watch": "tsc --watch"
- },
- "dependencies": {
- "@clux-cli/core": "*",
- "express": "^4.21.0",
- "ws": "^8.18.0"
- },
- "devDependencies": {
- "typescript": "^5.7.0",
- "@types/node": "^22.0.0",
- "@types/express": "^5.0.0",
- "@types/ws": "^8.5.0"
- }
-}
diff --git a/packages/web/tsconfig.json b/packages/web/tsconfig.json
deleted file mode 100644
index 8f24167..0000000
--- a/packages/web/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": "../../tsconfig.base.json",
- "compilerOptions": {
- "outDir": "./dist",
- "rootDir": "./src"
- },
- "include": ["src/**/*"]
-}
diff --git a/packages/web/public/index.html b/public/index.html
similarity index 100%
rename from packages/web/public/index.html
rename to public/index.html
diff --git a/packages/web/public/logo.svg b/public/logo.svg
similarity index 100%
rename from packages/web/public/logo.svg
rename to public/logo.svg
diff --git a/packages/cli/src/commands/claude.test.ts b/src/cli/commands/claude.test.ts
similarity index 100%
rename from packages/cli/src/commands/claude.test.ts
rename to src/cli/commands/claude.test.ts
diff --git a/packages/cli/src/commands/claude.ts b/src/cli/commands/claude.ts
similarity index 98%
rename from packages/cli/src/commands/claude.ts
rename to src/cli/commands/claude.ts
index 7697700..ddfe51e 100644
--- a/packages/cli/src/commands/claude.ts
+++ b/src/cli/commands/claude.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
import ora from 'ora';
import { spawn, spawnSync } from 'child_process';
diff --git a/packages/cli/src/commands/create.ts b/src/cli/commands/create.ts
similarity index 96%
rename from packages/cli/src/commands/create.ts
rename to src/cli/commands/create.ts
index b2e29bd..5e97043 100644
--- a/packages/cli/src/commands/create.ts
+++ b/src/cli/commands/create.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
import ora from 'ora';
import { printSessionDetails } from '../format';
diff --git a/packages/cli/src/commands/info.ts b/src/cli/commands/info.ts
similarity index 96%
rename from packages/cli/src/commands/info.ts
rename to src/cli/commands/info.ts
index b2b55e7..761b858 100644
--- a/packages/cli/src/commands/info.ts
+++ b/src/cli/commands/info.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
import { printSessionDetails } from '../format';
diff --git a/packages/cli/src/commands/list.ts b/src/cli/commands/list.ts
similarity index 97%
rename from packages/cli/src/commands/list.ts
rename to src/cli/commands/list.ts
index 27b1875..58557c7 100644
--- a/packages/cli/src/commands/list.ts
+++ b/src/cli/commands/list.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
import Table from 'cli-table3';
import { formatRelativeTime } from '../format';
diff --git a/packages/cli/src/commands/relay.ts b/src/cli/commands/relay.ts
similarity index 96%
rename from packages/cli/src/commands/relay.ts
rename to src/cli/commands/relay.ts
index 3ce62d0..7cccc22 100644
--- a/packages/cli/src/commands/relay.ts
+++ b/src/cli/commands/relay.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
export function registerRelayCommand(program: Command, manager: TmuxSessionManager): void {
diff --git a/packages/cli/src/commands/session.ts b/src/cli/commands/session.ts
similarity index 99%
rename from packages/cli/src/commands/session.ts
rename to src/cli/commands/session.ts
index d3f00c6..e6d93c0 100644
--- a/packages/cli/src/commands/session.ts
+++ b/src/cli/commands/session.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
import { printSessionDetails } from '../format';
diff --git a/packages/cli/src/commands/stats.ts b/src/cli/commands/stats.ts
similarity index 96%
rename from packages/cli/src/commands/stats.ts
rename to src/cli/commands/stats.ts
index 9ecb2a3..e2288ca 100644
--- a/packages/cli/src/commands/stats.ts
+++ b/src/cli/commands/stats.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
import chalk from 'chalk';
import Table from 'cli-table3';
import { formatRelativeTime } from '../format';
diff --git a/packages/cli/src/commands/web.ts b/src/cli/commands/web.ts
similarity index 81%
rename from packages/cli/src/commands/web.ts
rename to src/cli/commands/web.ts
index a3b2909..791fd86 100644
--- a/packages/cli/src/commands/web.ts
+++ b/src/cli/commands/web.ts
@@ -1,5 +1,5 @@
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
export function registerWebCommand(program: Command, _manager: TmuxSessionManager) {
program
@@ -10,6 +10,6 @@ export function registerWebCommand(program: Command, _manager: TmuxSessionManage
.action((opts) => {
process.env.PORT = opts.port;
process.env.HOST = opts.host;
- require('@clux-cli/web/dist/server');
+ require('../../web/server');
});
}
diff --git a/packages/cli/src/format.test.ts b/src/cli/format.test.ts
similarity index 100%
rename from packages/cli/src/format.test.ts
rename to src/cli/format.test.ts
diff --git a/packages/cli/src/format.ts b/src/cli/format.ts
similarity index 95%
rename from packages/cli/src/format.ts
rename to src/cli/format.ts
index 24836d7..5736a22 100644
--- a/packages/cli/src/format.ts
+++ b/src/cli/format.ts
@@ -1,5 +1,5 @@
import chalk from 'chalk';
-import type { TmuxSession } from '@clux-cli/core';
+import type { TmuxSession } from '../core';
export function printSessionDetails(session: TmuxSession): void {
console.log(`\n ${chalk.bold(session.name)}`);
diff --git a/packages/core/src/ProcessDetector.ts b/src/core/ProcessDetector.ts
similarity index 100%
rename from packages/core/src/ProcessDetector.ts
rename to src/core/ProcessDetector.ts
diff --git a/packages/core/src/SessionStore.test.ts b/src/core/SessionStore.test.ts
similarity index 100%
rename from packages/core/src/SessionStore.test.ts
rename to src/core/SessionStore.test.ts
diff --git a/packages/core/src/SessionStore.ts b/src/core/SessionStore.ts
similarity index 100%
rename from packages/core/src/SessionStore.ts
rename to src/core/SessionStore.ts
diff --git a/packages/core/src/TerminalParser.test.ts b/src/core/TerminalParser.test.ts
similarity index 100%
rename from packages/core/src/TerminalParser.test.ts
rename to src/core/TerminalParser.test.ts
diff --git a/packages/core/src/TerminalParser.ts b/src/core/TerminalParser.ts
similarity index 100%
rename from packages/core/src/TerminalParser.ts
rename to src/core/TerminalParser.ts
diff --git a/packages/core/src/TmuxControlClient.ts b/src/core/TmuxControlClient.ts
similarity index 100%
rename from packages/core/src/TmuxControlClient.ts
rename to src/core/TmuxControlClient.ts
diff --git a/packages/core/src/TmuxSessionManager.ts b/src/core/TmuxSessionManager.ts
similarity index 100%
rename from packages/core/src/TmuxSessionManager.ts
rename to src/core/TmuxSessionManager.ts
diff --git a/packages/core/src/index.ts b/src/core/index.ts
similarity index 100%
rename from packages/core/src/index.ts
rename to src/core/index.ts
diff --git a/packages/core/src/types.ts b/src/core/types.ts
similarity index 100%
rename from packages/core/src/types.ts
rename to src/core/types.ts
diff --git a/packages/cli/src/index.ts b/src/index.ts
similarity index 65%
rename from packages/cli/src/index.ts
rename to src/index.ts
index 3a88af3..e82b9d8 100644
--- a/packages/cli/src/index.ts
+++ b/src/index.ts
@@ -1,10 +1,11 @@
#!/usr/bin/env node
import { Command } from 'commander';
-import { TmuxSessionManager } from '@clux-cli/core';
-import { registerCreateCommand } from './commands/create';
-import { registerListCommand } from './commands/list';
-import { registerInfoCommand } from './commands/info';
+import { TmuxSessionManager } from './core';
+import pkg from '../package.json';
+import { registerCreateCommand } from './cli/commands/create';
+import { registerListCommand } from './cli/commands/list';
+import { registerInfoCommand } from './cli/commands/info';
import {
registerTagCommand,
registerDescribeCommand,
@@ -15,16 +16,16 @@ import {
registerExportCommand,
registerMonitorCommand,
registerWindowCommands,
-} from './commands/session';
-import { registerRelayCommand } from './commands/relay';
-import { registerStatsCommand } from './commands/stats';
-import { registerClaudeCommand } from './commands/claude';
-import { registerWebCommand } from './commands/web';
+} from './cli/commands/session';
+import { registerRelayCommand } from './cli/commands/relay';
+import { registerStatsCommand } from './cli/commands/stats';
+import { registerClaudeCommand } from './cli/commands/claude';
+import { registerWebCommand } from './cli/commands/web';
const manager = new TmuxSessionManager();
const program = new Command();
-program.name('clux').description('Clux — tmux session multiplexer').version('0.4.0');
+program.name('clux').description('Clux — tmux session multiplexer').version(pkg.version);
registerCreateCommand(program, manager);
registerListCommand(program, manager);
diff --git a/packages/web/src/routes/sessions.ts b/src/web/routes/sessions.ts
similarity index 98%
rename from packages/web/src/routes/sessions.ts
rename to src/web/routes/sessions.ts
index bf8a61f..d1ff124 100644
--- a/packages/web/src/routes/sessions.ts
+++ b/src/web/routes/sessions.ts
@@ -1,5 +1,5 @@
import { Router } from 'express';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
export function createSessionRoutes(manager: TmuxSessionManager): Router {
const router = Router();
diff --git a/packages/web/src/routes/settings.ts b/src/web/routes/settings.ts
similarity index 100%
rename from packages/web/src/routes/settings.ts
rename to src/web/routes/settings.ts
diff --git a/packages/web/src/server.ts b/src/web/server.ts
similarity index 93%
rename from packages/web/src/server.ts
rename to src/web/server.ts
index b252850..f933f18 100644
--- a/packages/web/src/server.ts
+++ b/src/web/server.ts
@@ -1,7 +1,7 @@
import express from 'express';
import http from 'http';
import path from 'path';
-import { TmuxSessionManager } from '@clux-cli/core';
+import { TmuxSessionManager } from '../core';
import { createSessionRoutes } from './routes/sessions';
import { createSettingsRoutes } from './routes/settings';
import { setupWebSocket } from './websocket/handler';
diff --git a/packages/web/src/websocket/handler.ts b/src/web/websocket/handler.ts
similarity index 98%
rename from packages/web/src/websocket/handler.ts
rename to src/web/websocket/handler.ts
index 910f741..a74f75b 100644
--- a/packages/web/src/websocket/handler.ts
+++ b/src/web/websocket/handler.ts
@@ -1,7 +1,7 @@
import { WebSocketServer, WebSocket } from 'ws';
import type { Server } from 'http';
-import { TmuxSessionManager } from '@clux-cli/core';
-import type { PaneOutputEvent, TmuxControlClient } from '@clux-cli/core';
+import { TmuxSessionManager } from '../../core';
+import type { PaneOutputEvent, TmuxControlClient } from '../../core';
const subscribers = new Map>();
const sessionMode = new Map();
diff --git a/tsconfig.base.json b/tsconfig.json
similarity index 93%
rename from tsconfig.base.json
rename to tsconfig.json
index 2ad8e2e..b51d085 100644
--- a/tsconfig.base.json
+++ b/tsconfig.json
@@ -13,5 +13,6 @@
"rootDir": "./src",
"sourceMap": true
},
+ "include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
diff --git a/vitest.config.ts b/vitest.config.ts
index 5c7aa29..51d7a09 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -4,11 +4,11 @@ export default defineConfig({
test: {
globals: true,
environment: 'node',
- include: ['packages/*/src/**/*.test.ts'],
+ include: ['src/**/*.test.ts'],
coverage: {
provider: 'v8',
- include: ['packages/*/src/**/*.ts'],
- exclude: ['packages/*/src/**/*.test.ts', 'packages/web/src/server.ts'],
+ include: ['src/**/*.ts'],
+ exclude: ['src/**/*.test.ts', 'src/web/server.ts'],
},
},
});