@weavetab/mcp 2.5.0-beta.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/AGENTS.md +48 -0
- package/ARCHITECTURE.md +590 -0
- package/LICENSE +631 -0
- package/README.md +909 -0
- package/SECURITY.md +196 -0
- package/TROUBLESHOOTING.md +365 -0
- package/dist/anticaptcha/detector.d.ts +49 -0
- package/dist/anticaptcha/detector.js +465 -0
- package/dist/anticaptcha/integration.d.ts +36 -0
- package/dist/anticaptcha/integration.js +123 -0
- package/dist/anticaptcha/solver.d.ts +27 -0
- package/dist/anticaptcha/solver.js +552 -0
- package/dist/audit/logger.d.ts +13 -0
- package/dist/audit/logger.js +177 -0
- package/dist/audit/telemetry.d.ts +36 -0
- package/dist/audit/telemetry.js +162 -0
- package/dist/cdp/bridge.d.ts +16 -0
- package/dist/cdp/bridge.js +826 -0
- package/dist/cdp/confirm.d.ts +26 -0
- package/dist/cdp/confirm.js +79 -0
- package/dist/cdp/connector.d.ts +37 -0
- package/dist/cdp/connector.js +661 -0
- package/dist/cdp/extension.d.ts +36 -0
- package/dist/cdp/extension.js +118 -0
- package/dist/cdp/finder.d.ts +1 -0
- package/dist/cdp/finder.js +2 -0
- package/dist/cdp/helpers.d.ts +11 -0
- package/dist/cdp/helpers.js +195 -0
- package/dist/cdp/label_cache.d.ts +12 -0
- package/dist/cdp/label_cache.js +51 -0
- package/dist/cdp/lock.d.ts +33 -0
- package/dist/cdp/lock.js +206 -0
- package/dist/cdp/omni_broker.d.ts +17 -0
- package/dist/cdp/omni_broker.js +119 -0
- package/dist/cdp/profiles.d.ts +1 -0
- package/dist/cdp/profiles.js +87 -0
- package/dist/cdp/pruner.d.ts +41 -0
- package/dist/cdp/pruner.js +263 -0
- package/dist/cdp/ref_cache.d.ts +101 -0
- package/dist/cdp/ref_cache.js +234 -0
- package/dist/cdp/retry.d.ts +5 -0
- package/dist/cdp/retry.js +39 -0
- package/dist/cdp/retry_enhanced.d.ts +44 -0
- package/dist/cdp/retry_enhanced.js +102 -0
- package/dist/cdp/security.d.ts +50 -0
- package/dist/cdp/security.js +237 -0
- package/dist/cdp/verify.d.ts +39 -0
- package/dist/cdp/verify.js +143 -0
- package/dist/cdp/walker.d.ts +91 -0
- package/dist/cdp/walker.js +896 -0
- package/dist/cdp/walker.test.d.ts +2 -0
- package/dist/cdp/walker.test.js +172 -0
- package/dist/cdp/websocket_transport.d.ts +15 -0
- package/dist/cdp/websocket_transport.js +118 -0
- package/dist/cli/plugin.d.ts +9 -0
- package/dist/cli/plugin.js +1134 -0
- package/dist/cli/updater.d.ts +1 -0
- package/dist/cli/updater.js +72 -0
- package/dist/config/loader.d.ts +120 -0
- package/dist/config/loader.js +704 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1248 -0
- package/dist/intelligence/hints.d.ts +11 -0
- package/dist/intelligence/hints.js +39 -0
- package/dist/intelligence/intent.d.ts +33 -0
- package/dist/intelligence/intent.js +171 -0
- package/dist/intelligence/sessionMemory.d.ts +66 -0
- package/dist/intelligence/sessionMemory.js +284 -0
- package/dist/intelligence/sessionMemory.test.d.ts +2 -0
- package/dist/intelligence/sessionMemory.test.js +62 -0
- package/dist/intelligence/trail.d.ts +64 -0
- package/dist/intelligence/trail.js +233 -0
- package/dist/intelligence/trail.test.d.ts +2 -0
- package/dist/intelligence/trail.test.js +110 -0
- package/dist/intelligence/vision.d.ts +24 -0
- package/dist/intelligence/vision.js +151 -0
- package/dist/lifecycle/mission_manager.d.ts +16 -0
- package/dist/lifecycle/mission_manager.js +44 -0
- package/dist/overlay/bubble.d.ts +16 -0
- package/dist/overlay/bubble.js +37 -0
- package/dist/overlay/ghost.d.ts +35 -0
- package/dist/overlay/ghost.js +508 -0
- package/dist/overlay/injector.d.ts +22 -0
- package/dist/overlay/injector.js +198 -0
- package/dist/plugin/interface.d.ts +134 -0
- package/dist/plugin/interface.js +1 -0
- package/dist/plugin/loader.d.ts +18 -0
- package/dist/plugin/loader.js +155 -0
- package/dist/plugin/registry.d.ts +50 -0
- package/dist/plugin/registry.js +234 -0
- package/dist/security/blacklist.d.ts +24 -0
- package/dist/security/blacklist.js +80 -0
- package/dist/security/filter.d.ts +2 -0
- package/dist/security/filter.js +20 -0
- package/dist/security/guard.d.ts +8 -0
- package/dist/security/guard.js +35 -0
- package/dist/security/ratelimit.d.ts +11 -0
- package/dist/security/ratelimit.js +57 -0
- package/dist/security/secrets.d.ts +75 -0
- package/dist/security/secrets.js +365 -0
- package/dist/sensors/actionability.d.ts +81 -0
- package/dist/sensors/actionability.js +303 -0
- package/dist/sensors/guard.d.ts +25 -0
- package/dist/sensors/guard.js +168 -0
- package/dist/sensors/mutations.d.ts +23 -0
- package/dist/sensors/mutations.js +93 -0
- package/dist/sensors/network.d.ts +67 -0
- package/dist/sensors/network.js +193 -0
- package/dist/sensors/operation_monitor.d.ts +80 -0
- package/dist/sensors/operation_monitor.js +203 -0
- package/dist/sensors/pacing.d.ts +44 -0
- package/dist/sensors/pacing.js +111 -0
- package/dist/sensors/thoughts.d.ts +2 -0
- package/dist/sensors/thoughts.js +59 -0
- package/dist/sensors/wait.d.ts +12 -0
- package/dist/sensors/wait.js +44 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +1687 -0
- package/dist/state/agent.d.ts +36 -0
- package/dist/state/agent.js +101 -0
- package/dist/state/cache.d.ts +16 -0
- package/dist/state/cache.js +92 -0
- package/dist/state/cache.test.d.ts +2 -0
- package/dist/state/cache.test.js +76 -0
- package/dist/state/delta.d.ts +71 -0
- package/dist/state/delta.js +234 -0
- package/dist/state/delta.test.d.ts +2 -0
- package/dist/state/delta.test.js +279 -0
- package/dist/state/groups.d.ts +15 -0
- package/dist/state/groups.js +80 -0
- package/dist/state/session.d.ts +30 -0
- package/dist/state/session.js +155 -0
- package/dist/tools/accessibility.d.ts +14 -0
- package/dist/tools/accessibility.js +32 -0
- package/dist/tools/ask.d.ts +14 -0
- package/dist/tools/ask.js +49 -0
- package/dist/tools/automation.d.ts +36 -0
- package/dist/tools/automation.js +218 -0
- package/dist/tools/browser_detect.d.ts +13 -0
- package/dist/tools/browser_detect.js +73 -0
- package/dist/tools/burst.d.ts +35 -0
- package/dist/tools/burst.js +344 -0
- package/dist/tools/canvas.d.ts +25 -0
- package/dist/tools/canvas.js +132 -0
- package/dist/tools/captcha.d.ts +38 -0
- package/dist/tools/captcha.js +209 -0
- package/dist/tools/click.d.ts +36 -0
- package/dist/tools/click.js +561 -0
- package/dist/tools/click_and_wait.d.ts +33 -0
- package/dist/tools/click_and_wait.js +149 -0
- package/dist/tools/clipboard.d.ts +29 -0
- package/dist/tools/clipboard.js +279 -0
- package/dist/tools/console.d.ts +21 -0
- package/dist/tools/console.js +107 -0
- package/dist/tools/cookies.d.ts +67 -0
- package/dist/tools/cookies.js +121 -0
- package/dist/tools/design_extract.d.ts +109 -0
- package/dist/tools/design_extract.js +641 -0
- package/dist/tools/dialog.d.ts +24 -0
- package/dist/tools/dialog.js +109 -0
- package/dist/tools/drag.d.ts +15 -0
- package/dist/tools/drag.js +29 -0
- package/dist/tools/emulation.d.ts +33 -0
- package/dist/tools/emulation.js +69 -0
- package/dist/tools/eval.d.ts +20 -0
- package/dist/tools/eval.js +92 -0
- package/dist/tools/fill.d.ts +41 -0
- package/dist/tools/fill.js +667 -0
- package/dist/tools/find.d.ts +30 -0
- package/dist/tools/find.js +60 -0
- package/dist/tools/geo.d.ts +19 -0
- package/dist/tools/geo.js +29 -0
- package/dist/tools/github/analyze.d.ts +4 -0
- package/dist/tools/github/analyze.js +113 -0
- package/dist/tools/github/cache.d.ts +21 -0
- package/dist/tools/github/cache.js +28 -0
- package/dist/tools/github/index.d.ts +4 -0
- package/dist/tools/github/index.js +4 -0
- package/dist/tools/github/issues.d.ts +9 -0
- package/dist/tools/github/issues.js +88 -0
- package/dist/tools/github/pr.d.ts +5 -0
- package/dist/tools/github/pr.js +88 -0
- package/dist/tools/github/rateLimiter.d.ts +4 -0
- package/dist/tools/github/rateLimiter.js +46 -0
- package/dist/tools/github/read.d.ts +34 -0
- package/dist/tools/github/read.js +74 -0
- package/dist/tools/github/repoContext.d.ts +20 -0
- package/dist/tools/github/repoContext.js +129 -0
- package/dist/tools/highlight.d.ts +20 -0
- package/dist/tools/highlight.js +140 -0
- package/dist/tools/hover.d.ts +19 -0
- package/dist/tools/hover.js +57 -0
- package/dist/tools/inspect.d.ts +17 -0
- package/dist/tools/inspect.js +125 -0
- package/dist/tools/integration.test.d.ts +2 -0
- package/dist/tools/integration.test.js +96 -0
- package/dist/tools/key.d.ts +25 -0
- package/dist/tools/key.js +173 -0
- package/dist/tools/macro_compiler.d.ts +7 -0
- package/dist/tools/macro_compiler.js +82 -0
- package/dist/tools/mouse.d.ts +21 -0
- package/dist/tools/mouse.js +62 -0
- package/dist/tools/navigate.d.ts +16 -0
- package/dist/tools/navigate.js +188 -0
- package/dist/tools/network_intercept.d.ts +17 -0
- package/dist/tools/network_intercept.js +151 -0
- package/dist/tools/office/index.d.ts +9 -0
- package/dist/tools/office/index.js +7 -0
- package/dist/tools/office/list.d.ts +15 -0
- package/dist/tools/office/list.js +41 -0
- package/dist/tools/office/parse.d.ts +20 -0
- package/dist/tools/office/parse.js +172 -0
- package/dist/tools/pdf.d.ts +22 -0
- package/dist/tools/pdf.js +42 -0
- package/dist/tools/performance.d.ts +12 -0
- package/dist/tools/performance.js +47 -0
- package/dist/tools/performance_test.d.ts +70 -0
- package/dist/tools/performance_test.js +128 -0
- package/dist/tools/plan.d.ts +39 -0
- package/dist/tools/plan.js +161 -0
- package/dist/tools/pointer.d.ts +35 -0
- package/dist/tools/pointer.js +522 -0
- package/dist/tools/read.d.ts +30 -0
- package/dist/tools/read.js +488 -0
- package/dist/tools/recording.d.ts +45 -0
- package/dist/tools/recording.js +124 -0
- package/dist/tools/response.d.ts +129 -0
- package/dist/tools/response.js +5 -0
- package/dist/tools/scrape.d.ts +24 -0
- package/dist/tools/scrape.js +140 -0
- package/dist/tools/screenshot.d.ts +40 -0
- package/dist/tools/screenshot.js +79 -0
- package/dist/tools/scroll.d.ts +23 -0
- package/dist/tools/scroll.js +196 -0
- package/dist/tools/select.d.ts +13 -0
- package/dist/tools/select.js +217 -0
- package/dist/tools/snapshot.d.ts +27 -0
- package/dist/tools/snapshot.js +99 -0
- package/dist/tools/storage.d.ts +18 -0
- package/dist/tools/storage.js +29 -0
- package/dist/tools/tabs.d.ts +77 -0
- package/dist/tools/tabs.js +342 -0
- package/dist/tools/thought.d.ts +16 -0
- package/dist/tools/thought.js +79 -0
- package/dist/tools/type.d.ts +65 -0
- package/dist/tools/type.js +1061 -0
- package/dist/tools/type_secret.d.ts +23 -0
- package/dist/tools/type_secret.js +229 -0
- package/dist/tools/upload.d.ts +19 -0
- package/dist/tools/upload.js +103 -0
- package/dist/tools/video_compiler.d.ts +24 -0
- package/dist/tools/video_compiler.js +199 -0
- package/dist/tools/viewport.d.ts +44 -0
- package/dist/tools/viewport.js +230 -0
- package/dist/tools/wait.d.ts +19 -0
- package/dist/tools/wait.js +202 -0
- package/dist/tools/wait_for.d.ts +23 -0
- package/dist/tools/wait_for.js +30 -0
- package/dist/tools/windows.d.ts +22 -0
- package/dist/tools/windows.js +57 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +12 -0
- package/docs/DEV_MODE.md +68 -0
- package/docs/DOCUMENTATION.md +532 -0
- package/docs/PLUGINS.md +538 -0
- package/docs/TOOLS.md +104 -0
- package/docs/dev_plugin.md +310 -0
- package/ext-dist/background.js +467 -0
- package/ext-dist/content.js +3089 -0
- package/ext-dist/dashboard.html +583 -0
- package/ext-dist/hud/hud.js +73 -0
- package/ext-dist/hud/index.html +20 -0
- package/ext-dist/manifest.json +77 -0
- package/ext-dist/sidepanel/sidepanel.js +25 -0
- package/ext-dist/sidepanel.html +547 -0
- package/ext-dist/styles.css +218 -0
- package/icon.png +0 -0
- package/mcp.json +796 -0
- package/package.json +113 -0
- package/server.json +23 -0
- package/smithery.yaml +11 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — audit/logger.ts
|
|
3
|
+
* Appends structured action records to ~/.weavetab-system/logs/mission_<timestamp>.log and JSON lines to mission_<timestamp>.jsonl.
|
|
4
|
+
* Only writes logs when devMode is true to prevent storage spam.
|
|
5
|
+
* Weavetab by fy2ne
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { broadcastTelemetry } from "./telemetry.js";
|
|
10
|
+
import { getSystemDir, getCachedConfig } from "../config/loader.js";
|
|
11
|
+
// Mission logs always go to the system dir (~/.weavetab-system/logs)
|
|
12
|
+
// to avoid polluting user workspaces with large log files.
|
|
13
|
+
const missionId = new Date().toISOString().replace(/[:.]/g, "-");
|
|
14
|
+
function getLogDir() { return getSystemDir("logs"); }
|
|
15
|
+
function getLogPath() { return path.join(getLogDir(), `mission_${missionId}.log`); }
|
|
16
|
+
function getJsonLogPath() { return path.join(getLogDir(), `mission_${missionId}.jsonl`); }
|
|
17
|
+
// Check if logging should be enabled based on devMode
|
|
18
|
+
let _isCheckingConfig = false;
|
|
19
|
+
function isLoggingEnabled() {
|
|
20
|
+
if (_isCheckingConfig)
|
|
21
|
+
return false;
|
|
22
|
+
try {
|
|
23
|
+
_isCheckingConfig = true;
|
|
24
|
+
const config = getCachedConfig();
|
|
25
|
+
return config ? (config.devMode || false) : false;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false; // Fail safe - no logging if config can't be read
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
_isCheckingConfig = false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Redact sensitive data patterns from logs
|
|
35
|
+
function redactSensitiveData(text) {
|
|
36
|
+
if (!text || typeof text !== 'string')
|
|
37
|
+
return text;
|
|
38
|
+
let redacted = text;
|
|
39
|
+
// Redact common secret patterns
|
|
40
|
+
const patterns = [
|
|
41
|
+
// API keys, tokens, secrets in URLs
|
|
42
|
+
/([?&](api_key|token|secret|password|credential|auth|access_token|refresh_token)=[^&\s]+)/gi,
|
|
43
|
+
// Bearer tokens
|
|
44
|
+
/(Bearer\s+[A-Za-z0-9\-._~+/]+)/gi,
|
|
45
|
+
// Basic auth in URLs
|
|
46
|
+
/(\/\/[^:]+:[^@]+@)/g,
|
|
47
|
+
// UUIDs that might be tokens
|
|
48
|
+
/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,
|
|
49
|
+
// Long alphanumeric strings that might be keys (30+ chars)
|
|
50
|
+
/\b[A-Za-z0-9+/]{30,}={0,2}\b/g,
|
|
51
|
+
];
|
|
52
|
+
for (const pattern of patterns) {
|
|
53
|
+
redacted = redacted.replace(pattern, (match) => {
|
|
54
|
+
// Keep the parameter name but redact the value
|
|
55
|
+
if (match.includes('=')) {
|
|
56
|
+
const [key, value] = match.split('=');
|
|
57
|
+
return `${key}=[REDACTED]`;
|
|
58
|
+
}
|
|
59
|
+
return '[REDACTED]';
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return redacted;
|
|
63
|
+
}
|
|
64
|
+
const plainBuffer = { lines: [], timer: null };
|
|
65
|
+
const jsonBuffer = { lines: [], timer: null };
|
|
66
|
+
function scheduleFlush(buffer, filePath) {
|
|
67
|
+
if (buffer.timer)
|
|
68
|
+
return; // already scheduled
|
|
69
|
+
buffer.timer = setTimeout(() => {
|
|
70
|
+
buffer.timer = null;
|
|
71
|
+
if (buffer.lines.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
const chunk = buffer.lines.join("");
|
|
74
|
+
buffer.lines = [];
|
|
75
|
+
fs.appendFile(filePath, chunk, () => { });
|
|
76
|
+
}, 100);
|
|
77
|
+
buffer.timer.unref?.();
|
|
78
|
+
}
|
|
79
|
+
// On exit, flush remaining buffered lines synchronously so no log is lost
|
|
80
|
+
process.on("exit", () => {
|
|
81
|
+
try {
|
|
82
|
+
if (plainBuffer.lines.length > 0) {
|
|
83
|
+
if (plainBuffer.timer) {
|
|
84
|
+
clearTimeout(plainBuffer.timer);
|
|
85
|
+
plainBuffer.timer = null;
|
|
86
|
+
}
|
|
87
|
+
fs.appendFileSync(getLogPath(), plainBuffer.lines.join(""), "utf-8");
|
|
88
|
+
plainBuffer.lines = [];
|
|
89
|
+
}
|
|
90
|
+
if (jsonBuffer.lines.length > 0) {
|
|
91
|
+
if (jsonBuffer.timer) {
|
|
92
|
+
clearTimeout(jsonBuffer.timer);
|
|
93
|
+
jsonBuffer.timer = null;
|
|
94
|
+
}
|
|
95
|
+
fs.appendFileSync(getJsonLogPath(), jsonBuffer.lines.join(""), "utf-8");
|
|
96
|
+
jsonBuffer.lines = [];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch { /* ignore — best-effort */ }
|
|
100
|
+
});
|
|
101
|
+
export function logAction(action, target, result) {
|
|
102
|
+
try {
|
|
103
|
+
// Redact sensitive data before logging
|
|
104
|
+
// Use a session-agnostic redaction for general logs (no specific session ID)
|
|
105
|
+
const redactedTarget = redactSensitiveData(target);
|
|
106
|
+
const redactedResult = redactSensitiveData(result);
|
|
107
|
+
// Always broadcast telemetry (separate from file logging)
|
|
108
|
+
broadcastTelemetry({ type: "log", payload: { action, target: redactedTarget, result: redactedResult } });
|
|
109
|
+
// Only write to log files if devMode is enabled
|
|
110
|
+
if (!isLoggingEnabled()) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const timestamp = new Date().toISOString();
|
|
114
|
+
const paddedAction = action.padEnd(10);
|
|
115
|
+
const line = `[${timestamp}] ${paddedAction} ${redactedTarget} → ${redactedResult}\n`;
|
|
116
|
+
// Ensure the log directory exists (only if we're about to write the first line)
|
|
117
|
+
if (plainBuffer.lines.length === 0) {
|
|
118
|
+
const dir = getLogDir();
|
|
119
|
+
if (!fs.existsSync(dir))
|
|
120
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
plainBuffer.lines.push(line);
|
|
123
|
+
scheduleFlush(plainBuffer, getLogPath());
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
127
|
+
process.stderr.write(`[!] Weave warning: Failed to write audit log: ${msg}\n`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export function logActionStructured(entry) {
|
|
131
|
+
try {
|
|
132
|
+
// Redact sensitive data before logging
|
|
133
|
+
const redactedEntry = {
|
|
134
|
+
...entry,
|
|
135
|
+
parameters: entry.parameters ? redactSensitiveDataInObject(entry.parameters) : undefined,
|
|
136
|
+
pageUrl: entry.pageUrl ? redactSensitiveData(entry.pageUrl) : undefined,
|
|
137
|
+
result: entry.result ? redactSensitiveData(entry.result) : "",
|
|
138
|
+
};
|
|
139
|
+
// Only write to log files if devMode is enabled
|
|
140
|
+
if (!isLoggingEnabled()) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const line = JSON.stringify(redactedEntry) + "\n";
|
|
144
|
+
if (jsonBuffer.lines.length === 0) {
|
|
145
|
+
const dir = getLogDir();
|
|
146
|
+
if (!fs.existsSync(dir))
|
|
147
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
jsonBuffer.lines.push(line);
|
|
150
|
+
scheduleFlush(jsonBuffer, getJsonLogPath());
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
154
|
+
process.stderr.write(`[!] Weave warning: Failed to write structured audit log: ${msg}\n`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Recursively redact sensitive data in objects
|
|
158
|
+
function redactSensitiveDataInObject(obj) {
|
|
159
|
+
const result = {};
|
|
160
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
161
|
+
if (typeof value === 'string') {
|
|
162
|
+
result[key] = redactSensitiveData(value);
|
|
163
|
+
}
|
|
164
|
+
else if (typeof value === 'object' && value !== null) {
|
|
165
|
+
result[key] = redactSensitiveDataInObject(value);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
result[key] = value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
export function logDebug(message, ...optionalParams) {
|
|
174
|
+
if (!isLoggingEnabled())
|
|
175
|
+
return;
|
|
176
|
+
process.stderr.write(`${message} ${optionalParams.join(' ')}\n`);
|
|
177
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — audit/telemetry.ts
|
|
3
|
+
* UDP IPC for broadcasting live telemetry to the CLI dashboard without breaking stdio MCP.
|
|
4
|
+
* Also tracks tool usage analytics locally (Phase 10g).
|
|
5
|
+
* Weavetab by fy2ne
|
|
6
|
+
*/
|
|
7
|
+
export interface TelemetryEvent {
|
|
8
|
+
type: "log" | "state" | "browser" | "tool_start" | "tool_end" | "chat";
|
|
9
|
+
timestamp: number;
|
|
10
|
+
payload: any;
|
|
11
|
+
}
|
|
12
|
+
export interface ToolUsageEntry {
|
|
13
|
+
tool: string;
|
|
14
|
+
domain: string;
|
|
15
|
+
duration: number;
|
|
16
|
+
success: boolean;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ToolUsageStats {
|
|
20
|
+
totalCalls: number;
|
|
21
|
+
perTool: Record<string, {
|
|
22
|
+
calls: number;
|
|
23
|
+
failures: number;
|
|
24
|
+
avgDurationMs: number;
|
|
25
|
+
}>;
|
|
26
|
+
perDomain: Record<string, {
|
|
27
|
+
calls: number;
|
|
28
|
+
failures: number;
|
|
29
|
+
}>;
|
|
30
|
+
recentEntries: ToolUsageEntry[];
|
|
31
|
+
}
|
|
32
|
+
export declare function recordToolUsage(entry: ToolUsageEntry): void;
|
|
33
|
+
export declare function getToolUsageStats(): ToolUsageStats;
|
|
34
|
+
export declare function clearToolUsageStats(): void;
|
|
35
|
+
/** Broadcast a telemetry event to any listening dashboard (wb run) */
|
|
36
|
+
export declare function broadcastTelemetry(event: Omit<TelemetryEvent, "timestamp">): void;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — audit/telemetry.ts
|
|
3
|
+
* UDP IPC for broadcasting live telemetry to the CLI dashboard without breaking stdio MCP.
|
|
4
|
+
* Also tracks tool usage analytics locally (Phase 10g).
|
|
5
|
+
* Weavetab by fy2ne
|
|
6
|
+
*/
|
|
7
|
+
import * as dgram from "node:dgram";
|
|
8
|
+
import * as fs from "node:fs";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import * as os from "node:os";
|
|
11
|
+
import * as crypto from "node:crypto";
|
|
12
|
+
const TELEMETRY_PORT = 9223;
|
|
13
|
+
const STATS_FILE = path.join(os.homedir(), ".weavetab-system", "stats.json");
|
|
14
|
+
let udpSocket = null;
|
|
15
|
+
// Generate or load telemetry secret for authentication
|
|
16
|
+
const TELEMETRY_SECRET_FILE = path.join(os.homedir(), ".weavetab-system", "telemetry-secret");
|
|
17
|
+
let telemetrySecret;
|
|
18
|
+
function getTelemetrySecret() {
|
|
19
|
+
if (telemetrySecret)
|
|
20
|
+
return telemetrySecret;
|
|
21
|
+
try {
|
|
22
|
+
if (fs.existsSync(TELEMETRY_SECRET_FILE)) {
|
|
23
|
+
telemetrySecret = fs.readFileSync(TELEMETRY_SECRET_FILE, "utf-8").trim();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
telemetrySecret = crypto.randomBytes(32).toString("hex");
|
|
27
|
+
const dir = path.dirname(TELEMETRY_SECRET_FILE);
|
|
28
|
+
if (!fs.existsSync(dir))
|
|
29
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
30
|
+
fs.writeFileSync(TELEMETRY_SECRET_FILE, telemetrySecret, { mode: 0o600 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
telemetrySecret = crypto.randomBytes(32).toString("hex");
|
|
35
|
+
}
|
|
36
|
+
return telemetrySecret;
|
|
37
|
+
}
|
|
38
|
+
let statsCache = null;
|
|
39
|
+
function loadStats() {
|
|
40
|
+
if (statsCache)
|
|
41
|
+
return statsCache;
|
|
42
|
+
try {
|
|
43
|
+
const data = fs.readFileSync(STATS_FILE, "utf-8");
|
|
44
|
+
statsCache = JSON.parse(data);
|
|
45
|
+
return statsCache;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
statsCache = {
|
|
49
|
+
totalCalls: 0,
|
|
50
|
+
perTool: {},
|
|
51
|
+
perDomain: {},
|
|
52
|
+
recentEntries: [],
|
|
53
|
+
};
|
|
54
|
+
return statsCache;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let statsDirty = false;
|
|
58
|
+
let saveStatsTimer = null;
|
|
59
|
+
function saveStats() {
|
|
60
|
+
if (!statsCache)
|
|
61
|
+
return;
|
|
62
|
+
// Mark as dirty and schedule an async flush at most once per 5 seconds.
|
|
63
|
+
// Previously this was a synchronous writeFileSync on every tool call,
|
|
64
|
+
// blocking the event loop. Now we batch writes to avoid that overhead.
|
|
65
|
+
statsDirty = true;
|
|
66
|
+
if (!saveStatsTimer) {
|
|
67
|
+
saveStatsTimer = setTimeout(() => {
|
|
68
|
+
saveStatsTimer = null;
|
|
69
|
+
if (!statsDirty || !statsCache)
|
|
70
|
+
return;
|
|
71
|
+
statsDirty = false;
|
|
72
|
+
const dir = path.dirname(STATS_FILE);
|
|
73
|
+
try {
|
|
74
|
+
if (!fs.existsSync(dir))
|
|
75
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
const data = JSON.stringify(statsCache, null, 2);
|
|
77
|
+
fs.writeFile(STATS_FILE, data, () => { });
|
|
78
|
+
}
|
|
79
|
+
catch { /* ignore */ }
|
|
80
|
+
}, 5000);
|
|
81
|
+
// Allow the timer to not prevent process exit
|
|
82
|
+
saveStatsTimer.unref?.();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Flush remaining dirty stats synchronously on exit so no data is lost
|
|
86
|
+
process.on("exit", () => {
|
|
87
|
+
if (!statsDirty || !statsCache)
|
|
88
|
+
return;
|
|
89
|
+
try {
|
|
90
|
+
const dir = path.dirname(STATS_FILE);
|
|
91
|
+
if (!fs.existsSync(dir))
|
|
92
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
93
|
+
fs.writeFileSync(STATS_FILE, JSON.stringify(statsCache, null, 2));
|
|
94
|
+
}
|
|
95
|
+
catch { /* ignore */ }
|
|
96
|
+
});
|
|
97
|
+
export function recordToolUsage(entry) {
|
|
98
|
+
const s = loadStats();
|
|
99
|
+
s.totalCalls++;
|
|
100
|
+
if (!s.perTool[entry.tool])
|
|
101
|
+
s.perTool[entry.tool] = { calls: 0, failures: 0, avgDurationMs: 0 };
|
|
102
|
+
const t = s.perTool[entry.tool];
|
|
103
|
+
t.calls++;
|
|
104
|
+
if (!entry.success)
|
|
105
|
+
t.failures++;
|
|
106
|
+
t.avgDurationMs = Math.round((t.avgDurationMs * (t.calls - 1) + entry.duration) / t.calls);
|
|
107
|
+
const domain = entry.domain || "(unknown)";
|
|
108
|
+
if (!s.perDomain[domain])
|
|
109
|
+
s.perDomain[domain] = { calls: 0, failures: 0 };
|
|
110
|
+
s.perDomain[domain].calls++;
|
|
111
|
+
if (!entry.success)
|
|
112
|
+
s.perDomain[domain].failures++;
|
|
113
|
+
s.recentEntries.unshift(entry);
|
|
114
|
+
if (s.recentEntries.length > 1000)
|
|
115
|
+
s.recentEntries.length = 1000;
|
|
116
|
+
saveStats();
|
|
117
|
+
}
|
|
118
|
+
export function getToolUsageStats() {
|
|
119
|
+
return loadStats();
|
|
120
|
+
}
|
|
121
|
+
export function clearToolUsageStats() {
|
|
122
|
+
statsCache = {
|
|
123
|
+
totalCalls: 0,
|
|
124
|
+
perTool: {},
|
|
125
|
+
perDomain: {},
|
|
126
|
+
recentEntries: [],
|
|
127
|
+
};
|
|
128
|
+
saveStats();
|
|
129
|
+
}
|
|
130
|
+
/** Broadcast a telemetry event to any listening dashboard (wb run) */
|
|
131
|
+
export function broadcastTelemetry(event) {
|
|
132
|
+
if (!udpSocket) {
|
|
133
|
+
try {
|
|
134
|
+
udpSocket = dgram.createSocket("udp4");
|
|
135
|
+
// Prevent the socket from keeping the process alive
|
|
136
|
+
udpSocket.unref();
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const fullEvent = {
|
|
143
|
+
...event,
|
|
144
|
+
timestamp: Date.now()
|
|
145
|
+
};
|
|
146
|
+
try {
|
|
147
|
+
const secret = getTelemetrySecret();
|
|
148
|
+
const payload = JSON.stringify(fullEvent);
|
|
149
|
+
const signature = crypto.createHmac("sha256", secret).update(payload).digest("hex");
|
|
150
|
+
const message = {
|
|
151
|
+
sig: signature,
|
|
152
|
+
payload: payload
|
|
153
|
+
};
|
|
154
|
+
const msg = Buffer.from(JSON.stringify(message) + "\n");
|
|
155
|
+
udpSocket.send(msg, 0, msg.length, TELEMETRY_PORT, "127.0.0.1", (err) => {
|
|
156
|
+
// Ignore broadcast errors (e.g. no dashboard listening)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Ignore stringify/send errors
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Config, BrowserEngine } from "../config/loader.js";
|
|
2
|
+
import CDP from "chrome-remote-interface";
|
|
3
|
+
export interface BrowserInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function findBrowser(preferred?: string): BrowserInfo | null;
|
|
8
|
+
export declare function findFirefox(): BrowserInfo | null;
|
|
9
|
+
export declare function probeAllBrowsers(): BrowserInfo[];
|
|
10
|
+
export declare function launchWithBridge(config: Config): Promise<{
|
|
11
|
+
path: string;
|
|
12
|
+
name: string;
|
|
13
|
+
port: number;
|
|
14
|
+
engine?: BrowserEngine;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function injectStealthScript(session: CDP.Client): Promise<void>;
|