@mmmbuto/nexuscli 0.9.10 → 0.9.12
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/CHANGELOG.md +80 -0
- package/README.md +19 -37
- package/lib/server/lib/getPty.js +4 -1
- package/lib/server/lib/pty-adapter.js +5 -4
- package/lib/server/lib/pty-provider.js +10 -3
- package/lib/server/lib/pty-utils-loader.js +136 -0
- package/lib/setup/postinstall-pty-check.js +183 -0
- package/lib/setup/postinstall.js +11 -1
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.9.12] - 2026-01-09
|
|
6
|
+
### Fixed
|
|
7
|
+
- Guard PTY utils loading to avoid hard crash when dependency is broken or missing
|
|
8
|
+
- Safer fallback adapter when native PTY stack is unavailable
|
|
9
|
+
- Updated @mmmbuto/pty-termux-utils to ^1.1.3
|
|
10
|
+
|
|
11
|
+
## [0.9.11] - 2026-01-09
|
|
12
|
+
### Fixed
|
|
13
|
+
- Added PTY dependency verification in postinstall
|
|
14
|
+
- Added platform-specific PTY provider installation
|
|
15
|
+
- Added @mmmbuto/pty-termux-utils installation check
|
|
16
|
+
- All PTY dependencies now verified during npm install
|
|
17
|
+
- Updated @mmmbuto/pty-termux-utils to ^1.1.2
|
|
18
|
+
|
|
19
|
+
## [0.9.10] - 2026-01-09
|
|
20
|
+
### Fixed
|
|
21
|
+
- Added PTY dependency check in postinstall to verify node-pty installation
|
|
22
|
+
- Added pty-termux-utils verification to ensure .cjs files are built
|
|
23
|
+
- Platform detection now installs correct PTY provider:
|
|
24
|
+
- `@mmmbuto/node-pty-android-arm64` for Termux
|
|
25
|
+
- `@lydell/node-pty-linux-arm64` for Linux ARM64
|
|
26
|
+
- Provides helpful error messages when PTY dependencies are missing
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## [0.9.9] - 2026-01-01
|
|
30
|
+
### Added
|
|
31
|
+
- Auto-update check on `nexuscli start` (npm + GitHub) with interactive prompt.
|
|
32
|
+
- `nexuscli update` / `nexuscli upgrade` command to update and restart server.
|
|
33
|
+
- Warnings when changing config while server is running.
|
|
34
|
+
- Live refresh of default model in UI (periodic + on focus).
|
|
35
|
+
|
|
36
|
+
## [0.9.8] - 2025-12-30
|
|
37
|
+
### Changed
|
|
38
|
+
- Update GLM routing to GLM-4.7 for Z.ai in Claude wrapper and model catalog.
|
|
39
|
+
### Docs
|
|
40
|
+
- README updated for GLM-4.7 and release version.
|
|
41
|
+
|
|
42
|
+
## [0.9.7004-termux] - 2025-12-28
|
|
43
|
+
### Fixed
|
|
44
|
+
- Force Qwen model selection so `vision-model` is honored for image prompts.
|
|
45
|
+
- Parse Qwen stream-json tool events to keep statusbar live.
|
|
46
|
+
- Improve light theme contrast and update mobile statusbar theme colors.
|
|
47
|
+
|
|
48
|
+
## [0.9.7-termux] - 2025-12-28
|
|
49
|
+
### Added
|
|
50
|
+
- QWEN engine integration (Qwen Code CLI) with SSE streaming.
|
|
51
|
+
- QWEN models in catalog: `coder-model`, `vision-model`.
|
|
52
|
+
- QWEN session import + resume support.
|
|
53
|
+
### Changed
|
|
54
|
+
- Statusbar now reflects QWEN tool activity in real time (stream-json parsing).
|
|
55
|
+
|
|
56
|
+
## [0.9.6] - 2025-12-26
|
|
57
|
+
### Fixed
|
|
58
|
+
- Restore Jobs CLI wrapper and Termux PTY adapter removed during cleanup.
|
|
59
|
+
- Use Termux-safe shell/runtime resolution for job execution (no hardcoded /bin or /usr/bin paths).
|
|
60
|
+
- Surface job stream errors correctly in the UI.
|
|
61
|
+
|
|
62
|
+
## [0.9.5] - 2025-12-25
|
|
63
|
+
### Added
|
|
64
|
+
- GPT-5.2 Codex set as default Codex model.
|
|
65
|
+
### Changed
|
|
66
|
+
- Updated Codex model catalog to match OpenAI CLI.
|
|
67
|
+
### Fixed
|
|
68
|
+
- i18n import after cleanup.
|
|
69
|
+
|
|
70
|
+
## [0.9.4] - 2025-12-25
|
|
71
|
+
### Added
|
|
72
|
+
- Dark/Light theme toggle with CSS variables and localStorage persistence.
|
|
73
|
+
- Rate limiting on chat endpoints (10 req/min per user).
|
|
74
|
+
- Architecture documentation (`docs/ARCHITECTURE.md`).
|
|
75
|
+
|
|
76
|
+
## [0.9.3] - 2025-12-19
|
|
77
|
+
### Fixed
|
|
78
|
+
- Normalize Termux workspace paths (auto-correct `/data/data/com/termux/...`) to prevent Claude spawn ENOENT and stalled GLM-4.6/DeepSeek runs.
|
|
79
|
+
- Workspaces API now filters and merges invalid paths to keep the UI dropdown clean.
|
|
80
|
+
- Session importer reads `cwd` from Claude session files when available for accurate workspace mapping.
|
package/README.md
CHANGED
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
# NexusCLI — AI Terminal Cockpit
|
|
2
|
-
|
|
3
|
-
<p align="center">
|
|
4
|
-
<img src=".github/header/header.png" width="900" />
|
|
5
|
-
</p>
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
1
|
## Overview
|
|
10
2
|
|
|
11
3
|
NexusCLI is a lightweight, Termux-first AI cockpit that orchestrates Claude Code, Codex CLI, Gemini CLI, and Qwen Code CLI from a single web/terminal UI. It supports live streaming, interrupts, session resume, workspace isolation, and remote voice input with auto HTTPS setup.
|
|
12
4
|
|
|
13
5
|
---
|
|
14
6
|
|
|
15
|
-
[](https://www.npmjs.com/package/@mmmbuto/nexuscli)
|
|
16
|
-
[](https://www.npmjs.com/package/@mmmbuto/nexuscli)
|
|
17
|
-
[](https://ko-fi.com/dionanos)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
7
|
## Screenshots
|
|
22
8
|
|
|
23
9
|
<p align="center">
|
|
@@ -27,18 +13,6 @@ NexusCLI is a lightweight, Termux-first AI cockpit that orchestrates Claude Code
|
|
|
27
13
|
|
|
28
14
|
---
|
|
29
15
|
|
|
30
|
-
## Highlights (v0.9.9)
|
|
31
|
-
|
|
32
|
-
- **Auto-update**: Update check on start (npm + GitHub) with interactive prompt
|
|
33
|
-
- **Update command**: `nexuscli update` / `nexuscli upgrade` (stop → update → restart)
|
|
34
|
-
- **Live default model**: UI refreshes config on focus/interval without restart
|
|
35
|
-
- **Restart warnings**: CLI warns when changes require stop/start
|
|
36
|
-
|
|
37
|
-
### Stable (v0.9.9)
|
|
38
|
-
|
|
39
|
-
- Update check is cached and non-blocking for normal startup
|
|
40
|
-
- GitHub-only releases show a notice without prompting
|
|
41
|
-
|
|
42
16
|
## Features
|
|
43
17
|
|
|
44
18
|
- Multi-engine orchestration (Claude, Codex, Gemini, Qwen)
|
|
@@ -52,6 +26,8 @@ NexusCLI is a lightweight, Termux-first AI cockpit that orchestrates Claude Code
|
|
|
52
26
|
- Conversation search + pin/bookmark
|
|
53
27
|
- Built-in jobs runner API for shell tasks
|
|
54
28
|
- Config API + rate limiting on chat endpoints
|
|
29
|
+
- Auto-update check on start with interactive prompt
|
|
30
|
+
- `nexuscli update` command to update and restart server
|
|
55
31
|
|
|
56
32
|
## Supported Engines
|
|
57
33
|
|
|
@@ -69,7 +45,7 @@ NexusCLI is a lightweight, Termux-first AI cockpit that orchestrates Claude Code
|
|
|
69
45
|
|
|
70
46
|
```bash
|
|
71
47
|
# From npm
|
|
72
|
-
npm install -g @mmmbuto/nexuscli
|
|
48
|
+
npm install -g @mmmbuto/nexuscli@0.9.12
|
|
73
49
|
|
|
74
50
|
# From GitHub
|
|
75
51
|
npm install -g github:DioNanos/nexuscli
|
|
@@ -79,7 +55,7 @@ npm install -g github:DioNanos/nexuscli
|
|
|
79
55
|
|
|
80
56
|
```bash
|
|
81
57
|
# Latest (default)
|
|
82
|
-
npm install -g @mmmbuto/nexuscli
|
|
58
|
+
npm install -g @mmmbuto/nexuscli@0.9.12
|
|
83
59
|
|
|
84
60
|
# Stable channel (pinned)
|
|
85
61
|
npm install -g @mmmbuto/nexuscli@stable
|
|
@@ -128,8 +104,6 @@ nexuscli start
|
|
|
128
104
|
| `nexuscli upgrade` | Alias for update |
|
|
129
105
|
| `nexuscli uninstall` | Remove NexusCLI |
|
|
130
106
|
|
|
131
|
-
---
|
|
132
|
-
|
|
133
107
|
> **Note**: On `nexuscli start`, an update check runs (cached) and will prompt in interactive shells.
|
|
134
108
|
|
|
135
109
|
## API Keys
|
|
@@ -195,8 +169,8 @@ engine CLIs alive in background; it spawns them on demand and resumes sessions.
|
|
|
195
169
|
- Install Termux:Boot to auto-restart after reboot or app kill.
|
|
196
170
|
- Keep a persistent notification (Termux:API helps prevent background kill).
|
|
197
171
|
|
|
198
|
-
**Reduce battery usage (when you don
|
|
199
|
-
- Stop
|
|
172
|
+
**Reduce battery usage (when you don't need it always-on):**
|
|
173
|
+
- Stop server when idle: `nexuscli stop`.
|
|
200
174
|
- Disable wake-lock and notifications when not needed.
|
|
201
175
|
- Prefer lighter models and lower reasoning settings.
|
|
202
176
|
|
|
@@ -240,11 +214,6 @@ npm run dev
|
|
|
240
214
|
|
|
241
215
|
---
|
|
242
216
|
|
|
243
|
-
## License
|
|
244
|
-
|
|
245
|
-
MIT License.
|
|
246
|
-
See `LICENSE` for details.
|
|
247
|
-
|
|
248
217
|
## PTY Support (Shared Library)
|
|
249
218
|
|
|
250
219
|
NexusCLI uses `@mmmbuto/pty-termux-utils` as a shared library for PTY
|
|
@@ -260,3 +229,16 @@ management across all Termux CLI projects (Gemini, Qwen, Nexus).
|
|
|
260
229
|
# Enable PTY debug logging
|
|
261
230
|
PTY_DEBUG=1 nexuscli start
|
|
262
231
|
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Changelog
|
|
236
|
+
|
|
237
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT License.
|
|
244
|
+
See `LICENSE` for details.
|
package/lib/server/lib/getPty.js
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
* @version 1.1.0
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const {
|
|
13
|
+
const { getPtyFn, getLogDebugFn } = require('./pty-utils-loader');
|
|
14
|
+
|
|
15
|
+
const getSharedPty = getPtyFn();
|
|
16
|
+
const logDebug = getLogDebugFn();
|
|
14
17
|
const tryRequire = (moduleName) => {
|
|
15
18
|
try {
|
|
16
19
|
require(moduleName);
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const {
|
|
9
|
+
const { getPtyFn, getFallbackAdapter } = require('./pty-utils-loader');
|
|
10
|
+
|
|
11
|
+
const getSharedPty = getPtyFn();
|
|
10
12
|
const tryRequire = (moduleName) => {
|
|
11
13
|
try {
|
|
12
14
|
require(moduleName);
|
|
@@ -17,7 +19,7 @@ const tryRequire = (moduleName) => {
|
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
// Create shared fallback adapter (always uses child_process)
|
|
20
|
-
const fallbackAdapter =
|
|
22
|
+
const fallbackAdapter = getFallbackAdapter();
|
|
21
23
|
|
|
22
24
|
// Cache for native PTY (sync access)
|
|
23
25
|
let cachedNativePty = null;
|
|
@@ -31,8 +33,7 @@ async function initNativePty() {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
try {
|
|
34
|
-
|
|
35
|
-
cachedNativePty = await getPty();
|
|
36
|
+
cachedNativePty = await getSharedPty();
|
|
36
37
|
return cachedNativePty;
|
|
37
38
|
} catch (e) {
|
|
38
39
|
cachedNativePty = false; // Error loading
|
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
getPtyFn,
|
|
11
|
+
getSpawnPtyFn,
|
|
12
|
+
getFallbackAdapter: getSafeFallbackAdapter
|
|
13
|
+
} = require('./pty-utils-loader');
|
|
14
|
+
|
|
15
|
+
const getSharedPty = getPtyFn();
|
|
16
|
+
const spawnPty = getSpawnPtyFn();
|
|
10
17
|
const tryRequire = (moduleName) => {
|
|
11
18
|
try {
|
|
12
19
|
require(moduleName);
|
|
@@ -33,7 +40,7 @@ async function getPty() {
|
|
|
33
40
|
* @returns {Object} Adapter with spawn method
|
|
34
41
|
*/
|
|
35
42
|
function getFallbackAdapter() {
|
|
36
|
-
return
|
|
43
|
+
return getSafeFallbackAdapter();
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
/**
|
|
@@ -52,5 +59,5 @@ module.exports = {
|
|
|
52
59
|
getFallbackAdapter,
|
|
53
60
|
isPtyAvailable,
|
|
54
61
|
// Re-export from shared library
|
|
55
|
-
spawnPty
|
|
62
|
+
spawnPty,
|
|
56
63
|
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe loader for @mmmbuto/pty-termux-utils with fallback adapter.
|
|
3
|
+
* Prevents hard crashes if the dependency is missing or broken.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { spawn } = require('child_process');
|
|
7
|
+
|
|
8
|
+
let cachedUtils;
|
|
9
|
+
let warned = false;
|
|
10
|
+
|
|
11
|
+
function warnOnce(error) {
|
|
12
|
+
if (warned) return;
|
|
13
|
+
warned = true;
|
|
14
|
+
const message = error && error.message ? error.message : String(error);
|
|
15
|
+
console.warn('[PTY] Failed to load @mmmbuto/pty-termux-utils. Using fallback adapter.');
|
|
16
|
+
console.warn(`[PTY] Reason: ${message}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function loadPtyUtils() {
|
|
20
|
+
if (cachedUtils !== undefined) return cachedUtils;
|
|
21
|
+
try {
|
|
22
|
+
cachedUtils = require('@mmmbuto/pty-termux-utils');
|
|
23
|
+
} catch (err) {
|
|
24
|
+
warnOnce(err);
|
|
25
|
+
cachedUtils = null;
|
|
26
|
+
}
|
|
27
|
+
return cachedUtils;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ensurePtyInterface(proc) {
|
|
31
|
+
if (!proc) return proc;
|
|
32
|
+
if (typeof proc.onData === 'function' && typeof proc.onExit === 'function') {
|
|
33
|
+
return proc;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const hasChildStd = !!(proc.stdout || proc.stderr);
|
|
37
|
+
const dataHandlers = [];
|
|
38
|
+
const exitHandlers = [];
|
|
39
|
+
|
|
40
|
+
if (typeof proc.on === 'function' && !hasChildStd) {
|
|
41
|
+
proc.on('data', (data) => {
|
|
42
|
+
dataHandlers.forEach((fn) => fn(data));
|
|
43
|
+
});
|
|
44
|
+
proc.on('exit', (code, signal) => {
|
|
45
|
+
exitHandlers.forEach((fn) => fn({ exitCode: code, signal }));
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
proc.stdout?.on('data', (data) => {
|
|
49
|
+
dataHandlers.forEach((fn) => fn(data.toString()));
|
|
50
|
+
});
|
|
51
|
+
proc.stderr?.on('data', (data) => {
|
|
52
|
+
dataHandlers.forEach((fn) => fn(data.toString()));
|
|
53
|
+
});
|
|
54
|
+
proc.on?.('exit', (code, signal) => {
|
|
55
|
+
exitHandlers.forEach((fn) => fn({ exitCode: code ?? -1, signal }));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
proc.onData = (fn) => dataHandlers.push(fn);
|
|
60
|
+
proc.onExit = (fn) => exitHandlers.push(fn);
|
|
61
|
+
|
|
62
|
+
if (typeof proc.onError !== 'function' && typeof proc.on === 'function') {
|
|
63
|
+
proc.onError = (fn) => proc.on('error', fn);
|
|
64
|
+
}
|
|
65
|
+
if (typeof proc.write !== 'function') {
|
|
66
|
+
proc.write = (data) => proc.stdin?.write(data);
|
|
67
|
+
}
|
|
68
|
+
if (typeof proc.sendEsc !== 'function') {
|
|
69
|
+
proc.sendEsc = () => {
|
|
70
|
+
if (proc.stdin?.writable) {
|
|
71
|
+
proc.stdin.write('\x1B');
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (typeof proc.resize !== 'function') {
|
|
78
|
+
proc.resize = () => {};
|
|
79
|
+
}
|
|
80
|
+
if (typeof proc.kill !== 'function' && proc.process?.kill) {
|
|
81
|
+
proc.kill = (signal = 'SIGTERM') => proc.process.kill(signal);
|
|
82
|
+
}
|
|
83
|
+
if (proc.pid == null && proc.process?.pid != null) {
|
|
84
|
+
proc.pid = proc.process.pid;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return proc;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function createLocalFallbackAdapter() {
|
|
91
|
+
return {
|
|
92
|
+
spawn: (file, args, options = {}) => {
|
|
93
|
+
const child = spawn(file, args, {
|
|
94
|
+
cwd: options.cwd,
|
|
95
|
+
env: options.env ? { ...process.env, ...options.env } : undefined,
|
|
96
|
+
});
|
|
97
|
+
return ensurePtyInterface(child);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getPtyFn() {
|
|
103
|
+
const utils = loadPtyUtils();
|
|
104
|
+
return utils?.getPty ? utils.getPty : async () => null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getSpawnPtyFn() {
|
|
108
|
+
const utils = loadPtyUtils();
|
|
109
|
+
return utils?.spawnPty
|
|
110
|
+
? utils.spawnPty
|
|
111
|
+
: async () => { throw new Error('Native PTY utilities unavailable'); };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getLogDebugFn() {
|
|
115
|
+
const utils = loadPtyUtils();
|
|
116
|
+
return utils?.logDebug ? utils.logDebug : () => {};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function getFallbackAdapter() {
|
|
120
|
+
const utils = loadPtyUtils();
|
|
121
|
+
if (utils?.createFallbackAdapter) {
|
|
122
|
+
const base = utils.createFallbackAdapter();
|
|
123
|
+
return {
|
|
124
|
+
spawn: (...args) => ensurePtyInterface(base.spawn(...args))
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return createLocalFallbackAdapter();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = {
|
|
131
|
+
getPtyFn,
|
|
132
|
+
getSpawnPtyFn,
|
|
133
|
+
getLogDebugFn,
|
|
134
|
+
getFallbackAdapter,
|
|
135
|
+
ensurePtyInterface
|
|
136
|
+
};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Dependency Check for NexusCLI Post-Install
|
|
3
|
+
* Detects platform and installs appropriate PTY provider
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const colors = {
|
|
11
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
12
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
13
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
14
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
15
|
+
gray: (s) => `\x1b[90m${s}\x1b[0m`
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function log(msg) { console.log(msg); }
|
|
19
|
+
function success(msg) { console.log(colors.green(` ✓ ${msg}`)); }
|
|
20
|
+
function warn(msg) { console.log(colors.yellow(` ⚠ ${msg}`)); }
|
|
21
|
+
function error(msg) { console.log(colors.red(` ✗ ${msg}`)); }
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Detect platform
|
|
25
|
+
*/
|
|
26
|
+
function detectPlatform() {
|
|
27
|
+
const isTermux =
|
|
28
|
+
process.env.PREFIX?.includes('com.termux') ||
|
|
29
|
+
fs.existsSync('/data/data/com.termux') ||
|
|
30
|
+
process.env.TERMUX_VERSION !== undefined;
|
|
31
|
+
|
|
32
|
+
const isLinuxArm64 = process.platform === 'linux' && process.arch === 'arm64';
|
|
33
|
+
|
|
34
|
+
if (isTermux) return 'termux';
|
|
35
|
+
if (isLinuxArm64) return 'linux-arm64';
|
|
36
|
+
return 'other';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if npm package is installed
|
|
41
|
+
*/
|
|
42
|
+
function isNpmPackageInstalled(packageName) {
|
|
43
|
+
try {
|
|
44
|
+
const nodeModulesPath = path.join(__dirname, '..', '..', 'node_modules', packageName);
|
|
45
|
+
return fs.existsSync(nodeModulesPath);
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if pty.node exists (native module)
|
|
53
|
+
*/
|
|
54
|
+
function checkPtyNode() {
|
|
55
|
+
try {
|
|
56
|
+
const nodeModulesPath = path.join(__dirname, '..', '..', 'node_modules');
|
|
57
|
+
|
|
58
|
+
// Check @mmmbuto/node-pty-android-arm64
|
|
59
|
+
const androidPtyPath = path.join(nodeModulesPath, '@mmmbuto', 'node-pty-android-arm64', 'build', 'Release', 'pty.node');
|
|
60
|
+
if (fs.existsSync(androidPtyPath)) {
|
|
61
|
+
return { found: true, provider: '@mmmbuto/node-pty-android-arm64', path: androidPtyPath };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check @lydell/node-pty-linux-arm64
|
|
65
|
+
const linuxPtyPath = path.join(nodeModulesPath, '@lydell', 'node-pty-linux-arm64', 'build', 'Release', 'pty.node');
|
|
66
|
+
if (fs.existsSync(linuxPtyPath)) {
|
|
67
|
+
return { found: true, provider: '@lydell/node-pty-linux-arm64', path: linuxPtyPath };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { found: false };
|
|
71
|
+
} catch {
|
|
72
|
+
return { found: false };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Install PTY provider
|
|
78
|
+
*/
|
|
79
|
+
function installPtyProvider(provider) {
|
|
80
|
+
try {
|
|
81
|
+
log(` Installing ${provider}...`);
|
|
82
|
+
|
|
83
|
+
const npmCmd = process.env.npm_execpath || 'npm';
|
|
84
|
+
execSync(`${npmCmd} install ${provider}`, {
|
|
85
|
+
stdio: 'inherit',
|
|
86
|
+
cwd: path.join(__dirname, '..', '..')
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
success(`${provider} installed`);
|
|
90
|
+
return true;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
warn(`${provider} installation failed: ${err.message}`);
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Main PTY check function
|
|
99
|
+
*/
|
|
100
|
+
function checkPtyDependencies() {
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(colors.cyan('Checking PTY dependencies:'));
|
|
103
|
+
|
|
104
|
+
const platform = detectPlatform();
|
|
105
|
+
let targetProvider = null;
|
|
106
|
+
|
|
107
|
+
// Determine target provider based on platform
|
|
108
|
+
if (platform === 'termux') {
|
|
109
|
+
targetProvider = '@mmmbuto/node-pty-android-arm64';
|
|
110
|
+
} else if (platform === 'linux-arm64') {
|
|
111
|
+
targetProvider = '@lydell/node-pty-linux-arm64';
|
|
112
|
+
} else {
|
|
113
|
+
log(colors.gray(' Skipped: Unsupported platform for PTY (not Termux/Linux ARM64)'));
|
|
114
|
+
log(colors.gray(' PTY will use fallback adapter (child_process)'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check if PTY native module exists
|
|
119
|
+
const ptyCheck = checkPtyNode();
|
|
120
|
+
|
|
121
|
+
if (ptyCheck.found) {
|
|
122
|
+
success(`Native PTY found: ${ptyCheck.provider}`);
|
|
123
|
+
} else {
|
|
124
|
+
// Check if package is installed but pty.node is missing
|
|
125
|
+
if (isNpmPackageInstalled(targetProvider)) {
|
|
126
|
+
warn(`${targetProvider} installed but pty.node missing - may need rebuild`);
|
|
127
|
+
warn(` Run: npm rebuild ${targetProvider}`);
|
|
128
|
+
} else {
|
|
129
|
+
warn(`${targetProvider} not installed`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Try to install
|
|
133
|
+
const installed = installPtyProvider(targetProvider);
|
|
134
|
+
if (installed) {
|
|
135
|
+
// Verify installation
|
|
136
|
+
const verify = checkPtyNode();
|
|
137
|
+
if (verify.found) {
|
|
138
|
+
success(`Native PTY verified: ${verify.provider}`);
|
|
139
|
+
} else {
|
|
140
|
+
warn(`PTY package installed but pty.node not found`);
|
|
141
|
+
warn(` You may need to rebuild: npm rebuild ${targetProvider}`);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
warn(`Cannot install ${targetProvider} - PTY will use fallback`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log('');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Check if pty-termux-utils is installed and has .cjs files
|
|
154
|
+
*/
|
|
155
|
+
function checkPtyTermuxUtils() {
|
|
156
|
+
try {
|
|
157
|
+
const ptyUtilsPath = path.join(__dirname, '..', '..', 'node_modules', '@mmmbuto', 'pty-termux-utils');
|
|
158
|
+
|
|
159
|
+
if (!fs.existsSync(ptyUtilsPath)) {
|
|
160
|
+
warn('@mmmbuto/pty-termux-utils not installed');
|
|
161
|
+
warn(' This is required for PTY support');
|
|
162
|
+
warn(' Run: npm install @mmmbuto/pty-termux-utils');
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const indexCjsPath = path.join(ptyUtilsPath, 'dist', 'index.cjs');
|
|
167
|
+
if (fs.existsSync(indexCjsPath)) {
|
|
168
|
+
success('@mmmbuto/pty-termux-utils installed with CJS support');
|
|
169
|
+
return true;
|
|
170
|
+
} else {
|
|
171
|
+
warn('@mmmbuto/pty-termux-utils installed but .cjs files missing');
|
|
172
|
+
warn(' Run: cd node_modules/@mmmbuto/pty-termux-utils && npm run build:cjs');
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
} catch (err) {
|
|
176
|
+
warn('Error checking @mmmbuto/pty-termux-utils: ' + err.message);
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = { checkPtyDependencies ,
|
|
182
|
+
checkPtyTermuxUtils
|
|
183
|
+
};
|
package/lib/setup/postinstall.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Termux-only: auto-run wizard if not configured
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
const { checkPtyDependencies, checkPtyTermuxUtils } = require('./postinstall-pty-check');
|
|
7
9
|
const { execSync, spawn } = require('child_process');
|
|
8
10
|
const fs = require('fs');
|
|
9
11
|
const path = require('path');
|
|
@@ -22,7 +24,6 @@ const colors = {
|
|
|
22
24
|
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
23
25
|
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
24
26
|
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
25
|
-
gray: (s) => `\x1b[90m${s}\x1b[0m`
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
function log(msg) {
|
|
@@ -144,6 +145,15 @@ async function main() {
|
|
|
144
145
|
for (const pkg of packages) {
|
|
145
146
|
installPackage(pkg);
|
|
146
147
|
}
|
|
148
|
+
|
|
149
|
+
// Check PTY dependencies
|
|
150
|
+
checkPtyDependencies();
|
|
151
|
+
|
|
152
|
+
// Check pty-termux-utils
|
|
153
|
+
checkPtyTermuxUtils();
|
|
154
|
+
|
|
155
|
+
// Check pty-termux-utils
|
|
156
|
+
checkPtyTermuxUtils();
|
|
147
157
|
console.log('');
|
|
148
158
|
|
|
149
159
|
// Create directories
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmmbuto/nexuscli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"description": "NexusCLI - TRI CLI Control Plane (Claude/Codex/Gemini/Qwen)",
|
|
5
5
|
"main": "lib/server/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"frontend/dist/",
|
|
45
45
|
"package.json",
|
|
46
46
|
"README.md",
|
|
47
|
+
"CHANGELOG.md",
|
|
47
48
|
"LICENSE"
|
|
48
49
|
],
|
|
49
50
|
"engines": {
|
|
@@ -58,7 +59,7 @@
|
|
|
58
59
|
"x64"
|
|
59
60
|
],
|
|
60
61
|
"dependencies": {
|
|
61
|
-
"@mmmbuto/pty-termux-utils": "^1.1.
|
|
62
|
+
"@mmmbuto/pty-termux-utils": "^1.1.3",
|
|
62
63
|
"bcryptjs": "^3.0.3",
|
|
63
64
|
"chalk": "^4.1.2",
|
|
64
65
|
"commander": "^12.1.0",
|