nikcli-remote 1.0.2 → 1.0.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/dist/{chunk-DRL7JX54.js → chunk-ONRUR3Z7.js} +59 -39
- package/dist/index.cjs +59 -39
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{server-J7SPDGZO.js → server-MURDBK6L.js} +1 -1
- package/package.json +1 -1
- package/src/web-client.ts +58 -36
|
@@ -1665,6 +1665,7 @@ function getWebClient() {
|
|
|
1665
1665
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
1666
1666
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
1667
1667
|
<title>NikCLI Remote</title>
|
|
1668
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
|
|
1668
1669
|
<style>
|
|
1669
1670
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1670
1671
|
:root {
|
|
@@ -1682,7 +1683,7 @@ function getWebClient() {
|
|
|
1682
1683
|
display: flex;
|
|
1683
1684
|
flex-direction: column;
|
|
1684
1685
|
}
|
|
1685
|
-
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); }
|
|
1686
|
+
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); padding: 8px; }
|
|
1686
1687
|
#input-area {
|
|
1687
1688
|
background: var(--bg-secondary);
|
|
1688
1689
|
border-top: 1px solid var(--border);
|
|
@@ -1797,10 +1798,10 @@ function getWebClient() {
|
|
|
1797
1798
|
</form>
|
|
1798
1799
|
</div>
|
|
1799
1800
|
|
|
1800
|
-
|
|
1801
|
-
<script src="https://cdn.jsdelivr.net/npm/
|
|
1801
|
+
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
|
|
1802
|
+
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
|
|
1802
1803
|
<script>
|
|
1803
|
-
let ws = null, term = null, connected = false, reconnectAttempts = 0;
|
|
1804
|
+
let ws = null, term = null, fitAddon = null, connected = false, reconnectAttempts = 0;
|
|
1804
1805
|
const token = new URLSearchParams(location.search).get('t') || '';
|
|
1805
1806
|
const sessionId = new URLSearchParams(location.search).get('s') || '';
|
|
1806
1807
|
|
|
@@ -1812,40 +1813,57 @@ function getWebClient() {
|
|
|
1812
1813
|
const sessionSpan = document.getElementById('session-id');
|
|
1813
1814
|
const cmdInput = document.getElementById('cmd-input');
|
|
1814
1815
|
|
|
1815
|
-
// Initialize
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1816
|
+
// Initialize xterm.js
|
|
1817
|
+
term = new Terminal({
|
|
1818
|
+
cursorBlink: true,
|
|
1819
|
+
fontSize: 14,
|
|
1820
|
+
fontFamily: '"SF Mono", Monaco, Consolas, monospace',
|
|
1821
|
+
theme: {
|
|
1822
|
+
background: '#0d1117',
|
|
1823
|
+
foreground: '#e6edf3',
|
|
1824
|
+
cursor: '#3fb950',
|
|
1825
|
+
selectionBackground: '#264f78',
|
|
1826
|
+
black: '#484f58',
|
|
1827
|
+
red: '#f85149',
|
|
1828
|
+
green: '#3fb950',
|
|
1829
|
+
yellow: '#d29922',
|
|
1830
|
+
blue: '#58a6ff',
|
|
1831
|
+
magenta: '#a371f7',
|
|
1832
|
+
cyan: '#39c5cf',
|
|
1833
|
+
white: '#e6edf3',
|
|
1834
|
+
brightBlack: '#6e7681',
|
|
1835
|
+
brightRed: '#ffa198',
|
|
1836
|
+
brightGreen: '#7ee787',
|
|
1837
|
+
brightYellow: '#f0883e',
|
|
1838
|
+
brightBlue: '#79c0ff',
|
|
1839
|
+
brightMagenta: '#d2a8ff',
|
|
1840
|
+
brightCyan: '#56d4db',
|
|
1841
|
+
brightWhite: '#f0f6fc'
|
|
1842
|
+
},
|
|
1843
|
+
convertEol: true
|
|
1844
|
+
});
|
|
1829
1845
|
|
|
1830
|
-
|
|
1831
|
-
term.
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
');
|
|
1836
|
-
connect();
|
|
1837
|
-
};
|
|
1838
|
-
term.decorate(document.getElementById('terminal'));
|
|
1839
|
-
term.start();
|
|
1846
|
+
fitAddon = new FitAddon.FitAddon();
|
|
1847
|
+
term.loadAddon(fitAddon);
|
|
1848
|
+
term.open(document.getElementById('terminal'));
|
|
1849
|
+
fitAddon.fit();
|
|
1850
|
+
term.writeln('\x1B[32mInitializing NikCLI Remote...\x1B[0m');
|
|
1851
|
+
term.writeln('\x1B[90mType commands below\x1B[0m');
|
|
1840
1852
|
|
|
1841
1853
|
// Resize handler
|
|
1842
1854
|
window.addEventListener('resize', () => {
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
term.setHeightAndWidth(el.clientHeight / 17, el.clientWidth / 8.53);
|
|
1846
|
-
}
|
|
1855
|
+
clearTimeout(window.resizeTimer);
|
|
1856
|
+
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
1847
1857
|
});
|
|
1848
1858
|
|
|
1859
|
+
// Visual viewport for mobile keyboard
|
|
1860
|
+
if (window.visualViewport) {
|
|
1861
|
+
window.visualViewport.addEventListener('resize', () => {
|
|
1862
|
+
clearTimeout(window.resizeTimer);
|
|
1863
|
+
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
1864
|
+
});
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1849
1867
|
function connect() {
|
|
1850
1868
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
1851
1869
|
ws = new WebSocket(protocol + '//' + location.host + '/ws');
|
|
@@ -1880,8 +1898,8 @@ function getWebClient() {
|
|
|
1880
1898
|
authOverlay.classList.add('hidden');
|
|
1881
1899
|
setStatus('connected', 'Connected');
|
|
1882
1900
|
sessionSpan.textContent = sessionId ? 'Session: ' + sessionId : '';
|
|
1883
|
-
term.
|
|
1884
|
-
\x1B[32m\u2713 Connected to NikCLI\x1B[0m
|
|
1901
|
+
term.writeln('
|
|
1902
|
+
\x1B[32m\u2713 Connected to NikCLI\x1B[0m
|
|
1885
1903
|
');
|
|
1886
1904
|
break;
|
|
1887
1905
|
case 'auth:failed':
|
|
@@ -1889,11 +1907,11 @@ function getWebClient() {
|
|
|
1889
1907
|
authText.textContent = 'Authentication failed';
|
|
1890
1908
|
break;
|
|
1891
1909
|
case 'terminal:output':
|
|
1892
|
-
if (msg.payload?.data) term.
|
|
1910
|
+
if (msg.payload?.data) term.write(msg.payload.data);
|
|
1893
1911
|
break;
|
|
1894
1912
|
case 'terminal:exit':
|
|
1895
|
-
term.
|
|
1896
|
-
\x1B[33m[Process exited: ' + (msg.payload?.code || 0) + ']\x1B[0m
|
|
1913
|
+
term.writeln('
|
|
1914
|
+
\x1B[33m[Process exited: ' + (msg.payload?.code || 0) + ']\x1B[0m
|
|
1897
1915
|
');
|
|
1898
1916
|
break;
|
|
1899
1917
|
}
|
|
@@ -1909,7 +1927,7 @@ function getWebClient() {
|
|
|
1909
1927
|
const value = cmdInput.value.trim();
|
|
1910
1928
|
if (!value || !connected) return;
|
|
1911
1929
|
cmdInput.value = '';
|
|
1912
|
-
term.
|
|
1930
|
+
term.write('$ ' + value + '\r
|
|
1913
1931
|
');
|
|
1914
1932
|
ws.send(JSON.stringify({ type: 'terminal:input', data: value + '\r' }));
|
|
1915
1933
|
setTimeout(() => cmdInput.focus(), 50);
|
|
@@ -1918,7 +1936,7 @@ function getWebClient() {
|
|
|
1918
1936
|
|
|
1919
1937
|
function send(cmd) {
|
|
1920
1938
|
if (!connected) return;
|
|
1921
|
-
term.
|
|
1939
|
+
term.write('$ ' + cmd + '\r
|
|
1922
1940
|
');
|
|
1923
1941
|
ws.send(JSON.stringify({ type: 'terminal:input', data: cmd + '\r' }));
|
|
1924
1942
|
}
|
|
@@ -1933,6 +1951,8 @@ function getWebClient() {
|
|
|
1933
1951
|
document.getElementById('terminal')?.addEventListener('click', () => {
|
|
1934
1952
|
if (connected) cmdInput.focus();
|
|
1935
1953
|
});
|
|
1954
|
+
|
|
1955
|
+
connect();
|
|
1936
1956
|
</script>
|
|
1937
1957
|
</body>
|
|
1938
1958
|
</html>`;
|
package/dist/index.cjs
CHANGED
|
@@ -5507,6 +5507,7 @@ function getWebClient() {
|
|
|
5507
5507
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
5508
5508
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
5509
5509
|
<title>NikCLI Remote</title>
|
|
5510
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
|
|
5510
5511
|
<style>
|
|
5511
5512
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
5512
5513
|
:root {
|
|
@@ -5524,7 +5525,7 @@ function getWebClient() {
|
|
|
5524
5525
|
display: flex;
|
|
5525
5526
|
flex-direction: column;
|
|
5526
5527
|
}
|
|
5527
|
-
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); }
|
|
5528
|
+
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); padding: 8px; }
|
|
5528
5529
|
#input-area {
|
|
5529
5530
|
background: var(--bg-secondary);
|
|
5530
5531
|
border-top: 1px solid var(--border);
|
|
@@ -5639,10 +5640,10 @@ function getWebClient() {
|
|
|
5639
5640
|
</form>
|
|
5640
5641
|
</div>
|
|
5641
5642
|
|
|
5642
|
-
|
|
5643
|
-
<script src="https://cdn.jsdelivr.net/npm/
|
|
5643
|
+
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
|
|
5644
|
+
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
|
|
5644
5645
|
<script>
|
|
5645
|
-
let ws = null, term = null, connected = false, reconnectAttempts = 0;
|
|
5646
|
+
let ws = null, term = null, fitAddon = null, connected = false, reconnectAttempts = 0;
|
|
5646
5647
|
const token = new URLSearchParams(location.search).get('t') || '';
|
|
5647
5648
|
const sessionId = new URLSearchParams(location.search).get('s') || '';
|
|
5648
5649
|
|
|
@@ -5654,40 +5655,57 @@ function getWebClient() {
|
|
|
5654
5655
|
const sessionSpan = document.getElementById('session-id');
|
|
5655
5656
|
const cmdInput = document.getElementById('cmd-input');
|
|
5656
5657
|
|
|
5657
|
-
// Initialize
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5658
|
+
// Initialize xterm.js
|
|
5659
|
+
term = new Terminal({
|
|
5660
|
+
cursorBlink: true,
|
|
5661
|
+
fontSize: 14,
|
|
5662
|
+
fontFamily: '"SF Mono", Monaco, Consolas, monospace',
|
|
5663
|
+
theme: {
|
|
5664
|
+
background: '#0d1117',
|
|
5665
|
+
foreground: '#e6edf3',
|
|
5666
|
+
cursor: '#3fb950',
|
|
5667
|
+
selectionBackground: '#264f78',
|
|
5668
|
+
black: '#484f58',
|
|
5669
|
+
red: '#f85149',
|
|
5670
|
+
green: '#3fb950',
|
|
5671
|
+
yellow: '#d29922',
|
|
5672
|
+
blue: '#58a6ff',
|
|
5673
|
+
magenta: '#a371f7',
|
|
5674
|
+
cyan: '#39c5cf',
|
|
5675
|
+
white: '#e6edf3',
|
|
5676
|
+
brightBlack: '#6e7681',
|
|
5677
|
+
brightRed: '#ffa198',
|
|
5678
|
+
brightGreen: '#7ee787',
|
|
5679
|
+
brightYellow: '#f0883e',
|
|
5680
|
+
brightBlue: '#79c0ff',
|
|
5681
|
+
brightMagenta: '#d2a8ff',
|
|
5682
|
+
brightCyan: '#56d4db',
|
|
5683
|
+
brightWhite: '#f0f6fc'
|
|
5684
|
+
},
|
|
5685
|
+
convertEol: true
|
|
5686
|
+
});
|
|
5671
5687
|
|
|
5672
|
-
|
|
5673
|
-
term.
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
');
|
|
5678
|
-
connect();
|
|
5679
|
-
};
|
|
5680
|
-
term.decorate(document.getElementById('terminal'));
|
|
5681
|
-
term.start();
|
|
5688
|
+
fitAddon = new FitAddon.FitAddon();
|
|
5689
|
+
term.loadAddon(fitAddon);
|
|
5690
|
+
term.open(document.getElementById('terminal'));
|
|
5691
|
+
fitAddon.fit();
|
|
5692
|
+
term.writeln('\x1B[32mInitializing NikCLI Remote...\x1B[0m');
|
|
5693
|
+
term.writeln('\x1B[90mType commands below\x1B[0m');
|
|
5682
5694
|
|
|
5683
5695
|
// Resize handler
|
|
5684
5696
|
window.addEventListener('resize', () => {
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
term.setHeightAndWidth(el.clientHeight / 17, el.clientWidth / 8.53);
|
|
5688
|
-
}
|
|
5697
|
+
clearTimeout(window.resizeTimer);
|
|
5698
|
+
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
5689
5699
|
});
|
|
5690
5700
|
|
|
5701
|
+
// Visual viewport for mobile keyboard
|
|
5702
|
+
if (window.visualViewport) {
|
|
5703
|
+
window.visualViewport.addEventListener('resize', () => {
|
|
5704
|
+
clearTimeout(window.resizeTimer);
|
|
5705
|
+
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
5706
|
+
});
|
|
5707
|
+
}
|
|
5708
|
+
|
|
5691
5709
|
function connect() {
|
|
5692
5710
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
5693
5711
|
ws = new WebSocket(protocol + '//' + location.host + '/ws');
|
|
@@ -5722,8 +5740,8 @@ function getWebClient() {
|
|
|
5722
5740
|
authOverlay.classList.add('hidden');
|
|
5723
5741
|
setStatus('connected', 'Connected');
|
|
5724
5742
|
sessionSpan.textContent = sessionId ? 'Session: ' + sessionId : '';
|
|
5725
|
-
term.
|
|
5726
|
-
\x1B[32m\u2713 Connected to NikCLI\x1B[0m
|
|
5743
|
+
term.writeln('
|
|
5744
|
+
\x1B[32m\u2713 Connected to NikCLI\x1B[0m
|
|
5727
5745
|
');
|
|
5728
5746
|
break;
|
|
5729
5747
|
case 'auth:failed':
|
|
@@ -5731,11 +5749,11 @@ function getWebClient() {
|
|
|
5731
5749
|
authText.textContent = 'Authentication failed';
|
|
5732
5750
|
break;
|
|
5733
5751
|
case 'terminal:output':
|
|
5734
|
-
if (msg.payload?.data) term.
|
|
5752
|
+
if (msg.payload?.data) term.write(msg.payload.data);
|
|
5735
5753
|
break;
|
|
5736
5754
|
case 'terminal:exit':
|
|
5737
|
-
term.
|
|
5738
|
-
\x1B[33m[Process exited: ' + (msg.payload?.code || 0) + ']\x1B[0m
|
|
5755
|
+
term.writeln('
|
|
5756
|
+
\x1B[33m[Process exited: ' + (msg.payload?.code || 0) + ']\x1B[0m
|
|
5739
5757
|
');
|
|
5740
5758
|
break;
|
|
5741
5759
|
}
|
|
@@ -5751,7 +5769,7 @@ function getWebClient() {
|
|
|
5751
5769
|
const value = cmdInput.value.trim();
|
|
5752
5770
|
if (!value || !connected) return;
|
|
5753
5771
|
cmdInput.value = '';
|
|
5754
|
-
term.
|
|
5772
|
+
term.write('$ ' + value + '\r
|
|
5755
5773
|
');
|
|
5756
5774
|
ws.send(JSON.stringify({ type: 'terminal:input', data: value + '\r' }));
|
|
5757
5775
|
setTimeout(() => cmdInput.focus(), 50);
|
|
@@ -5760,7 +5778,7 @@ function getWebClient() {
|
|
|
5760
5778
|
|
|
5761
5779
|
function send(cmd) {
|
|
5762
5780
|
if (!connected) return;
|
|
5763
|
-
term.
|
|
5781
|
+
term.write('$ ' + cmd + '\r
|
|
5764
5782
|
');
|
|
5765
5783
|
ws.send(JSON.stringify({ type: 'terminal:input', data: cmd + '\r' }));
|
|
5766
5784
|
}
|
|
@@ -5775,6 +5793,8 @@ function getWebClient() {
|
|
|
5775
5793
|
document.getElementById('terminal')?.addEventListener('click', () => {
|
|
5776
5794
|
if (connected) cmdInput.focus();
|
|
5777
5795
|
});
|
|
5796
|
+
|
|
5797
|
+
connect();
|
|
5778
5798
|
</script>
|
|
5779
5799
|
</body>
|
|
5780
5800
|
</html>`;
|
package/dist/index.d.cts
CHANGED
|
@@ -285,7 +285,7 @@ declare class TerminalManager extends EventEmitter {
|
|
|
285
285
|
|
|
286
286
|
/**
|
|
287
287
|
* @nikcli/remote - Ghostty-web Style Terminal Client
|
|
288
|
-
* Uses
|
|
288
|
+
* Uses xterm.js with full terminal emulation
|
|
289
289
|
*/
|
|
290
290
|
declare function getWebClient(): string;
|
|
291
291
|
|
package/dist/index.d.ts
CHANGED
|
@@ -285,7 +285,7 @@ declare class TerminalManager extends EventEmitter {
|
|
|
285
285
|
|
|
286
286
|
/**
|
|
287
287
|
* @nikcli/remote - Ghostty-web Style Terminal Client
|
|
288
|
-
* Uses
|
|
288
|
+
* Uses xterm.js with full terminal emulation
|
|
289
289
|
*/
|
|
290
290
|
declare function getWebClient(): string;
|
|
291
291
|
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
RemoteServer,
|
|
5
5
|
TerminalManager,
|
|
6
6
|
getWebClient
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ONRUR3Z7.js";
|
|
8
8
|
import "./chunk-MCKGQKYU.js";
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
11
|
async function createRemoteServer(config = {}) {
|
|
12
|
-
const { RemoteServer: RemoteServer2 } = await import("./server-
|
|
12
|
+
const { RemoteServer: RemoteServer2 } = await import("./server-MURDBK6L.js");
|
|
13
13
|
const server = new RemoteServer2(config);
|
|
14
14
|
const session = await server.start();
|
|
15
15
|
return { server, session };
|
package/package.json
CHANGED
package/src/web-client.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @nikcli/remote - Ghostty-web Style Terminal Client
|
|
3
|
-
* Uses
|
|
3
|
+
* Uses xterm.js with full terminal emulation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export function getWebClient(): string {
|
|
@@ -12,6 +12,7 @@ export function getWebClient(): string {
|
|
|
12
12
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
13
13
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
14
14
|
<title>NikCLI Remote</title>
|
|
15
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
|
|
15
16
|
<style>
|
|
16
17
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
18
|
:root {
|
|
@@ -29,7 +30,7 @@ export function getWebClient(): string {
|
|
|
29
30
|
display: flex;
|
|
30
31
|
flex-direction: column;
|
|
31
32
|
}
|
|
32
|
-
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); }
|
|
33
|
+
#terminal { flex: 1; overflow: hidden; background: var(--bg-primary); padding: 8px; }
|
|
33
34
|
#input-area {
|
|
34
35
|
background: var(--bg-secondary);
|
|
35
36
|
border-top: 1px solid var(--border);
|
|
@@ -144,10 +145,10 @@ export function getWebClient(): string {
|
|
|
144
145
|
</form>
|
|
145
146
|
</div>
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
<script src="https://cdn.jsdelivr.net/npm/
|
|
148
|
+
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
|
|
149
|
+
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
|
|
149
150
|
<script>
|
|
150
|
-
let ws = null, term = null, connected = false, reconnectAttempts = 0;
|
|
151
|
+
let ws = null, term = null, fitAddon = null, connected = false, reconnectAttempts = 0;
|
|
151
152
|
const token = new URLSearchParams(location.search).get('t') || '';
|
|
152
153
|
const sessionId = new URLSearchParams(location.search).get('s') || '';
|
|
153
154
|
|
|
@@ -159,38 +160,57 @@ export function getWebClient(): string {
|
|
|
159
160
|
const sessionSpan = document.getElementById('session-id');
|
|
160
161
|
const cmdInput = document.getElementById('cmd-input');
|
|
161
162
|
|
|
162
|
-
// Initialize
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
163
|
+
// Initialize xterm.js
|
|
164
|
+
term = new Terminal({
|
|
165
|
+
cursorBlink: true,
|
|
166
|
+
fontSize: 14,
|
|
167
|
+
fontFamily: '"SF Mono", Monaco, Consolas, monospace',
|
|
168
|
+
theme: {
|
|
169
|
+
background: '#0d1117',
|
|
170
|
+
foreground: '#e6edf3',
|
|
171
|
+
cursor: '#3fb950',
|
|
172
|
+
selectionBackground: '#264f78',
|
|
173
|
+
black: '#484f58',
|
|
174
|
+
red: '#f85149',
|
|
175
|
+
green: '#3fb950',
|
|
176
|
+
yellow: '#d29922',
|
|
177
|
+
blue: '#58a6ff',
|
|
178
|
+
magenta: '#a371f7',
|
|
179
|
+
cyan: '#39c5cf',
|
|
180
|
+
white: '#e6edf3',
|
|
181
|
+
brightBlack: '#6e7681',
|
|
182
|
+
brightRed: '#ffa198',
|
|
183
|
+
brightGreen: '#7ee787',
|
|
184
|
+
brightYellow: '#f0883e',
|
|
185
|
+
brightBlue: '#79c0ff',
|
|
186
|
+
brightMagenta: '#d2a8ff',
|
|
187
|
+
brightCyan: '#56d4db',
|
|
188
|
+
brightWhite: '#f0f6fc'
|
|
189
|
+
},
|
|
190
|
+
convertEol: true
|
|
191
|
+
});
|
|
176
192
|
|
|
177
|
-
|
|
178
|
-
term.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
term.decorate(document.getElementById('terminal'));
|
|
184
|
-
term.start();
|
|
193
|
+
fitAddon = new FitAddon.FitAddon();
|
|
194
|
+
term.loadAddon(fitAddon);
|
|
195
|
+
term.open(document.getElementById('terminal'));
|
|
196
|
+
fitAddon.fit();
|
|
197
|
+
term.writeln('\x1b[32mInitializing NikCLI Remote...\x1b[0m');
|
|
198
|
+
term.writeln('\x1b[90mType commands below\x1b[0m');
|
|
185
199
|
|
|
186
200
|
// Resize handler
|
|
187
201
|
window.addEventListener('resize', () => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
term.setHeightAndWidth(el.clientHeight / 17, el.clientWidth / 8.53);
|
|
191
|
-
}
|
|
202
|
+
clearTimeout(window.resizeTimer);
|
|
203
|
+
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
192
204
|
});
|
|
193
205
|
|
|
206
|
+
// Visual viewport for mobile keyboard
|
|
207
|
+
if (window.visualViewport) {
|
|
208
|
+
window.visualViewport.addEventListener('resize', () => {
|
|
209
|
+
clearTimeout(window.resizeTimer);
|
|
210
|
+
window.resizeTimer = setTimeout(() => fitAddon.fit(), 100);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
194
214
|
function connect() {
|
|
195
215
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
196
216
|
ws = new WebSocket(protocol + '//' + location.host + '/ws');
|
|
@@ -225,17 +245,17 @@ export function getWebClient(): string {
|
|
|
225
245
|
authOverlay.classList.add('hidden');
|
|
226
246
|
setStatus('connected', 'Connected');
|
|
227
247
|
sessionSpan.textContent = sessionId ? 'Session: ' + sessionId : '';
|
|
228
|
-
term.
|
|
248
|
+
term.writeln('\n\x1b[32m✓ Connected to NikCLI\x1b[0m\n');
|
|
229
249
|
break;
|
|
230
250
|
case 'auth:failed':
|
|
231
251
|
authMsg.classList.add('error');
|
|
232
252
|
authText.textContent = 'Authentication failed';
|
|
233
253
|
break;
|
|
234
254
|
case 'terminal:output':
|
|
235
|
-
if (msg.payload?.data) term.
|
|
255
|
+
if (msg.payload?.data) term.write(msg.payload.data);
|
|
236
256
|
break;
|
|
237
257
|
case 'terminal:exit':
|
|
238
|
-
term.
|
|
258
|
+
term.writeln('\n\x1b[33m[Process exited: ' + (msg.payload?.code || 0) + ']\x1b[0m\n');
|
|
239
259
|
break;
|
|
240
260
|
}
|
|
241
261
|
}
|
|
@@ -250,7 +270,7 @@ export function getWebClient(): string {
|
|
|
250
270
|
const value = cmdInput.value.trim();
|
|
251
271
|
if (!value || !connected) return;
|
|
252
272
|
cmdInput.value = '';
|
|
253
|
-
term.
|
|
273
|
+
term.write('$ ' + value + '\r\n');
|
|
254
274
|
ws.send(JSON.stringify({ type: 'terminal:input', data: value + '\r' }));
|
|
255
275
|
setTimeout(() => cmdInput.focus(), 50);
|
|
256
276
|
return false;
|
|
@@ -258,7 +278,7 @@ export function getWebClient(): string {
|
|
|
258
278
|
|
|
259
279
|
function send(cmd) {
|
|
260
280
|
if (!connected) return;
|
|
261
|
-
term.
|
|
281
|
+
term.write('$ ' + cmd + '\r\n');
|
|
262
282
|
ws.send(JSON.stringify({ type: 'terminal:input', data: cmd + '\r' }));
|
|
263
283
|
}
|
|
264
284
|
|
|
@@ -272,6 +292,8 @@ export function getWebClient(): string {
|
|
|
272
292
|
document.getElementById('terminal')?.addEventListener('click', () => {
|
|
273
293
|
if (connected) cmdInput.focus();
|
|
274
294
|
});
|
|
295
|
+
|
|
296
|
+
connect();
|
|
275
297
|
</script>
|
|
276
298
|
</body>
|
|
277
299
|
</html>`;
|