zelari-code 1.18.0 → 1.18.1

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.
@@ -4,8 +4,9 @@
4
4
  * The "visual verification loop" for web projects: after the agent edits a UI,
5
5
  * it navigates the running app and gets back the signals an LLM can actually
6
6
  * act on — console errors, uncaught page exceptions, failed network requests,
7
- * the final title/URL, whether an expected selector is present, and a saved
8
- * screenshot path. Far stronger than "the tests pass" for front-end work.
7
+ * the final title/URL, whether an expected selector is present, evaluate
8
+ * results, and a saved screenshot path. Far stronger than "the tests pass"
9
+ * for front-end work.
9
10
  *
10
11
  * Playwright is an OPTIONAL dependency, loaded via dynamic import so it is not
11
12
  * a hard requirement of the package. When it (or a browser) isn't available,
@@ -19,6 +20,12 @@
19
20
  import { createRequire } from 'node:module';
20
21
  import path from 'node:path';
21
22
  import { pathToFileURL } from 'node:url';
23
+ /** Max length of an evaluate expression (chars). */
24
+ const MAX_EVAL_EXPR = 4_000;
25
+ /** Max JSON-serialized evaluate result size. */
26
+ const MAX_EVAL_RESULT = 8_000;
27
+ /** Max body text sample returned to the agent. */
28
+ const MAX_BODY_SNIPPET = 2_000;
22
29
  /** Coerce a dynamic-import module shape into PlaywrightLike (or null). */
