doc-detective 4.41.6 → 4.42.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 (155) hide show
  1. package/README.md +3 -4
  2. package/bin/doc-detective-lsp.js +2 -0
  3. package/dist/agents/adapters/claude-code.js +1 -1
  4. package/dist/agents/adapters/claude-code.js.map +1 -1
  5. package/dist/agents/adapters/copilot-cli.js +2 -2
  6. package/dist/agents/adapters/copilot-cli.js.map +1 -1
  7. package/dist/agents/adapters/gemini-cli.js +1 -1
  8. package/dist/agents/adapters/gemini-cli.js.map +1 -1
  9. package/dist/agents/adapters/qwen-code.js +1 -1
  10. package/dist/agents/adapters/qwen-code.js.map +1 -1
  11. package/dist/cli.js +27 -6
  12. package/dist/cli.js.map +1 -1
  13. package/dist/common/src/schemas/schemas.json +2 -2
  14. package/dist/common/src/schemas/schemasReferenced.json +448 -294
  15. package/dist/common/src/schemas/validators.cjs +140 -124
  16. package/dist/common/src/schemas/validatorsCheck.cjs +1 -1
  17. package/dist/common/src/types/generated/annotate_v3.d.ts +12 -12
  18. package/dist/common/src/types/generated/annotate_v3.d.ts.map +1 -1
  19. package/dist/common/src/types/generated/annotation_v3.d.ts +6 -6
  20. package/dist/common/src/types/generated/annotation_v3.d.ts.map +1 -1
  21. package/dist/common/src/types/generated/checkLink_v3.d.ts +4 -0
  22. package/dist/common/src/types/generated/checkLink_v3.d.ts.map +1 -1
  23. package/dist/common/src/types/generated/click_v3.d.ts +2 -2
  24. package/dist/common/src/types/generated/click_v3.d.ts.map +1 -1
  25. package/dist/common/src/types/generated/config_v3.d.ts +260 -108
  26. package/dist/common/src/types/generated/config_v3.d.ts.map +1 -1
  27. package/dist/common/src/types/generated/context_v3.d.ts +10 -2
  28. package/dist/common/src/types/generated/context_v3.d.ts.map +1 -1
  29. package/dist/common/src/types/generated/dragAndDrop_v3.d.ts +2 -2
  30. package/dist/common/src/types/generated/dragAndDrop_v3.d.ts.map +1 -1
  31. package/dist/common/src/types/generated/find_v3.d.ts +6 -6
  32. package/dist/common/src/types/generated/find_v3.d.ts.map +1 -1
  33. package/dist/common/src/types/generated/goTo_v3.d.ts +1 -1
  34. package/dist/common/src/types/generated/goTo_v3.d.ts.map +1 -1
  35. package/dist/common/src/types/generated/httpRequest_v3.d.ts +2 -2
  36. package/dist/common/src/types/generated/httpRequest_v3.d.ts.map +1 -1
  37. package/dist/common/src/types/generated/record_v3.d.ts +5 -5
  38. package/dist/common/src/types/generated/record_v3.d.ts.map +1 -1
  39. package/dist/common/src/types/generated/report_v3.d.ts +529 -207
  40. package/dist/common/src/types/generated/report_v3.d.ts.map +1 -1
  41. package/dist/common/src/types/generated/resolvedTests_v3.d.ts +754 -314
  42. package/dist/common/src/types/generated/resolvedTests_v3.d.ts.map +1 -1
  43. package/dist/common/src/types/generated/runCode_v3.d.ts +11 -2
  44. package/dist/common/src/types/generated/runCode_v3.d.ts.map +1 -1
  45. package/dist/common/src/types/generated/runShell_v3.d.ts +11 -2
  46. package/dist/common/src/types/generated/runShell_v3.d.ts.map +1 -1
  47. package/dist/common/src/types/generated/screenshot_v3.d.ts +12 -12
  48. package/dist/common/src/types/generated/screenshot_v3.d.ts.map +1 -1
  49. package/dist/common/src/types/generated/spec_v3.d.ts +494 -206
  50. package/dist/common/src/types/generated/spec_v3.d.ts.map +1 -1
  51. package/dist/common/src/types/generated/startSurface_v3.d.ts +24 -6
  52. package/dist/common/src/types/generated/startSurface_v3.d.ts.map +1 -1
  53. package/dist/common/src/types/generated/step_v3.d.ts +223 -100
  54. package/dist/common/src/types/generated/step_v3.d.ts.map +1 -1
  55. package/dist/common/src/types/generated/test_v3.d.ts +482 -202
  56. package/dist/common/src/types/generated/test_v3.d.ts.map +1 -1
  57. package/dist/common/src/types/generated/type_v3.d.ts +3 -3
  58. package/dist/common/src/types/generated/type_v3.d.ts.map +1 -1
  59. package/dist/common/src/types/generated/waitUntil_v3.d.ts +2 -2
  60. package/dist/common/src/types/generated/waitUntil_v3.d.ts.map +1 -1
  61. package/dist/common/src/types/generated/wait_v3.d.ts +2 -3
  62. package/dist/common/src/types/generated/wait_v3.d.ts.map +1 -1
  63. package/dist/core/config.d.ts.map +1 -1
  64. package/dist/core/config.js +6 -4
  65. package/dist/core/config.js.map +1 -1
  66. package/dist/core/files.d.ts +18 -3
  67. package/dist/core/files.d.ts.map +1 -1
  68. package/dist/core/files.js +58 -18
  69. package/dist/core/files.js.map +1 -1
  70. package/dist/core/index.d.ts.map +1 -1
  71. package/dist/core/index.js +16 -0
  72. package/dist/core/index.js.map +1 -1
  73. package/dist/core/integrations/index.d.ts +2 -1
  74. package/dist/core/integrations/index.d.ts.map +1 -1
  75. package/dist/core/integrations/index.js +15 -5
  76. package/dist/core/integrations/index.js.map +1 -1
  77. package/dist/core/openapi.d.ts.map +1 -1
  78. package/dist/core/openapi.js +122 -6
  79. package/dist/core/openapi.js.map +1 -1
  80. package/dist/core/ptyWatchdog.d.ts.map +1 -1
  81. package/dist/core/ptyWatchdog.js +6 -3
  82. package/dist/core/ptyWatchdog.js.map +1 -1
  83. package/dist/core/resolveTests.d.ts.map +1 -1
  84. package/dist/core/resolveTests.js +5 -3
  85. package/dist/core/resolveTests.js.map +1 -1
  86. package/dist/core/telem.d.ts.map +1 -1
  87. package/dist/core/telem.js +5 -7
  88. package/dist/core/telem.js.map +1 -1
  89. package/dist/core/tests/checkLink.d.ts.map +1 -1
  90. package/dist/core/tests/checkLink.js +12 -7
  91. package/dist/core/tests/checkLink.js.map +1 -1
  92. package/dist/core/tests/click.d.ts.map +1 -1
  93. package/dist/core/tests/click.js +7 -0
  94. package/dist/core/tests/click.js.map +1 -1
  95. package/dist/core/tests/findElement.d.ts.map +1 -1
  96. package/dist/core/tests/findElement.js +3 -2
  97. package/dist/core/tests/findElement.js.map +1 -1
  98. package/dist/core/tests/goTo.d.ts.map +1 -1
  99. package/dist/core/tests/goTo.js +2 -1
  100. package/dist/core/tests/goTo.js.map +1 -1
  101. package/dist/core/tests/httpRequest.d.ts.map +1 -1
  102. package/dist/core/tests/httpRequest.js +4 -5
  103. package/dist/core/tests/httpRequest.js.map +1 -1
  104. package/dist/core/tests/processSurface.d.ts +4 -1
  105. package/dist/core/tests/processSurface.d.ts.map +1 -1
  106. package/dist/core/tests/processSurface.js +3 -0
  107. package/dist/core/tests/processSurface.js.map +1 -1
  108. package/dist/core/tests/saveScreenshot.d.ts.map +1 -1
  109. package/dist/core/tests/saveScreenshot.js +8 -3
  110. package/dist/core/tests/saveScreenshot.js.map +1 -1
  111. package/dist/core/tests/startRecording.d.ts.map +1 -1
  112. package/dist/core/tests/startRecording.js +2 -1
  113. package/dist/core/tests/startRecording.js.map +1 -1
  114. package/dist/core/tests/stopRecording.d.ts.map +1 -1
  115. package/dist/core/tests/stopRecording.js +2 -1
  116. package/dist/core/tests/stopRecording.js.map +1 -1
  117. package/dist/core/tests/timing.d.ts +4 -0
  118. package/dist/core/tests/timing.d.ts.map +1 -0
  119. package/dist/core/tests/timing.js +8 -0
  120. package/dist/core/tests/timing.js.map +1 -0
  121. package/dist/core/tests.d.ts +15 -0
  122. package/dist/core/tests.d.ts.map +1 -1
  123. package/dist/core/tests.js +77 -30
  124. package/dist/core/tests.js.map +1 -1
  125. package/dist/core/utils.d.ts +42 -2
  126. package/dist/core/utils.d.ts.map +1 -1
  127. package/dist/core/utils.js +281 -89
  128. package/dist/core/utils.js.map +1 -1
  129. package/dist/debug/index.d.ts.map +1 -1
  130. package/dist/debug/index.js +8 -36
  131. package/dist/debug/index.js.map +1 -1
  132. package/dist/hints/hints.js +2 -2
  133. package/dist/hints/hints.js.map +1 -1
  134. package/dist/index.cjs +684 -235
  135. package/dist/reporters/htmlReporter.js +1 -1
  136. package/dist/runtime/cacheDir.d.ts.map +1 -1
  137. package/dist/runtime/cacheDir.js +6 -11
  138. package/dist/runtime/cacheDir.js.map +1 -1
  139. package/dist/runtime/heavyDeps.d.ts +12 -0
  140. package/dist/runtime/heavyDeps.d.ts.map +1 -1
  141. package/dist/runtime/heavyDeps.js +31 -7
  142. package/dist/runtime/heavyDeps.js.map +1 -1
  143. package/dist/runtime/selfUpdate.d.ts +3 -3
  144. package/dist/runtime/selfUpdate.d.ts.map +1 -1
  145. package/dist/runtime/selfUpdate.js +34 -5
  146. package/dist/runtime/selfUpdate.js.map +1 -1
  147. package/dist/upgradeNotice.d.ts +41 -0
  148. package/dist/upgradeNotice.d.ts.map +1 -0
  149. package/dist/upgradeNotice.js +356 -0
  150. package/dist/upgradeNotice.js.map +1 -0
  151. package/dist/utils.d.ts.map +1 -1
  152. package/dist/utils.js +17 -8
  153. package/dist/utils.js.map +1 -1
  154. package/package.json +2 -2
  155. package/scripts/postinstall.js +1 -1
