cbrowser 19.2.0 → 19.2.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/README.md +2 -2
- package/dist/analysis/accessibility-empathy.d.ts +6 -0
- package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
- package/dist/analysis/accessibility-empathy.js +28 -77
- package/dist/analysis/accessibility-empathy.js.map +1 -1
- package/dist/analysis/competitive-benchmark.js +2 -2
- package/dist/analysis/competitive-benchmark.js.map +1 -1
- package/dist/analysis/persona-comparison.d.ts.map +1 -1
- package/dist/analysis/persona-comparison.js +5 -1
- package/dist/analysis/persona-comparison.js.map +1 -1
- package/dist/browser.js +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +44 -7
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +2 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +8 -1
- package/dist/daemon.js.map +1 -1
- package/dist/mcp-server-remote.d.ts +3 -0
- package/dist/mcp-server-remote.d.ts.map +1 -1
- package/dist/mcp-server-remote.js +12 -1
- package/dist/mcp-server-remote.js.map +1 -1
- package/dist/mcp-tools/account-personas.d.ts +3 -2
- package/dist/mcp-tools/account-personas.d.ts.map +1 -1
- package/dist/mcp-tools/account-personas.js +13 -4
- package/dist/mcp-tools/account-personas.js.map +1 -1
- package/dist/mcp-tools/base/advanced-interaction-tools.js +1 -1
- package/dist/mcp-tools/base/advanced-interaction-tools.js.map +1 -1
- package/dist/mcp-tools/base/audit-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/audit-tools.js +49 -15
- package/dist/mcp-tools/base/audit-tools.js.map +1 -1
- package/dist/mcp-tools/base/browser-state-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/browser-state-tools.js +25 -4
- package/dist/mcp-tools/base/browser-state-tools.js.map +1 -1
- package/dist/mcp-tools/base/cognitive-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/cognitive-tools.js +14 -2
- package/dist/mcp-tools/base/cognitive-tools.js.map +1 -1
- package/dist/mcp-tools/base/gif-tools.d.ts +19 -0
- package/dist/mcp-tools/base/gif-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/gif-tools.js +53 -24
- package/dist/mcp-tools/base/gif-tools.js.map +1 -1
- package/dist/mcp-tools/base/persona-comparison-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/persona-comparison-tools.js +44 -28
- package/dist/mcp-tools/base/persona-comparison-tools.js.map +1 -1
- package/dist/mcp-tools/base/values-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/values-tools.js +12 -0
- package/dist/mcp-tools/base/values-tools.js.map +1 -1
- package/dist/mcp-tools/base/visual-testing-tools.d.ts +17 -0
- package/dist/mcp-tools/base/visual-testing-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/visual-testing-tools.js +184 -148
- package/dist/mcp-tools/base/visual-testing-tools.js.map +1 -1
- package/dist/mcp-tools/inline-image.d.ts +82 -0
- package/dist/mcp-tools/inline-image.d.ts.map +1 -0
- package/dist/mcp-tools/inline-image.js +163 -0
- package/dist/mcp-tools/inline-image.js.map +1 -0
- package/dist/personas.d.ts +37 -0
- package/dist/personas.d.ts.map +1 -1
- package/dist/personas.js +137 -3
- package/dist/personas.js.map +1 -1
- package/dist/security/audit-wrapper.d.ts.map +1 -1
- package/dist/security/audit-wrapper.js +1 -0
- package/dist/security/audit-wrapper.js.map +1 -1
- package/dist/security/script-gate.d.ts +33 -0
- package/dist/security/script-gate.d.ts.map +1 -0
- package/dist/security/script-gate.js +37 -0
- package/dist/security/script-gate.js.map +1 -0
- package/dist/security/tool-permissions.d.ts.map +1 -1
- package/dist/security/tool-permissions.js +4 -0
- package/dist/security/tool-permissions.js.map +1 -1
- package/package.json +1 -1
package/dist/personas.js
CHANGED
|
@@ -14,7 +14,7 @@ import { join } from "path";
|
|
|
14
14
|
import { homedir } from "os";
|
|
15
15
|
import { applyTraitCorrelations } from "./persona-questionnaire.js";
|
|
16
16
|
import { AGENT_PERSONAS, isAgentPersona, getAgentPersona, listAgentPersonas, isAgentPersonaObject } from "./agent-personas.js";
|
|
17
|
-
import { scopedDataDir } from "./persona-scope.js";
|
|
17
|
+
import { scopedDataDir, scopedAccountId } from "./persona-scope.js";
|
|
18
18
|
import { TRAIT_DEFINITIONS, canonicalizeTraits } from "./trait-reference.js";
|
|
19
19
|
// ============================================================================
|
|
20
20
|
// Custom Personas Storage
|
|
@@ -45,6 +45,35 @@ function personasDirFor() {
|
|
|
45
45
|
* @since 16.17.0
|
|
46
46
|
*/
|
|
47
47
|
const RUNTIME_PERSONAS = {};
|
|
48
|
+
/**
|
|
49
|
+
* An account's custom personas, loaded from the CMS, keyed by account.
|
|
50
|
+
*
|
|
51
|
+
* These used to go into RUNTIME_PERSONAS, which is one map for the whole
|
|
52
|
+
* process and is checked FIRST by getAnyPersona. So once any account ran
|
|
53
|
+
* attention_analysis, its personas resolved by name for every other caller in
|
|
54
|
+
* that process - a cross-tenant read - and the trait vector a measurement read
|
|
55
|
+
* for a name depended on whether that had happened yet. list_cognitive_personas
|
|
56
|
+
* never consulted the map, so the roster and persona_lookup returned different
|
|
57
|
+
* records for alexa-eden (WM 0.25 vs 0.40, FOMO 0.25 vs 0.60). (2026-10-09)
|
|
58
|
+
*
|
|
59
|
+
* Stored process-wide because the load is expensive, but READ only through the
|
|
60
|
+
* request's persona scope, so request A can never see account B's personas. And
|
|
61
|
+
* consulted AFTER the on-disk store, which for a scoped request is that
|
|
62
|
+
* account's mirror of the same rows, so every reader agrees on one record.
|
|
63
|
+
*/
|
|
64
|
+
const ACCOUNT_PERSONAS = new Map();
|
|
65
|
+
/** Replace an account's loaded personas. Never visible outside that account's scope. */
|
|
66
|
+
export function registerAccountPersonas(accountId, personas) {
|
|
67
|
+
const byName = {};
|
|
68
|
+
for (const p of personas)
|
|
69
|
+
byName[p.name] = p;
|
|
70
|
+
ACCOUNT_PERSONAS.set(accountId, byName);
|
|
71
|
+
}
|
|
72
|
+
/** The current request's account personas; empty when unscoped. */
|
|
73
|
+
function scopedAccountPersonas() {
|
|
74
|
+
const id = scopedAccountId();
|
|
75
|
+
return id === undefined ? {} : ACCOUNT_PERSONAS.get(id) ?? {};
|
|
76
|
+
}
|
|
48
77
|
function ensurePersonasDir() {
|
|
49
78
|
if (!existsSync(DATA_DIR)) {
|
|
50
79
|
mkdirSync(DATA_DIR, { recursive: true });
|
|
@@ -1725,6 +1754,12 @@ export function getPersona(name) {
|
|
|
1725
1754
|
if (customPersonas[name]) {
|
|
1726
1755
|
return customPersonas[name];
|
|
1727
1756
|
}
|
|
1757
|
+
// Then the calling account's CMS personas, in the same order getAnyPersona
|
|
1758
|
+
// uses, so list_cognitive_personas and persona_lookup cannot disagree.
|
|
1759
|
+
const accountPersonas = scopedAccountPersonas();
|
|
1760
|
+
if (accountPersonas[name]) {
|
|
1761
|
+
return accountPersonas[name];
|
|
1762
|
+
}
|
|
1728
1763
|
// Fall back to built-ins
|
|
1729
1764
|
return BUILTIN_PERSONAS[name];
|
|
1730
1765
|
}
|
|
@@ -1734,8 +1769,9 @@ export function getPersona(name) {
|
|
|
1734
1769
|
export function listPersonas() {
|
|
1735
1770
|
const builtinNames = Object.keys(BUILTIN_PERSONAS);
|
|
1736
1771
|
const customNames = Object.keys(loadCustomPersonas());
|
|
1772
|
+
const accountNames = Object.keys(scopedAccountPersonas());
|
|
1737
1773
|
// Combine and dedupe (custom personas with same name as built-in take precedence in getPersona)
|
|
1738
|
-
return [...new Set([...builtinNames, ...customNames])];
|
|
1774
|
+
return [...new Set([...builtinNames, ...customNames, ...accountNames])];
|
|
1739
1775
|
}
|
|
1740
1776
|
/**
|
|
1741
1777
|
* List only custom persona names.
|
|
@@ -3330,6 +3366,13 @@ export function getAnyPersona(name) {
|
|
|
3330
3366
|
if (customPersonas[name]) {
|
|
3331
3367
|
return customPersonas[name];
|
|
3332
3368
|
}
|
|
3369
|
+
// 2b. The calling account's CMS personas (scoped; empty when unscoped).
|
|
3370
|
+
// Same position as in getPersona, so the roster and every measurement
|
|
3371
|
+
// resolve a name to the same record.
|
|
3372
|
+
const accountPersonas = scopedAccountPersonas();
|
|
3373
|
+
if (accountPersonas[name]) {
|
|
3374
|
+
return accountPersonas[name];
|
|
3375
|
+
}
|
|
3333
3376
|
// 3. Check built-in personas
|
|
3334
3377
|
if (BUILTIN_PERSONAS[name]) {
|
|
3335
3378
|
return BUILTIN_PERSONAS[name];
|
|
@@ -3442,6 +3485,96 @@ export function resolvePersonaOrThrow(name, syntheticTraits) {
|
|
|
3442
3485
|
}
|
|
3443
3486
|
throw new UnknownPersonaError(name, suggestPersonaNames(name));
|
|
3444
3487
|
}
|
|
3488
|
+
/**
|
|
3489
|
+
* Shorthand -> roster name, shared by every persona-accepting tool.
|
|
3490
|
+
* v14.2.5: Added elderly-user mapping (issue #190 - persona dropout)
|
|
3491
|
+
*/
|
|
3492
|
+
export const PERSONA_ALIASES = {
|
|
3493
|
+
"motor-tremor": "motor-impairment-tremor",
|
|
3494
|
+
"motor": "motor-impairment-tremor",
|
|
3495
|
+
"tremor": "motor-impairment-tremor",
|
|
3496
|
+
"low-vision": "low-vision-magnified",
|
|
3497
|
+
"vision": "low-vision-magnified",
|
|
3498
|
+
"magnified": "low-vision-magnified",
|
|
3499
|
+
"adhd": "cognitive-adhd",
|
|
3500
|
+
"cognitive": "cognitive-adhd",
|
|
3501
|
+
"attention": "cognitive-adhd",
|
|
3502
|
+
"dyslexia": "dyslexic-user",
|
|
3503
|
+
"dyslexic": "dyslexic-user",
|
|
3504
|
+
"reading": "dyslexic-user",
|
|
3505
|
+
"deaf": "deaf-user",
|
|
3506
|
+
"hearing": "deaf-user",
|
|
3507
|
+
"elderly": "elderly-low-vision",
|
|
3508
|
+
"elderly-user": "elderly-low-vision", // v14.2.5: Added missing mapping
|
|
3509
|
+
"elderly-low-vision": "elderly-low-vision",
|
|
3510
|
+
"senior": "elderly-low-vision",
|
|
3511
|
+
"old": "elderly-low-vision", // v14.2.5: Additional synonym
|
|
3512
|
+
"color-blind": "color-blind-deuteranopia",
|
|
3513
|
+
"colorblind": "color-blind-deuteranopia",
|
|
3514
|
+
"deuteranopia": "color-blind-deuteranopia",
|
|
3515
|
+
// v18.35.0: New research-backed cognitive disability personas
|
|
3516
|
+
"autism": "autism-spectrum",
|
|
3517
|
+
"autistic": "autism-spectrum",
|
|
3518
|
+
"asd": "autism-spectrum",
|
|
3519
|
+
"autism-spectrum": "autism-spectrum",
|
|
3520
|
+
"intellectual-disability": "intellectual-disability",
|
|
3521
|
+
"intellectual": "intellectual-disability",
|
|
3522
|
+
"learning-disability": "intellectual-disability",
|
|
3523
|
+
"aphasia": "aphasia-receptive",
|
|
3524
|
+
"aphasia-receptive": "aphasia-receptive",
|
|
3525
|
+
"wernicke": "aphasia-receptive",
|
|
3526
|
+
"dyscalculia": "dyscalculia",
|
|
3527
|
+
"numeracy": "dyscalculia",
|
|
3528
|
+
};
|
|
3529
|
+
/**
|
|
3530
|
+
* Resolve a persona name for a measuring tool, or refuse - the one resolver.
|
|
3531
|
+
*
|
|
3532
|
+
* Every tool that measures "as" a persona must call this BEFORE measuring.
|
|
3533
|
+
* Three tools did their own resolution and each failed open differently:
|
|
3534
|
+
* empathy_audit returned empathyScore 0 with errors: [] for a name that does not
|
|
3535
|
+
* exist, attention_analysis handed the bare string to the relevance LLM, which
|
|
3536
|
+
* role-played it (a one-letter typo of cognitive-adhd scored 81 against the real
|
|
3537
|
+
* persona's 80), and attention_compare reported a nonexistent persona as more
|
|
3538
|
+
* different from power-user than the deliberately extreme real pair. (2026-10-09)
|
|
3539
|
+
*
|
|
3540
|
+
* `aliases` maps shorthand to a roster name (empathy_audit's disability terms).
|
|
3541
|
+
* When the name that measured differs from the one asked for, `resolvedFrom`
|
|
3542
|
+
* says so; a silent substitution reads as the requested persona's result.
|
|
3543
|
+
*/
|
|
3544
|
+
export function resolvePersonaForTool(requested, aliases = PERSONA_ALIASES, aliasFirst = false) {
|
|
3545
|
+
// One alias table for every tool: "motor-tremor" resolved in empathy_audit
|
|
3546
|
+
// and was refused by attention_analysis (report v2). Aliases are a FALLBACK by
|
|
3547
|
+
// default, so an exact roster name always wins; empathy_audit passes
|
|
3548
|
+
// aliasFirst because its table deliberately maps elderly-user to the
|
|
3549
|
+
// elderly-low-vision accessibility persona. (2026-10-09)
|
|
3550
|
+
const alias = aliases[requested.toLowerCase()];
|
|
3551
|
+
const aliased = alias && (aliasFirst || !getAnyPersona(requested)) ? alias : requested;
|
|
3552
|
+
const persona = getAnyPersona(aliased);
|
|
3553
|
+
if (!persona)
|
|
3554
|
+
throw new UnknownPersonaError(requested, suggestPersonaNames(requested));
|
|
3555
|
+
const name = persona.name ?? aliased;
|
|
3556
|
+
return name === requested ? { name, persona } : { name, persona, resolvedFrom: requested };
|
|
3557
|
+
}
|
|
3558
|
+
/**
|
|
3559
|
+
* A cognitive persona for a journey engine, refusing names nothing knows.
|
|
3560
|
+
*
|
|
3561
|
+
* Journey and benchmark engines used `getPersona(name) || first-timer`, so a
|
|
3562
|
+
* typo ran as first-timer and the result was reported under the typo. A name no
|
|
3563
|
+
* registry knows now throws UnknownPersonaError. A name that IS known but is not
|
|
3564
|
+
* a cognitive persona (an accessibility or agent persona) keeps the old
|
|
3565
|
+
* first-timer substitution -- a named limit, not fixed here. (2026-10-09)
|
|
3566
|
+
*/
|
|
3567
|
+
export function getPersonaOrRefuse(name) {
|
|
3568
|
+
if (!name)
|
|
3569
|
+
return BUILTIN_PERSONAS["first-timer"];
|
|
3570
|
+
const direct = getPersona(name);
|
|
3571
|
+
if (direct)
|
|
3572
|
+
return direct;
|
|
3573
|
+
const any = getAnyPersona(name);
|
|
3574
|
+
if (!any)
|
|
3575
|
+
throw new UnknownPersonaError(name, suggestPersonaNames(name));
|
|
3576
|
+
return getPersona(any.name) ?? BUILTIN_PERSONAS["first-timer"];
|
|
3577
|
+
}
|
|
3445
3578
|
export function listAllPersonas() {
|
|
3446
3579
|
const runtimeNames = Object.keys(RUNTIME_PERSONAS);
|
|
3447
3580
|
const builtinNames = Object.keys(BUILTIN_PERSONAS);
|
|
@@ -3449,8 +3582,9 @@ export function listAllPersonas() {
|
|
|
3449
3582
|
const emotionalNames = Object.keys(EMOTIONAL_PERSONAS);
|
|
3450
3583
|
const agentNames = Object.keys(AGENT_PERSONAS);
|
|
3451
3584
|
const customNames = Object.keys(loadCustomPersonas());
|
|
3585
|
+
const accountNames = Object.keys(scopedAccountPersonas());
|
|
3452
3586
|
// Combine and dedupe (runtime first for Enterprise priority)
|
|
3453
|
-
return [...new Set([...runtimeNames, ...builtinNames, ...accessibilityNames, ...emotionalNames, ...agentNames, ...customNames])];
|
|
3587
|
+
return [...new Set([...runtimeNames, ...builtinNames, ...accessibilityNames, ...emotionalNames, ...agentNames, ...customNames, ...accountNames])];
|
|
3454
3588
|
}
|
|
3455
3589
|
/**
|
|
3456
3590
|
* Register personas at runtime without disk writes.
|