junis 0.1.1 → 0.1.2
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/cli/index.js +128 -31
- package/dist/server/mcp.js +0 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -55,9 +55,11 @@ function clearConfig() {
|
|
|
55
55
|
var import_open = __toESM(require("open"));
|
|
56
56
|
var JUNIS_API = process.env.JUNIS_API_URL ?? "https://api.junis.ai";
|
|
57
57
|
var JUNIS_WEB = process.env.JUNIS_WEB_URL ?? "https://junis.ai";
|
|
58
|
-
async function authenticate() {
|
|
58
|
+
async function authenticate(deviceName, platform2, onBrowserOpen, onWaiting) {
|
|
59
59
|
const startRes = await fetch(`${JUNIS_API}/api/auth/device/start`, {
|
|
60
|
-
method: "POST"
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: { "Content-Type": "application/json" },
|
|
62
|
+
body: JSON.stringify({ device_name: deviceName, platform: platform2 })
|
|
61
63
|
});
|
|
62
64
|
if (!startRes.ok) {
|
|
63
65
|
throw new Error(`Auth \uC2DC\uC791 \uC2E4\uD328: ${startRes.status}`);
|
|
@@ -67,24 +69,27 @@ async function authenticate() {
|
|
|
67
69
|
/^https?:\/\/[^/]+/,
|
|
68
70
|
JUNIS_WEB
|
|
69
71
|
);
|
|
70
|
-
|
|
71
|
-
console.log(` URL: ${verificationUri}
|
|
72
|
-
`);
|
|
72
|
+
onBrowserOpen?.(verificationUri);
|
|
73
73
|
await (0, import_open.default)(verificationUri);
|
|
74
74
|
const deadline = Date.now() + startData.expires_in * 1e3;
|
|
75
75
|
const intervalMs = startData.interval * 1e3;
|
|
76
|
+
let waitingCallbackCalled = false;
|
|
76
77
|
while (Date.now() < deadline) {
|
|
77
78
|
await sleep(intervalMs);
|
|
78
79
|
const pollRes = await fetch(
|
|
79
80
|
`${JUNIS_API}/api/auth/device/poll?code=${startData.device_code}`
|
|
80
81
|
);
|
|
81
82
|
if (pollRes.status === 202) {
|
|
82
|
-
|
|
83
|
+
if (!waitingCallbackCalled) {
|
|
84
|
+
waitingCallbackCalled = true;
|
|
85
|
+
onWaiting?.();
|
|
86
|
+
} else {
|
|
87
|
+
onWaiting?.();
|
|
88
|
+
}
|
|
83
89
|
continue;
|
|
84
90
|
}
|
|
85
91
|
if (pollRes.status === 200) {
|
|
86
92
|
const result = await pollRes.json();
|
|
87
|
-
console.log("\n\u2705 \uC778\uC99D \uC644\uB8CC!\n");
|
|
88
93
|
return result;
|
|
89
94
|
}
|
|
90
95
|
if (pollRes.status === 410) {
|
|
@@ -885,7 +890,6 @@ async function startMCPServer(port) {
|
|
|
885
890
|
const actualPort = await tryListen(httpServer, port, 10);
|
|
886
891
|
resolvedPort = actualPort;
|
|
887
892
|
mcpPort = actualPort;
|
|
888
|
-
console.log(`MCP \uC11C\uBC84 \uC2DC\uC791: http://localhost:${actualPort}/mcp`);
|
|
889
893
|
const cleanup = async () => {
|
|
890
894
|
if (globalBrowserTools) {
|
|
891
895
|
await globalBrowserTools.cleanup();
|
|
@@ -929,38 +933,137 @@ async function handleMCPRequest(id, payload) {
|
|
|
929
933
|
}
|
|
930
934
|
|
|
931
935
|
// src/cli/index.ts
|
|
932
|
-
import_commander.program.name("junis").description("AI\uAC00 \uB0B4 \uB514\uBC14\uC774\uC2A4\uB97C \uC644\uC804 \uC81C\uC5B4\uD558\uB294 MCP \uC11C\uBC84").version("0.1.
|
|
936
|
+
import_commander.program.name("junis").description("AI\uAC00 \uB0B4 \uB514\uBC14\uC774\uC2A4\uB97C \uC644\uC804 \uC81C\uC5B4\uD558\uB294 MCP \uC11C\uBC84").version("0.1.2");
|
|
937
|
+
function getSystemInfo() {
|
|
938
|
+
const platform2 = process.platform;
|
|
939
|
+
if (platform2 === "darwin") {
|
|
940
|
+
try {
|
|
941
|
+
const { execSync } = require("child_process");
|
|
942
|
+
const sw = execSync("sw_vers -productVersion", { encoding: "utf8" }).trim();
|
|
943
|
+
const hw = execSync("sysctl -n machdep.cpu.brand_string", { encoding: "utf8" }).trim();
|
|
944
|
+
return `macOS ${sw} (${hw})`;
|
|
945
|
+
} catch {
|
|
946
|
+
return "macOS";
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (platform2 === "win32") return "Windows";
|
|
950
|
+
return "Linux";
|
|
951
|
+
}
|
|
952
|
+
function getDeviceName() {
|
|
953
|
+
const platform2 = process.platform;
|
|
954
|
+
if (platform2 === "darwin") return "Mac";
|
|
955
|
+
if (platform2 === "win32") return "Windows PC";
|
|
956
|
+
return "Linux PC";
|
|
957
|
+
}
|
|
958
|
+
function printBanner() {
|
|
959
|
+
console.log("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
960
|
+
console.log("\u2551 \u2551");
|
|
961
|
+
console.log("\u2551 \u{1F99E} J U N I S v0.1.2 \u2551");
|
|
962
|
+
console.log("\u2551 \u2551");
|
|
963
|
+
console.log("\u2551 Device Agent for AI Teams \u2551");
|
|
964
|
+
console.log("\u2551 \u2551");
|
|
965
|
+
console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
|
|
966
|
+
console.log("");
|
|
967
|
+
}
|
|
968
|
+
function printStep1(port) {
|
|
969
|
+
const sysInfo = getSystemInfo();
|
|
970
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
971
|
+
console.log(" STEP 1 \xB7 Initializing Device");
|
|
972
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
973
|
+
console.log(` \u25C9 Scanning system ............... ${sysInfo}`);
|
|
974
|
+
console.log(" \u25C9 Loading MCP tools");
|
|
975
|
+
console.log(" \u251C\u2500\u2500 file_system files, directories, search \u2705 ready");
|
|
976
|
+
console.log(" \u251C\u2500\u2500 shell terminal commands, processes \u2705 ready");
|
|
977
|
+
console.log(" \u251C\u2500\u2500 browser web automation via Playwright \u2705 ready");
|
|
978
|
+
console.log(" \u251C\u2500\u2500 notebook Jupyter cell editing \u2705 ready");
|
|
979
|
+
console.log(" \u2514\u2500\u2500 device camera, screen, alerts \u2705 ready");
|
|
980
|
+
console.log(` \u25C9 Local MCP endpoint ........... http://localhost:${port}/mcp`);
|
|
981
|
+
console.log("");
|
|
982
|
+
}
|
|
933
983
|
import_commander.program.command("start", { isDefault: true }).description("Junis \uC5D0\uC774\uC804\uD2B8\uC640 \uC5F0\uACB0 \uC2DC\uC791").option("--local", "\uB85C\uCEEC MCP \uC11C\uBC84\uB9CC \uC2E4\uD589 (\uD074\uB77C\uC6B0\uB4DC \uC5F0\uACB0 \uC5C6\uC74C)").option("--port <number>", "\uD3EC\uD2B8 \uBC88\uD638", "3000").option("--reset", "\uAE30\uC874 \uC778\uC99D \uCD08\uAE30\uD654 \uD6C4 \uC7AC\uB85C\uADF8\uC778").action(async (options) => {
|
|
934
984
|
const port = parseInt(options.port, 10);
|
|
985
|
+
printBanner();
|
|
935
986
|
if (options.local) {
|
|
936
|
-
|
|
937
|
-
|
|
987
|
+
const actualPort = await startMCPServer(port);
|
|
988
|
+
printStep1(actualPort);
|
|
989
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
990
|
+
console.log(" \u2705 ALL SET \u2014 Local MCP server is running");
|
|
991
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
938
992
|
return;
|
|
939
993
|
}
|
|
940
994
|
let config = options.reset ? null : loadConfig();
|
|
941
995
|
if (!config) {
|
|
942
|
-
|
|
943
|
-
const
|
|
996
|
+
const deviceName = `${process.env["USER"] ?? "user"}'s ${getDeviceName()}`;
|
|
997
|
+
const platformName = process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : "linux";
|
|
998
|
+
const actualPort = await startMCPServer(port);
|
|
999
|
+
printStep1(actualPort);
|
|
1000
|
+
let waitingPrinted = false;
|
|
1001
|
+
const authResult = await authenticate(
|
|
1002
|
+
deviceName,
|
|
1003
|
+
platformName,
|
|
1004
|
+
(uri) => {
|
|
1005
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1006
|
+
console.log(" STEP 2 \xB7 Connect to Junis Cloud");
|
|
1007
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1008
|
+
console.log(" Opening browser...");
|
|
1009
|
+
console.log(` \u2192 ${uri}`);
|
|
1010
|
+
process.stdout.write(" Waiting for login \xB7");
|
|
1011
|
+
},
|
|
1012
|
+
() => {
|
|
1013
|
+
if (!waitingPrinted) {
|
|
1014
|
+
waitingPrinted = true;
|
|
1015
|
+
} else {
|
|
1016
|
+
process.stdout.write("\xB7");
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
console.log("");
|
|
1021
|
+
console.log(` \u2705 Authenticated as ${authResult.email ?? "your account"}`);
|
|
1022
|
+
console.log("");
|
|
944
1023
|
config = {
|
|
945
1024
|
device_key: authResult.device_key,
|
|
946
1025
|
token: authResult.token,
|
|
947
|
-
device_name:
|
|
1026
|
+
device_name: deviceName,
|
|
948
1027
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
949
1028
|
};
|
|
950
1029
|
saveConfig(config);
|
|
951
|
-
console.log(
|
|
1030
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1031
|
+
console.log(" STEP 3 \xB7 Register Device");
|
|
1032
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1033
|
+
console.log(` \u25C9 Device name .................. ${deviceName}`);
|
|
1034
|
+
console.log(` \u25C9 Device key ................... ${authResult.device_key}`);
|
|
1035
|
+
console.log(` \u25C9 Cloud relay connected ........ wss://api.junis.ai/ws/devices/${authResult.device_key}`);
|
|
1036
|
+
console.log(" \u25C9 Status ....................... \u{1F7E2} online");
|
|
1037
|
+
console.log("");
|
|
1038
|
+
if (authResult.agent_id) {
|
|
1039
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1040
|
+
console.log(" STEP 4 \xB7 Create AI Team");
|
|
1041
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1042
|
+
console.log(" No existing team found. Creating your first AI team...");
|
|
1043
|
+
console.log(` \u25C9 Agent created ................ ${authResult.agent_name}`);
|
|
1044
|
+
console.log(` \u25C9 Device linked ................ ${deviceName} \u2192 ${authResult.agent_name}`);
|
|
1045
|
+
console.log(" \u25C9 Tools assigned ............... file_system, shell, browser, notebook, device");
|
|
1046
|
+
console.log("");
|
|
1047
|
+
}
|
|
1048
|
+
const relay = new RelayClient(config, handleMCPRequest);
|
|
1049
|
+
await relay.connect();
|
|
952
1050
|
} else {
|
|
953
|
-
|
|
1051
|
+
const actualPort = await startMCPServer(port);
|
|
1052
|
+
printStep1(actualPort);
|
|
1053
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1054
|
+
console.log(" STEP 3 \xB7 Register Device");
|
|
1055
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1056
|
+
console.log(` \u25C9 Device name .................. ${config.device_name}`);
|
|
1057
|
+
console.log(` \u25C9 Device key ................... ${config.device_key}`);
|
|
1058
|
+
console.log(` \u25C9 Cloud relay connected ........ wss://api.junis.ai/ws/devices/${config.device_key}`);
|
|
1059
|
+
console.log(" \u25C9 Status ....................... \u{1F7E2} online");
|
|
1060
|
+
console.log("");
|
|
1061
|
+
const relay = new RelayClient(config, handleMCPRequest);
|
|
1062
|
+
await relay.connect();
|
|
954
1063
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
console.log(`
|
|
959
|
-
\u2728 Junis \uC2DC\uC791 \uC644\uB8CC!
|
|
960
|
-
\uB85C\uCEEC MCP: http://localhost:${actualPort}/mcp
|
|
961
|
-
\uB514\uBC14\uC774\uC2A4: ${config.device_name}
|
|
962
|
-
\uC0C1\uD0DC: \uD074\uB77C\uC6B0\uB4DC \uB9B4\uB808\uC774 \uC5F0\uACB0\uB428
|
|
963
|
-
`);
|
|
1064
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1065
|
+
console.log(" \u2705 ALL SET \u2014 Your AI can now control this device");
|
|
1066
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
964
1067
|
});
|
|
965
1068
|
import_commander.program.command("logout").description("\uC778\uC99D \uC815\uBCF4 \uC0AD\uC81C").action(() => {
|
|
966
1069
|
clearConfig();
|
|
@@ -978,10 +1081,4 @@ import_commander.program.command("status").description("\uD604\uC7AC \uC0C1\uD0D
|
|
|
978
1081
|
);
|
|
979
1082
|
}
|
|
980
1083
|
});
|
|
981
|
-
function getDeviceName() {
|
|
982
|
-
const platform2 = process.platform;
|
|
983
|
-
if (platform2 === "darwin") return "Mac";
|
|
984
|
-
if (platform2 === "win32") return "Windows PC";
|
|
985
|
-
return "Linux PC";
|
|
986
|
-
}
|
|
987
1084
|
import_commander.program.parse();
|
package/dist/server/mcp.js
CHANGED
|
@@ -744,7 +744,6 @@ async function startMCPServer(port) {
|
|
|
744
744
|
const actualPort = await tryListen(httpServer, port, 10);
|
|
745
745
|
resolvedPort = actualPort;
|
|
746
746
|
mcpPort = actualPort;
|
|
747
|
-
console.log(`MCP \uC11C\uBC84 \uC2DC\uC791: http://localhost:${actualPort}/mcp`);
|
|
748
747
|
const cleanup = async () => {
|
|
749
748
|
if (globalBrowserTools) {
|
|
750
749
|
await globalBrowserTools.cleanup();
|