@@ -15,7 +15,7 @@ import { requiredBrowserAssets, ensureBrowserInstalled, } from "../runtime/brows
15
15
  // Single source of truth for browser/driver-requiring step keys.
16
16
  import { BROWSER_STEP_KEYS as driverActions, startSurfaceDescriptors, stepOpensBrowserSurface, stepTargetsProcessSurface, stepIsSurfacelessInteraction, testHasNonBrowserSurfaceSignal, } from "../runtime/browserStepKeys.js";
17
17
  import os from "node:os";
18
- import { log, logLevelEnabled, replaceEnvs, selectSpecsForRun, findFreePort, runConcurrent, runResourceAware, createResourceRegistry, rollUpResults, createAppiumPool, getRunOutputDir, runArchivesArtifacts, sanitizeFilesystemName, evaluateContextRequirements, isRetryableSessionError, classifyContextRetry, guardBlankDocumentNavigation, applyBrowserSize, isViewportFloored, loadAxios, } from "./utils.js";
18
+ import { log, logLevelEnabled, replaceEnvs, selectSpecsForRun, findFreePort, runConcurrent, runResourceAware, createResourceRegistry, rollUpResults, createAppiumPool, getRunOutputDir, runArchivesArtifacts, sanitizeFilesystemName, evaluateContextRequirements, isRetryableSessionError, classifyContextRetry, guardBlankDocumentNavigation, applyBrowserSize, isViewportFloored, loadAxios, sessionVersions, } from "./utils.js";
19
19
  import { instantiateCursor } from "./tests/moveTo.js";
