yunti-browser-runtime 0.1.3 → 0.2.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 +25 -4
- package/bin/yunti-browser-runtime.js +6 -0
- package/docs/ACTION_RESULT_COVERAGE.md +41 -0
- package/docs/AGENT_WORKFLOW_CONTRACT.md +97 -0
- package/docs/EXECUTION_PLAN.md +1399 -5
- package/docs/EXTENSION_DISTRIBUTION.md +145 -0
- package/docs/EXTENSION_PERMISSION_STRATEGY.md +164 -0
- package/docs/EXTENSION_STORE_COPY.md +210 -0
- package/docs/INSTALL.md +2 -1
- package/docs/NEXT_MAJOR_PLAN.md +808 -0
- package/docs/PROJECT_STATUS.md +1012 -6
- package/docs/PUBLISHING_BLOCKERS.md +1 -1
- package/docs/RELEASE.md +6 -2
- package/docs/RELEASE_0_2_0_CHECKLIST.md +820 -0
- package/docs/ROADMAP.md +44 -0
- package/docs/SECURITY.md +34 -0
- package/docs/TOOL_GUIDE.md +282 -5
- package/extension/content.js +76 -7
- package/extension/dom-observer.js +588 -0
- package/extension/manifest.json +2 -2
- package/extension/session-manager.js +2 -0
- package/extension/tool-handlers.js +1120 -94
- package/mcp/bridge-hub.js +257 -3
- package/mcp/http-server.js +213 -0
- package/mcp/memory.js +5 -5
- package/mcp/redaction.js +52 -3
- package/mcp/server.js +2 -0
- package/mcp/tools.js +417 -38
- package/package.json +4 -2
- package/scripts/check-action-result-coverage.js +145 -0
- package/scripts/doctor.js +4 -0
- package/scripts/package-extension.js +1 -0
- package/scripts/release-check.js +3 -0
- package/skills/yunti-browser-runtime/SKILL.md +125 -2
package/mcp/redaction.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
const SENSITIVE_KEY_RE =
|
|
2
2
|
/cookie|authorization|token|secret|password|passwd|pwd|sid|session|ticket|tgc|captcha|验证码|密码/i
|
|
3
|
+
const JWT_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g
|
|
4
|
+
const BEARER_RE = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/gi
|
|
5
|
+
const PRIVATE_KEY_RE = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
|
|
6
|
+
const LONG_RANDOM_RE = /\b[A-Za-z0-9_-]{32,}\b/g
|
|
7
|
+
const EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi
|
|
8
|
+
const PHONE_RE = /(?:\+?\d[\d\s().-]{7,}\d)/g
|
|
9
|
+
const PAYMENT_CARD_RE = /(?:^|[^\d])((?:\d[ -]?){13,19})(?=$|[^\d])/g
|
|
10
|
+
const ADDRESS_RE =
|
|
11
|
+
/\b\d{1,6}\s+[\p{L}0-9 .'-]{2,}\s+(street|st|road|rd|avenue|ave|lane|ln|boulevard|blvd|drive|dr|way|court|ct)\b|[\p{Script=Han}]{1,20}(省|市|区|县|路|街|号楼|单元|室)/giu
|
|
3
12
|
|
|
4
13
|
export function clampNumber(value, min, max, fallback = min) {
|
|
5
14
|
const number = Number(value)
|
|
@@ -17,12 +26,52 @@ export function redactValue(key, value) {
|
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
export function redactLikelySecrets(text) {
|
|
20
|
-
return
|
|
21
|
-
|
|
29
|
+
return redactLikelySensitiveText(text, 1500)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function redactLikelySensitiveText(text, max = 1500) {
|
|
33
|
+
const redacted = truncateText(text, max)
|
|
34
|
+
.replace(PRIVATE_KEY_RE, "[REDACTED_PRIVATE_KEY]")
|
|
35
|
+
.replace(JWT_RE, "[REDACTED_JWT]")
|
|
36
|
+
.replace(BEARER_RE, "Bearer [REDACTED]")
|
|
37
|
+
.replace(
|
|
38
|
+
/(cookie|authorization|token|secret|password|passwd|pwd|sid|session|ticket|tgc|captcha|api[-_]?key)(["'\s:=]+)([^"',\s}&]+)/gi,
|
|
39
|
+
"$1$2[REDACTED]"
|
|
40
|
+
)
|
|
41
|
+
.replace(LONG_RANDOM_RE, "[REDACTED_TOKEN]")
|
|
42
|
+
.replace(EMAIL_RE, "[REDACTED_EMAIL]")
|
|
43
|
+
.replace(PAYMENT_CARD_RE, (match, digitsPart) => {
|
|
44
|
+
const digits = String(digitsPart || "").replace(/\D/g, "")
|
|
45
|
+
if (!isPaymentCardLike(digits)) return match
|
|
46
|
+
return match.replace(digitsPart, "[REDACTED_PAYMENT_CARD]")
|
|
47
|
+
})
|
|
48
|
+
.replace(PHONE_RE, "[REDACTED_PHONE]")
|
|
49
|
+
.replace(ADDRESS_RE, "[REDACTED_ADDRESS]")
|
|
50
|
+
return redacted.replace(
|
|
51
|
+
/\b(authorization|cookie|token|secret|password|passwd|pwd|sid|session|ticket|tgc|captcha|api[-_]?key)(["'\s:=]+)\[REDACTED\](?:\s+\[REDACTED(?:_[A-Z]+)?\])+/gi,
|
|
22
52
|
"$1$2[REDACTED]"
|
|
23
53
|
)
|
|
24
54
|
}
|
|
25
55
|
|
|
56
|
+
function isPaymentCardLike(digits) {
|
|
57
|
+
return digits.length >= 13 && digits.length <= 19 && passesLuhn(digits)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function passesLuhn(digits) {
|
|
61
|
+
let sum = 0
|
|
62
|
+
let shouldDouble = false
|
|
63
|
+
for (let index = digits.length - 1; index >= 0; index -= 1) {
|
|
64
|
+
let digit = Number(digits[index])
|
|
65
|
+
if (shouldDouble) {
|
|
66
|
+
digit *= 2
|
|
67
|
+
if (digit > 9) digit -= 9
|
|
68
|
+
}
|
|
69
|
+
sum += digit
|
|
70
|
+
shouldDouble = !shouldDouble
|
|
71
|
+
}
|
|
72
|
+
return sum % 10 === 0
|
|
73
|
+
}
|
|
74
|
+
|
|
26
75
|
export function sanitizeUrl(rawUrl) {
|
|
27
76
|
try {
|
|
28
77
|
const url = new URL(String(rawUrl || ""))
|
|
@@ -51,7 +100,7 @@ export function sanitizeRequestBody(body) {
|
|
|
51
100
|
}
|
|
52
101
|
}
|
|
53
102
|
if (Number.isFinite(Number(body.rawBytes))) out.rawBytes = Number(body.rawBytes)
|
|
54
|
-
if (typeof body.preview === "string") out.preview =
|
|
103
|
+
if (typeof body.preview === "string") out.preview = redactLikelySensitiveText(body.preview)
|
|
55
104
|
return Object.keys(out).length ? out : null
|
|
56
105
|
}
|
|
57
106
|
|
package/mcp/server.js
CHANGED
|
@@ -214,6 +214,7 @@ export async function runStdio() {
|
|
|
214
214
|
console.error(
|
|
215
215
|
`[yunti-browser-runtime] bridge ${bridge.mode} on http://${bridge.host}:${bridge.port}`
|
|
216
216
|
)
|
|
217
|
+
console.error(`[yunti-browser-runtime] console http://${bridge.host}:${bridge.port}/console`)
|
|
217
218
|
if (bridge.mode === "owner") {
|
|
218
219
|
if (bridge.authRequired) {
|
|
219
220
|
console.error(
|
|
@@ -253,6 +254,7 @@ export async function runBridgeOnly() {
|
|
|
253
254
|
console.error(
|
|
254
255
|
`[yunti-browser-runtime] bridge ${bridge.mode} on http://${bridge.host}:${bridge.port}`
|
|
255
256
|
)
|
|
257
|
+
console.error(`[yunti-browser-runtime] console http://${bridge.host}:${bridge.port}/console`)
|
|
256
258
|
if (bridge.mode === "owner") {
|
|
257
259
|
if (bridge.authRequired) {
|
|
258
260
|
console.error(
|