@mmmbuto/nexuscli 0.9.9 → 0.9.10
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 +16 -0
- package/lib/server/lib/getPty.js +48 -0
- package/lib/server/lib/pty-adapter.js +100 -57
- package/lib/server/lib/pty-provider.js +56 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -244,3 +244,19 @@ npm run dev
|
|
|
244
244
|
|
|
245
245
|
MIT License.
|
|
246
246
|
See `LICENSE` for details.
|
|
247
|
+
|
|
248
|
+
## PTY Support (Shared Library)
|
|
249
|
+
|
|
250
|
+
NexusCLI uses `@mmmbuto/pty-termux-utils` as a shared library for PTY
|
|
251
|
+
management across all Termux CLI projects (Gemini, Qwen, Nexus).
|
|
252
|
+
|
|
253
|
+
- **Native PTY:** Uses `@mmmbuto/node-pty-android-arm64@~1.1.0` when available
|
|
254
|
+
- **Linux ARM64:** Uses `@lydell/node-pty-linux-arm64@~1.2.0-beta.2` when available
|
|
255
|
+
- **Fallback:** Gracefully degrades to `child_process` adapter
|
|
256
|
+
- **Debug Logging:** Enable with `PTY_DEBUG=1` environment variable
|
|
257
|
+
- **Architecture:** See `@mmmbuto/pty-termux-utils` documentation
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Enable PTY debug logging
|
|
261
|
+
PTY_DEBUG=1 nexuscli start
|
|
262
|
+
```
|
|
@@ -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
|
-
*
|
|
4
|
-
*
|
|
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.
|
|
6
|
+
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const {
|
|
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
|
-
*
|
|
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
|
|
49
|
+
* @returns {Object} PTY-like interface
|
|
17
50
|
*/
|
|
18
51
|
function spawn(command, args, options = {}) {
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
37
|
-
const
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
77
|
+
proc.on('data', (data) => {
|
|
78
|
+
dataHandlers.forEach((fn) => fn(data));
|
|
79
|
+
});
|
|
45
80
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
81
|
+
proc.on('exit', (code, signal) => {
|
|
82
|
+
exitHandlers.forEach((fn) => fn({ exitCode: code, signal }));
|
|
83
|
+
});
|
|
50
84
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
*
|
|
75
|
-
*
|
|
105
|
+
* Synchronous check if PTY is available
|
|
106
|
+
* @returns {boolean}
|
|
76
107
|
*/
|
|
77
108
|
function isPtyAvailable() {
|
|
78
|
-
return
|
|
109
|
+
return (
|
|
110
|
+
tryRequire('@mmmbuto/node-pty-android-arm64') ||
|
|
111
|
+
tryRequire('@lydell/node-pty-linux-arm64')
|
|
112
|
+
);
|
|
79
113
|
}
|
|
80
114
|
|
|
81
|
-
|
|
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
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmmbuto/nexuscli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.10",
|
|
4
4
|
"description": "NexusCLI - TRI CLI Control Plane (Claude/Codex/Gemini/Qwen)",
|
|
5
5
|
"main": "lib/server/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"x64"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
+
"@mmmbuto/pty-termux-utils": "^1.1.0",
|
|
61
62
|
"bcryptjs": "^3.0.3",
|
|
62
63
|
"chalk": "^4.1.2",
|
|
63
64
|
"commander": "^12.1.0",
|
|
@@ -75,5 +76,8 @@
|
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
77
78
|
"jest": "^30.2.0"
|
|
79
|
+
},
|
|
80
|
+
"optionalDependencies": {
|
|
81
|
+
"@mmmbuto/node-pty-android-arm64": "~1.1.0"
|
|
78
82
|
}
|
|
79
83
|
}
|