20
20
  import { goTo } from "./tests/goTo.js";
21
21
  import { findElement } from "./tests/findElement.js";
@@ -45,6 +45,7 @@ import { mobileBrowserGate, buildMobileBrowserCapabilities, CHROMEDRIVER_AUTODOW
45
45
  import { planWarmTasks, executeWarmTasks, raceBootInitiation, wrapInitiationEffects, RUNTIME_INSTALL_RESOURCE, } from "./warmPhase.js";
46
46
  import { locateManagedWda } from "../runtime/wdaProducts.js";
47
47
  import { getCacheDir } from "../runtime/cacheDir.js";
48
+ import { packageRoot } from "../runtime/heavyDeps.js";
48
49
  import { detectAndroidSdk } from "../runtime/androidSdk.js";
49
50
  import { hostAbi, listInstalledSystemImages, installAndroid, } from "../runtime/androidInstaller.js";
50
51
  import { buildAcquireDeviceDeps, findUia2Helpers, checkEmulatorAcceleration, hostHasKvm, planDeviceAcquisition, planAndroidToolchain, normalizeDeviceDescriptor, acquireDevice, createDeviceRegistry, teardownDeviceRegistry, shutdownEmulator, } from "./tests/androidEmulator.js";
@@ -64,8 +65,6 @@ import { getEnvironment, getAvailableApps, clearAppCache, resolveConcurrentRunne
64
65
  import { uploadChangedFiles } from "./integrations/index.js";
65
66
  import http from "node:http";
66
67
  import https from "node:https";
67
- import { fileURLToPath } from "node:url";
68
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
69
68
  // Idle browser-pool Appium servers kept between runs in this process, only
70
69
  // when DOC_DETECTIVE_REUSE_APPIUM is set (ADR 01125). Empty otherwise.
71
70
  // killTree is a hoisted function declaration, called only when a server dies.
@@ -1017,6 +1016,8 @@ async function runViaApi({ resolvedTests, apiKey, config = {} }) {
1017
1016
  steps: { pass: 0, fail: 0, warning: 0, skipped: 0 },
1018
1017
  },
1019
1018
  // Nothing ran, but the shape stays parity with runSpecs' short-circuit.
1019
+ startedAt: new Date().toISOString(),
1020
+ environment: getEnvironment(),
1020
1021
  durationMs: 0,
1021
1022
  specs: [],
1022
1023
  };
@@ -1163,6 +1164,8 @@ async function runSpecs({ resolvedTests }) {
1163
1164
  contexts: { pass: 0, fail: 0, warning: 0, skipped: 0 },
1164
1165
  steps: { pass: 0, fail: 0, warning: 0, skipped: 0 },
1165
1166
  },
1167
+ startedAt: new Date(runStart).toISOString(),
1168
+ environment: getEnvironment(),
1166
1169
  durationMs: Date.now() - runStart,
1167
1170
  specs: [],
1168
1171
  };
