@tangle-network/browser-agent-driver 0.29.0 → 0.30.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.
Files changed (58) hide show
  1. package/dist/brain/index.d.ts +15 -1
  2. package/dist/brain/index.d.ts.map +1 -1
  3. package/dist/brain/index.js +67 -5
  4. package/dist/brain/index.js.map +1 -1
  5. package/dist/cli-design-audit.d.ts +4 -0
  6. package/dist/cli-design-audit.d.ts.map +1 -1
  7. package/dist/cli-design-audit.js +144 -7
  8. package/dist/cli-design-audit.js.map +1 -1
  9. package/dist/cli-ui.d.ts.map +1 -1
  10. package/dist/cli-ui.js +5 -1
  11. package/dist/cli-ui.js.map +1 -1
  12. package/dist/cli.js +23 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config.d.ts +4 -4
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/design/audit/evaluate.d.ts +69 -0
  17. package/dist/design/audit/evaluate.d.ts.map +1 -1
  18. package/dist/design/audit/evaluate.js +414 -55
  19. package/dist/design/audit/evaluate.js.map +1 -1
  20. package/dist/design/audit/pipeline.d.ts +14 -0
  21. package/dist/design/audit/pipeline.d.ts.map +1 -1
  22. package/dist/design/audit/pipeline.js +67 -2
  23. package/dist/design/audit/pipeline.js.map +1 -1
  24. package/dist/design/audit/rubric/fragments/universal-product-intent.md +48 -0
  25. package/dist/design/audit/rubric/loader.d.ts.map +1 -1
  26. package/dist/design/audit/rubric/loader.js +32 -1
  27. package/dist/design/audit/rubric/loader.js.map +1 -1
  28. package/dist/provider-defaults.d.ts +1 -1
  29. package/dist/provider-defaults.d.ts.map +1 -1
  30. package/dist/provider-defaults.js +8 -0
  31. package/dist/provider-defaults.js.map +1 -1
  32. package/dist/supervisor/critic.d.ts +1 -1
  33. package/dist/supervisor/critic.d.ts.map +1 -1
  34. package/dist/supervisor/critic.js +50 -5
  35. package/dist/supervisor/critic.js.map +1 -1
  36. package/dist/telemetry/client.d.ts +42 -0
  37. package/dist/telemetry/client.d.ts.map +1 -0
  38. package/dist/telemetry/client.js +203 -0
  39. package/dist/telemetry/client.js.map +1 -0
  40. package/dist/telemetry/hash.d.ts +4 -0
  41. package/dist/telemetry/hash.d.ts.map +1 -0
  42. package/dist/telemetry/hash.js +7 -0
  43. package/dist/telemetry/hash.js.map +1 -0
  44. package/dist/telemetry/index.d.ts +6 -0
  45. package/dist/telemetry/index.d.ts.map +1 -0
  46. package/dist/telemetry/index.js +5 -0
  47. package/dist/telemetry/index.js.map +1 -0
  48. package/dist/telemetry/schema.d.ts +85 -0
  49. package/dist/telemetry/schema.d.ts.map +1 -0
  50. package/dist/telemetry/schema.js +13 -0
  51. package/dist/telemetry/schema.js.map +1 -0
  52. package/dist/telemetry/sink.d.ts +46 -0
  53. package/dist/telemetry/sink.d.ts.map +1 -0
  54. package/dist/telemetry/sink.js +97 -0
  55. package/dist/telemetry/sink.js.map +1 -0
  56. package/dist/types.d.ts +5 -5
  57. package/dist/types.d.ts.map +1 -1
  58. package/package.json +4 -1
@@ -15,7 +15,10 @@ import { resolveProviderApiKey, resolveProviderModelName } from './provider-defa
15
15
  import { loadLocalEnvFiles } from './env-loader.js';
16
16
  import { cliError } from './cli-ui.js';
17
17
  import { auditOnePage } from './design/audit/pipeline.js';
18
+ import { resolveAuditPasses } from './design/audit/evaluate.js';
18
19
  import { detectSystemicFindings, topByRoi } from './design/audit/roi.js';
20
+ import { getTelemetry, setInvocation } from './telemetry/index.js';
21
+ import { randomUUID } from 'node:crypto';
19
22
  // ---------------------------------------------------------------------------
