@mmmbuto/nexuscli 0.9.9 → 0.9.11

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 ADDED
@@ -0,0 +1,74 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.9.10] - 2026-01-09
6
+ ### Fixed
7
+ - Added PTY dependency check in postinstall to verify node-pty installation
8
+ - Added pty-termux-utils verification to ensure .cjs files are built
9
+ - Platform detection now installs correct PTY provider:
10
+ - `@mmmbuto/node-pty-android-arm64` for Termux
11
+ - `@lydell/node-pty-linux-arm64` for Linux ARM64
12
+ - Provides helpful error messages when PTY dependencies are missing
13
+ ## [0.9.11] - 2026-01-09
14
+ ### Fixed
15
+ - Added PTY dependency verification in postinstall
16
+ - Added platform-specific PTY provider installation
17
+ - Added @mmmbuto/pty-termux-utils installation check
18
+ - All PTY dependencies now verified during npm install
19
+ - Updated @mmmbuto/pty-termux-utils to ^1.1.2
20
+
21
+
22
+
23
+ ## [0.9.9] - 2026-01-01
24
+ ### Added
25
+ - Auto-update check on `nexuscli start` (npm + GitHub) with interactive prompt.
26
+ - `nexuscli update` / `nexuscli upgrade` command to update and restart server.
27
+ - Warnings when changing config while server is running.
28
+ - Live refresh of default model in UI (periodic + on focus).
29
+
30
+ ## [0.9.8] - 2025-12-30
31
+ ### Changed
32
+ - Update GLM routing to GLM-4.7 for Z.ai in Claude wrapper and model catalog.
33
+ ### Docs
34
+ - README updated for GLM-4.7 and release version.
35
+
36
+ ## [0.9.7004-termux] - 2025-12-28
37
+ ### Fixed
38
+ - Force Qwen model selection so `vision-model` is honored for image prompts.
39
+ - Parse Qwen stream-json tool events to keep statusbar live.
40
+ - Improve light theme contrast and update mobile statusbar theme colors.
41
+
42
+ ## [0.9.7-termux] - 2025-12-28
43
+ ### Added
44
+ - QWEN engine integration (Qwen Code CLI) with SSE streaming.
45
+ - QWEN models in catalog: `coder-model`, `vision-model`.
46
+ - QWEN session import + resume support.
47
+ ### Changed
48
+ - Statusbar now reflects QWEN tool activity in real time (stream-json parsing).
49
+
50
+ ## [0.9.6] - 2025-12-26
51
+ ### Fixed
52
+ - Restore Jobs CLI wrapper and Termux PTY adapter removed during cleanup.
53
+ - Use Termux-safe shell/runtime resolution for job execution (no hardcoded /bin or /usr/bin paths).
54
+ - Surface job stream errors correctly in the UI.
55
+
56
+ ## [0.9.5] - 2025-12-25
57
+ ### Added
58
+ - GPT-5.2 Codex set as default Codex model.
59
+ ### Changed
60
+ - Updated Codex model catalog to match OpenAI CLI.
61
+ ### Fixed
62
+ - i18n import after cleanup.
63
+
64
+ ## [0.9.4] - 2025-12-25
65
+ ### Added
66
+ - Dark/Light theme toggle with CSS variables and localStorage persistence.
67
+ - Rate limiting on chat endpoints (10 req/min per user).
68
+ - Architecture documentation (`docs/ARCHITECTURE.md`).
69
+
70
+ ## [0.9.3] - 2025-12-19
71
+ ### Fixed
72
+ - Normalize Termux workspace paths (auto-correct `/data/data/com/termux/...`) to prevent Claude spawn ENOENT and stalled GLM-4.6/DeepSeek runs.
73
+ - Workspaces API now filters and merges invalid paths to keep the UI dropdown clean.
74
+ - Session importer reads `cwd` from Claude session files when available for accurate workspace mapping.
package/README.md CHANGED
@@ -6,39 +6,18 @@
6
6
 
7
7
  ---
