cbrowser 18.75.1 → 18.75.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.
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgvIpE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC,CAE1D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvE;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAWpD"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAo0IpE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC,CAE1D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvE;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAWpD"}
@@ -12,6 +12,7 @@
12
12
  * Or: npx cbrowser mcp-server
13
13
  */
14
14
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
15
+ import { PERSONA_CATEGORIES } from "./persona-questionnaire.js";
15
16
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
16
17
  import { z } from "zod";
17
18
  import { CBrowser } from "./browser.js";
@@ -230,6 +231,33 @@ const VALUES_QUESTIONS = [
230
231
  },
231
232
  ];
232
233
  const questionnaireSessionsMap = new Map();
234
+ /**
235
+ * Group a flat Schwartz/SDT value record into the nested schema every other
236
+ * values-returning path uses (schwartz / higherOrder / sdt / maslowLevel).
237
+ *
238
+ * persona_questionnaire_build emitted `values` FLAT, with Schwartz and SDT
239
+ * merged and no higherOrder grouping — so the C4b nested-schema fix never
240
+ * reached the creation path, and a persona built through the questionnaire had
241
+ * a different value shape from the same persona loaded back. Three sites
242
+ * already hand-write this grouping; this is the shared one. (2026-07-29)
243
+ */
244
+ function nestPersonaValues(values) {
245
+ if (!values)
246
+ return undefined;
247
+ const pick = (...keys) => {
248
+ const out = {};
249
+ for (const k of keys)
250
+ if (values[k] !== undefined)
251
+ out[k] = values[k];
252
+ return out;
253
+ };
254
+ return {
255
+ schwartz: pick("selfDirection", "stimulation", "hedonism", "achievement", "power", "security", "conformity", "tradition", "benevolence", "universalism"),
256
+ higherOrder: pick("openness", "selfEnhancement", "conservation", "selfTranscendence"),
257
+ sdt: pick("autonomyNeed", "competenceNeed", "relatednessNeed"),
258
+ maslowLevel: values.maslowLevel,
259
+ };
260
+ }
233
261
  function getQuestionnaireSession(sessionId) {
234
262
  return questionnaireSessionsMap.get(sessionId);
235
263
  }
@@ -942,6 +970,37 @@ async function registerCBrowserTools() {
942
970
  url: result.url,
943
971
  overallStatus: result.overallStatus,
944
972
  summary: result.summary,
973
+ // The evidence used to be collapsed to two integers —
974
+ // screenshotCount / comparisonCount — while `result` carried every
975
+ // screenshot path, every pairwise similarity score, and
976
+ // problematicBrowsers. So the caller received an absolute verdict
977
+ // ("renders consistently across all tested browsers") with every
978
+ // number that could falsify it removed, and no way to open the
979
+ // screenshots it said it had taken.
980
+ //
981
+ // It also explains the contradiction with cross_browser_diff: this
982
+ // tool compares ABOVE-THE-FOLD PIXELS at a forced 1920x1080, while
983
+ // the diff compares FULL-PAGE TEXT at 1280x720. Two different
984
+ // measurements reported in language that claims to settle the same
985
+ // question. `scope` now says which one you are reading.
986
+ // (2026-07-29)
987
+ scope: "above-the-fold pixels at 1920x1080; page TEXT is not compared — use cross_browser_diff for content",
988
+ screenshots: result.screenshots.map((s) => ({
989
+ browser: s.browser,
990
+ path: s.screenshotPath,
991
+ viewport: s.viewport,
992
+ })),
993
+ comparisons: result.comparisons.map((c) => ({
994
+ browserA: c.browserA,
995
+ browserB: c.browserB,
996
+ status: c.analysis?.overallStatus,
997
+ similarity: c.analysis?.similarityScore,
998
+ changes: (c.analysis?.changes ?? []).map((ch) => ({
999
+ severity: ch.severity,
1000
+ description: ch.description,
1001
+ })),
1002
+ })),
1003
+ ...(result.problematicBrowsers?.length ? { problematicBrowsers: result.problematicBrowsers } : {}),
945
1004
  screenshotCount: result.screenshots.length,
946
1005
  comparisonCount: result.comparisons.length,
947
1006
  ...(result.missingBrowsers?.length ? { missingBrowsers: result.missingBrowsers } : {}),
@@ -987,6 +1046,24 @@ async function registerCBrowserTools() {
987
1046
  url: result.url,
988
1047
  overallStatus: result.overallStatus,
989
1048
  summary: result.summary,
1049
+ // `result.issues` and `problematicViewports` were both computed and
1050
+ // then dropped here, so the caller got "13 issues: 7 overflow, 2
1051
+ // unreadable text..." with no way to learn WHICH viewport or WHICH
1052
+ // element — a count they could not act on. Same computed-then-
1053
+ // discarded shape as the cross-browser handler above. (2026-07-29)
1054
+ issues: (result.issues ?? []).map((i) => ({
1055
+ type: i.type,
1056
+ severity: i.severity,
1057
+ description: i.description,
1058
+ affectedViewports: i.affectedViewports,
1059
+ ...(i.breakpointRange ? { breakpointRange: i.breakpointRange } : {}),
1060
+ })),
1061
+ ...(result.problematicViewports?.length ? { problematicViewports: result.problematicViewports } : {}),
1062
+ viewports: result.screenshots.map((s) => ({
1063
+ name: s.viewport
1064
+ ?? s.name,
1065
+ path: s.screenshotPath,
1066
+ })),
990
1067
  viewportsCount: result.screenshots.length,
991
1068
  }, null, 2),