20
23
  // Page discovery — find key pages by crawling links
21
24
  // ---------------------------------------------------------------------------
@@ -194,15 +197,34 @@ export async function runDesignAudit(opts) {
194
197
  const provider = (opts.provider ?? 'claude-code');
195
198
  const modelName = resolveProviderModelName(provider, opts.model);
196
199
  const apiKey = opts.apiKey ?? resolveProviderApiKey(provider);
200
+ const auditPasses = resolveAuditPasses(opts.auditPasses);
201
+ // Telemetry: every design-audit invocation gets a stable runId. Children
202
+ // (per-page, evolve rounds) link back via parentRunId so a fleet rollup can
203
+ // reconstruct the tree.
204
+ const runId = randomUUID();
205
+ const runStartedAt = Date.now();
206
+ const invocation = opts.evolve ? 'design-audit:evolve' : opts.reproducibility ? 'design-audit:reproducibility' : 'design-audit';
207
+ setInvocation(invocation);
208
+ const telemetry = getTelemetry();
197
209
  const [vw, vh] = (opts.viewport ?? '1440x900').split('x').map(Number);
198
210
  console.log('');
199
211
  console.log(` ${chalk.bold('bad design-audit')}`);
200
212
  const profileLabel = profile ?? chalk.dim('auto-classify');
201
- console.log(` ${profileLabel} ${chalk.dim('·')} ${chalk.cyan(modelName)} ${chalk.dim('·')} ${vw}×${vh} ${chalk.dim('·')} up to ${maxPages} pages`);
213
+ const passLabel = auditPasses.length === 1 && auditPasses[0] === 'standard'
214
+ ? '1 audit pass'
215
+ : `${auditPasses.length} audit passes (${auditPasses.join(', ')})`;
216
+ console.log(` ${profileLabel} ${chalk.dim('·')} ${chalk.cyan(modelName)} ${chalk.dim('·')} ${vw}×${vh} ${chalk.dim('·')} ${passLabel} ${chalk.dim('·')} up to ${maxPages} pages`);
202
217
  console.log(` ${chalk.dim('→')} ${opts.url}`);
203
218
  console.log('');
219
+ const storageState = opts.storageState ? path.resolve(opts.storageState) : undefined;
220
+ if (storageState && !fs.existsSync(storageState)) {
221
+ cliError(`storage state file not found: ${storageState}`);
222
+ }
204
223
  const browser = await chromium.launch({ headless: opts.headless ?? true });
205
- const context = await browser.newContext({ viewport: { width: vw, height: vh } });
224
+ const context = await browser.newContext({
225
+ viewport: { width: vw, height: vh },
226
+ ...(storageState ? { storageState } : {}),
227
+ });
206
228
  const page = await context.newPage();
207
229
  // Discover pages
208
230
  console.log(` ${chalk.dim('Discovering pages…')}`);
@@ -220,7 +242,8 @@ export async function runDesignAudit(opts) {
220
242
  const brain = new Brain({
221
243
  model: modelName,
222
244
  apiKey,
223
- provider: opts.provider,
245
+ provider: provider,
246
+ baseUrl: opts.baseUrl ?? process.env.LLM_BASE_URL,
224
247
  vision: true,
225
248
  debug: opts.debug,
226
249
  llmTimeoutMs: 120_000, // design audits generate ~8k tokens of structured JSON — need 2min
@@ -239,6 +262,10 @@ export async function runDesignAudit(opts) {
239
262
  profileOverride: profile,
240
263
  screenshotDir,
241
264
  userRubricsDir: opts.rubricsDir,
265
+ auditPasses,
266
+ runId,
267
+ provider,
268
+ model: modelName,
242
269
  });
243
270
  const result = gen2;
244
271
  results.push(result);
@@ -310,6 +337,11 @@ export async function runDesignAudit(opts) {
310
337
  url,
311
338
  profileOverride: profile,
312
339
  userRubricsDir: opts.rubricsDir,
340
+ auditPasses,
341
+ runId,
342
+ provider,
343
+ model: modelName,
344
+ parentRunId: runId,
313
345
  });
314
346
  repResults.push(gen2);
315
347
  }
@@ -343,11 +375,11 @@ export async function runDesignAudit(opts) {
343
375
  if (evolveMode !== 'css') {
344
376
  // Agent-dispatched evolve — a coding agent edits the actual source code
345
377
  const projectDir = opts.projectDir ?? process.cwd();
346
- evolveResult = await runAgentEvolveLoop(brain, driver, page, pages, evolveProfile, results, outputDir, opts.evolveRounds ?? 3, evolveMode, projectDir, opts.debug);
378
+ evolveResult = await runAgentEvolveLoop(brain, driver, page, pages, evolveProfile, results, outputDir, opts.evolveRounds ?? 3, evolveMode, projectDir, opts.debug, auditPasses, runId, provider, modelName);
347
379
  }
348
380
  else {
349
381
  // CSS-injection evolve — ephemeral fixes injected into the browser page
350
- evolveResult = await runEvolveLoop(brain, driver, page, pages, evolveProfile, results, outputDir, opts.evolveRounds ?? 3);
382
+ evolveResult = await runEvolveLoop(brain, driver, page, pages, evolveProfile, results, outputDir, opts.evolveRounds ?? 3, auditPasses, runId, provider, modelName);
351
383
  }
352
384
  // Write evolve report
353
385
  const evolvePath = path.join(outputDir, 'evolve-report.md');
@@ -364,10 +396,62 @@ export async function runDesignAudit(opts) {
364
396
  fs.writeFileSync(evJsonPath, JSON.stringify(evolveResult, null, 2));
365
397
  }
366
398
  console.log('');
399
+ telemetry.emit({
400
+ kind: 'design-evolve-run',
401
+ runId,
402
+ ok: true,
403
+ durationMs: Date.now() - runStartedAt,
404
+ model: { provider, name: modelName },
405
+ data: {
406
+ url: opts.url,
407
+ pages: pages.length,
408
+ rounds: evolveResult.scoreHistory.length - 1,
409
+ scoreHistory: evolveResult.scoreHistory,
410
+ appliedFixCount: evolveResult.appliedFixes?.length ?? 0,
411
+ evolveMode: evolveMode === 'css' ? 'css' : `agent:${evolveMode}`,
412
+ },
413
+ metrics: {
414
+ initialScore: evolveResult.scoreHistory[0] ?? 0,
415
+ finalScore: evolveResult.scoreHistory[evolveResult.scoreHistory.length - 1] ?? 0,
416
+ delta: (evolveResult.scoreHistory[evolveResult.scoreHistory.length - 1] ?? 0) - (evolveResult.scoreHistory[0] ?? 0),
417
+ rounds: evolveResult.scoreHistory.length - 1,
418
+ },
419
+ });
367
420
  }
421
+ // Run-level summary envelope — fires for every design-audit invocation,
422
+ // evolve or not. This is the row a fleet rollup queries to track audit
423
+ // health across repos over time.
424
+ telemetry.emit({
425
+ kind: 'design-audit-run',
426
+ runId,
427
+ ok: true,
428
+ durationMs: Date.now() - runStartedAt,
429
+ model: { provider, name: modelName },
430
+ data: {
431
+ url: opts.url,
432
+ pages: pages.length,
433
+ profile: profile ?? null,
434
+ auditPasses,
435
+ outputDir,
436
+ },
437
+ metrics: {
438
+ avgScore,
439
+ pageCount: pages.length,
440
+ totalFindings: allFindings.length,
441
+ criticalFindings: critical,
442
+ majorFindings: major,
443
+ minorFindings: minor,
444
+ topFixCount: topFixes.length,
445
+ },
446
+ tags: {
447
+ evolveMode: opts.evolve ? (opts.evolve === true || opts.evolve === 'css' ? 'css' : 'agent') : 'off',
448
+ reproducibility: opts.reproducibility ? 'on' : 'off',
449
+ },
450
+ });
368
451
  await browser.close();
369
452
  }
