visionclaw 0.1.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 +116 -0
- package/dist/agent/context.d.ts +56 -0
- package/dist/agent/context.d.ts.map +1 -0
- package/dist/agent/context.js +142 -0
- package/dist/agent/context.js.map +1 -0
- package/dist/agent/loop.d.ts +18 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +323 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/session.d.ts +49 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +200 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +10 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +167 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/calendar/google-calendar.d.ts +46 -0
- package/dist/calendar/google-calendar.d.ts.map +1 -0
- package/dist/calendar/google-calendar.js +132 -0
- package/dist/calendar/google-calendar.js.map +1 -0
- package/dist/calendar/scheduler.d.ts +7 -0
- package/dist/calendar/scheduler.d.ts.map +1 -0
- package/dist/calendar/scheduler.js +33 -0
- package/dist/calendar/scheduler.js.map +1 -0
- package/dist/channels/discord.d.ts +19 -0
- package/dist/channels/discord.d.ts.map +1 -0
- package/dist/channels/discord.js +169 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/gmail.d.ts +31 -0
- package/dist/channels/gmail.d.ts.map +1 -0
- package/dist/channels/gmail.js +300 -0
- package/dist/channels/gmail.js.map +1 -0
- package/dist/channels/interface.d.ts +45 -0
- package/dist/channels/interface.d.ts.map +1 -0
- package/dist/channels/interface.js +2 -0
- package/dist/channels/interface.js.map +1 -0
- package/dist/channels/manager.d.ts +36 -0
- package/dist/channels/manager.d.ts.map +1 -0
- package/dist/channels/manager.js +108 -0
- package/dist/channels/manager.js.map +1 -0
- package/dist/channels/queue.d.ts +17 -0
- package/dist/channels/queue.d.ts.map +1 -0
- package/dist/channels/queue.js +85 -0
- package/dist/channels/queue.js.map +1 -0
- package/dist/channels/slack.d.ts +17 -0
- package/dist/channels/slack.d.ts.map +1 -0
- package/dist/channels/slack.js +142 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/sms.d.ts +19 -0
- package/dist/channels/sms.d.ts.map +1 -0
- package/dist/channels/sms.js +111 -0
- package/dist/channels/sms.js.map +1 -0
- package/dist/channels/telegram.d.ts +28 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +246 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +28 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +292 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/config/index.d.ts +24 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +104 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +227 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +45 -0
- package/dist/config/types.js.map +1 -0
- package/dist/files.d.ts +20 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +82 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +384 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/store.d.ts +24 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +71 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/obs/server.d.ts +10 -0
- package/dist/obs/server.d.ts.map +1 -0
- package/dist/obs/server.js +406 -0
- package/dist/obs/server.js.map +1 -0
- package/dist/onboarding/google-auth.d.ts +11 -0
- package/dist/onboarding/google-auth.d.ts.map +1 -0
- package/dist/onboarding/google-auth.js +113 -0
- package/dist/onboarding/google-auth.js.map +1 -0
- package/dist/onboarding/index.d.ts +2 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +213 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/macos-permissions.d.ts +37 -0
- package/dist/onboarding/macos-permissions.d.ts.map +1 -0
- package/dist/onboarding/macos-permissions.js +207 -0
- package/dist/onboarding/macos-permissions.js.map +1 -0
- package/dist/skills/install.d.ts +7 -0
- package/dist/skills/install.d.ts.map +1 -0
- package/dist/skills/install.js +63 -0
- package/dist/skills/install.js.map +1 -0
- package/dist/tools/browser.d.ts +7 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +202 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/calendar.d.ts +12 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +210 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/computer-use.d.ts +28 -0
- package/dist/tools/computer-use.d.ts.map +1 -0
- package/dist/tools/computer-use.js +311 -0
- package/dist/tools/computer-use.js.map +1 -0
- package/dist/tools/coordinate-resolver.d.ts +26 -0
- package/dist/tools/coordinate-resolver.d.ts.map +1 -0
- package/dist/tools/coordinate-resolver.js +157 -0
- package/dist/tools/coordinate-resolver.js.map +1 -0
- package/dist/tools/desktop-executor.d.ts +52 -0
- package/dist/tools/desktop-executor.d.ts.map +1 -0
- package/dist/tools/desktop-executor.js +202 -0
- package/dist/tools/desktop-executor.js.map +1 -0
- package/dist/tools/finish.d.ts +5 -0
- package/dist/tools/finish.d.ts.map +1 -0
- package/dist/tools/finish.js +18 -0
- package/dist/tools/finish.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory.d.ts +14 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +269 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/notify.d.ts +12 -0
- package/dist/tools/notify.d.ts.map +1 -0
- package/dist/tools/notify.js +108 -0
- package/dist/tools/notify.js.map +1 -0
- package/dist/tools/screenshot.d.ts +7 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +189 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/skill.d.ts +8 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +133 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/tools/upgrade.d.ts +5 -0
- package/dist/tools/upgrade.d.ts.map +1 -0
- package/dist/tools/upgrade.js +89 -0
- package/dist/tools/upgrade.js.map +1 -0
- package/dist/tools/wait.d.ts +5 -0
- package/dist/tools/wait.d.ts.map +1 -0
- package/dist/tools/wait.js +21 -0
- package/dist/tools/wait.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { URL } from "node:url";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
function escHtml(s) {
|
|
5
|
+
return s
|
|
6
|
+
.replaceAll("&", "&")
|
|
7
|
+
.replaceAll("<", "<")
|
|
8
|
+
.replaceAll(">", ">")
|
|
9
|
+
.replaceAll('"', """)
|
|
10
|
+
.replaceAll("'", "'");
|
|
11
|
+
}
|
|
12
|
+
function renderIndexHtml() {
|
|
13
|
+
// Minimal, dependency-free UI. Uses SSE for streaming logs.
|
|
14
|
+
return `<!doctype html>
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="utf-8" />
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
19
|
+
<title>VisionClaw • Observability</title>
|
|
20
|
+
<style>
|
|
21
|
+
:root {
|
|
22
|
+
--bg: #0b1020;
|
|
23
|
+
--panel: #0f1731;
|
|
24
|
+
--border: rgba(255,255,255,0.10);
|
|
25
|
+
--text: rgba(255,255,255,0.92);
|
|
26
|
+
--muted: rgba(255,255,255,0.70);
|
|
27
|
+
--dim: rgba(255,255,255,0.55);
|
|
28
|
+
--good: #31d0aa;
|
|
29
|
+
--warn: #ffcc66;
|
|
30
|
+
--bad: #ff5c7a;
|
|
31
|
+
--accent: #7aa2ff;
|
|
32
|
+
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
33
|
+
--sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
|
|
34
|
+
}
|
|
35
|
+
body { margin: 0; background: radial-gradient(1200px 800px at 15% 10%, rgba(122,162,255,0.18), transparent 60%), var(--bg); color: var(--text); font-family: var(--sans); }
|
|
36
|
+
header { position: sticky; top: 0; backdrop-filter: blur(10px); background: rgba(11,16,32,0.6); border-bottom: 1px solid var(--border); }
|
|
37
|
+
.wrap { max-width: 1200px; margin: 0 auto; padding: 14px 16px; }
|
|
38
|
+
.row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
|
|
39
|
+
h1 { margin: 0; font-size: 14px; letter-spacing: 0.2px; font-weight: 650; }
|
|
40
|
+
.pill { border: 1px solid var(--border); background: rgba(255,255,255,0.06); color: var(--muted); padding: 6px 10px; border-radius: 999px; font-size: 12px; }
|
|
41
|
+
.pill b { color: var(--text); }
|
|
42
|
+
.btn { cursor: pointer; border: 1px solid var(--border); background: rgba(255,255,255,0.06); color: var(--text); padding: 8px 10px; border-radius: 10px; font-size: 12px; }
|
|
43
|
+
.btn:active { transform: translateY(1px); }
|
|
44
|
+
.input { border: 1px solid var(--border); background: rgba(0,0,0,0.25); color: var(--text); padding: 8px 10px; border-radius: 10px; font-size: 12px; font-family: var(--mono); min-width: 220px; }
|
|
45
|
+
main .wrap { padding-top: 16px; }
|
|
46
|
+
.grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
|
|
47
|
+
.panel { border: 1px solid var(--border); background: rgba(15,23,49,0.65); border-radius: 14px; overflow: hidden; }
|
|
48
|
+
.panel-head { padding: 10px 12px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
|
|
49
|
+
.panel-head .title { font-size: 12px; color: var(--muted); }
|
|
50
|
+
.panel-body { padding: 0; }
|
|
51
|
+
.logs { height: calc(100vh - 140px); overflow: auto; font-family: var(--mono); font-size: 12px; line-height: 1.35; }
|
|
52
|
+
.line { padding: 6px 10px; border-bottom: 1px solid rgba(255,255,255,0.06); display: grid; grid-template-columns: 120px 66px 120px 1fr; gap: 10px; align-items: baseline; }
|
|
53
|
+
.line:hover { background: rgba(255,255,255,0.04); }
|
|
54
|
+
.ts { color: var(--dim); }
|
|
55
|
+
.lvl { font-weight: 650; }
|
|
56
|
+
.lvl.debug { color: var(--dim); }
|
|
57
|
+
.lvl.info { color: #9bb6ff; }
|
|
58
|
+
.lvl.warn { color: var(--warn); }
|
|
59
|
+
.lvl.error { color: var(--bad); }
|
|
60
|
+
.cat { color: rgba(255,255,255,0.80); }
|
|
61
|
+
.msg { color: var(--text); white-space: pre-wrap; word-break: break-word; }
|
|
62
|
+
.msg.collapsed { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
63
|
+
.msg-wrap { display: flex; gap: 8px; align-items: flex-start; }
|
|
64
|
+
.toggle { cursor: pointer; user-select: none; border: 1px solid var(--border); background: rgba(255,255,255,0.06); color: var(--muted); padding: 2px 6px; border-radius: 8px; font-size: 11px; line-height: 1.4; flex: 0 0 auto; }
|
|
65
|
+
.toggle.hidden { display: none; }
|
|
66
|
+
.meta { color: var(--dim); font-size: 11px; }
|
|
67
|
+
.badged { display: inline-flex; align-items: center; gap: 8px; }
|
|
68
|
+
.dot { width: 8px; height: 8px; border-radius: 999px; background: var(--bad); box-shadow: 0 0 0 3px rgba(255,92,122,0.15); }
|
|
69
|
+
.dot.ok { background: var(--good); box-shadow: 0 0 0 3px rgba(49,208,170,0.18); }
|
|
70
|
+
</style>
|
|
71
|
+
</head>
|
|
72
|
+
<body>
|
|
73
|
+
<header>
|
|
74
|
+
<div class="wrap">
|
|
75
|
+
<div class="row" style="justify-content: space-between;">
|
|
76
|
+
<div class="row">
|
|
77
|
+
<h1>VisionClaw • Observability</h1>
|
|
78
|
+
<span class="pill">SSE: <span id="sse">connecting…</span></span>
|
|
79
|
+
<span class="pill">Buffer: <b id="count">0</b></span>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="row">
|
|
82
|
+
<input id="filter" class="input" placeholder="filter (text/category/level)" />
|
|
83
|
+
<button id="expandAll" class="btn">Expand all</button>
|
|
84
|
+
<button id="pause" class="btn">Pause</button>
|
|
85
|
+
<button id="clear" class="btn">Clear</button>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</header>
|
|
90
|
+
<main>
|
|
91
|
+
<div class="wrap">
|
|
92
|
+
<div class="grid">
|
|
93
|
+
<section class="panel">
|
|
94
|
+
<div class="panel-head">
|
|
95
|
+
<div class="badged">
|
|
96
|
+
<div id="dot" class="dot"></div>
|
|
97
|
+
<div class="title">Live logs (latest first disabled; auto-scroll)</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="meta" id="meta">/obs/events</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="panel-body">
|
|
102
|
+
<div id="logs" class="logs" aria-live="polite"></div>
|
|
103
|
+
</div>
|
|
104
|
+
</section>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</main>
|
|
108
|
+
<script>
|
|
109
|
+
const $logs = document.getElementById('logs');
|
|
110
|
+
const $count = document.getElementById('count');
|
|
111
|
+
const $filter = document.getElementById('filter');
|
|
112
|
+
const $pause = document.getElementById('pause');
|
|
113
|
+
const $clear = document.getElementById('clear');
|
|
114
|
+
const $expandAll = document.getElementById('expandAll');
|
|
115
|
+
const $sse = document.getElementById('sse');
|
|
116
|
+
const $dot = document.getElementById('dot');
|
|
117
|
+
|
|
118
|
+
const MAX = 2000;
|
|
119
|
+
const COLLAPSE_AT = 260;
|
|
120
|
+
let paused = false;
|
|
121
|
+
let filter = '';
|
|
122
|
+
let expandAll = false;
|
|
123
|
+
|
|
124
|
+
function match(entry) {
|
|
125
|
+
if (!filter) return true;
|
|
126
|
+
const f = filter.toLowerCase();
|
|
127
|
+
return (
|
|
128
|
+
(entry.message || '').toLowerCase().includes(f) ||
|
|
129
|
+
(entry.category || '').toLowerCase().includes(f) ||
|
|
130
|
+
(entry.level || '').toLowerCase().includes(f)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function addLine(entry) {
|
|
135
|
+
if (!match(entry)) return;
|
|
136
|
+
|
|
137
|
+
const line = document.createElement('div');
|
|
138
|
+
line.className = 'line';
|
|
139
|
+
|
|
140
|
+
const ts = document.createElement('div');
|
|
141
|
+
ts.className = 'ts';
|
|
142
|
+
ts.textContent = (entry.timestamp || '').replace('T', ' ').replace('Z','');
|
|
143
|
+
|
|
144
|
+
const lvl = document.createElement('div');
|
|
145
|
+
lvl.className = 'lvl ' + (entry.level || 'info');
|
|
146
|
+
lvl.textContent = (entry.level || 'info').toUpperCase();
|
|
147
|
+
|
|
148
|
+
const cat = document.createElement('div');
|
|
149
|
+
cat.className = 'cat';
|
|
150
|
+
cat.textContent = entry.category || 'system';
|
|
151
|
+
|
|
152
|
+
const msgWrap = document.createElement('div');
|
|
153
|
+
msgWrap.className = 'msg-wrap';
|
|
154
|
+
|
|
155
|
+
const toggle = document.createElement('button');
|
|
156
|
+
toggle.className = 'toggle hidden';
|
|
157
|
+
toggle.type = 'button';
|
|
158
|
+
toggle.textContent = 'Expand';
|
|
159
|
+
|
|
160
|
+
const msg = document.createElement('div');
|
|
161
|
+
msg.className = 'msg';
|
|
162
|
+
const full = entry.message || '';
|
|
163
|
+
msg.textContent = full;
|
|
164
|
+
|
|
165
|
+
// Collapse long content by default
|
|
166
|
+
const shouldCollapse = full.length > COLLAPSE_AT;
|
|
167
|
+
if (shouldCollapse && !expandAll) {
|
|
168
|
+
msg.classList.add('collapsed');
|
|
169
|
+
toggle.classList.remove('hidden');
|
|
170
|
+
toggle.textContent = 'Expand';
|
|
171
|
+
} else if (shouldCollapse && expandAll) {
|
|
172
|
+
toggle.classList.remove('hidden');
|
|
173
|
+
toggle.textContent = 'Collapse';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
toggle.addEventListener('click', () => {
|
|
177
|
+
const isCollapsed = msg.classList.toggle('collapsed');
|
|
178
|
+
toggle.textContent = isCollapsed ? 'Expand' : 'Collapse';
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
msgWrap.appendChild(toggle);
|
|
182
|
+
msgWrap.appendChild(msg);
|
|
183
|
+
|
|
184
|
+
line.appendChild(ts);
|
|
185
|
+
line.appendChild(lvl);
|
|
186
|
+
line.appendChild(cat);
|
|
187
|
+
line.appendChild(msgWrap);
|
|
188
|
+
|
|
189
|
+
$logs.appendChild(line);
|
|
190
|
+
|
|
191
|
+
// Trim
|
|
192
|
+
while ($logs.childElementCount > MAX) {
|
|
193
|
+
$logs.removeChild($logs.firstChild);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
$count.textContent = String($logs.childElementCount);
|
|
197
|
+
|
|
198
|
+
if (!paused) {
|
|
199
|
+
$logs.scrollTop = $logs.scrollHeight;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
$filter.addEventListener('input', () => {
|
|
204
|
+
filter = ($filter.value || '').trim();
|
|
205
|
+
// Simple approach: clear and re-request snapshot, then stream.
|
|
206
|
+
$logs.textContent = '';
|
|
207
|
+
$count.textContent = '0';
|
|
208
|
+
fetch('/obs/snapshot').then(r => r.json()).then(items => {
|
|
209
|
+
for (const e of items) addLine(e);
|
|
210
|
+
$logs.scrollTop = $logs.scrollHeight;
|
|
211
|
+
}).catch(() => {});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
$pause.addEventListener('click', () => {
|
|
215
|
+
paused = !paused;
|
|
216
|
+
$pause.textContent = paused ? 'Resume' : 'Pause';
|
|
217
|
+
if (!paused) $logs.scrollTop = $logs.scrollHeight;
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
$expandAll.addEventListener('click', () => {
|
|
221
|
+
expandAll = !expandAll;
|
|
222
|
+
$expandAll.textContent = expandAll ? 'Collapse all' : 'Expand all';
|
|
223
|
+
// Apply to existing rows
|
|
224
|
+
document.querySelectorAll('.msg').forEach((el) => {
|
|
225
|
+
const full = el.textContent || '';
|
|
226
|
+
if (full.length <= COLLAPSE_AT) return;
|
|
227
|
+
if (expandAll) {
|
|
228
|
+
el.classList.remove('collapsed');
|
|
229
|
+
} else {
|
|
230
|
+
el.classList.add('collapsed');
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
document.querySelectorAll('.toggle').forEach((btn) => {
|
|
234
|
+
if (btn.classList.contains('hidden')) return;
|
|
235
|
+
btn.textContent = expandAll ? 'Collapse' : 'Expand';
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
$clear.addEventListener('click', () => {
|
|
240
|
+
$logs.textContent = '';
|
|
241
|
+
$count.textContent = '0';
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Initial snapshot
|
|
245
|
+
fetch('/obs/snapshot').then(r => r.json()).then(items => {
|
|
246
|
+
for (const e of items) addLine(e);
|
|
247
|
+
$logs.scrollTop = $logs.scrollHeight;
|
|
248
|
+
}).catch(() => {});
|
|
249
|
+
|
|
250
|
+
// SSE
|
|
251
|
+
const es = new EventSource('/obs/events');
|
|
252
|
+
es.onopen = () => {
|
|
253
|
+
$sse.textContent = 'connected';
|
|
254
|
+
$dot.classList.add('ok');
|
|
255
|
+
};
|
|
256
|
+
es.onerror = () => {
|
|
257
|
+
$sse.textContent = 'disconnected';
|
|
258
|
+
$dot.classList.remove('ok');
|
|
259
|
+
};
|
|
260
|
+
es.onmessage = (ev) => {
|
|
261
|
+
try {
|
|
262
|
+
const entry = JSON.parse(ev.data);
|
|
263
|
+
addLine(entry);
|
|
264
|
+
} catch {}
|
|
265
|
+
};
|
|
266
|
+
</script>
|
|
267
|
+
</body>
|
|
268
|
+
</html>`;
|
|
269
|
+
}
|
|
270
|
+
export function startObsServer(options = {}) {
|
|
271
|
+
const host = options.host ?? "127.0.0.1";
|
|
272
|
+
const port = options.port ?? 0;
|
|
273
|
+
// Ring buffer for snapshot
|
|
274
|
+
const buffer = [];
|
|
275
|
+
const maxBuffer = options.bufferSize ?? 1000;
|
|
276
|
+
const sseClients = new Set();
|
|
277
|
+
const unsubscribe = logger.onLog((entry) => {
|
|
278
|
+
buffer.push(entry);
|
|
279
|
+
if (buffer.length > maxBuffer)
|
|
280
|
+
buffer.shift();
|
|
281
|
+
if (sseClients.size > 0) {
|
|
282
|
+
const payload = `data: ${JSON.stringify(entry)}\n\n`;
|
|
283
|
+
for (const res of sseClients) {
|
|
284
|
+
try {
|
|
285
|
+
res.write(payload);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// ignore
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
const server = http.createServer((req, res) => {
|
|
294
|
+
try {
|
|
295
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
296
|
+
const pathname = url.pathname;
|
|
297
|
+
if (pathname === "/" || pathname === "/obs" || pathname === "/obs/") {
|
|
298
|
+
const html = renderIndexHtml();
|
|
299
|
+
res.statusCode = 200;
|
|
300
|
+
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
301
|
+
res.setHeader("cache-control", "no-store");
|
|
302
|
+
res.end(html);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (pathname === "/obs/health") {
|
|
306
|
+
res.statusCode = 200;
|
|
307
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
308
|
+
res.setHeader("cache-control", "no-store");
|
|
309
|
+
res.end(JSON.stringify({ ok: true }));
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (pathname === "/obs/snapshot") {
|
|
313
|
+
res.statusCode = 200;
|
|
314
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
315
|
+
res.setHeader("cache-control", "no-store");
|
|
316
|
+
res.end(JSON.stringify(buffer));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (pathname === "/obs/events") {
|
|
320
|
+
res.statusCode = 200;
|
|
321
|
+
res.setHeader("content-type", "text/event-stream; charset=utf-8");
|
|
322
|
+
res.setHeader("cache-control", "no-store");
|
|
323
|
+
res.setHeader("connection", "keep-alive");
|
|
324
|
+
res.setHeader("x-content-type-options", "nosniff");
|
|
325
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
326
|
+
// Send an initial comment to establish stream
|
|
327
|
+
res.write(`: connected\n\n`);
|
|
328
|
+
// Add client
|
|
329
|
+
sseClients.add(res);
|
|
330
|
+
// Heartbeat
|
|
331
|
+
const heartbeatMs = 15000;
|
|
332
|
+
const t = setInterval(() => {
|
|
333
|
+
try {
|
|
334
|
+
res.write(`: ping\n\n`);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// ignore
|
|
338
|
+
}
|
|
339
|
+
}, heartbeatMs);
|
|
340
|
+
req.on("close", () => {
|
|
341
|
+
clearInterval(t);
|
|
342
|
+
sseClients.delete(res);
|
|
343
|
+
});
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
// Basic 404
|
|
347
|
+
res.statusCode = 404;
|
|
348
|
+
res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
349
|
+
res.end(escHtml(`Not found: ${pathname}`));
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
res.statusCode = 500;
|
|
353
|
+
res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
354
|
+
res.end("Internal error");
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
let closed = false;
|
|
358
|
+
server.on("error", (err) => {
|
|
359
|
+
// Don't crash the agent if OBS can't bind.
|
|
360
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
361
|
+
logger.warn(`Observability server failed to start: ${msg}`);
|
|
362
|
+
// Best-effort cleanup
|
|
363
|
+
if (!closed) {
|
|
364
|
+
closed = true;
|
|
365
|
+
try {
|
|
366
|
+
unsubscribe();
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// ignore
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
server.close();
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
// ignore
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
server.listen(port, host, () => {
|
|
380
|
+
const address = server.address();
|
|
381
|
+
const actualPort = typeof address === "object" && address ? address.port : port;
|
|
382
|
+
logger.system(`Observability server listening on http://${host}:${actualPort}/obs`);
|
|
383
|
+
});
|
|
384
|
+
const address = server.address();
|
|
385
|
+
const actualPort = typeof address === "object" && address ? address.port : port;
|
|
386
|
+
return {
|
|
387
|
+
port: actualPort,
|
|
388
|
+
close: async () => {
|
|
389
|
+
closed = true;
|
|
390
|
+
unsubscribe();
|
|
391
|
+
for (const res of sseClients) {
|
|
392
|
+
try {
|
|
393
|
+
res.end();
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
// ignore
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
sseClients.clear();
|
|
400
|
+
await new Promise((resolve) => {
|
|
401
|
+
server.close(() => resolve());
|
|
402
|
+
});
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/obs/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GoogleTokens } from "../config/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run the Google OAuth2 flow:
|
|
4
|
+
* 1. Start a local HTTP server on a random port
|
|
5
|
+
* 2. Open the consent URL in the user's browser
|
|
6
|
+
* 3. Receive the callback with the authorization code
|
|
7
|
+
* 4. Exchange the code for tokens
|
|
8
|
+
* 5. Save the tokens to disk
|
|
9
|
+
*/
|
|
10
|
+
export declare function runGoogleOAuth(clientId: string, clientSecret: string): Promise<GoogleTokens>;
|
|
11
|
+
//# sourceMappingURL=google-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-auth.d.ts","sourceRoot":"","sources":["../../src/onboarding/google-auth.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAUvD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,YAAY,CAAC,CAgHvB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { URL } from "node:url";
|
|
3
|
+
import open from "open";
|
|
4
|
+
import { google } from "googleapis";
|
|
5
|
+
import { saveGoogleTokens } from "../config/index.js";
|
|
6
|
+
const SCOPES = [
|
|
7
|
+
"https://www.googleapis.com/auth/gmail.modify",
|
|
8
|
+
"https://www.googleapis.com/auth/gmail.send",
|
|
9
|
+
"https://www.googleapis.com/auth/calendar",
|
|
10
|
+
"https://www.googleapis.com/auth/calendar.events",
|
|
11
|
+
"https://www.googleapis.com/auth/drive.file",
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Run the Google OAuth2 flow:
|
|
15
|
+
* 1. Start a local HTTP server on a random port
|
|
16
|
+
* 2. Open the consent URL in the user's browser
|
|
17
|
+
* 3. Receive the callback with the authorization code
|
|
18
|
+
* 4. Exchange the code for tokens
|
|
19
|
+
* 5. Save the tokens to disk
|
|
20
|
+
*/
|
|
21
|
+
export async function runGoogleOAuth(clientId, clientSecret) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
// Create a temporary HTTP server to receive the OAuth callback
|
|
24
|
+
const server = http.createServer();
|
|
25
|
+
server.listen(0, "127.0.0.1", () => {
|
|
26
|
+
const addr = server.address();
|
|
27
|
+
if (!addr || typeof addr === "string") {
|
|
28
|
+
reject(new Error("Failed to start local server"));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const redirectUri = `http://127.0.0.1:${addr.port}/callback`;
|
|
32
|
+
const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, redirectUri);
|
|
33
|
+
const authUrl = oauth2Client.generateAuthUrl({
|
|
34
|
+
access_type: "offline",
|
|
35
|
+
scope: SCOPES,
|
|
36
|
+
prompt: "consent",
|
|
37
|
+
});
|
|
38
|
+
console.log("\nOpening browser for Google OAuth consent...");
|
|
39
|
+
console.log(`If the browser doesn't open, visit:\n${authUrl}\n`);
|
|
40
|
+
open(authUrl).catch(() => {
|
|
41
|
+
// Ignore errors opening browser -- the URL is printed above
|
|
42
|
+
});
|
|
43
|
+
server.on("request", (req, res) => {
|
|
44
|
+
void (async () => {
|
|
45
|
+
try {
|
|
46
|
+
const url = new URL(req.url ?? "/", `http://127.0.0.1:${addr.port}`);
|
|
47
|
+
if (url.pathname !== "/callback") {
|
|
48
|
+
res.writeHead(404);
|
|
49
|
+
res.end("Not found");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const code = url.searchParams.get("code");
|
|
53
|
+
const error = url.searchParams.get("error");
|
|
54
|
+
if (error) {
|
|
55
|
+
res.writeHead(400);
|
|
56
|
+
res.end(`Authorization error: ${error}`);
|
|
57
|
+
server.close();
|
|
58
|
+
reject(new Error(`Google OAuth error: ${error}`));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!code) {
|
|
62
|
+
res.writeHead(400);
|
|
63
|
+
res.end("No authorization code received");
|
|
64
|
+
server.close();
|
|
65
|
+
reject(new Error("No authorization code received"));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Exchange the code for tokens
|
|
69
|
+
const { tokens } = await oauth2Client.getToken(code);
|
|
70
|
+
if (!tokens.refresh_token) {
|
|
71
|
+
res.writeHead(400);
|
|
72
|
+
res.end("No refresh token received. Please revoke access and try again.");
|
|
73
|
+
server.close();
|
|
74
|
+
reject(new Error("No refresh token received"));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const googleTokens = {
|
|
78
|
+
access_token: tokens.access_token ?? "",
|
|
79
|
+
refresh_token: tokens.refresh_token,
|
|
80
|
+
token_type: tokens.token_type ?? "Bearer",
|
|
81
|
+
expiry_date: tokens.expiry_date ?? 0,
|
|
82
|
+
scope: tokens.scope ?? SCOPES.join(" "),
|
|
83
|
+
};
|
|
84
|
+
saveGoogleTokens(googleTokens);
|
|
85
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
86
|
+
res.end(`
|
|
87
|
+
<html>
|
|
88
|
+
<body style="font-family: system-ui; text-align: center; padding: 50px;">
|
|
89
|
+
<h1>VisionClaw Authorization Complete</h1>
|
|
90
|
+
<p>You can close this window and return to the terminal.</p>
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
93
|
+
`);
|
|
94
|
+
server.close();
|
|
95
|
+
resolve(googleTokens);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
res.writeHead(500);
|
|
99
|
+
res.end("Internal error");
|
|
100
|
+
server.close();
|
|
101
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
102
|
+
}
|
|
103
|
+
})();
|
|
104
|
+
});
|
|
105
|
+
// Timeout after 5 minutes
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
server.close();
|
|
108
|
+
reject(new Error("OAuth flow timed out (5 minutes)"));
|
|
109
|
+
}, 5 * 60 * 1000);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=google-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-auth.js","sourceRoot":"","sources":["../../src/onboarding/google-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/onboarding/index.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAmQnD"}
|