992
1069
  },
@@ -1953,7 +2030,7 @@ This ensures personas are grounded in research, not stereotypes.
1953
2030
  };
1954
2031
  });
1955
2032
  server.tool("persona_category_guidance", "Get research-based guidance for a specific persona category. Explains what values are appropriate and why, with citations. Use before building a persona to understand category constraints.", {
1956
- category: z.enum(["cognitive", "physical", "sensory", "emotional", "general"]).describe("Persona category to get guidance for"),
2033
+ category: z.enum(PERSONA_CATEGORIES).describe("Persona category to get guidance for"),
1957
2034
  }, async ({ category }) => {
1958
2035
  const { getCategoryValuePreset, COGNITIVE_SUBTYPES, } = await import("./persona-questionnaire.js");
1959
2036
  const preset = getCategoryValuePreset(category);
@@ -1983,6 +2060,11 @@ This ensures personas are grounded in research, not stereotypes.
1983
2060
  sensory: "Use neutral (0.5) values. Sensory perception ≠ motivational psychology. Color-blindness doesn't make someone more/less achievement-oriented.",
1984
2061
  emotional: "Apply trait-based values from personality psychology (e.g., anxiety = high security-seeking).",
1985
2062
  general: "Use population baselines. Specific characteristics come from cognitive traits, not disability-based value shifts.",
2063
+ // Added 2026-07-29: this table covered five of the six
2064
+ // categories, and TypeScript flagged it the moment the enum
2065
+ // stopped silently excluding "agent". An unlisted key would have
2066
+ // yielded `undefined` guidance beside a populated preset.
2067
+ agent: "Agent personas are not human — motivational values do not apply. Use trait-based capability values (parsing, retrieval, tool use) and do NOT project human needs like security or belonging onto them.",
1986
2068
  }[category],
1987
2069
  }, null, 2),
1988
2070
  },
@@ -1993,7 +2075,7 @@ This ensures personas are grounded in research, not stereotypes.
1993
2075
  name: z.string().describe("Name for the new persona"),
1994
2076
  description: z.string().describe("Description of the persona"),
1995
2077
  answers: z.record(z.string(), z.number()).describe("Map of trait names to values (0-1), e.g. {patience: 0.25, riskTolerance: 0.75}"),
1996
- category: z.enum(["cognitive", "physical", "sensory", "emotional", "general"]).optional().describe("Persona category for value safeguards. Auto-detected from name/description if not provided."),
2078
+ category: z.enum(PERSONA_CATEGORIES).optional().describe("Persona category for value safeguards. Auto-detected from name/description if not provided."),
1997
2079
  valueOverrides: z.record(z.string(), z.number()).optional().describe("Override specific Schwartz values (0-1), e.g. {security: 0.8, stimulation: 0.3}"),
1998
2080
  save: z.boolean().optional().default(true).describe("Save the persona to disk for future use"),
1999
2081
  }, async ({ name, description, answers, category, valueOverrides, save }) => {
@@ -2047,7 +2129,10 @@ This ensures personas are grounded in research, not stereotypes.
2047
2129
  strategy: categoryResult.valueStrategy,
2048
2130
  guidance: categoryResult.guidance,
2049
2131
  },
2132
+ // Flat shape retained for callers that already read it; the nested
2133
+ // grouping is what every other values-returning path emits.
2050
2134
  values: categoryResult.values,
2135
+ valuesNested: nestPersonaValues(categoryResult.values),
2051
2136
  researchBasis: subtypeValues
2052
2137
  ? [...categoryResult.researchBasis, subtypeValues.researchBasis]
2053
2138
  : categoryResult.researchBasis,