@mmmbuto/nexuscrew 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -94
- package/bin/nexuscrew.js +28 -11
- package/frontend/dist/assets/{index-BsldfYnr.js → index-CSPyKzmq.js} +46 -46
- package/frontend/dist/assets/{index-DcQGg3dp.css → index-Cl7bxc7X.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/lib/config/paths.js +30 -0
- package/lib/server/routes/hosts.js +16 -13
- package/lib/server/routes/launchers.js +6 -1
- package/lib/server/routes/models.js +7 -3
- package/lib/server/routes/runtime.js +5 -1
- package/lib/server/routes/send.js +72 -16
- package/lib/server/routes/status.js +10 -6
- package/lib/server/routes/tmux.js +8 -5
- package/lib/server/server.js +12 -8
- package/lib/services/engine-discovery.js +99 -34
- package/lib/services/tmux-manager.js +85 -2
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -1,72 +1,73 @@
|
|
|
1
|
-
|
|
1
|
+
# NexusCrew
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.org/package/@mmmbuto/nexuscrew)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
NexusCrew is a tmux-first AI cockpit for Claude Code, Codex CLI, Gemini CLI, and Qwen Code.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
> **Disclaimer**: This project is experimental. The automation pipeline is fast enough that it may be generated, tested, and published before I finish thinking about it. Expect incomplete features, mistakes, and breaking changes.
|
|
7
|
+
It is built around one core rule: chat targets real tmux sessions that already exist, or new tmux sessions that are created explicitly from launchers detected on the current machine.
|
|
10
8
|
|
|
11
9
|
---
|
|
12
10
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
| Problem | NexusCLI (PTY) | NexusCrew (tmux) |
|
|
16
|
-
|---------|---------------|-------------------|
|
|
17
|
-
| Server crash | All sessions die | Sessions survive |
|
|
18
|
-
| Direct access | Web UI only | Web UI + `tmux attach` |
|
|
19
|
-
| Remote machines | Not supported | Experimental host registry |
|
|
20
|
-
| Native deps | node-pty required | SQLite native addon |
|
|
21
|
-
| Session recovery | Manual | Automatic |
|
|
11
|
+
## About
|
|
22
12
|
|
|
23
|
-
|
|
13
|
+
- Runtime model: active tmux sessions + explicit tmux creation
|
|
14
|
+
- Launcher discovery: runtime-driven, shell-agnostic, user-agnostic
|
|
15
|
+
- Primary verified environment: Termux on Android
|
|
16
|
+
- Linux/macOS: supported by design, not yet fully revalidated in the current cycle
|
|
17
|
+
- Remote hosts: registry and connectivity exist, but end-to-end remote session flow is still experimental
|
|
24
18
|
|
|
25
|
-
##
|
|
19
|
+
## Project Scope
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
- **Multi-engine** — Claude Code, Codex CLI, Gemini CLI, Qwen Code
|
|
29
|
-
- **Auto-discovery** — detects installed CLIs plus live shell aliases/functions and generic shell config fallbacks
|
|
30
|
-
- **Explicit tmux creation** — create a new tmux session only from a detected runnable launcher
|
|
31
|
-
- **Unified web UI** — attach chat to real active tmux sessions
|
|
32
|
-
- **SSE streaming** — real-time output from tmux sessions
|
|
33
|
-
- **Cross-platform** — Linux, macOS, Termux (Android)
|
|
21
|
+
### What It Does
|
|
34
22
|
|
|
35
|
-
|
|
23
|
+
- Lists real active tmux sessions on the host
|
|
24
|
+
- Lets the UI attach chat to an existing tmux session
|
|
25
|
+
- Detects runnable launchers from:
|
|
26
|
+
- PATH binaries
|
|
27
|
+
- live shell aliases/functions
|
|
28
|
+
- generic shell config fallbacks
|
|
29
|
+
- Creates a new standalone tmux session only when you explicitly ask for it
|
|
30
|
+
- Stores conversation state locally in SQLite
|
|
31
|
+
- Streams output back through SSE
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
### What It Does Not Do
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
- It does not create hidden tmux master sessions
|
|
36
|
+
- It does not keep a hardcoded list of AI models or wrappers
|
|
37
|
+
- It does not assume a user-specific home like `/home/dag`
|
|
38
|
+
- It does not treat shell-file-only detections as runnable unless the active shell confirms them
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
2. **Live shell wrappers** — aliases/functions available in the current login shell
|
|
43
|
-
3. **Shell-file fallbacks** — wrappers detected from `.zshrc`, `.bashrc`, `.profile`, and optional extra shell sources
|
|
40
|
+
---
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
## Installation
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
### Quick Start
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
Install:
|
|
50
47
|
|
|
51
48
|
```bash
|
|
52
49
|
npm install -g @mmmbuto/nexuscrew
|
|
53
50
|
```
|
|
54
51
|
|
|
55
|
-
|
|
52
|
+
Initialize local config:
|
|
56
53
|
|
|
57
54
|
```bash
|
|
58
55
|
nexuscrew init
|
|
59
56
|
```
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
Start the server:
|
|
62
59
|
|
|
63
60
|
```bash
|
|
64
61
|
nexuscrew start
|
|
65
62
|
```
|
|
66
63
|
|
|
67
|
-
Open
|
|
64
|
+
Open:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
http://localhost:41820
|
|
68
|
+
```
|
|
68
69
|
|
|
69
|
-
### Termux
|
|
70
|
+
### Termux Quick Start
|
|
70
71
|
|
|
71
72
|
```bash
|
|
72
73
|
pkg install tmux nodejs
|
|
@@ -75,103 +76,126 @@ nexuscrew init
|
|
|
75
76
|
nexuscrew start
|
|
76
77
|
```
|
|
77
78
|
|
|
79
|
+
Notes:
|
|
80
|
+
|
|
81
|
+
- the package uses a Termux-compatible SQLite dependency path during install
|
|
82
|
+
- detailed install notes live in [docs/INSTALLATION.md](docs/INSTALLATION.md)
|
|
83
|
+
|
|
78
84
|
---
|
|
79
85
|
|
|
80
|
-
##
|
|
86
|
+
## Runtime Model
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
NexusCrew now works with standalone tmux sessions.
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
nexuscrew hosts add --name vps1 --host example.com --user user
|
|
86
|
-
nexuscrew hosts add --name vps2 --host 192.168.1.10 --user admin --port 2222
|
|
87
|
-
```
|
|
90
|
+
That means:
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
- one AI runtime = one tmux session
|
|
93
|
+
- chat sends to an existing tmux session
|
|
94
|
+
- new tmux sessions are created explicitly from a detected launcher
|
|
95
|
+
- session output is piped to log files and watched by the server
|
|
96
|
+
|
|
97
|
+
Architecture:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
Browser <--SSE--> Express server <--tmux--> active tmux sessions
|
|
101
|
+
|- claude-work
|
|
102
|
+
|- codex-debug
|
|
103
|
+
`- qwen-sandbox
|
|
104
|
+
```
|
|
90
105
|
|
|
91
106
|
---
|
|
92
107
|
|
|
93
|
-
##
|
|
108
|
+
## Launcher Discovery
|
|
94
109
|
|
|
95
|
-
|
|
96
|
-
|---------|-------------|
|
|
97
|
-
| `nexuscrew init` | First-time setup (config, hosts, tmux check) |
|
|
98
|
-
| `nexuscrew start` | Start server |
|
|
99
|
-
| `nexuscrew stop` | Stop server |
|
|
100
|
-
| `nexuscrew status` | Server + tmux + hosts status |
|
|
101
|
-
| `nexuscrew engines` | Discover available AI CLIs and aliases |
|
|
102
|
-
| `nexuscrew sessions` | List tmux sessions |
|
|
103
|
-
| `nexuscrew attach` | Attach to tmux session directly |
|
|
104
|
-
| `nexuscrew config` | View/edit configuration |
|
|
105
|
-
| `nexuscrew hosts list` | List configured hosts |
|
|
106
|
-
| `nexuscrew hosts add` | Add remote SSH host |
|
|
107
|
-
| `nexuscrew hosts remove` | Remove a host |
|
|
110
|
+
Discovery is environment-agnostic and shell-agnostic.
|
|
108
111
|
|
|
109
|
-
|
|
112
|
+
Sources, in order:
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
1. live shell introspection
|
|
115
|
+
2. generic shell files such as `.zshrc`, `.bashrc`, `.profile`
|
|
116
|
+
3. PATH binaries
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
Detection families are inferred from what is actually present, not from a static product catalog.
|
|
114
119
|
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
"port": 41820,
|
|
118
|
-
"logDir": "~/.nexuscrew/logs",
|
|
119
|
-
"autoDiscovery": true,
|
|
120
|
-
"preferredShell": "",
|
|
121
|
-
"extraShellSources": []
|
|
122
|
-
}
|
|
123
|
-
```
|
|
120
|
+
Current launcher families:
|
|
124
121
|
|
|
125
|
-
|
|
122
|
+
- `claude`
|
|
123
|
+
- `codex`
|
|
124
|
+
- `gemini`
|
|
125
|
+
- `qwen`
|
|
126
|
+
- `custom`
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
]
|
|
132
|
-
```
|
|
128
|
+
Important distinction:
|
|
129
|
+
|
|
130
|
+
- `runnable: true` means the launcher is valid for explicit tmux creation now
|
|
131
|
+
- `runnable: false` means it was detected from shell config metadata only
|
|
133
132
|
|
|
134
133
|
---
|
|
135
134
|
|
|
136
|
-
##
|
|
135
|
+
## Commands
|
|
137
136
|
|
|
138
|
-
|
|
|
139
|
-
|
|
140
|
-
|
|
|
137
|
+
| Command | Description |
|
|
138
|
+
|---------|-------------|
|
|
139
|
+
| `nexuscrew init` | Create config, hosts file, and logs directory |
|
|
140
|
+
| `nexuscrew start` | Start the web server |
|
|
141
|
+
| `nexuscrew stop` | Stop the server |
|
|
142
|
+
| `nexuscrew status` | Show server, tmux, and host status |
|
|
143
|
+
| `nexuscrew sessions` | List active tmux sessions |
|
|
144
|
+
| `nexuscrew attach -s <name>` | Attach to a tmux session directly |
|
|
145
|
+
| `nexuscrew engines` | Print discovered launchers |
|
|
146
|
+
| `nexuscrew config --list` | Show config |
|
|
147
|
+
| `nexuscrew config --set key=value` | Update config |
|
|
148
|
+
| `nexuscrew hosts list` | List stored hosts |
|
|
149
|
+
| `nexuscrew hosts add ...` | Add an SSH host entry |
|
|
150
|
+
| `nexuscrew hosts remove ...` | Remove an SSH host entry |
|
|
141
151
|
|
|
142
152
|
---
|
|
143
153
|
|
|
144
|
-
##
|
|
154
|
+
## Documentation
|
|
145
155
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
- [Installation Guide](docs/INSTALLATION.md)
|
|
157
|
+
- [Configuration Guide](docs/CONFIGURATION.md)
|
|
158
|
+
- [Current State](docs/CURRENT_STATE.md)
|
|
159
|
+
- [Changelog](CHANGELOG.md)
|
|
160
|
+
|
|
161
|
+
---
|
|
152
162
|
|
|
153
|
-
|
|
163
|
+
## Support Matrix
|
|
164
|
+
|
|
165
|
+
| Area | State |
|
|
166
|
+
|------|----------------|
|
|
167
|
+
| Local tmux session listing | Verified |
|
|
168
|
+
| Explicit local tmux creation | Verified |
|
|
169
|
+
| Runtime launcher discovery | Verified |
|
|
170
|
+
| Bucketed launcher discovery | Verified |
|
|
171
|
+
| Shell-file-only launcher gating | Verified |
|
|
172
|
+
| Host-scoped tmux/session selection | Implemented |
|
|
173
|
+
| SSE send flow | Improved, basic smoke tested |
|
|
174
|
+
| Interrupt flow | Improved, not deeply stress-tested |
|
|
175
|
+
| Remote host registry | Present |
|
|
176
|
+
| Remote host execution | Implemented, pending live smoke |
|
|
154
177
|
|
|
155
178
|
---
|
|
156
179
|
|
|
157
180
|
## Development
|
|
158
181
|
|
|
159
182
|
```bash
|
|
160
|
-
git clone https://github.com/
|
|
183
|
+
git clone https://github.com/DioNanos/nexuscrew
|
|
161
184
|
cd nexuscrew
|
|
162
185
|
npm install
|
|
163
|
-
|
|
186
|
+
npm run build
|
|
164
187
|
npm run dev
|
|
165
188
|
```
|
|
166
189
|
|
|
167
190
|
---
|
|
168
191
|
|
|
169
|
-
##
|
|
192
|
+
## Known Gaps
|
|
170
193
|
|
|
171
|
-
|
|
194
|
+
- remote tmux workflows still need live multi-host smoke before being advertised as stable
|
|
195
|
+
- send/interrupt should still be stress-tested against long-running CLI pauses
|
|
172
196
|
|
|
173
197
|
---
|
|
174
198
|
|
|
175
199
|
## License
|
|
176
200
|
|
|
177
|
-
MIT
|
|
201
|
+
MIT. See `LICENSE`.
|
package/bin/nexuscrew.js
CHANGED
|
@@ -8,11 +8,13 @@ const os = require('os');
|
|
|
8
8
|
const { execSync, spawn } = require('child_process');
|
|
9
9
|
|
|
10
10
|
const EngineDiscovery = require('../lib/services/engine-discovery');
|
|
11
|
+
const TmuxManager = require('../lib/services/tmux-manager');
|
|
12
|
+
const { getConfigDir, getConfigPath, getHostsPath, getDefaultLogDir } = require('../lib/config/paths');
|
|
11
13
|
const packageJson = require('../package.json');
|
|
12
14
|
|
|
13
|
-
const CONFIG_DIR =
|
|
14
|
-
const CONFIG_PATH =
|
|
15
|
-
const HOSTS_PATH =
|
|
15
|
+
const CONFIG_DIR = getConfigDir();
|
|
16
|
+
const CONFIG_PATH = getConfigPath();
|
|
17
|
+
const HOSTS_PATH = getHostsPath();
|
|
16
18
|
|
|
17
19
|
const DEFAULT_PORT = '41820';
|
|
18
20
|
|
|
@@ -41,7 +43,7 @@ program.command('init')
|
|
|
41
43
|
if (!fs.existsSync(CONFIG_PATH)) {
|
|
42
44
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify({
|
|
43
45
|
port: Number(DEFAULT_PORT),
|
|
44
|
-
logDir:
|
|
46
|
+
logDir: getDefaultLogDir(),
|
|
45
47
|
autoDiscovery: true,
|
|
46
48
|
preferredShell: '',
|
|
47
49
|
extraShellSources: []
|
|
@@ -56,7 +58,7 @@ program.command('init')
|
|
|
56
58
|
log('Created hosts.json');
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
const logDir =
|
|
61
|
+
const logDir = getDefaultLogDir();
|
|
60
62
|
if (!fs.existsSync(logDir)) {
|
|
61
63
|
fs.mkdirSync(logDir, { recursive: true });
|
|
62
64
|
}
|
|
@@ -241,13 +243,28 @@ hostsCmd.command('remove')
|
|
|
241
243
|
|
|
242
244
|
program.command('engines')
|
|
243
245
|
.description('Discover available launchers')
|
|
244
|
-
.
|
|
245
|
-
|
|
246
|
+
.option('-H, --host <name>', 'Host name', 'local')
|
|
247
|
+
.action((opts) => {
|
|
248
|
+
const config = readConfig();
|
|
249
|
+
const hosts = fs.existsSync(HOSTS_PATH)
|
|
250
|
+
? JSON.parse(fs.readFileSync(HOSTS_PATH, 'utf8'))
|
|
251
|
+
: [{ name: 'local', type: 'local', default: true }];
|
|
252
|
+
const tmux = new TmuxManager({
|
|
253
|
+
configDir: CONFIG_DIR,
|
|
254
|
+
logDir: config.logDir || getDefaultLogDir(),
|
|
255
|
+
preferredShell: config.preferredShell || process.env.SHELL || '/bin/sh',
|
|
256
|
+
hosts
|
|
257
|
+
});
|
|
258
|
+
const launchers = new EngineDiscovery({ ...config, tmux }).discover(opts.host || 'local');
|
|
246
259
|
console.log('\nDiscovered Launchers:\n');
|
|
247
|
-
for (const
|
|
248
|
-
|
|
249
|
-
console.log(`
|
|
250
|
-
|
|
260
|
+
for (const [bucket, items] of Object.entries(launchers.buckets)) {
|
|
261
|
+
if (items.length === 0) continue;
|
|
262
|
+
console.log(` ${bucket}:`);
|
|
263
|
+
for (const launcher of items) {
|
|
264
|
+
console.log(` ${launcher.label}: ${launcher.kind} [${launcher.family}]${launcher.runnable ? '' : ' (detected only)'}`);
|
|
265
|
+
console.log(` command: ${launcher.commandPreview}`);
|
|
266
|
+
console.log(` source: ${launcher.source}`);
|
|
267
|
+
}
|
|
251
268
|
}
|
|
252
269
|
console.log('');
|
|
253
270
|
});
|