@darksol/terminal 0.10.0 → 0.11.0
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 +111 -1
- package/package.json +4 -1
- package/src/browser/actions.js +58 -0
- package/src/cli.js +136 -0
- package/src/config/keys.js +12 -2
- package/src/daemon/index.js +225 -0
- package/src/daemon/manager.js +148 -0
- package/src/daemon/pid.js +80 -0
- package/src/services/browser.js +659 -0
- package/src/services/telegram.js +570 -0
- package/src/web/commands.js +135 -1
- package/src/web/server.js +21 -2
package/src/web/commands.js
CHANGED
|
@@ -11,6 +11,7 @@ import { spawn } from 'child_process';
|
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
import { getConfiguredModel, getModelSelectionMeta, getProviderDefaultModel } from '../llm/models.js';
|
|
13
13
|
import { pokerNewGame, pokerAction, pokerStatus, pokerHistory } from '../services/poker.js';
|
|
14
|
+
import { sendBrowserCommand, installPlaywrightBrowsers } from '../services/browser.js';
|
|
14
15
|
|
|
15
16
|
// ══════════════════════════════════════════════════
|
|
16
17
|
// CHAT LOG PERSISTENCE
|
|
@@ -917,6 +918,8 @@ export async function handleCommand(cmd, ws) {
|
|
|
917
918
|
return await cmdCasino(args, ws);
|
|
918
919
|
case 'poker':
|
|
919
920
|
return await cmdPoker(args, ws);
|
|
921
|
+
case 'browser':
|
|
922
|
+
return await cmdBrowser(args, ws);
|
|
920
923
|
case 'facilitator':
|
|
921
924
|
return await cmdFacilitator(args, ws);
|
|
922
925
|
case 'send':
|
|
@@ -940,7 +943,7 @@ export async function handleCommand(cmd, ws) {
|
|
|
940
943
|
return await cmdChatLogs(args, ws);
|
|
941
944
|
default: {
|
|
942
945
|
// Fuzzy: if it looks like natural language, route to AI
|
|
943
|
-
const nlKeywords = /\b(swap|buy|sell|send|transfer|price|what|how|should|analyze|check|balance|gas|dca|order|card|prepaid|visa|mastercard|bet|coinflip|flip|dice|slots|hilo|gamble|play|casino|poker|holdem|bridge|cross-chain|crosschain)\b/i;
|
|
946
|
+
const nlKeywords = /\b(swap|buy|sell|send|transfer|price|what|how|should|analyze|check|balance|gas|dca|order|card|prepaid|visa|mastercard|bet|coinflip|flip|dice|slots|hilo|gamble|play|casino|poker|holdem|bridge|cross-chain|crosschain|browser|screenshot|click)\b/i;
|
|
944
947
|
if (nlKeywords.test(cmd)) {
|
|
945
948
|
return await cmdAI(cmd.split(/\s+/), ws);
|
|
946
949
|
}
|
|
@@ -954,6 +957,137 @@ export async function handleCommand(cmd, ws) {
|
|
|
954
957
|
// ══════════════════════════════════════════════════
|
|
955
958
|
// PRICE
|
|
956
959
|
// ══════════════════════════════════════════════════
|
|
960
|
+
async function cmdBrowser(args, ws) {
|
|
961
|
+
const sub = args[0]?.toLowerCase() || 'status';
|
|
962
|
+
|
|
963
|
+
if (sub === 'help') {
|
|
964
|
+
ws.sendLine(`${ANSI.gold} ◆ BROWSER AUTOMATION${ANSI.reset}`);
|
|
965
|
+
ws.sendLine(`${ANSI.dim} ${'─'.repeat(50)}${ANSI.reset}`);
|
|
966
|
+
ws.sendLine('');
|
|
967
|
+
ws.sendLine(` ${ANSI.green}browser status${ANSI.reset} ${ANSI.dim}Show browser state${ANSI.reset}`);
|
|
968
|
+
ws.sendLine(` ${ANSI.green}browser navigate https://...${ANSI.reset} ${ANSI.dim}Navigate active page${ANSI.reset}`);
|
|
969
|
+
ws.sendLine(` ${ANSI.green}browser screenshot${ANSI.reset} ${ANSI.dim}Save + refresh browser panel${ANSI.reset}`);
|
|
970
|
+
ws.sendLine(` ${ANSI.green}browser click <selector>${ANSI.reset} ${ANSI.dim}Click an element${ANSI.reset}`);
|
|
971
|
+
ws.sendLine(` ${ANSI.green}browser type <selector> <text>${ANSI.reset} ${ANSI.dim}Type text into an input${ANSI.reset}`);
|
|
972
|
+
ws.sendLine(` ${ANSI.green}browser eval <js>${ANSI.reset} ${ANSI.dim}Run JavaScript in page context${ANSI.reset}`);
|
|
973
|
+
ws.sendLine(` ${ANSI.green}browser close${ANSI.reset} ${ANSI.dim}Close the browser service${ANSI.reset}`);
|
|
974
|
+
ws.sendLine('');
|
|
975
|
+
return {};
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
if (sub === 'install') {
|
|
979
|
+
try {
|
|
980
|
+
await installPlaywrightBrowsers();
|
|
981
|
+
ws.sendLine(` ${ANSI.green}✓ Playwright Chromium install complete${ANSI.reset}`);
|
|
982
|
+
ws.sendLine('');
|
|
983
|
+
} catch (err) {
|
|
984
|
+
ws.sendLine(` ${ANSI.red}✗ ${err.message}${ANSI.reset}`);
|
|
985
|
+
ws.sendLine('');
|
|
986
|
+
}
|
|
987
|
+
return {};
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
try {
|
|
991
|
+
if (sub === 'status') {
|
|
992
|
+
const status = await sendBrowserCommand('status');
|
|
993
|
+
ws.sendLine(`${ANSI.gold} ◆ BROWSER STATUS${ANSI.reset}`);
|
|
994
|
+
ws.sendLine(`${ANSI.dim} ${'─'.repeat(50)}${ANSI.reset}`);
|
|
995
|
+
ws.sendLine(` ${ANSI.darkGold}Running${ANSI.reset} ${status.running ? ANSI.green + 'yes' : ANSI.dim + 'no'}${ANSI.reset}`);
|
|
996
|
+
ws.sendLine(` ${ANSI.darkGold}Type${ANSI.reset} ${ANSI.white}${status.browserType || 'chromium'}${ANSI.reset}`);
|
|
997
|
+
ws.sendLine(` ${ANSI.darkGold}Profile${ANSI.reset} ${ANSI.white}${status.profile || 'default'}${ANSI.reset}`);
|
|
998
|
+
ws.sendLine(` ${ANSI.darkGold}Mode${ANSI.reset} ${ANSI.white}${status.headed ? 'headed' : 'headless'}${ANSI.reset}`);
|
|
999
|
+
ws.sendLine(` ${ANSI.darkGold}URL${ANSI.reset} ${status.url ? ANSI.white + status.url : ANSI.dim + '(blank)'}${ANSI.reset}`);
|
|
1000
|
+
ws.sendLine(` ${ANSI.darkGold}Title${ANSI.reset} ${status.title ? ANSI.white + status.title : ANSI.dim + '(none)'}${ANSI.reset}`);
|
|
1001
|
+
ws.sendLine(` ${ANSI.darkGold}Pages${ANSI.reset} ${ANSI.white}${status.pageCount || 0}${ANSI.reset}`);
|
|
1002
|
+
ws.sendLine('');
|
|
1003
|
+
return {};
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (sub === 'navigate') {
|
|
1007
|
+
const url = args[1];
|
|
1008
|
+
if (!url) {
|
|
1009
|
+
ws.sendLine(` ${ANSI.dim}Usage: browser navigate <url>${ANSI.reset}`);
|
|
1010
|
+
ws.sendLine('');
|
|
1011
|
+
return {};
|
|
1012
|
+
}
|
|
1013
|
+
const status = await sendBrowserCommand('navigate', { url });
|
|
1014
|
+
ws.sendLine(` ${ANSI.green}✓ Navigated to ${status.url}${ANSI.reset}`);
|
|
1015
|
+
ws.sendLine('');
|
|
1016
|
+
ws.send(JSON.stringify({ type: 'browser:refresh' }));
|
|
1017
|
+
return {};
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
if (sub === 'screenshot') {
|
|
1021
|
+
const result = await sendBrowserCommand('screenshot', {});
|
|
1022
|
+
ws.sendLine(` ${ANSI.green}✓ Screenshot saved${ANSI.reset}`);
|
|
1023
|
+
ws.sendLine(` ${ANSI.dim}${result.path}${ANSI.reset}`);
|
|
1024
|
+
ws.sendLine('');
|
|
1025
|
+
ws.send(JSON.stringify({ type: 'browser:refresh' }));
|
|
1026
|
+
return {};
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (sub === 'click') {
|
|
1030
|
+
const selector = args[1];
|
|
1031
|
+
if (!selector) {
|
|
1032
|
+
ws.sendLine(` ${ANSI.dim}Usage: browser click <selector>${ANSI.reset}`);
|
|
1033
|
+
ws.sendLine('');
|
|
1034
|
+
return {};
|
|
1035
|
+
}
|
|
1036
|
+
await sendBrowserCommand('click', { selector });
|
|
1037
|
+
ws.sendLine(` ${ANSI.green}✓ Clicked ${selector}${ANSI.reset}`);
|
|
1038
|
+
ws.sendLine('');
|
|
1039
|
+
return {};
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
if (sub === 'type') {
|
|
1043
|
+
const selector = args[1];
|
|
1044
|
+
const text = args.slice(2).join(' ');
|
|
1045
|
+
if (!selector || !text) {
|
|
1046
|
+
ws.sendLine(` ${ANSI.dim}Usage: browser type <selector> <text>${ANSI.reset}`);
|
|
1047
|
+
ws.sendLine('');
|
|
1048
|
+
return {};
|
|
1049
|
+
}
|
|
1050
|
+
await sendBrowserCommand('type', { selector, text });
|
|
1051
|
+
ws.sendLine(` ${ANSI.green}✓ Typed into ${selector}${ANSI.reset}`);
|
|
1052
|
+
ws.sendLine('');
|
|
1053
|
+
return {};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (sub === 'eval') {
|
|
1057
|
+
const expression = args.slice(1).join(' ');
|
|
1058
|
+
if (!expression) {
|
|
1059
|
+
ws.sendLine(` ${ANSI.dim}Usage: browser eval <js>${ANSI.reset}`);
|
|
1060
|
+
ws.sendLine('');
|
|
1061
|
+
return {};
|
|
1062
|
+
}
|
|
1063
|
+
const result = await sendBrowserCommand('eval', { expression });
|
|
1064
|
+
ws.sendLine(`${ANSI.gold} ◆ BROWSER EVAL${ANSI.reset}`);
|
|
1065
|
+
ws.sendLine(`${ANSI.dim} ${'─'.repeat(50)}${ANSI.reset}`);
|
|
1066
|
+
ws.sendLine(` ${ANSI.white}${String(result.formatted)}${ANSI.reset}`);
|
|
1067
|
+
ws.sendLine('');
|
|
1068
|
+
return {};
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (sub === 'close') {
|
|
1072
|
+
await sendBrowserCommand('close');
|
|
1073
|
+
ws.sendLine(` ${ANSI.green}✓ Browser closed${ANSI.reset}`);
|
|
1074
|
+
ws.sendLine('');
|
|
1075
|
+
ws.send(JSON.stringify({ type: 'browser:refresh' }));
|
|
1076
|
+
return {};
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
ws.sendLine(` ${ANSI.red}✗ Unknown browser subcommand: ${sub}${ANSI.reset}`);
|
|
1080
|
+
ws.sendLine(` ${ANSI.dim}Try: browser help${ANSI.reset}`);
|
|
1081
|
+
ws.sendLine('');
|
|
1082
|
+
} catch (err) {
|
|
1083
|
+
ws.sendLine(` ${ANSI.red}✗ ${err.message}${ANSI.reset}`);
|
|
1084
|
+
ws.sendLine(` ${ANSI.dim}Start it with: darksol browser launch${ANSI.reset}`);
|
|
1085
|
+
ws.sendLine('');
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
return {};
|
|
1089
|
+
}
|
|
1090
|
+
|
|
957
1091
|
async function cmdPrice(tokens, ws) {
|
|
958
1092
|
if (!tokens.length) {
|
|
959
1093
|
return { output: ` ${ANSI.dim}Usage: price ETH AERO VIRTUAL${ANSI.reset}\r\n` };
|
package/src/web/server.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createServer } from 'http';
|
|
2
2
|
import { WebSocketServer } from 'ws';
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { dirname, join } from 'path';
|
|
6
6
|
import open from 'open';
|
|
7
7
|
import { theme } from '../ui/theme.js';
|
|
8
8
|
import { getRecentMemories } from '../memory/index.js';
|
|
9
9
|
import { getSoul, hasSoul } from '../soul/index.js';
|
|
10
|
+
import { getBrowserScreenshotPath, sendBrowserCommand } from '../services/browser.js';
|
|
10
11
|
import { createRequire } from 'module';
|
|
11
12
|
const require = createRequire(import.meta.url);
|
|
12
13
|
const { version: PKG_VERSION } = require('../../package.json');
|
|
@@ -36,7 +37,7 @@ export async function startWebShell(opts = {}) {
|
|
|
36
37
|
const css = readFileSync(join(__dirname, 'terminal.css'), 'utf-8');
|
|
37
38
|
const js = readFileSync(join(__dirname, 'terminal.js'), 'utf-8');
|
|
38
39
|
|
|
39
|
-
const server = createServer((req, res) => {
|
|
40
|
+
const server = createServer(async (req, res) => {
|
|
40
41
|
try {
|
|
41
42
|
const pathname = req.url.split('?')[0];
|
|
42
43
|
|
|
@@ -52,6 +53,24 @@ export async function startWebShell(opts = {}) {
|
|
|
52
53
|
} else if (pathname === '/health') {
|
|
53
54
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
54
55
|
res.end(JSON.stringify({ status: 'ok', version: PKG_VERSION }));
|
|
56
|
+
} else if (pathname === '/browser/status') {
|
|
57
|
+
try {
|
|
58
|
+
const status = await sendBrowserCommand('status');
|
|
59
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
60
|
+
res.end(JSON.stringify(status));
|
|
61
|
+
} catch {
|
|
62
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
63
|
+
res.end(JSON.stringify({ running: false }));
|
|
64
|
+
}
|
|
65
|
+
} else if (pathname === '/browser/screenshot') {
|
|
66
|
+
const screenshotPath = getBrowserScreenshotPath();
|
|
67
|
+
if (!existsSync(screenshotPath)) {
|
|
68
|
+
res.writeHead(404);
|
|
69
|
+
res.end('No screenshot available');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
res.writeHead(200, { 'Content-Type': 'image/png', 'Cache-Control': 'no-store' });
|
|
73
|
+
res.end(readFileSync(screenshotPath));
|
|
55
74
|
} else {
|
|
56
75
|
res.writeHead(404);
|
|
57
76
|
res.end('Not found');
|