@@ -1212,6 +1215,10 @@ async function runSpecs({ resolvedTests }) {
1212
1215
  const report = {
1213
1216
  runId,
1214
1217
  runDir,
1218
+ // Run metadata (ADR 01163): when execution started and the host that ran
1219
+ // it, so a consumer can tell product drift from environment drift.
1220
+ startedAt: new Date(runStart).toISOString(),
1221
+ environment: runnerDetails.environment,
1215
1222
  summary: {
1216
1223
  specs: {
1217
1224
  pass: 0,
@@ -1968,35 +1975,44 @@ async function runSpecs({ resolvedTests }) {
1968
1975
  process.off("SIGINT", onSignal);
1969
1976
  process.off("SIGTERM", onSignal);
1970
1977
  }
1971
- // Upload changed files back to source integrations (best-effort)
1972
- // This automatically syncs any changed screenshots back to their source CMS
1973
- // Only upload if uploadOnChange is enabled (defaults to true for backward compatibility)
1974
- // Check both global config.uploadOnChange and per-integration uploadOnChange settings
1975
- const herettoConfigs = config?.integrations?.heretto || [];
1976
- const hasUploadEnabledIntegration = herettoConfigs.some((h) => h.uploadOnChange !== false // Default to true if not explicitly set to false
1977
- );
1978
- const globalUploadOnChange = config?.uploadOnChange ?? true;
1979
- if (globalUploadOnChange && hasUploadEnabledIntegration && herettoConfigs.length > 0) {
1980
- try {
1981
- const uploadResults = await uploadChangedFiles({ config, report, log });
1982
- report.uploadResults = uploadResults;
1983
- }
1984
- catch (error) {
1985
- log(config, "warning", `Failed to upload changed files: ${error.message}`);
1986
- report.uploadResults = {
1987
- total: 0,
1988
- successful: 0,
1989
- failed: 0,
1990
- skipped: 0,
1991
- error: error.message,
1992
- };
1993
- }
1994
- }
1978
+ // An absent `report.uploadResults` means no integration opted in, so no
1979
+ // upload was attempted.
1980
+ const uploadResults = await uploadChangedFilesIfEnabled({ config, report, log });
1981
+ if (uploadResults)
1982
+ report.uploadResults = uploadResults;
1995
1983
  // Stamped last, after teardown and any Heretto upload, so the number matches
1996
1984
  // the elapsed time a user actually observes.
1997
1985
  report.durationMs = Date.now() - runStart;
1998
1986
  return report;
1999
1987
  }
1988
+ /**
1989
+ * Upload changed files back to their source integrations (best-effort). Opt-in:
1990
+ * runs only when some integration, of any type, sets `uploadOnChange: true`
1991
+ * (schema default false); uploadChangedFiles then skips files from
1992
+ * integrations that didn't. Returns undefined when nothing opted in. A thrown
1993
+ * upload still returns the success shape, with empty `details` and `error`.
1994
+ * `upload` is injectable for tests.
1995
+ */
1996
+ export async function uploadChangedFilesIfEnabled({ config, report, log: logFn, upload = uploadChangedFiles, }) {
1997
+ const integrationEntries = Object.values(config?.integrations ?? {}).flatMap((entries) => (Array.isArray(entries) ? entries : []));
1998
+ if (!integrationEntries.some((entry) => entry?.uploadOnChange === true)) {
1999
+ return undefined;
2000
+ }
2001
+ try {
2002
+ return await upload({ config, report, log: logFn });
2003
+ }
2004
+ catch (error) {
2005
+ logFn(config, "warning", `Failed to upload changed files: ${error.message}`);
2006
+ return {
2007
+ total: 0,
2008
+ successful: 0,
2009
+ failed: 0,
2010
+ skipped: 0,
2011
+ details: [],
2012
+ error: error.message,
2013
+ };
2014
+ }
2015
+ }
2000
2016
  /**
2001
2017
  * Sequencer for a single ROUTED spec (one whose `specIsRouted` is true). Runs
2002
2018
  * the spec's tests in input order, evaluating test-level routing between them.
@@ -3633,6 +3649,16 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
3633
3649
  engine: String(mobileWebBrowserName).toLowerCase(),
3634
3650
  driver,
3635
3651
  });
3652
+ // Device browser versions, as far as the session reports them (ADR
3653
+ // 01163); there's no desktop app entry to fall back on.
3654
+ const versions = sessionVersions({ capabilities: driver?.capabilities });
3655
+ if (versions.browserVersion)
3656
+ contextReport.browser = {
3657
+ ...contextReport.browser,
3658
+ version: versions.browserVersion,
3659
+ };
3660
+ if (versions.driver)
3661
+ contextReport.driver = versions.driver;
3636
3662
  /* c8 ignore stop */
3637
3663
  }
3638
3664
  else if (driverRequired) {
@@ -3810,6 +3836,19 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
3810
3836
  };
3811
3837
  clog("warning", fellBackNote);
3812
3838
  }
3839
+ // The browser and driver that actually ran, for the report (ADR 01163).
3840
+ // A copy, so the version never feeds back into the context's settings.
3841
+ const versions = sessionVersions({
3842
+ capabilities: driver?.capabilities,
3843
+ app: availableApps.find((app) => app.name === normalizeBrowserName(startedName)),
3844
+ });
3845
+ if (versions.browserVersion)
3846
+ contextReport.browser = {
3847
+ ...contextReport.browser,
3848
+ version: versions.browserVersion,
3849
+ };
3850
+ if (versions.driver)
3851
+ contextReport.driver = versions.driver;
3813
3852
  // Multi-surface Phase 4 (ADR 01019): register the default session in the
3814
3853
  // context's session registry under its engine name, so it resolves like
3815
3854
  // any named surface. The launcher closure lets goTo open ADDITIONAL
@@ -4106,7 +4145,12 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
4106
4145
  // and `r` is the runStep result — neither may clobber the timing.
4107
4146
  // On retry the loop below discards this report wholesale, so the
4108
4147
  // surviving value is the FINAL attempt's, per ADR 01083.
4109
- return { ...step, ...r, durationMs: Date.now() - stepStart };
4148
+ return {
4149
+ ...step,
4150
+ ...r,
4151
+ startedAt: new Date(stepStart).toISOString(),
4152
+ durationMs: Date.now() - stepStart,
4153
+ };
4110
4154
  };