370
- async function runEvolveLoop(brain, driver, page, pages, profile, initialResults, outputDir, maxRounds) {
453
+ async function runEvolveLoop(brain, driver, page, pages, profile, initialResults, outputDir, maxRounds, auditPasses, parentRunId, provider, model) {
454
+ const telemetry = parentRunId ? getTelemetry() : undefined;
371
455
  const initialAvg = initialResults.reduce((s, r) => s + r.score, 0) / initialResults.length;
372
456
  const scoreHistory = [initialAvg];
373
457
  const appliedFixes = [];
@@ -463,6 +547,10 @@ async function runEvolveLoop(brain, driver, page, pages, profile, initialResults
463
547
  url,
464
548
  profileOverride: profile,
465
549
  screenshotDir,
550
+ auditPasses,
551
+ ...(parentRunId ? { runId: parentRunId, parentRunId } : {}),
552
+ ...(provider ? { provider } : {}),
553
+ ...(model ? { model } : {}),
466
554
  }));
467
555
  roundResults.push(result);
468
556
  }
@@ -482,6 +570,28 @@ async function runEvolveLoop(brain, driver, page, pages, profile, initialResults
482
570
  const delta = roundAvg - currentAvg;
483
571
  const deltaStr = delta >= 0 ? chalk.green(`+${delta.toFixed(1)}`) : chalk.red(delta.toFixed(1));
484
572
  console.log(` ${chalk.dim(' Score:')} ${roundAvg.toFixed(1)}/10 (${deltaStr})`);
573
+ if (telemetry && parentRunId) {
574
+ telemetry.emit({
575
+ kind: 'design-evolve-round',
576
+ runId: parentRunId,
577
+ parentRunId,
578
+ ok: true,
579
+ durationMs: 0, // round-level wall time would require a per-round timer; the parent run captures total duration
580
+ ...(provider && model ? { model: { provider, name: model } } : {}),
581
+ data: {
582
+ mode: 'css',
583
+ round,
584
+ fixesApplied: fixableFixes.length,
585
+ },
586
+ metrics: {
587
+ round,
588
+ beforeScore: currentAvg,
589
+ afterScore: roundAvg,
590
+ delta,
591
+ fixesApplied: fixableFixes.length,
592
+ },
593
+ });
594
+ }
485
595
  currentResults = roundResults;
486
596
  currentAvg = roundAvg;
487
597
  // Check convergence — if no improvement, stop
@@ -638,7 +748,8 @@ Do NOT:
638
748
  - Refactor unrelated code
639
749
  - Change component structure or HTML semantics unless a finding specifically requires it`;
640
750
  }
641
- async function runAgentEvolveLoop(brain, driver, page, pages, profile, initialResults, outputDir, maxRounds, agentName, projectDir, debug) {
751
+ async function runAgentEvolveLoop(brain, driver, page, pages, profile, initialResults, outputDir, maxRounds, agentName, projectDir, debug, auditPasses, parentRunId, provider, model) {
752
+ const telemetry = parentRunId ? getTelemetry() : undefined;
642
753
  const initialAvg = initialResults.reduce((s, r) => s + r.score, 0) / initialResults.length;
643
754
  const scoreHistory = [initialAvg];
644
755
  const appliedFixes = [];
@@ -719,6 +830,10 @@ async function runAgentEvolveLoop(brain, driver, page, pages, profile, initialRe
719
830
  url,
720
831
  profileOverride: profile,
721
832
  screenshotDir: roundScreenshotDir,
833
+ auditPasses,
834
+ ...(parentRunId ? { runId: parentRunId, parentRunId } : {}),
835
+ ...(provider ? { provider } : {}),
836
+ ...(model ? { model } : {}),
722
837
  }));
723
838
  roundResults.push(result);
724
839
  }
@@ -738,6 +853,28 @@ async function runAgentEvolveLoop(brain, driver, page, pages, profile, initialRe
738
853
  finding: `Score: ${currentAvg.toFixed(1)} → ${roundAvg.toFixed(1)}`,
739
854
  });
740
855
  }
856
+ if (telemetry && parentRunId) {
857
+ telemetry.emit({
858
+ kind: 'design-evolve-round',
859
+ runId: parentRunId,
860
+ parentRunId,
861
+ ok: true,
862
+ durationMs: 0,
863
+ ...(provider && model ? { model: { provider, name: model } } : {}),
864
+ data: {
865
+ mode: `agent:${agentName}`,
866
+ round,
867
+ resolvedCount,
868
+ },
869
+ metrics: {
870
+ round,
871
+ beforeScore: currentAvg,
872
+ afterScore: roundAvg,
873
+ delta,
874
+ findingsResolved: resolvedCount,
875
+ },
876
+ });
877
+ }
741
878
  currentResults = roundResults;
742
879
  currentAvg = roundAvg;
743
880
  // Check convergence