23
30
  function asPlaywright(mod) {
24
31
  if (!mod || typeof mod !== 'object')
@@ -74,6 +81,50 @@ export async function loadPlaywright(cwd) {
74
81
  * Prefer `loadPlaywright(explicitCwd)` at call sites that know the workspace.
75
82
  */
76
83
  export const defaultPlaywrightLoader = async () => loadPlaywright(process.cwd());
84
+ /** Cap and JSON-safe-clone evaluate return values for the agent. */
85
+ export function serializeEvaluateValue(value) {
86
+ try {
87
+ const json = JSON.stringify(value, (_k, v) => {
88
+ if (typeof v === 'function')
89
+ return '[Function]';
90
+ if (typeof v === 'bigint')
91
+ return v.toString();
92
+ if (v instanceof Error)
93
+ return { name: v.name, message: v.message };
94
+ return v;
95
+ });
96
+ if (json === undefined)
97
+ return null;
98
+ if (json.length > MAX_EVAL_RESULT) {
99
+ return {
100
+ truncated: true,
101
+ preview: json.slice(0, MAX_EVAL_RESULT),
102
+ };
103
+ }
104
+ return JSON.parse(json);
105
+ }
106
+ catch (err) {
107
+ return {
108
+ error: `non-serializable: ${err instanceof Error ? err.message : String(err)}`,
109
+ };
110
+ }
111
+ }
112
+ /**
113
+ * Wrap a user expression as a Playwright evaluate **function body**.
114
+ * Playwright treats string pageFunctions as `function(){ <body> }`, so we
115
+ * must `return` the value.
116
+ */
117
+ export function wrapEvaluateExpression(expression) {
118
+ const expr = expression.trim();
119
+ if (!expr)
120
+ return 'return undefined';
121
+ // Multi-statement or already has return → use as body (ensure return if missing).
122
+ if (/\breturn\b/.test(expr) || expr.includes('\n')) {
123
+ return expr;
124
+ }
125
+ // Single expression
126
+ return `return (${expr})`;
127
+ }
77
128
  /**
78
129
  * Navigate to a URL (optionally running a sequence of actions) and collect
79
130
  * verification signals. Best-effort — never throws; a missing browser or a
@@ -83,6 +134,7 @@ export async function runBrowserCheck(options, loader) {
83
134
  const consoleErrors = [];
84
135
  const pageErrors = [];
85
136
  const failedRequests = [];
137
+ const evaluateResults = [];
86
138
  const base = { ok: false, consoleErrors, pageErrors, failedRequests };
87
139
  const resolve = loader ??
88
140
  (() => loadPlaywright(options.cwd ?? process.cwd()));
@@ -99,6 +151,7 @@ export async function runBrowserCheck(options, loader) {
99
151
  }
100
152
  const timeout = options.timeoutMs ?? 15_000;
101
153
  let browser;
154
+ let textFound;
102
155
  try {
103
156
  browser = await pw.chromium.launch({ headless: true });
104
157
  const page = await browser.newPage();
@@ -126,6 +179,61 @@ export async function runBrowserCheck(options, loader) {
126
179
  case 'wait':
127
180
  await page.waitForTimeout(action.ms);
128
181
  break;
182
+ case 'press': {
183
+ const key = action.key.trim();
184
+ if (!key)
185
+ break;
186
+ if (page.keyboard && typeof page.keyboard.press === 'function') {
187
+ await page.keyboard.press(key, { timeout });
188
+ }
189
+ else {
190
+ // Fallback for fakes / surfaces without keyboard
191
+ await page.evaluate(wrapEvaluateExpression(`document.dispatchEvent(new KeyboardEvent('keydown',{key:${JSON.stringify(key)},bubbles:true})); true`));
192
+ }
193
+ break;
194
+ }
195
+ case 'waitForText': {
196
+ const needle = action.text;
197
+ const t = action.timeoutMs ?? timeout;
198
+ try {
199
+ // String function body: Playwright injects as function(arg) { ... }
200
+ await page.waitForFunction(`return (document.body && (document.body.innerText || document.body.textContent || '')).includes(arguments[0])`, needle, { timeout: t });
201
+ textFound = textFound === false ? false : true;
202
+ }
203
+ catch {
204
+ textFound = false;
205
+ }
206
+ break;
207
+ }
208
+ case 'evaluate': {
209
+ const raw = action.expression ?? '';
210
+ if (raw.length > MAX_EVAL_EXPR) {
211
+ evaluateResults.push({
212
+ expression: raw.slice(0, 120) + '…',
213
+ error: `expression too long (max ${MAX_EVAL_EXPR} chars)`,
214
+ });
215
+ break;
216
+ }
217
+ if (!raw.trim()) {
218
+ evaluateResults.push({ expression: raw, error: 'empty expression' });
219
+ break;
220
+ }
221
+ try {
222
+ const wrapped = wrapEvaluateExpression(raw);
223
+ const value = await page.evaluate(wrapped);
224
+ evaluateResults.push({
225
+ expression: raw.length > 200 ? raw.slice(0, 200) + '…' : raw,
226
+ value: serializeEvaluateValue(value),
227
+ });
228
+ }
229
+ catch (err) {
230
+ evaluateResults.push({
231
+ expression: raw.length > 200 ? raw.slice(0, 200) + '…' : raw,
232
+ error: err instanceof Error ? err.message : String(err),
233
+ });
234
+ }
235
+ break;
236
+ }
129
237
  default:
130
238
  break;
131
239
  }
@@ -140,6 +248,21 @@ export async function runBrowserCheck(options, loader) {
140
248
  selectorFound = false;
141
249
  }
142
250
  }
251
+ let bodyTextSnippet;
252
+ if (options.textSample) {
253
+ try {
254
+ const text = await page.evaluate(wrapEvaluateExpression(`(document.body?.innerText || document.body?.textContent || '').trim()`));
255
+ if (typeof text === 'string' && text.length > 0) {
256
+ bodyTextSnippet =
257
+ text.length > MAX_BODY_SNIPPET
258
+ ? text.slice(0, MAX_BODY_SNIPPET) + '…'
259
+ : text;
260
+ }
261
+ }
262
+ catch {
263
+ // ignore
264
+ }
265
+ }
143
266
  let screenshotPath;
144
267
  if (options.screenshotPath) {
145
268
  try {
@@ -159,6 +282,9 @@ export async function runBrowserCheck(options, loader) {
159
282
  url: page.url(),
160
283
  ...(title !== undefined ? { title } : {}),
161
284
  ...(selectorFound !== undefined ? { selectorFound } : {}),
285
+ ...(evaluateResults.length > 0 ? { evaluateResults } : {}),
286
+ ...(textFound !== undefined ? { textFound } : {}),
287
+ ...(bodyTextSnippet !== undefined ? { bodyTextSnippet } : {}),
162
288
  ...(screenshotPath ? { screenshotPath } : {}),
163
289
  };
164
290
  }
@@ -1 +1 @@
1
- {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/cli/browser/driver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/cli/browser/driver.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,10 @@
2
2
  * browser/tools — the `browser_check` visual-verification tool.
3
3
  *
4
4
  * Lets the agent confirm a web change actually works in a real browser:
5
- * navigate the running app, optionally click/fill, and get back console
6
- * errors, uncaught exceptions, failed requests, the title/URL, whether an
7
- * expected element appeared, and a screenshot path. Optional Playwright dep —
8
- * degrades with install instructions when it's not present.
5
+ * navigate the running app, optionally click/fill/evaluate/press, and get back
6
+ * console errors, uncaught exceptions, failed requests, the title/URL, whether
7
+ * an expected element/text appeared, evaluate results, and a screenshot path.
8
+ * Optional Playwright dep — degrades with install instructions when absent.
9
9
  */
10
10
  import path from 'node:path';
11
11
  import os from 'node:os';
@@ -17,24 +17,54 @@ const ActionSchema = z.discriminatedUnion('type', [
17
17
  z.object({ type: z.literal('fill'), selector: z.string().min(1), value: z.string() }),
18
18
  z.object({ type: z.literal('wait'), ms: z.number().int().positive().max(30_000) }),
19
19
  z.object({ type: z.literal('goto'), url: z.string().min(1) }),
20
+ z.object({
21
+ type: z.literal('evaluate'),
22
+ expression: z
23
+ .string()
24
+ .min(1)
25
+ .max(4_000)
26
+ .describe('JS expression or statements run in the page (page.evaluate). Prefer DOM reads ' +
27
+ '(document.querySelector…), not assuming window.game exists. Return JSON-safe values.'),
28
+ }),
29
+ z.object({
30
+ type: z.literal('press'),
31
+ key: z
32
+ .string()
33
+ .min(1)
34
+ .describe('Playwright key name, e.g. "Space", "KeyW", "ArrowLeft", "Enter".'),
35
+ }),
36
+ z.object({
37
+ type: z.literal('waitForText'),
38
+ text: z.string().min(1).describe('Substring that must appear in document body text.'),
39
+ timeoutMs: z.number().int().positive().max(60_000).optional(),
40
+ }),
20
41
  ]);
21
42
  export function createBrowserTool(deps = {}) {
22
43
  return {
23
44
  name: 'browser_check',
24
45
  description: 'Open a URL in a headless browser to VERIFY a web change: optionally run ' +
25
- 'click/fill/goto/wait actions, then report console errors, uncaught page ' +
26
- 'exceptions, failed network requests, the final title/URL, whether an ' +
27
- 'expected selector appeared, and a screenshot path. Use it to confirm UI ' +
28
- 'edits actually render and run stronger than "tests pass" for front-end. ' +
29
- 'Requires Playwright (optional dependency).',
46
+ 'click/fill/goto/wait/press/waitForText/evaluate actions, then report console errors, ' +
47
+ 'uncaught page exceptions, failed network requests, final title/URL, selector/text ' +
48
+ 'presence, evaluate results, and a screenshot path. ' +
49
+ 'Prefer DOM assertions (waitForSelector, waitForText, evaluate on document.querySelector) ' +
50
+ 'over window.* globals — ES modules and const keep symbols off window. ' +
51
+ 'Absence of console errors after a short wait is WEAK smoke only; assert UI state when ' +
52
+ 'claiming a fix is verified. Requires Playwright (optional dependency).',
30
53
  permissions: ['network'],
31
54
  // A browser launch + navigation can take a while.
32
55
  timeoutMs: 60_000,
33
56
  inputSchema: z.object({
34
57
  url: z.string().min(1).describe('URL to open (e.g. http://localhost:3000).'),
35
- actions: z.array(ActionSchema).optional().describe('Optional sequence of interactions before checking.'),
58
+ actions: z
59
+ .array(ActionSchema)
60
+ .optional()
61
+ .describe('Optional sequence of interactions / probes before checking.'),
36
62
  waitForSelector: z.string().optional().describe('Assert this CSS selector is present after actions.'),
37
63
  screenshot: z.boolean().optional().describe('Save a screenshot (default true).'),
64
+ textSample: z
65
+ .boolean()
66
+ .optional()
67
+ .describe('Include a short body.innerText snippet (HUD / Game Over text).'),
38
68
  }),
39
69
  execute: async (args, ctx) => {
40
70
  const a = args;
@@ -48,6 +78,7 @@ export function createBrowserTool(deps = {}) {
48
78
  ...(a.actions ? { actions: a.actions } : {}),
49
79
  ...(a.waitForSelector ? { waitForSelector: a.waitForSelector } : {}),
50
80
  ...(screenshotPath ? { screenshotPath } : {}),
81
+ ...(a.textSample ? { textSample: true } : {}),
51
82
  }, deps.loader);
52
83
  if (!result.ok) {
53
84
  return typedOk({ ok: false, note: result.error ?? 'browser check failed' });
@@ -56,7 +87,14 @@ export function createBrowserTool(deps = {}) {
56
87
  const clean = result.consoleErrors.length === 0 &&
57
88
  result.pageErrors.length === 0 &&
58
89
  result.failedRequests.length === 0 &&
59
- result.selectorFound !== false;
90
+ result.selectorFound !== false &&
91
+ result.textFound !== false;
92
+ const hadDomAssertion = result.selectorFound !== undefined ||
93
+ result.textFound !== undefined ||
94
+ (result.evaluateResults !== undefined && result.evaluateResults.length > 0) ||
95
+ !!result.bodyTextSnippet;
96
+ // Only waits / navigate / screenshot with no errors → weak smoke.
97
+ const onlyWeakSmoke = clean && !hadDomAssertion;
60
98
  return typedOk({
61
99
  ok: true,
62
100
  clean,
@@ -66,7 +104,18 @@ export function createBrowserTool(deps = {}) {
66
104
  pageErrors: result.pageErrors,
67
105
  failedRequests: result.failedRequests,
68
106
  ...(result.selectorFound !== undefined ? { selectorFound: result.selectorFound } : {}),
107
+ ...(result.evaluateResults ? { evaluateResults: result.evaluateResults } : {}),
108
+ ...(result.textFound !== undefined ? { textFound: result.textFound } : {}),
109
+ ...(result.bodyTextSnippet ? { bodyTextSnippet: result.bodyTextSnippet } : {}),
69
110
  ...(result.screenshotPath ? { screenshotPath: result.screenshotPath } : {}),
111
+ ...(onlyWeakSmoke
112
+ ? {
113
+ note: 'Weak smoke only: no selector/text/evaluate assertions. ' +
114
+ 'No console/page errors is necessary but not sufficient to claim a logic fix. ' +
115
+ 'Add waitForSelector, waitForText, or evaluate (DOM/read hooks) for stronger evidence.',
116
+ smokeStrength: 'weak',
117
+ }
118
+ : { smokeStrength: 'asserted' }),
70
119
  });
71
120
  },
72
121
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/browser/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAuB,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,eAAe,EAA6C,MAAM,aAAa,CAAC;AAEzF,MAAM,YAAY,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAChD,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACrF,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;IAClF,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;CAC9D,CAAC,CAAC;AASH,MAAM,UAAU,iBAAiB,CAAC,OAAwB,EAAE;IAC1D,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,0EAA0E;YAC1E,0EAA0E;YAC1E,uEAAuE;YACvE,0EAA0E;YAC1E,4EAA4E;YAC5E,4CAA4C;QAC9C,WAAW,EAAE,CAAC,SAAS,CAAC;QACxB,kDAAkD;QAClD,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,2CAA2C,CAAC;YAC5E,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;YACxG,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;YACrG,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;SACjF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC3B,MAAM,CAAC,GAAG,IAKT,CAAC;YACF,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YAC9C,MAAM,cAAc,GAClB,CAAC,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC1F,sEAAsE;YACtE,uEAAuE;YACvE,MAAM,MAAM,GAAG,MAAM,eAAe,CAClC;gBACE,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5C,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9C,EACD,IAAI,CAAC,MAAM,CACZ,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,OAAO,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9E,CAAC;YACD,wEAAwE;YACxE,MAAM,KAAK,GACT,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;gBACjC,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;gBAC9B,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC;gBAClC,MAAM,CAAC,aAAa,KAAK,KAAK,CAAC;YACjC,OAAO,OAAO,CAAC;gBACb,EAAE,EAAE,IAAI;gBACR,KAAK;gBACL,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,cAAc,EAAE,MAAM,CAAC,cAAc;gBACrC,GAAG,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtF,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/browser/tools.ts"],"names":[],"mappings":"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"}
@@ -18431,7 +18431,8 @@ Earlier members' outputs are shared context. Build on them; do not re-derive or
18431
18431
  - **Verify**: after non-trivial edits, run the project's tests/typecheck/build when available; fix failures you introduced.
18432
18432
  - **Use project scripts**: prefer package.json / Makefile / existing tooling over ad-hoc commands.
18433
18433
  - **Finish**: list the paths you wrote/edited and how to verify. If you wrote nothing, say so honestly \u2014 do not invent a done report.
18434
- - **No spam**: never repeat the same paragraph or status line. One diagnosis, then tools (or one short final answer).`
18434
+ - **No spam**: never repeat the same paragraph or status line. One diagnosis, then tools (or one short final answer).
18435
+ - **Browser smoke honesty**: with \`browser_check\`, prefer \`waitForSelector\` / \`waitForText\` / \`evaluate\` on DOM (or explicit test hooks). Do not claim a logic fix is verified from \u201Cno console errors after N seconds\u201D alone (\`smokeStrength: weak\`). ES modules keep symbols off \`window\` \u2014 do not loop on exposing globals; assert visible UI or inject \`evaluate\` on \`document\`.`
18435
18436
  };
18436
18437
  CLARIFICATION_PROTOCOL_MODULE = {
18437
18438
  type: "custom",
@@ -22623,10 +22624,41 @@ async function loadPlaywright(cwd) {
22623
22624
  return null;
22624
22625
  }
22625
22626
  }
22627
+ function serializeEvaluateValue(value) {
22628
+ try {
22629
+ const json2 = JSON.stringify(value, (_k, v) => {
22630
+ if (typeof v === "function") return "[Function]";
22631
+ if (typeof v === "bigint") return v.toString();
22632
+ if (v instanceof Error) return { name: v.name, message: v.message };
22633
+ return v;
22634
+ });
22635
+ if (json2 === void 0) return null;
22636
+ if (json2.length > MAX_EVAL_RESULT) {
22637
+ return {
22638
+ truncated: true,
22639
+ preview: json2.slice(0, MAX_EVAL_RESULT)
22640
+ };
22641
+ }
22642
+ return JSON.parse(json2);
22643
+ } catch (err) {
22644
+ return {
22645
+ error: `non-serializable: ${err instanceof Error ? err.message : String(err)}`
22646
+ };
22647
+ }
22648
+ }
22649
+ function wrapEvaluateExpression(expression) {
22650
+ const expr = expression.trim();
22651
+ if (!expr) return "return undefined";
22652
+ if (/\breturn\b/.test(expr) || expr.includes("\n")) {
22653
+ return expr;
22654
+ }
22655
+ return `return (${expr})`;
22656
+ }
22626
22657
  async function runBrowserCheck(options, loader) {
22627
22658
  const consoleErrors = [];
22628
22659
  const pageErrors = [];
22629
22660
  const failedRequests = [];
22661
+ const evaluateResults = [];
22630
22662
  const base = { ok: false, consoleErrors, pageErrors, failedRequests };
22631
22663
  const resolve = loader ?? (() => loadPlaywright(options.cwd ?? process.cwd()));
22632
22664
  const pw = await resolve();
@@ -22638,6 +22670,7 @@ async function runBrowserCheck(options, loader) {
22638
22670
  }
22639
22671
  const timeout = options.timeoutMs ?? 15e3;
22640
22672
  let browser;
22673
+ let textFound;
22641
22674
  try {
22642
22675
  browser = await pw.chromium.launch({ headless: true });
22643
22676
  const page = await browser.newPage();
@@ -22664,6 +22697,63 @@ async function runBrowserCheck(options, loader) {
22664
22697
  case "wait":
22665
22698
  await page.waitForTimeout(action.ms);
22666
22699
  break;
22700
+ case "press": {
22701
+ const key = action.key.trim();
22702
+ if (!key) break;
22703
+ if (page.keyboard && typeof page.keyboard.press === "function") {
22704
+ await page.keyboard.press(key, { timeout });
22705
+ } else {
22706
+ await page.evaluate(
22707
+ wrapEvaluateExpression(
22708
+ `document.dispatchEvent(new KeyboardEvent('keydown',{key:${JSON.stringify(key)},bubbles:true})); true`
22709
+ )
22710
+ );
22711
+ }
22712
+ break;
22713
+ }
22714
+ case "waitForText": {
22715
+ const needle = action.text;
22716
+ const t = action.timeoutMs ?? timeout;
22717
+ try {
22718
+ await page.waitForFunction(
22719
+ `return (document.body && (document.body.innerText || document.body.textContent || '')).includes(arguments[0])`,
22720
+ needle,
22721
+ { timeout: t }
22722
+ );
22723
+ textFound = textFound === false ? false : true;
22724
+ } catch {
22725
+ textFound = false;
22726
+ }
22727
+ break;
22728
+ }
22729
+ case "evaluate": {
22730
+ const raw = action.expression ?? "";
22731
+ if (raw.length > MAX_EVAL_EXPR) {
22732
+ evaluateResults.push({
22733
+ expression: raw.slice(0, 120) + "\u2026",
22734
+ error: `expression too long (max ${MAX_EVAL_EXPR} chars)`
22735
+ });
22736
+ break;
22737
+ }
22738
+ if (!raw.trim()) {
22739
+ evaluateResults.push({ expression: raw, error: "empty expression" });
22740
+ break;
22741
+ }
22742
+ try {
22743
+ const wrapped = wrapEvaluateExpression(raw);
22744
+ const value = await page.evaluate(wrapped);
22745
+ evaluateResults.push({
22746
+ expression: raw.length > 200 ? raw.slice(0, 200) + "\u2026" : raw,
22747
+ value: serializeEvaluateValue(value)
22748
+ });
22749
+ } catch (err) {
22750
+ evaluateResults.push({
22751
+ expression: raw.length > 200 ? raw.slice(0, 200) + "\u2026" : raw,
22752
+ error: err instanceof Error ? err.message : String(err)
22753
+ });
22754
+ }
22755
+ break;
22756
+ }
22667
22757
  default:
22668
22758
  break;
22669
22759
  }
@@ -22677,6 +22767,20 @@ async function runBrowserCheck(options, loader) {
22677
22767
  selectorFound = false;
22678
22768
  }
22679
22769
  }
22770
+ let bodyTextSnippet;
22771
+ if (options.textSample) {
22772
+ try {
22773
+ const text = await page.evaluate(
22774
+ wrapEvaluateExpression(
22775
+ `(document.body?.innerText || document.body?.textContent || '').trim()`
22776
+ )
22777
+ );
22778
+ if (typeof text === "string" && text.length > 0) {
22779
+ bodyTextSnippet = text.length > MAX_BODY_SNIPPET ? text.slice(0, MAX_BODY_SNIPPET) + "\u2026" : text;
22780
+ }
22781
+ } catch {
22782
+ }
22783
+ }
22680
22784
  let screenshotPath;
22681
22785
  if (options.screenshotPath) {
22682
22786
  try {
@@ -22694,6 +22798,9 @@ async function runBrowserCheck(options, loader) {
22694
22798
  url: page.url(),
22695
22799
  ...title !== void 0 ? { title } : {},
22696
22800
  ...selectorFound !== void 0 ? { selectorFound } : {},
22801
+ ...evaluateResults.length > 0 ? { evaluateResults } : {},
22802
+ ...textFound !== void 0 ? { textFound } : {},
22803
+ ...bodyTextSnippet !== void 0 ? { bodyTextSnippet } : {},
22697
22804
  ...screenshotPath ? { screenshotPath } : {}
22698
22805
  };
22699
22806
  } catch (err) {
@@ -22705,9 +22812,13 @@ async function runBrowserCheck(options, loader) {
22705
22812
  }
22706
22813
  }
22707
22814
  }
22815
+ var MAX_EVAL_EXPR, MAX_EVAL_RESULT, MAX_BODY_SNIPPET;
22708
22816
  var init_driver = __esm({
22709
22817
  "src/cli/browser/driver.ts"() {
22710
22818
  "use strict";
22819
+ MAX_EVAL_EXPR = 4e3;
22820
+ MAX_EVAL_RESULT = 8e3;
22821
+ MAX_BODY_SNIPPET = 2e3;
22711
22822
  }
22712
22823
  });
22713
22824
 
@@ -22717,15 +22828,16 @@ import os7 from "node:os";
22717
22828
  function createBrowserTool(deps = {}) {
22718
22829
  return {
22719
22830
  name: "browser_check",
22720
- description: 'Open a URL in a headless browser to VERIFY a web change: optionally run click/fill/goto/wait actions, then report console errors, uncaught page exceptions, failed network requests, the final title/URL, whether an expected selector appeared, and a screenshot path. Use it to confirm UI edits actually render and run \u2014 stronger than "tests pass" for front-end. Requires Playwright (optional dependency).',
22831
+ description: "Open a URL in a headless browser to VERIFY a web change: optionally run click/fill/goto/wait/press/waitForText/evaluate actions, then report console errors, uncaught page exceptions, failed network requests, final title/URL, selector/text presence, evaluate results, and a screenshot path. Prefer DOM assertions (waitForSelector, waitForText, evaluate on document.querySelector) over window.* globals \u2014 ES modules and const keep symbols off window. Absence of console errors after a short wait is WEAK smoke only; assert UI state when claiming a fix is verified. Requires Playwright (optional dependency).",
22721
22832
  permissions: ["network"],
22722
22833
  // A browser launch + navigation can take a while.
22723
22834
  timeoutMs: 6e4,
22724
22835
  inputSchema: external_exports.object({
22725
22836
  url: external_exports.string().min(1).describe("URL to open (e.g. http://localhost:3000)."),
22726
- actions: external_exports.array(ActionSchema).optional().describe("Optional sequence of interactions before checking."),
22837
+ actions: external_exports.array(ActionSchema).optional().describe("Optional sequence of interactions / probes before checking."),
22727
22838
  waitForSelector: external_exports.string().optional().describe("Assert this CSS selector is present after actions."),
22728
- screenshot: external_exports.boolean().optional().describe("Save a screenshot (default true).")
22839
+ screenshot: external_exports.boolean().optional().describe("Save a screenshot (default true)."),
22840
+ textSample: external_exports.boolean().optional().describe("Include a short body.innerText snippet (HUD / Game Over text).")
22729
22841
  }),
22730
22842
  execute: async (args, ctx) => {
22731
22843
  const a = args;
@@ -22737,14 +22849,17 @@ function createBrowserTool(deps = {}) {
22737
22849
  cwd: ctx.cwd,
22738
22850
  ...a.actions ? { actions: a.actions } : {},
22739
22851
  ...a.waitForSelector ? { waitForSelector: a.waitForSelector } : {},
22740
- ...screenshotPath ? { screenshotPath } : {}
22852
+ ...screenshotPath ? { screenshotPath } : {},
22853
+ ...a.textSample ? { textSample: true } : {}
22741
22854
  },
22742
22855
  deps.loader
22743
22856
  );
22744
22857
  if (!result.ok) {
22745
22858
  return typedOk({ ok: false, note: result.error ?? "browser check failed" });
22746
22859
  }
22747
- const clean = result.consoleErrors.length === 0 && result.pageErrors.length === 0 && result.failedRequests.length === 0 && result.selectorFound !== false;
22860
+ const clean = result.consoleErrors.length === 0 && result.pageErrors.length === 0 && result.failedRequests.length === 0 && result.selectorFound !== false && result.textFound !== false;
22861
+ const hadDomAssertion = result.selectorFound !== void 0 || result.textFound !== void 0 || result.evaluateResults !== void 0 && result.evaluateResults.length > 0 || !!result.bodyTextSnippet;
22862
+ const onlyWeakSmoke = clean && !hadDomAssertion;
22748
22863
  return typedOk({
22749
22864
  ok: true,
22750
22865
  clean,
@@ -22754,7 +22869,14 @@ function createBrowserTool(deps = {}) {
22754
22869
  pageErrors: result.pageErrors,
22755
22870
  failedRequests: result.failedRequests,
22756
22871
  ...result.selectorFound !== void 0 ? { selectorFound: result.selectorFound } : {},
22757
- ...result.screenshotPath ? { screenshotPath: result.screenshotPath } : {}
22872
+ ...result.evaluateResults ? { evaluateResults: result.evaluateResults } : {},
22873
+ ...result.textFound !== void 0 ? { textFound: result.textFound } : {},
22874
+ ...result.bodyTextSnippet ? { bodyTextSnippet: result.bodyTextSnippet } : {},
22875
+ ...result.screenshotPath ? { screenshotPath: result.screenshotPath } : {},
22876
+ ...onlyWeakSmoke ? {
22877
+ note: "Weak smoke only: no selector/text/evaluate assertions. No console/page errors is necessary but not sufficient to claim a logic fix. Add waitForSelector, waitForText, or evaluate (DOM/read hooks) for stronger evidence.",
22878
+ smokeStrength: "weak"
22879
+ } : { smokeStrength: "asserted" }
22758
22880
  });
22759
22881
  }
22760
22882
  };
@@ -22770,7 +22892,22 @@ var init_tools5 = __esm({
22770
22892
  external_exports.object({ type: external_exports.literal("click"), selector: external_exports.string().min(1) }),
22771
22893
  external_exports.object({ type: external_exports.literal("fill"), selector: external_exports.string().min(1), value: external_exports.string() }),
22772
22894
  external_exports.object({ type: external_exports.literal("wait"), ms: external_exports.number().int().positive().max(3e4) }),
22773
- external_exports.object({ type: external_exports.literal("goto"), url: external_exports.string().min(1) })
22895
+ external_exports.object({ type: external_exports.literal("goto"), url: external_exports.string().min(1) }),
22896
+ external_exports.object({
22897
+ type: external_exports.literal("evaluate"),
22898
+ expression: external_exports.string().min(1).max(4e3).describe(
22899
+ "JS expression or statements run in the page (page.evaluate). Prefer DOM reads (document.querySelector\u2026), not assuming window.game exists. Return JSON-safe values."
22900
+ )
22901
+ }),
22902
+ external_exports.object({
22903
+ type: external_exports.literal("press"),
22904
+ key: external_exports.string().min(1).describe('Playwright key name, e.g. "Space", "KeyW", "ArrowLeft", "Enter".')
22905
+ }),
22906
+ external_exports.object({
22907
+ type: external_exports.literal("waitForText"),
22908
+ text: external_exports.string().min(1).describe("Substring that must appear in document body text."),
22909
+ timeoutMs: external_exports.number().int().positive().max(6e4).optional()
22910
+ })
22774
22911
  ]);
22775
22912
  }
22776
22913
  });