8
8
 
9
- ## Overview
10
-
11
- 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
-
13
- ---
14
-
15
9
  [![npm](https://img.shields.io/npm/v/@mmmbuto/nexuscli?style=flat-square&logo=npm)](https://www.npmjs.com/package/@mmmbuto/nexuscli)
16
10
  [![downloads](https://img.shields.io/npm/dt/@mmmbuto/nexuscli?style=flat-square)](https://www.npmjs.com/package/@mmmbuto/nexuscli)
17
11
  [![ko-fi](https://img.shields.io/badge/☕_Support-Ko--fi-FF5E5B?style=flat-square&logo=ko-fi)](https://ko-fi.com/dionanos)
18
12
 
19
13
  ---
20
14
 
21
- ## Screenshots
15
+ ## Overview
22
16
 
23
- <p align="center">
24
- <img src="docs/assets/screenshots/nexuscli-multilang-preview.png" width="45%" />
25
- <img src="docs/assets/screenshots/nexuscli-mobile-glm.png" width="45%" />
26
- </p>
17
+ 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.
27
18
 
28
19
  ---
29
20
 
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
21
  ## Features
43
22
 
44
23
  - Multi-engine orchestration (Claude, Codex, Gemini, Qwen)
@@ -52,6 +31,8 @@ NexusCLI is a lightweight, Termux-first AI cockpit that orchestrates Claude Code
52
31
  - Conversation search + pin/bookmark
53
32
  - Built-in jobs runner API for shell tasks
54
33
  - Config API + rate limiting on chat endpoints
34
+ - Auto-update check on start with interactive prompt
35
+ - `nexuscli update` command to update and restart server
55
36
 
56
37
  ## Supported Engines
57
38
 
@@ -65,6 +46,15 @@ NexusCLI is a lightweight, Termux-first AI cockpit that orchestrates Claude Code
65
46
 
66
47
  ---
67
48
 
49
+ ## Screenshots
50
+
51
+ <p align="center">
52
+ <img src="docs/assets/screenshots/nexuscli-multilang-preview.png" width="45%" />
53
+ <img src="docs/assets/screenshots/nexuscli-mobile-glm.png" width="45%" />
54
+ </p>
55
+
56
+ ---
57
+
68
58
  ## Install
69
59
 
70
60
  ```bash
@@ -128,8 +118,6 @@ nexuscli start
128
118
  | `nexuscli upgrade` | Alias for update |
129
119
  | `nexuscli uninstall` | Remove NexusCLI |
130
120
 
131
- ---
132
-
133
121
  > **Note**: On `nexuscli start`, an update check runs (cached) and will prompt in interactive shells.
134
122
 
135
123
  ## API Keys
@@ -195,8 +183,8 @@ engine CLIs alive in background; it spawns them on demand and resumes sessions.
195
183
  - Install Termux:Boot to auto-restart after reboot or app kill.
196
184
  - Keep a persistent notification (Termux:API helps prevent background kill).
197
185
 
198
- **Reduce battery usage (when you dont need it always-on):**
199
- - Stop the server when idle: `nexuscli stop`.
186
+ **Reduce battery usage (when you don't need it always-on):**
187
+ - Stop server when idle: `nexuscli stop`.
200
188
  - Disable wake-lock and notifications when not needed.
201
189
  - Prefer lighter models and lower reasoning settings.
202
190
 
@@ -240,6 +228,30 @@ npm run dev
240
228
 
241
229
  ---
242
230
 
231
+ ## PTY Support (Shared Library)
232
+
233
+ NexusCLI uses `@mmmbuto/pty-termux-utils` as a shared library for PTY
234
+ management across all Termux CLI projects (Gemini, Qwen, Nexus).
235
+
236
+ - **Native PTY:** Uses `@mmmbuto/node-pty-android-arm64@~1.1.0` when available
237
+ - **Linux ARM64:** Uses `@lydell/node-pty-linux-arm64@~1.2.0-beta.2` when available
238
+ - **Fallback:** Gracefully degrades to `child_process` adapter
239
+ - **Debug Logging:** Enable with `PTY_DEBUG=1` environment variable
240
+ - **Architecture:** See `@mmmbuto/pty-termux-utils` documentation
241
+
242
+ ```bash
243
+ # Enable PTY debug logging
244
+ PTY_DEBUG=1 nexuscli start
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Changelog
250
+
251
+ See [CHANGELOG.md](CHANGELOG.md) for version history.
252
+
253
+ ---
254
+
243
255
  ## License
244
256
 
245
257
  MIT License.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * PTY Loader for NexusCLI (legacy compatibility wrapper)
3
+ * Delegates to @mmmbuto/pty-termux-utils multi-provider strategy.
4
+ *
5
+ * Provider priority:
6
+ * 1. Termux: @mmmbuto/node-pty-android-arm64
7
+ * 2. Linux ARM64: @lydell/node-pty-linux-arm64
8
+ * 3. Fallback: child_process adapter (pty-adapter.js)
9
+ *
10
+ * @version 1.1.0
11
+ */
12
+
13
+ const { getPty: getSharedPty, logDebug } = require('@mmmbuto/pty-termux-utils');
14
+ const tryRequire = (moduleName) => {
15
+ try {
16
+ require(moduleName);
17
+ return true;
18
+ } catch (_) {
19
+ return false;
20
+ }
21
+ };
22
+
23
+ module.exports = {
24
+ /**
25
+ * Get PTY implementation with fallback
26
+ * @returns {Promise<{module: any, name: string}|null>}
27
+ */
28
+ async getPty() {
29
+ const pty = await getSharedPty();
30
+ if (pty) {
31
+ logDebug(`Using native PTY provider: ${pty.name}`);
32
+ return pty;
33
+ }
34
+ logDebug('Native PTY not available, using fallback adapter');
35
+ return null;
36
+ },
37
+
38
+ /**
39
+ * Synchronous check if PTY is available
40
+ * @returns {boolean}
41
+ */
42
+ isPtyAvailable() {
43
+ return (
44
+ tryRequire('@mmmbuto/node-pty-android-arm64') ||
45
+ tryRequire('@lydell/node-pty-linux-arm64')
46
+ );
47
+ }
48
+ };
@@ -1,81 +1,124 @@
1
1
  /**
2
- * PTY Adapter for NexusCLI (Termux)
3
- * Provides node-pty-like interface using child_process.spawn
4
- * Termux-only: no native node-pty compilation needed
2
+ * PTY Adapter for NexusCLI (Termux + Linux ARM64)
3
+ * Wrapper around @mmmbuto/pty-termux-utils shared library
4
+ * Provides node-pty-like interface with graceful fallback
5
5
  *
6
- * @version 0.5.0 - Added stdin support for interrupt (ESC key)
6
+ * @version 1.0.0
7
7
  */
8
8
 
9
- const { spawn: cpSpawn } = require('child_process');
9
+ const { createFallbackAdapter } = require('@mmmbuto/pty-termux-utils');
10
+ const tryRequire = (moduleName) => {
11
+ try {
12
+ require(moduleName);
13
+ return true;
14
+ } catch (_) {
15
+ return false;
16
+ }
17
+ };
18
+
19
+ // Create shared fallback adapter (always uses child_process)
20
+ const fallbackAdapter = createFallbackAdapter();
21
+
22
+ // Cache for native PTY (sync access)
23
+ let cachedNativePty = null;
10
24
 
11
25
  /**
12
- * Spawn a process with node-pty-like interface
26
+ * Initialize native PTY (called at startup)
27
+ */
28
+ async function initNativePty() {
29
+ if (cachedNativePty !== null) {
30
+ return cachedNativePty;
31
+ }
32
+
33
+ try {
34
+ const { getPty } = require('@mmmbuto/pty-termux-utils');
35
+ cachedNativePty = await getPty();
36
+ return cachedNativePty;
37
+ } catch (e) {
38
+ cachedNativePty = false; // Error loading
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Synchronous spawn (for compatibility with existing wrapper code)
45
+ * Uses fallback adapter for simplicity (no native PTY in sync mode)
13
46
  * @param {string} command - Command to spawn
14
47
  * @param {string[]} args - Arguments
15
48
  * @param {Object} options - Spawn options (cwd, env)
16
- * @returns {Object} PTY-like interface with onData, onExit, kill
49
+ * @returns {Object} PTY-like interface
17
50
  */
18
51
  function spawn(command, args, options = {}) {
19
- const proc = cpSpawn(command, args, {
20
- cwd: options.cwd,
21
- env: options.env,
22
- shell: false,
23
- stdio: ['pipe', 'pipe', 'pipe'], // stdin enabled for interrupt support
24
- });
25
-
26
- const dataHandlers = [];
27
- const exitHandlers = [];
28
- const errorHandlers = [];
52
+ return fallbackAdapter.spawn(command, args, options);
53
+ }
29
54
 
30
- proc.stdout.on('data', (buf) => {
31
- const data = buf.toString();
32
- console.log('[PTY-Adapter] stdout:', data.substring(0, 200));
33
- dataHandlers.forEach((fn) => fn(data));
34
- });
55
+ /**
56
+ * Async spawn with native PTY support
57
+ * @param {string} command - Command to spawn
58
+ * @param {string[]} args - Arguments
59
+ * @param {Object} options - Spawn options (cwd, env)
60
+ * @returns {Promise<Object>} PTY-like interface
61
+ */
62
+ async function spawnAsync(command, args, options = {}) {
63
+ const pty = await initNativePty();
64
+
65
+ if (pty) {
66
+ // Use native PTY
67
+ const proc = pty.module.spawn(command, args, {
68
+ cols: options.cols || 80,
69
+ rows: options.rows || 24,
70
+ cwd: options.cwd,
71
+ env: options.env,
72
+ });
35
73
 
36
- proc.stderr.on('data', (buf) => {
37
- const data = buf.toString();
38
- console.log('[PTY-Adapter] stderr:', data.substring(0, 200));
39
- dataHandlers.forEach((fn) => fn(data));
40
- });
74
+ const dataHandlers = [];
75
+ const exitHandlers = [];
41
76
 
42
- proc.on('close', (code) => {
43
- exitHandlers.forEach((fn) => fn({ exitCode: code ?? 0 }));
44
- });
77
+ proc.on('data', (data) => {
78
+ dataHandlers.forEach((fn) => fn(data));
79
+ });
45
80
 
46
- proc.on('error', (err) => {
47
- console.error('[PTY-Adapter] Error:', err.message);
48
- errorHandlers.forEach((fn) => fn(err));
49
- });
81
+ proc.on('exit', (code, signal) => {
82
+ exitHandlers.forEach((fn) => fn({ exitCode: code, signal }));
83
+ });
50
84
 
51
- return {
52
- onData: (fn) => dataHandlers.push(fn),
53
- onExit: (fn) => exitHandlers.push(fn),
54
- onError: (fn) => errorHandlers.push(fn),
55
- write: (data) => proc.stdin?.writable && proc.stdin.write(data),
56
- /**
57
- * Send ESC key (0x1B) to interrupt CLI
58
- * Used to gracefully stop Claude/Gemini CLI execution
59
- * @returns {boolean} true if ESC was sent successfully
60
- */
61
- sendEsc: () => {
62
- if (proc.stdin?.writable) {
63
- proc.stdin.write('\x1B');
85
+ return {
86
+ onData: (fn) => dataHandlers.push(fn),
87
+ onExit: (fn) => exitHandlers.push(fn),
88
+ onError: (fn) => {}, // No error event in native PTY
89
+ write: (data) => proc.write(data),
90
+ sendEsc: () => {
91
+ proc.write('\x1B');
64
92
  return true;
65
- }
66
- return false;
67
- },
68
- kill: (signal = 'SIGTERM') => proc.kill(signal),
69
- pid: proc.pid,
70
- };
93
+ },
94
+ resize: (cols, rows) => proc.resize(cols, rows),
95
+ kill: (signal = 'SIGTERM') => proc.kill(signal),
96
+ pid: proc.pid,
97
+ };
98
+ } else {
99
+ // Use fallback adapter
100
+ return fallbackAdapter.spawn(command, args, options);
101
+ }
71
102
  }
72
103
 
73
104
  /**
74
- * Check if native PTY is available
75
- * Always returns false on Termux (we use spawn adapter)
105
+ * Synchronous check if PTY is available
106
+ * @returns {boolean}
76
107
  */
77
108
  function isPtyAvailable() {
78
- return false;
109
+ return (
110
+ tryRequire('@mmmbuto/node-pty-android-arm64') ||
111
+ tryRequire('@lydell/node-pty-linux-arm64')
112
+ );
79
113
  }
80
114
 
81
- module.exports = { spawn, isPtyAvailable };
115
+ // Initialize native PTY in background (non-blocking)
116
+ initNativePty().catch(() => {
117
+ // Silently ignore initialization errors
118
+ });
119
+
120
+ module.exports = {
121
+ spawn, // Sync spawn (uses fallback)
122
+ spawnAsync, // Async spawn (uses native PTY if available)
123
+ isPtyAvailable,
124
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * PTY Provider for NexusCLI (Termux + Linux ARM64)
3
+ * Provides PTY detection with fallback to child_process adapter
4
+ * Uses @mmmbuto/pty-termux-utils shared library
5
+ *
6
+ * @version 1.0.0
7
+ */
8
+
9
+ const { getPty: getSharedPty, createFallbackAdapter } = require('@mmmbuto/pty-termux-utils');
10
+ const tryRequire = (moduleName) => {
11
+ try {
12
+ require(moduleName);
13
+ return true;
14
+ } catch (_) {
15
+ return false;
16
+ }
17
+ };
18
+
19
+ /**
20
+ * Get PTY implementation with fallback
21
+ * @returns {Promise<{module: any, name: string}|null>}
22
+ */
23
+ async function getPty() {
24
+ const pty = await getSharedPty();
25
+ if (pty) {
26
+ return pty;
27
+ }
28
+ return null;
29
+ }
30
+
31
+ /**
32
+ * Get fallback adapter (child_process)
33
+ * @returns {Object} Adapter with spawn method
34
+ */
35
+ function getFallbackAdapter() {
36
+ return createFallbackAdapter();
37
+ }
38
+
39
+ /**
40
+ * Synchronous check if PTY is available
41
+ * @returns {boolean}
42
+ */
43
+ function isPtyAvailable() {
44
+ return (
45
+ tryRequire('@mmmbuto/node-pty-android-arm64') ||
46
+ tryRequire('@lydell/node-pty-linux-arm64')
47
+ );
48
+ }
49
+
50
+ module.exports = {
51
+ getPty,
52
+ getFallbackAdapter,
53
+ isPtyAvailable,
54
+ // Re-export from shared library
55
+ spawnPty: require('@mmmbuto/pty-termux-utils').spawnPty,
56
+ };
@@ -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
+ };
@@ -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.9",
3
+ "version": "0.9.11",
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,6 +59,7 @@
58
59
  "x64"
59
60
  ],
60
61
  "dependencies": {
62
+ "@mmmbuto/pty-termux-utils": "^1.1.2",
61
63
  "bcryptjs": "^3.0.3",
62
64
  "chalk": "^4.1.2",
63
65
  "commander": "^12.1.0",
@@ -75,5 +77,8 @@
75
77
  },
76
78
  "devDependencies": {
77
79
  "jest": "^30.2.0"
80
+ },
81
+ "optionalDependencies": {
82
+ "@mmmbuto/node-pty-android-arm64": "~1.1.0"
78
83
  }
79
- }
84
+ }