4111
4155
  // Run the step, then resolve routing. A `retry` decision re-runs the step
4112
4156
  // (up to `limit` retries — so `limit + 1` total runs — waiting `delay`
@@ -4480,6 +4524,7 @@ delayMs = (attempt) => 500 * (attempt + 1)) {
4480
4524
  const start = Date.now();
4481
4525
  const report = await runContextFn(a);
4482
4526
  if (report && typeof report === "object") {
4527
+ report.startedAt = new Date(start).toISOString();
4483
4528
  report.durationMs = Date.now() - start;
4484
4529
  }
4485
4530
  return report;
@@ -4581,6 +4626,7 @@ async function stopAllRecordings({ config, context, driver, contextReport, }) {
4581
4626
  contextReport.steps.push({
4582
4627
  ...stopRecordStep,
4583
4628
  ...stepResult,
4629
+ startedAt: new Date(stopStart).toISOString(),
4584
4630
  durationMs: Date.now() - stopStart,
4585
4631
  });
4586
4632
  }
@@ -4593,6 +4639,7 @@ async function stopAllRecordings({ config, context, driver, contextReport, }) {
4593
4639
  ...stopRecordStep,
4594
4640
  result: "FAIL",
4595
4641
  resultDescription: `Couldn't stop recording. ${error?.message ?? error}`,
4642
+ startedAt: new Date(stopStart).toISOString(),
4596
4643
  durationMs: Date.now() - stopStart,
4597
4644
  });
4598
4645
  }
@@ -5011,7 +5058,7 @@ nodeArgs) {
5011
5058
  ...(extraArgs ?? []),
5012
5059
  ], {
5013
5060
  windowsHide: true,
5014
- cwd: path.join(__dirname, "../.."),
5061
+ cwd: packageRoot(),
5015
5062
  env,
5016
5063
  });
5017
5064
  proc.on("error", (err) => {
@@ -5326,7 +5373,7 @@ async function getRunner(options = {}) {
5326
5373
  ...useDriversArgs(process.env.APPIUM_HOME, browserPoolDriverPackages(process.platform)),
5327
5374
  ], {
5328
5375
  windowsHide: true,
5329
- cwd: path.join(__dirname, "../.."),
5376
+ cwd: packageRoot(),
5330
5377
  });
5331
5378
  // Without a listener an "error" event from spawn (e.g. ENOENT, EACCES)
5332
5379
  // would crash the process before appiumIsReady's timeout could surface