evot-agent 0.2.1 → 0.2.3
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 +15 -5
- package/bin/evot-agent.js +1 -1
- package/package.json +1 -1
- package/src/browse.js +26 -3
- package/src/connect.js +7 -3
- package/src/install.js +3 -1
- package/src/login.js +16 -1
- package/src/sync.js +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ evot에서 Vot에게 "내 컴퓨터 브라우저로 ○○ 수집해줘"라고
|
|
|
13
13
|
|
|
14
14
|
## 설치 & 연결
|
|
15
15
|
|
|
16
|
-
1. evot.io에 로그인 → **Settings → Integrations →
|
|
16
|
+
1. evot.io에 로그인 → **Settings → Integrations → Computer Use** → 코드 발급.
|
|
17
17
|
2. 코드로 연결:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
@@ -36,10 +36,13 @@ npx evot-agent connect <code> # 예: npx evot-agent connect ABCD2345
|
|
|
36
36
|
```bash
|
|
37
37
|
npm install -g evot-agent
|
|
38
38
|
evot-agent start # 기본 10분마다 폴링
|
|
39
|
-
evot-agent install # macOS
|
|
39
|
+
evot-agent install # macOS 전용: 로그인 시 자동 시작 + 백그라운드 상주
|
|
40
40
|
evot-agent uninstall # 상주 등록 해제
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
> `install`은 현재 **macOS(launchd) 전용**이다. Windows/Linux는 `evot-agent start`를
|
|
44
|
+
> 터미널에 띄워두거나, 작업 스케줄러/systemd 등으로 로그인 시 실행되게 등록한다.
|
|
45
|
+
|
|
43
46
|
데몬을 켜두면 evot이 잡을 큐에 넣는 대로 가져와 실행한다. **새 UI는 없다** — 기존처럼 쓰면 된다:
|
|
44
47
|
|
|
45
48
|
- **대화**: 쓰레드에서 Vot 멘션으로 "Use my computer's browser to summarize today's top AI
|
|
@@ -54,13 +57,20 @@ evot-agent uninstall # 상주 등록 해제
|
|
|
54
57
|
## 로그인이 필요한 사이트 (선택)
|
|
55
58
|
|
|
56
59
|
```bash
|
|
57
|
-
evot-agent login https://
|
|
60
|
+
evot-agent login x.com # 스킴 생략 가능 (https:// 자동 보정)
|
|
61
|
+
evot-agent login https://x.com
|
|
58
62
|
```
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
평소 쓰는 Chrome과 **별개인 전용 프로필**로 창이 뜬다. 즉 평소 브라우저에 로그인돼 있어도
|
|
65
|
+
에이전트에는 상속되지 않으므로, 로그인이 필요한 사이트는 여기서 한 번 로그인해둬야 한다.
|
|
66
|
+
대상 사이트에 로그인 후 창을 닫으면 세션이 전용 프로필에 저장되어 이후 잡에 재사용된다.
|
|
67
|
+
아이디/비번은 저장되지 않고 브라우저 세션 쿠키만 남는다.
|
|
62
68
|
수집 중 로그인이 풀리면 실패 셀에 재로그인 안내가 표시된다.
|
|
63
69
|
|
|
70
|
+
> **소셜 로그인(Google·Apple 등) 주의**: 자동화가 제어하는 브라우저라 Google 등이 로그인을
|
|
71
|
+
> "browser may not be secure"로 막을 수 있다. 그럴 땐 사이트 자체 로그인(이메일/비밀번호)을
|
|
72
|
+
> 사용하면 우회된다.
|
|
73
|
+
|
|
64
74
|
## 안전
|
|
65
75
|
|
|
66
76
|
- 에이전트는 read-only로 동작하도록 지시받는다 (구매·게시·폼 제출·설정변경 금지).
|
package/bin/evot-agent.js
CHANGED
|
@@ -26,7 +26,7 @@ A manual job file (for "run") looks like:
|
|
|
26
26
|
"title": "HN AI digest"
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
Auth model: get a one-time code from evot.io → Settings →
|
|
29
|
+
Auth model: get a one-time code from evot.io → Settings → Computer Use, then run
|
|
30
30
|
"connect <code>". Only that code is entered — never your evot password or keys.
|
|
31
31
|
The code is exchanged for a scoped, revocable token stored locally.
|
|
32
32
|
`;
|
package/package.json
CHANGED
package/src/browse.js
CHANGED
|
@@ -102,19 +102,42 @@ export async function runBrowseJob(job) {
|
|
|
102
102
|
return finalText.trim();
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* 마커 도메인이 평범한 호스트네임 형태인지 검증한다.
|
|
107
|
+
* 신뢰 불가한 페이지가 모델을 속여 가짜 도메인을 주입 → 재로그인 안내로 피싱 URL을
|
|
108
|
+
* 흘리는 것을 막는다(경로·포트·IP·인접 점 차단).
|
|
109
|
+
*/
|
|
110
|
+
function isSafeDomain(d) {
|
|
111
|
+
return (
|
|
112
|
+
typeof d === "string" &&
|
|
113
|
+
/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i.test(d) &&
|
|
114
|
+
!d.includes("..") &&
|
|
115
|
+
/\.[a-z]{2,}$/i.test(d)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
105
119
|
/**
|
|
106
120
|
* 잡 실패를 셀/텔레그램에 남길 사용자용 텍스트로 조립한다.
|
|
107
121
|
* loginDomain(세션만료 마커)이 있으면 재로그인 절차를 안내한다.
|
|
108
122
|
*/
|
|
109
123
|
export function describeJobFailure(err) {
|
|
110
|
-
if (err?.loginDomain) {
|
|
124
|
+
if (err?.loginDomain && isSafeDomain(err.loginDomain)) {
|
|
111
125
|
return [
|
|
112
|
-
`The
|
|
126
|
+
`The agent is signed out of ${err.loginDomain}, so this task could not be completed.`,
|
|
113
127
|
"",
|
|
114
128
|
"To fix it, on the connected computer run:",
|
|
115
129
|
` evot-agent login https://${err.loginDomain}`,
|
|
116
130
|
"sign in once in the window that opens, then ask the Vot to retry this task.",
|
|
117
131
|
].join("\n");
|
|
118
132
|
}
|
|
119
|
-
|
|
133
|
+
if (err?.loginDomain) {
|
|
134
|
+
// 도메인이 의심스러우면 URL을 그대로 흘리지 않고 유저가 직접 지정하게 안내.
|
|
135
|
+
return [
|
|
136
|
+
"The agent hit a login wall it could not pass, so this task could not be completed.",
|
|
137
|
+
"",
|
|
138
|
+
"To fix it, on the connected computer run `evot-agent login <site-url>`",
|
|
139
|
+
"with the site you want to collect from, sign in once, then ask the Vot to retry.",
|
|
140
|
+
].join("\n");
|
|
141
|
+
}
|
|
142
|
+
return `The agent could not complete this task.\n\nReason: ${err?.message ?? "unknown"}`;
|
|
120
143
|
}
|
package/src/connect.js
CHANGED
|
@@ -15,13 +15,13 @@ function prompt(query) {
|
|
|
15
15
|
/**
|
|
16
16
|
* evot.io에서 발급한 일회용 연결 코드를 전용 토큰으로 교환한다.
|
|
17
17
|
* 계정 비밀번호·이메일·anon key 아무것도 입력하지 않는다 — 오직 코드만.
|
|
18
|
-
* (코드는 evot.io → Settings →
|
|
18
|
+
* (코드는 evot.io → Settings → Computer Use → "Connect a device"에서 발급.)
|
|
19
19
|
*/
|
|
20
20
|
export async function runConnect(codeArg) {
|
|
21
21
|
let code = (codeArg ?? "").trim();
|
|
22
22
|
if (!code) {
|
|
23
23
|
console.log(
|
|
24
|
-
"Get a connection code from evot.io → Settings →
|
|
24
|
+
"Get a connection code from evot.io → Settings → Computer Use → Connect a device.\n",
|
|
25
25
|
);
|
|
26
26
|
code = await prompt("Connection code: ");
|
|
27
27
|
}
|
|
@@ -49,5 +49,9 @@ export async function runConnect(codeArg) {
|
|
|
49
49
|
`Token expires ${new Date(data.expires_at).toLocaleDateString()}. Re-connect to refresh.`,
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
|
-
console.log("You can revoke this device anytime from evot Settings →
|
|
52
|
+
console.log("You can revoke this device anytime from evot Settings → Computer Use.");
|
|
53
|
+
console.log(
|
|
54
|
+
'\nTip: for sites that need a sign-in, run "evot-agent login <url>" once —\n' +
|
|
55
|
+
"the agent browses in its own profile, so your everyday Chrome logins don't carry over.",
|
|
56
|
+
);
|
|
53
57
|
}
|
package/src/install.js
CHANGED
package/src/login.js
CHANGED
|
@@ -11,10 +11,25 @@ export async function runLogin(url) {
|
|
|
11
11
|
channel: "chrome",
|
|
12
12
|
headless: false,
|
|
13
13
|
viewport: null,
|
|
14
|
+
// navigator.webdriver 자동화 신호를 숨겨 일부 소셜 로그인(Google 등)의
|
|
15
|
+
// "browser may not be secure" 차단을 완화한다. 만능은 아님(구글은 여러 신호를 함께 봄).
|
|
16
|
+
args: ["--disable-blink-features=AutomationControlled"],
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
const page = context.pages()[0] ?? (await context.newPage());
|
|
17
|
-
if (url)
|
|
20
|
+
if (url) {
|
|
21
|
+
// 스킴 없는 입력(예: "x.com")도 받도록 https:// 보정.
|
|
22
|
+
// 이동 실패해도 창은 열어둔 채 수동 이동을 안내한다(로그인 세션은 어차피 프로필에 저장됨).
|
|
23
|
+
const target = /^https?:\/\//i.test(url) ? url : `https://${url}`;
|
|
24
|
+
try {
|
|
25
|
+
await page.goto(target, { waitUntil: "domcontentloaded" });
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.log(
|
|
28
|
+
`Couldn't open ${target} automatically (${err.message}).\n` +
|
|
29
|
+
"Type the address in the window and sign in there.",
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
18
33
|
|
|
19
34
|
console.log(
|
|
20
35
|
"\nA dedicated browser window is open.\n" +
|
package/src/sync.js
CHANGED
|
@@ -57,7 +57,7 @@ async function runJob(job) {
|
|
|
57
57
|
status = "error";
|
|
58
58
|
}
|
|
59
59
|
try {
|
|
60
|
-
const cellId = await reportResult({ jobId: job.id, text, title: "
|
|
60
|
+
const cellId = await reportResult({ jobId: job.id, text, title: "Computer Use", status });
|
|
61
61
|
console.log(`Reported job ${job.id}${cellId ? ` → cell ${cellId}` : ""}.`);
|
|
62
62
|
} catch (err) {
|
|
63
63
|
// 보고 실패 시 잡은 running으로 남고, running 타임아웃 후 서버가 expired 처리한다.
|