playwright-intelligence-engine 0.0.0-stage → 2.0.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.
Files changed (353) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +229 -3
  3. package/bin/pw-intel.js +37 -0
  4. package/dist/authoring/author.d.ts +83 -0
  5. package/dist/authoring/author.d.ts.map +1 -0
  6. package/dist/authoring/generation-contract.d.ts +90 -0
  7. package/dist/authoring/generation-contract.d.ts.map +1 -0
  8. package/dist/authoring/hybrid-author.d.ts +6 -0
  9. package/dist/authoring/hybrid-author.d.ts.map +1 -0
  10. package/dist/authoring/index.d.ts +7 -0
  11. package/dist/authoring/index.d.ts.map +1 -0
  12. package/dist/authoring/llm-author.d.ts +28 -0
  13. package/dist/authoring/llm-author.d.ts.map +1 -0
  14. package/dist/authoring/naming/index.d.ts +4 -0
  15. package/dist/authoring/naming/index.d.ts.map +1 -0
  16. package/dist/authoring/naming/name-plan.d.ts +45 -0
  17. package/dist/authoring/naming/name-plan.d.ts.map +1 -0
  18. package/dist/authoring/naming/name-planner.d.ts +25 -0
  19. package/dist/authoring/naming/name-planner.d.ts.map +1 -0
  20. package/dist/authoring/naming/naming-linter.d.ts +20 -0
  21. package/dist/authoring/naming/naming-linter.d.ts.map +1 -0
  22. package/dist/authoring/template-author.d.ts +6 -0
  23. package/dist/authoring/template-author.d.ts.map +1 -0
  24. package/dist/cli/index.d.ts +2 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/collectors/collector-interface.d.ts +7 -0
  27. package/dist/collectors/collector-interface.d.ts.map +1 -0
  28. package/dist/collectors/environment-collector.d.ts +12 -0
  29. package/dist/collectors/environment-collector.d.ts.map +1 -0
  30. package/dist/collectors/error-collector.d.ts +18 -0
  31. package/dist/collectors/error-collector.d.ts.map +1 -0
  32. package/dist/collectors/git-diff-collector.d.ts +20 -0
  33. package/dist/collectors/git-diff-collector.d.ts.map +1 -0
  34. package/dist/collectors/live-browser-collector.d.ts +45 -0
  35. package/dist/collectors/live-browser-collector.d.ts.map +1 -0
  36. package/dist/collectors/network-collector.d.ts +28 -0
  37. package/dist/collectors/network-collector.d.ts.map +1 -0
  38. package/dist/collectors/static-ast-collector.d.ts +32 -0
  39. package/dist/collectors/static-ast-collector.d.ts.map +1 -0
  40. package/dist/collectors/trace-collector.d.ts +12 -0
  41. package/dist/collectors/trace-collector.d.ts.map +1 -0
  42. package/dist/config/project-config.d.ts +33 -0
  43. package/dist/config/project-config.d.ts.map +1 -0
  44. package/dist/core/errors/engine-errors.d.ts +34 -0
  45. package/dist/core/errors/engine-errors.d.ts.map +1 -0
  46. package/dist/core/types/diagnostic-context.d.ts +151 -0
  47. package/dist/core/types/diagnostic-context.d.ts.map +1 -0
  48. package/dist/core/types/repair-evidence.d.ts +56 -0
  49. package/dist/core/types/repair-evidence.d.ts.map +1 -0
  50. package/dist/core/version.d.ts +13 -0
  51. package/dist/core/version.d.ts.map +1 -0
  52. package/dist/diagnostics/diagnostic-contract.d.ts +52 -0
  53. package/dist/diagnostics/diagnostic-contract.d.ts.map +1 -0
  54. package/dist/diagnostics/diagnostic-report.d.ts +11 -0
  55. package/dist/diagnostics/diagnostic-report.d.ts.map +1 -0
  56. package/dist/diagnostics/evidence-correlator.d.ts +22 -0
  57. package/dist/diagnostics/evidence-correlator.d.ts.map +1 -0
  58. package/dist/diagnostics/external-failure-evidence.d.ts +18 -0
  59. package/dist/diagnostics/external-failure-evidence.d.ts.map +1 -0
  60. package/dist/diagnostics/failure-category.d.ts +4 -0
  61. package/dist/diagnostics/failure-category.d.ts.map +1 -0
  62. package/dist/diagnostics/failure-classifier.d.ts +58 -0
  63. package/dist/diagnostics/failure-classifier.d.ts.map +1 -0
  64. package/dist/evaluation/evaluation-scorecard.d.ts +72 -0
  65. package/dist/evaluation/evaluation-scorecard.d.ts.map +1 -0
  66. package/dist/evaluation/repository-inspector.d.ts +21 -0
  67. package/dist/evaluation/repository-inspector.d.ts.map +1 -0
  68. package/dist/evaluation/repository-runner.d.ts +24 -0
  69. package/dist/evaluation/repository-runner.d.ts.map +1 -0
  70. package/dist/evidence/evidence-model.d.ts +88 -0
  71. package/dist/evidence/evidence-model.d.ts.map +1 -0
  72. package/dist/evidence/evidence-normalizer.d.ts +19 -0
  73. package/dist/evidence/evidence-normalizer.d.ts.map +1 -0
  74. package/dist/evidence/evidence-redactor.d.ts +37 -0
  75. package/dist/evidence/evidence-redactor.d.ts.map +1 -0
  76. package/dist/framework/config-adapter.d.ts +28 -0
  77. package/dist/framework/config-adapter.d.ts.map +1 -0
  78. package/dist/gate/index.d.ts +21 -0
  79. package/dist/gate/index.d.ts.map +1 -0
  80. package/dist/gate/oracle.d.ts +26 -0
  81. package/dist/gate/oracle.d.ts.map +1 -0
  82. package/dist/gate/quality.d.ts +27 -0
  83. package/dist/gate/quality.d.ts.map +1 -0
  84. package/dist/gate/safety.d.ts +28 -0
  85. package/dist/gate/safety.d.ts.map +1 -0
  86. package/dist/generator/architecture-generator.d.ts +55 -0
  87. package/dist/generator/architecture-generator.d.ts.map +1 -0
  88. package/dist/generator/assertion-quality-gate.d.ts +18 -0
  89. package/dist/generator/assertion-quality-gate.d.ts.map +1 -0
  90. package/dist/generator/candidate-writer.d.ts +34 -0
  91. package/dist/generator/candidate-writer.d.ts.map +1 -0
  92. package/dist/generator/test-generator.d.ts +26 -0
  93. package/dist/generator/test-generator.d.ts.map +1 -0
  94. package/dist/governance/audit-log.d.ts +23 -0
  95. package/dist/governance/audit-log.d.ts.map +1 -0
  96. package/dist/governance/governance-policy.d.ts +24 -0
  97. package/dist/governance/governance-policy.d.ts.map +1 -0
  98. package/dist/governance/team-dashboard.d.ts +51 -0
  99. package/dist/governance/team-dashboard.d.ts.map +1 -0
  100. package/dist/governance/workflow-audit.d.ts +13 -0
  101. package/dist/governance/workflow-audit.d.ts.map +1 -0
  102. package/dist/index.d.ts +90 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +20318 -0
  105. package/dist/integrations/ci-summary.d.ts +14 -0
  106. package/dist/integrations/ci-summary.d.ts.map +1 -0
  107. package/dist/integrations/playwright-report-adapter.d.ts +22 -0
  108. package/dist/integrations/playwright-report-adapter.d.ts.map +1 -0
  109. package/dist/integrations/quality-gate.d.ts +35 -0
  110. package/dist/integrations/quality-gate.d.ts.map +1 -0
  111. package/dist/integrations/sarif-report.d.ts +48 -0
  112. package/dist/integrations/sarif-report.d.ts.map +1 -0
  113. package/dist/intelligence/autonomous-repair-workflow.d.ts +31 -0
  114. package/dist/intelligence/autonomous-repair-workflow.d.ts.map +1 -0
  115. package/dist/intelligence/business-intent.d.ts +58 -0
  116. package/dist/intelligence/business-intent.d.ts.map +1 -0
  117. package/dist/intelligence/evidence-bundle.d.ts +364 -0
  118. package/dist/intelligence/evidence-bundle.d.ts.map +1 -0
  119. package/dist/intelligence/failure-clustering.d.ts +38 -0
  120. package/dist/intelligence/failure-clustering.d.ts.map +1 -0
  121. package/dist/intelligence/generation-agent.d.ts +120 -0
  122. package/dist/intelligence/generation-agent.d.ts.map +1 -0
  123. package/dist/intelligence/generation-verifier.d.ts +151 -0
  124. package/dist/intelligence/generation-verifier.d.ts.map +1 -0
  125. package/dist/intelligence/llm-proposal.d.ts +377 -0
  126. package/dist/intelligence/llm-proposal.d.ts.map +1 -0
  127. package/dist/intelligence/locator-disambiguation-engine.d.ts +38 -0
  128. package/dist/intelligence/locator-disambiguation-engine.d.ts.map +1 -0
  129. package/dist/intelligence/model-contract.d.ts +86 -0
  130. package/dist/intelligence/model-contract.d.ts.map +1 -0
  131. package/dist/intelligence/model-provider.d.ts +75 -0
  132. package/dist/intelligence/model-provider.d.ts.map +1 -0
  133. package/dist/intelligence/project-intelligence.d.ts +22 -0
  134. package/dist/intelligence/project-intelligence.d.ts.map +1 -0
  135. package/dist/intelligence/repair-agent.d.ts +46 -0
  136. package/dist/intelligence/repair-agent.d.ts.map +1 -0
  137. package/dist/intelligence/repository-profile.d.ts +131 -0
  138. package/dist/intelligence/repository-profile.d.ts.map +1 -0
  139. package/dist/intelligence/suite-intelligence.d.ts +59 -0
  140. package/dist/intelligence/suite-intelligence.d.ts.map +1 -0
  141. package/dist/intelligence/test-intelligence.d.ts +44 -0
  142. package/dist/intelligence/test-intelligence.d.ts.map +1 -0
  143. package/dist/intelligence/trace-proposal-workflow.d.ts +30 -0
  144. package/dist/intelligence/trace-proposal-workflow.d.ts.map +1 -0
  145. package/dist/intelligence/verified-llm-repair-workflow.d.ts +21 -0
  146. package/dist/intelligence/verified-llm-repair-workflow.d.ts.map +1 -0
  147. package/dist/intelligence/workflow-planner.d.ts +278 -0
  148. package/dist/intelligence/workflow-planner.d.ts.map +1 -0
  149. package/dist/mcp/server.d.ts +32 -0
  150. package/dist/mcp/server.d.ts.map +1 -0
  151. package/dist/memory/stability-ledger.d.ts +46 -0
  152. package/dist/memory/stability-ledger.d.ts.map +1 -0
  153. package/dist/perception/app-model.d.ts +55 -0
  154. package/dist/perception/app-model.d.ts.map +1 -0
  155. package/dist/perception/crawler.d.ts +18 -0
  156. package/dist/perception/crawler.d.ts.map +1 -0
  157. package/dist/perception/index.d.ts +3 -0
  158. package/dist/perception/index.d.ts.map +1 -0
  159. package/dist/repair/approval-service.d.ts +139 -0
  160. package/dist/repair/approval-service.d.ts.map +1 -0
  161. package/dist/repair/assertion-hasher.d.ts +62 -0
  162. package/dist/repair/assertion-hasher.d.ts.map +1 -0
  163. package/dist/repair/ast-patcher.d.ts +36 -0
  164. package/dist/repair/ast-patcher.d.ts.map +1 -0
  165. package/dist/repair/browser-operation-executor.d.ts +27 -0
  166. package/dist/repair/browser-operation-executor.d.ts.map +1 -0
  167. package/dist/repair/diff-allowlist.d.ts +74 -0
  168. package/dist/repair/diff-allowlist.d.ts.map +1 -0
  169. package/dist/repair/intent-validator.d.ts +157 -0
  170. package/dist/repair/intent-validator.d.ts.map +1 -0
  171. package/dist/repair/repair-operations.d.ts +40 -0
  172. package/dist/repair/repair-operations.d.ts.map +1 -0
  173. package/dist/repair/repair-planner.d.ts +98 -0
  174. package/dist/repair/repair-planner.d.ts.map +1 -0
  175. package/dist/repair/repair-workflow.d.ts +42 -0
  176. package/dist/repair/repair-workflow.d.ts.map +1 -0
  177. package/dist/repair/safe-operation-compiler.d.ts +15 -0
  178. package/dist/repair/safe-operation-compiler.d.ts.map +1 -0
  179. package/dist/repair/source-mapper.d.ts +19 -0
  180. package/dist/repair/source-mapper.d.ts.map +1 -0
  181. package/dist/repair/statement-patcher.d.ts +75 -0
  182. package/dist/repair/statement-patcher.d.ts.map +1 -0
  183. package/dist/repair/verification-gates.d.ts +25 -0
  184. package/dist/repair/verification-gates.d.ts.map +1 -0
  185. package/dist/repair/workflow-plan.d.ts +35 -0
  186. package/dist/repair/workflow-plan.d.ts.map +1 -0
  187. package/dist/repair/workspace-promoter.d.ts +43 -0
  188. package/dist/repair/workspace-promoter.d.ts.map +1 -0
  189. package/dist/reproduce/diagnostic-rerunner.d.ts +40 -0
  190. package/dist/reproduce/diagnostic-rerunner.d.ts.map +1 -0
  191. package/dist/reproduce/direct-browser-investigator.d.ts +41 -0
  192. package/dist/reproduce/direct-browser-investigator.d.ts.map +1 -0
  193. package/dist/reproduce/interactive-workflow-runner.d.ts +43 -0
  194. package/dist/reproduce/interactive-workflow-runner.d.ts.map +1 -0
  195. package/dist/sandbox/dependency-strategy.d.ts +45 -0
  196. package/dist/sandbox/dependency-strategy.d.ts.map +1 -0
  197. package/dist/sandbox/execution-runner.d.ts +81 -0
  198. package/dist/sandbox/execution-runner.d.ts.map +1 -0
  199. package/dist/sandbox/worktree-manager.d.ts +51 -0
  200. package/dist/sandbox/worktree-manager.d.ts.map +1 -0
  201. package/dist/selector/abstention-policy.d.ts +34 -0
  202. package/dist/selector/abstention-policy.d.ts.map +1 -0
  203. package/dist/selector/candidate-extractor.d.ts +71 -0
  204. package/dist/selector/candidate-extractor.d.ts.map +1 -0
  205. package/dist/selector/live-locator-verifier.d.ts +28 -0
  206. package/dist/selector/live-locator-verifier.d.ts.map +1 -0
  207. package/dist/selector/repair-candidate-ranker.d.ts +10 -0
  208. package/dist/selector/repair-candidate-ranker.d.ts.map +1 -0
  209. package/dist/selector/selector-scorer.d.ts +43 -0
  210. package/dist/selector/selector-scorer.d.ts.map +1 -0
  211. package/dist/trace/adapters/adapter-registry.d.ts +18 -0
  212. package/dist/trace/adapters/adapter-registry.d.ts.map +1 -0
  213. package/dist/trace/adapters/trace-adapter.d.ts +21 -0
  214. package/dist/trace/adapters/trace-adapter.d.ts.map +1 -0
  215. package/dist/trace/adapters/unknown-adapter.d.ts +10 -0
  216. package/dist/trace/adapters/unknown-adapter.d.ts.map +1 -0
  217. package/dist/trace/adapters/v10-adapter.d.ts +10 -0
  218. package/dist/trace/adapters/v10-adapter.d.ts.map +1 -0
  219. package/dist/trace/adapters/v4-adapter.d.ts +11 -0
  220. package/dist/trace/adapters/v4-adapter.d.ts.map +1 -0
  221. package/dist/trace/adapters/v8-adapter.d.ts +10 -0
  222. package/dist/trace/adapters/v8-adapter.d.ts.map +1 -0
  223. package/dist/trace/adapters/v9-adapter.d.ts +10 -0
  224. package/dist/trace/adapters/v9-adapter.d.ts.map +1 -0
  225. package/dist/trace/archive-reader.d.ts +44 -0
  226. package/dist/trace/archive-reader.d.ts.map +1 -0
  227. package/dist/trace/snapshot-resolver.d.ts +55 -0
  228. package/dist/trace/snapshot-resolver.d.ts.map +1 -0
  229. package/dist/trace/trace-parser.d.ts +50 -0
  230. package/dist/trace/trace-parser.d.ts.map +1 -0
  231. package/dist/trace/version-detector.d.ts +20 -0
  232. package/dist/trace/version-detector.d.ts.map +1 -0
  233. package/package.json +76 -6
  234. package/skills/README.md +20 -0
  235. package/skills/pie-failure-investigation/SKILL.md +16 -0
  236. package/skills/pie-quality-engineer/SKILL.md +66 -0
  237. package/skills/pie-release-readiness/SKILL.md +22 -0
  238. package/skills/pie-repair-review/SKILL.md +21 -0
  239. package/skills/pie-trace-to-repair/SKILL.md +35 -0
  240. package/src/authoring/author.ts +81 -0
  241. package/src/authoring/generation-contract.ts +283 -0
  242. package/src/authoring/hybrid-author.ts +115 -0
  243. package/src/authoring/index.ts +7 -0
  244. package/src/authoring/llm-author.ts +282 -0
  245. package/src/authoring/naming/index.ts +4 -0
  246. package/src/authoring/naming/name-plan.ts +28 -0
  247. package/src/authoring/naming/name-planner.ts +339 -0
  248. package/src/authoring/naming/naming-linter.ts +292 -0
  249. package/src/authoring/template-author.ts +39 -0
  250. package/src/cli/index.ts +1172 -0
  251. package/src/collectors/collector-interface.ts +8 -0
  252. package/src/collectors/environment-collector.ts +103 -0
  253. package/src/collectors/error-collector.ts +177 -0
  254. package/src/collectors/git-diff-collector.ts +190 -0
  255. package/src/collectors/live-browser-collector.ts +412 -0
  256. package/src/collectors/network-collector.ts +90 -0
  257. package/src/collectors/static-ast-collector.ts +226 -0
  258. package/src/collectors/trace-collector.ts +66 -0
  259. package/src/config/project-config.ts +114 -0
  260. package/src/core/errors/engine-errors.ts +90 -0
  261. package/src/core/types/diagnostic-context.ts +94 -0
  262. package/src/core/types/repair-evidence.ts +45 -0
  263. package/src/core/version.ts +25 -0
  264. package/src/diagnostics/diagnostic-contract.ts +79 -0
  265. package/src/diagnostics/diagnostic-report.ts +204 -0
  266. package/src/diagnostics/evidence-correlator.ts +117 -0
  267. package/src/diagnostics/external-failure-evidence.ts +72 -0
  268. package/src/diagnostics/failure-category.ts +40 -0
  269. package/src/diagnostics/failure-classifier.ts +701 -0
  270. package/src/evaluation/evaluation-scorecard.ts +198 -0
  271. package/src/evaluation/repository-inspector.ts +143 -0
  272. package/src/evaluation/repository-runner.ts +197 -0
  273. package/src/evidence/evidence-model.ts +76 -0
  274. package/src/evidence/evidence-normalizer.ts +322 -0
  275. package/src/evidence/evidence-redactor.ts +218 -0
  276. package/src/framework/config-adapter.ts +131 -0
  277. package/src/gate/index.ts +43 -0
  278. package/src/gate/oracle.ts +69 -0
  279. package/src/gate/quality.ts +101 -0
  280. package/src/gate/safety.ts +94 -0
  281. package/src/generator/architecture-generator.ts +582 -0
  282. package/src/generator/assertion-quality-gate.ts +88 -0
  283. package/src/generator/candidate-writer.ts +288 -0
  284. package/src/generator/test-generator.ts +52 -0
  285. package/src/governance/audit-log.ts +115 -0
  286. package/src/governance/governance-policy.ts +72 -0
  287. package/src/governance/team-dashboard.ts +189 -0
  288. package/src/governance/workflow-audit.ts +72 -0
  289. package/src/index.ts +107 -0
  290. package/src/integrations/ci-summary.ts +37 -0
  291. package/src/integrations/playwright-report-adapter.ts +173 -0
  292. package/src/integrations/quality-gate.ts +95 -0
  293. package/src/integrations/sarif-report.ts +110 -0
  294. package/src/intelligence/autonomous-repair-workflow.ts +139 -0
  295. package/src/intelligence/business-intent.ts +163 -0
  296. package/src/intelligence/evidence-bundle.ts +300 -0
  297. package/src/intelligence/failure-clustering.ts +134 -0
  298. package/src/intelligence/generation-agent.ts +561 -0
  299. package/src/intelligence/generation-verifier.ts +1115 -0
  300. package/src/intelligence/llm-proposal.ts +519 -0
  301. package/src/intelligence/locator-disambiguation-engine.ts +331 -0
  302. package/src/intelligence/model-contract.ts +205 -0
  303. package/src/intelligence/model-provider.ts +348 -0
  304. package/src/intelligence/project-intelligence.ts +140 -0
  305. package/src/intelligence/repair-agent.ts +297 -0
  306. package/src/intelligence/repository-profile.ts +796 -0
  307. package/src/intelligence/suite-intelligence.ts +305 -0
  308. package/src/intelligence/test-intelligence.ts +136 -0
  309. package/src/intelligence/trace-proposal-workflow.ts +318 -0
  310. package/src/intelligence/verified-llm-repair-workflow.ts +48 -0
  311. package/src/intelligence/workflow-planner.ts +966 -0
  312. package/src/mcp/server.ts +970 -0
  313. package/src/memory/stability-ledger.ts +243 -0
  314. package/src/perception/app-model.ts +32 -0
  315. package/src/perception/crawler.ts +263 -0
  316. package/src/perception/index.ts +3 -0
  317. package/src/repair/approval-service.ts +541 -0
  318. package/src/repair/assertion-hasher.ts +386 -0
  319. package/src/repair/ast-patcher.ts +223 -0
  320. package/src/repair/browser-operation-executor.ts +263 -0
  321. package/src/repair/diff-allowlist.ts +612 -0
  322. package/src/repair/intent-validator.ts +761 -0
  323. package/src/repair/repair-operations.ts +65 -0
  324. package/src/repair/repair-planner.ts +467 -0
  325. package/src/repair/repair-workflow.ts +241 -0
  326. package/src/repair/safe-operation-compiler.ts +68 -0
  327. package/src/repair/source-mapper.ts +156 -0
  328. package/src/repair/statement-patcher.ts +544 -0
  329. package/src/repair/verification-gates.ts +46 -0
  330. package/src/repair/workflow-plan.ts +59 -0
  331. package/src/repair/workspace-promoter.ts +313 -0
  332. package/src/reproduce/diagnostic-rerunner.ts +287 -0
  333. package/src/reproduce/direct-browser-investigator.ts +208 -0
  334. package/src/reproduce/interactive-workflow-runner.ts +828 -0
  335. package/src/sandbox/dependency-strategy.ts +215 -0
  336. package/src/sandbox/execution-runner.ts +408 -0
  337. package/src/sandbox/worktree-manager.ts +287 -0
  338. package/src/selector/abstention-policy.ts +175 -0
  339. package/src/selector/candidate-extractor.ts +343 -0
  340. package/src/selector/live-locator-verifier.ts +139 -0
  341. package/src/selector/repair-candidate-ranker.ts +92 -0
  342. package/src/selector/selector-scorer.ts +344 -0
  343. package/src/trace/adapters/adapter-registry.ts +49 -0
  344. package/src/trace/adapters/trace-adapter.ts +28 -0
  345. package/src/trace/adapters/unknown-adapter.ts +50 -0
  346. package/src/trace/adapters/v10-adapter.ts +39 -0
  347. package/src/trace/adapters/v4-adapter.ts +31 -0
  348. package/src/trace/adapters/v8-adapter.ts +42 -0
  349. package/src/trace/adapters/v9-adapter.ts +39 -0
  350. package/src/trace/archive-reader.ts +246 -0
  351. package/src/trace/snapshot-resolver.ts +308 -0
  352. package/src/trace/trace-parser.ts +467 -0
  353. package/src/trace/version-detector.ts +81 -0
@@ -0,0 +1,970 @@
1
+ import readline from 'node:readline';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import { ArchiveReader } from '../trace/archive-reader.js';
5
+ import { VersionDetector } from '../trace/version-detector.js';
6
+ import { TraceAdapterRegistry } from '../trace/adapters/adapter-registry.js';
7
+ import { EvidenceCorrelator } from '../diagnostics/evidence-correlator.js';
8
+ import { DiagnosticReportGenerator } from '../diagnostics/diagnostic-report.js';
9
+ import { AstPatcher } from '../repair/ast-patcher.js';
10
+ import { AssertionHasher } from '../repair/assertion-hasher.js';
11
+ import { DiffAllowlistValidator } from '../repair/diff-allowlist.js';
12
+ import { ApprovalService } from '../repair/approval-service.js';
13
+ import { WorkspacePromoter } from '../repair/workspace-promoter.js';
14
+ import { TestGenerator } from '../generator/test-generator.js';
15
+ import { ENGINE_MILESTONE, getRuntimeProvenance, PACKAGE_VERSION } from '../core/version.js';
16
+ import { bootstrapProjectIntelligence, recordProjectFailure, recordProjectRepairAccepted } from '../intelligence/project-intelligence.js';
17
+ import { initProjectConfig } from '../config/project-config.js';
18
+ import { buildRepositoryProfile, writeRepositoryProfile } from '../intelligence/repository-profile.js';
19
+ import { clusterFailures, FailureObservation } from '../intelligence/failure-clustering.js';
20
+ import { analyzeTestStability, analyzeRepositoryImpact, TestRunObservation } from '../intelligence/suite-intelligence.js';
21
+ import { compileSafeRepairOperation } from '../repair/safe-operation-compiler.js';
22
+ import { evaluateQualityGate, QualityGateInput } from '../integrations/quality-gate.js';
23
+ import { planArchitecture, writeArchitecturePlan, ArchitectureMode } from '../generator/architecture-generator.js';
24
+ import { buildCiEvidenceReport } from '../integrations/playwright-report-adapter.js';
25
+ import { buildSarifReport } from '../integrations/sarif-report.js';
26
+ import { recordArchitectureWorkflow, recordCiWorkflow } from '../governance/workflow-audit.js';
27
+ import { buildTeamDashboard, TeamEvidenceRun } from '../governance/team-dashboard.js';
28
+ import { parseExternalFailureEvidence, supplementDiagnosticContext } from '../diagnostics/external-failure-evidence.js';
29
+ import { runRepairWorkflow } from '../repair/repair-workflow.js';
30
+ import { normalizeFailureCategory } from '../diagnostics/failure-category.js';
31
+ import { runTraceProposalWorkflow } from '../intelligence/trace-proposal-workflow.js';
32
+ import { runAutonomousRepairWorkflow } from '../intelligence/autonomous-repair-workflow.js';
33
+ import { runEvidenceDrivenGeneration } from '../intelligence/generation-verifier.js';
34
+ import type { AuthorKind } from '../authoring/index.js';
35
+
36
+ export interface JsonRpcRequest {
37
+ jsonrpc: '2.0';
38
+ id?: number | string | null | undefined;
39
+ method: string;
40
+ params?: any;
41
+ }
42
+
43
+ export interface JsonRpcResponse {
44
+ jsonrpc: '2.0';
45
+ id: number | string | null;
46
+ result?: any;
47
+ error?: {
48
+ code: number;
49
+ message: string;
50
+ data?: any;
51
+ };
52
+ }
53
+
54
+ export class McpServer {
55
+ private readonly rl: readline.Interface;
56
+ private readonly workspaceRoot: string;
57
+
58
+ constructor(workspaceRoot = process.cwd()) {
59
+ this.workspaceRoot = path.resolve(workspaceRoot);
60
+ this.rl = readline.createInterface({
61
+ input: process.stdin,
62
+ output: process.stdout,
63
+ terminal: false,
64
+ });
65
+ }
66
+
67
+ /**
68
+ * Asserts that a file path resolves within the authorized workspace boundary.
69
+ * Uses canonical filesystem resolution (fs.realpathSync) to prevent symlink,
70
+ * junction, or reparse point bypasses outside the workspace boundary (AUDIT-05).
71
+ * Unconditionally fails closed if canonical realpath resolution fails.
72
+ */
73
+ public assertPathInWorkspace(targetPath: string): string {
74
+ // Cross-platform absolute path validation:
75
+ // If a path contains a Windows drive letter or UNC prefix, but we are running on Linux/macOS,
76
+ // POSIX path.resolve would mistakenly treat it as a relative filename inside workspaceRoot.
77
+ // Explicitly reject Windows drive letters (C:\...) and UNC paths (\\...) on non-Windows platforms.
78
+ if (
79
+ process.platform !== 'win32' &&
80
+ (/^[a-zA-Z]:[/\\]/.test(targetPath) || targetPath.startsWith('\\\\'))
81
+ ) {
82
+ throw new Error(
83
+ `Workspace Security Violation: Path '${targetPath}' resolves outside authorized workspace boundary '${this.workspaceRoot}'.`
84
+ );
85
+ }
86
+
87
+ const normalizedTarget = process.platform === 'win32' ? targetPath : targetPath.replace(/\\/g, '/');
88
+ const resolved = path.resolve(this.workspaceRoot, normalizedTarget);
89
+
90
+ if (!fs.existsSync(this.workspaceRoot)) {
91
+ throw new Error(`Workspace root does not exist: '${this.workspaceRoot}'`);
92
+ }
93
+
94
+ const canonicalWorkspace = fs.realpathSync(this.workspaceRoot);
95
+ let canonicalTarget: string;
96
+
97
+ if (fs.existsSync(resolved)) {
98
+ canonicalTarget = fs.realpathSync(resolved);
99
+ } else {
100
+ const parent = path.dirname(resolved);
101
+ if (fs.existsSync(parent)) {
102
+ canonicalTarget = path.join(fs.realpathSync(parent), path.basename(resolved));
103
+ } else {
104
+ throw new Error(
105
+ `Workspace Security Violation: Path '${targetPath}' cannot be resolved inside authorized workspace boundary '${canonicalWorkspace}'.`
106
+ );
107
+ }
108
+ }
109
+
110
+ const rel = path.relative(canonicalWorkspace, canonicalTarget);
111
+ if (rel.startsWith('..') || path.isAbsolute(rel)) {
112
+ throw new Error(
113
+ `Workspace Security Violation: Path '${targetPath}' resolves to '${canonicalTarget}' outside authorized workspace boundary '${canonicalWorkspace}'.`
114
+ );
115
+ }
116
+
117
+ return canonicalTarget;
118
+ }
119
+
120
+ public start(): void {
121
+ this.rl.on('line', async (line) => {
122
+ const trimmed = line.trim();
123
+ if (!trimmed) return;
124
+
125
+ let req: any;
126
+ try {
127
+ req = JSON.parse(trimmed);
128
+ } catch (err: any) {
129
+ // Spec compliance: Parse error returns id: null
130
+ const errRes: JsonRpcResponse = {
131
+ jsonrpc: '2.0',
132
+ id: null,
133
+ error: { code: -32700, message: `Parse error: ${err.message}` },
134
+ };
135
+ process.stdout.write(JSON.stringify(errRes) + '\n');
136
+ return;
137
+ }
138
+
139
+ const res = await this.handleRequest(req);
140
+ process.stdout.write(JSON.stringify(res) + '\n');
141
+ });
142
+ }
143
+
144
+ public async handleRequest(req: JsonRpcRequest): Promise<JsonRpcResponse> {
145
+ const id = req.id ?? null;
146
+
147
+ if (req.jsonrpc !== '2.0') {
148
+ return {
149
+ jsonrpc: '2.0',
150
+ id,
151
+ error: { code: -32600, message: 'Invalid Request: jsonrpc must be "2.0"' },
152
+ };
153
+ }
154
+
155
+ switch (req.method) {
156
+ case 'initialize':
157
+ return {
158
+ jsonrpc: '2.0',
159
+ id,
160
+ result: {
161
+ protocolVersion: '2024-11-05',
162
+ capabilities: { tools: {} },
163
+ serverInfo: {
164
+ name: 'playwright-intelligence-mcp',
165
+ version: PACKAGE_VERSION,
166
+ },
167
+ },
168
+ };
169
+
170
+ case 'tools/list':
171
+ return {
172
+ jsonrpc: '2.0',
173
+ id,
174
+ result: {
175
+ tools: [
176
+ {
177
+ name: 'diagnose_trace',
178
+ description: 'Analyzes a Playwright trace.zip archive and outputs root-cause classification with causal evidence.',
179
+ inputSchema: {
180
+ type: 'object',
181
+ properties: {
182
+ tracePath: { type: 'string', description: 'Workspace-relative or absolute path to trace.zip archive' },
183
+ errorContextPath: { type: 'string', description: 'Optional workspace-relative path to Playwright error-context.md when the trace lacks a failed action' },
184
+ },
185
+ required: ['tracePath'],
186
+ },
187
+ },
188
+ {
189
+ name: 'repair_trace',
190
+ description: 'Builds a fail-closed repair proposal from a trace, optionally verifies it in an isolated worktree, and never promotes source without explicit approval.',
191
+ inputSchema: {
192
+ type: 'object',
193
+ properties: {
194
+ tracePath: { type: 'string', description: 'Workspace-relative or absolute path to trace.zip archive' },
195
+ errorContextPath: { type: 'string', description: 'Optional Playwright error-context.md path' },
196
+ testPath: { type: 'string', description: 'Failing test spec path, required to build a repair proposal' },
197
+ pomPath: { type: 'string', description: 'Page Object path, required to build a repair proposal' },
198
+ className: { type: 'string', description: 'Page Object class name' },
199
+ memberName: { type: 'string', description: 'Locator member name' },
200
+ configPath: { type: 'string', description: 'Optional Playwright config path for isolated verification' },
201
+ execute: { type: 'boolean', description: 'When true, verify only inside a dedicated worktree; still requires approval to promote' },
202
+ worktreeId: { type: 'string', description: 'Optional stable worktree identifier' },
203
+ operation: { type: 'object', description: 'Optional allowlisted repair operation, such as replace_locator, add_frame_scope, or add_shadow_scope' },
204
+ },
205
+ required: ['tracePath'],
206
+ },
207
+ },
208
+ {
209
+ name: 'propose_repair',
210
+ description: 'Runs a bounded, redaction-aware optional model proposal workflow after deterministic PIE classification; never executes or promotes model output.',
211
+ inputSchema: {
212
+ type: 'object',
213
+ properties: {
214
+ tracePath: { type: 'string', description: 'Workspace-relative or absolute path to trace.zip archive' },
215
+ errorContextPath: { type: 'string', description: 'Optional Playwright error-context.md path' },
216
+ executionId: { type: 'string' },
217
+ testIdentity: { type: 'string' },
218
+ enableBrowserInvestigation: { type: 'boolean', description: 'Explicitly opt in to read-only browser-state investigation when the model requests it' },
219
+ browserUrl: { type: 'string', description: 'Browser URL for opt-in investigation' },
220
+ browserAllowedHosts: { type: 'array', items: { type: 'string' }, description: 'Explicit host allowlist required for browser investigation' },
221
+ },
222
+ required: ['tracePath'],
223
+ },
224
+ },
225
+ {
226
+ name: 'autonomous_repair',
227
+ description: 'Runs the bounded reasoning agent, allowlisted repository/browser tools, isolated repair verification, and optional explicitly authorized promotion.',
228
+ inputSchema: {
229
+ type: 'object',
230
+ properties: {
231
+ tracePath: { type: 'string' },
232
+ errorContextPath: { type: 'string' },
233
+ testPath: { type: 'string' },
234
+ pomPath: { type: 'string' },
235
+ className: { type: 'string' },
236
+ memberName: { type: 'string' },
237
+ configPath: { type: 'string' },
238
+ execute: { type: 'boolean' },
239
+ autoPromote: { type: 'boolean', description: 'Promote only after isolated verification; use only under explicit repository policy.' },
240
+ enableBrowserInvestigation: { type: 'boolean' },
241
+ browserUrl: { type: 'string' },
242
+ browserAllowedHosts: { type: 'array', items: { type: 'string' } },
243
+ enableTestExecution: { type: 'boolean' },
244
+ worktreeId: { type: 'string' },
245
+ },
246
+ required: ['tracePath'],
247
+ },
248
+ },
249
+ {
250
+ name: 'repair_page_object',
251
+ description: 'Safely refactors a Playwright Page Object file using ts-morph AST within authorized workspace, with strict locator grammar and assertion immutability validation.',
252
+ inputSchema: {
253
+ type: 'object',
254
+ properties: {
255
+ pomPath: { type: 'string', description: 'Path to Page Object file within workspace' },
256
+ testPath: { type: 'string', description: 'Path to test spec file within workspace' },
257
+ className: { type: 'string', description: 'Page Object class name' },
258
+ memberName: { type: 'string', description: 'Target locator member name' },
259
+ replacementSelector: { type: 'string', description: 'Replacement locator expression' },
260
+ approvalToken: { type: 'string', description: 'Cryptographic single-use approval token required to apply changes to workspace' },
261
+ },
262
+ required: ['pomPath', 'testPath', 'className', 'memberName', 'replacementSelector'],
263
+ },
264
+ },
265
+ {
266
+ name: 'generate_playwright_test',
267
+ description: 'Generates enterprise-grade TypeScript Playwright Page Object and spec code with web-first assertions.',
268
+ inputSchema: {
269
+ type: 'object',
270
+ properties: {
271
+ featureName: { type: 'string', description: 'Name of the feature/page' },
272
+ baseUrl: { type: 'string', description: 'Target application URL' },
273
+ steps: { type: 'array', description: 'Array of interaction steps' },
274
+ },
275
+ required: ['featureName', 'steps'],
276
+ },
277
+ },
278
+ {
279
+ name: 'plan_test_architecture',
280
+ description: 'Plans a greenfield or repository-aware brownfield Playwright test architecture; optionally creates only missing files when write is explicitly true.',
281
+ inputSchema: {
282
+ type: 'object',
283
+ properties: {
284
+ featureName: { type: 'string' },
285
+ mode: { type: 'string', enum: ['greenfield', 'brownfield'] },
286
+ baseUrl: { type: 'string' },
287
+ requirements: { type: 'string' },
288
+ steps: { type: 'array' },
289
+ write: { type: 'boolean' },
290
+ },
291
+ required: ['featureName', 'mode'],
292
+ },
293
+ },
294
+ {
295
+ name: 'run_qa_pipeline',
296
+ description: 'Runs the 4-phase evidence-driven QA generation, live exploration, assertion-preserving verification, and mutation falsification pipeline.',
297
+ inputSchema: {
298
+ type: 'object',
299
+ properties: {
300
+ featureName: { type: 'string' },
301
+ workspaceRoot: { type: 'string' },
302
+ baseUrl: { type: 'string' },
303
+ prompt: { type: 'string' },
304
+ markdown: { type: 'string' },
305
+ jsonRequirements: {},
306
+ featureText: { type: 'string' },
307
+ editedFeatureText: { type: 'string' },
308
+ author: { type: 'string', enum: ['template', 'hybrid', 'llm'] },
309
+ outArtifactDir: { type: 'string' },
310
+ allowMutatingActions: { type: 'boolean' },
311
+ write: { type: 'boolean' },
312
+ verify: { type: 'boolean' },
313
+ runMutations: { type: 'boolean' },
314
+ },
315
+ },
316
+ },
317
+ {
318
+ name: 'get_product_status',
319
+ description: 'Returns the verified PIE package identity, safety mode, and currently implemented capability surface.',
320
+ inputSchema: { type: 'object', properties: {} },
321
+ },
322
+ {
323
+ name: 'initialize_project',
324
+ description: 'Creates or loads the project-local PIE configuration without modifying application source files.',
325
+ inputSchema: { type: 'object', properties: {} },
326
+ },
327
+ {
328
+ name: 'profile_repository',
329
+ description: 'Builds and persists a repository convention profile for project-aware diagnosis and generation.',
330
+ inputSchema: { type: 'object', properties: {} },
331
+ },
332
+ {
333
+ name: 'cluster_failures',
334
+ description: 'Groups normalized failure observations by deterministic fingerprints.',
335
+ inputSchema: { type: 'object', properties: { observations: { type: 'array' } }, required: ['observations'] },
336
+ },
337
+ {
338
+ name: 'suite_health',
339
+ description: 'Calculates flaky-test, pass-rate, failure-history, and duration summaries.',
340
+ inputSchema: { type: 'object', properties: { runs: { type: 'array' } }, required: ['runs'] },
341
+ },
342
+ {
343
+ name: 'build_team_dashboard',
344
+ description: 'Aggregates normalized CI evidence across repositories into a team quality dashboard and deterministic gate.',
345
+ inputSchema: { type: 'object', properties: { runs: { type: 'array' }, policy: { type: 'object' } }, required: ['runs'] },
346
+ },
347
+ {
348
+ name: 'analyze_repository_impact',
349
+ description: 'Discovers Playwright test dependencies and selects impacted tests from changed files.',
350
+ inputSchema: { type: 'object', properties: { changedFiles: { type: 'array', items: { type: 'string' } } }, required: ['changedFiles'] },
351
+ },
352
+ {
353
+ name: 'compile_repair_operation',
354
+ description: 'Validates and compiles an allowlisted repair operation into an immutable proposal.',
355
+ inputSchema: { type: 'object', properties: { operation: { type: 'object' } }, required: ['operation'] },
356
+ },
357
+ {
358
+ name: 'evaluate_quality_gate',
359
+ description: 'Evaluates deterministic CI/release quality gates from PIE clusters, stability summaries, oracle state, and repair evidence.',
360
+ inputSchema: { type: 'object', properties: {} },
361
+ },
362
+ {
363
+ name: 'ingest_playwright_report',
364
+ description: 'Converts a Playwright JSON report into PIE test observations, failure clusters, stability summaries, a deterministic CI quality gate, and SARIF-compatible results.',
365
+ inputSchema: {
366
+ type: 'object',
367
+ properties: {
368
+ report: { type: 'object' },
369
+ repository: { type: 'string' },
370
+ runId: { type: 'string' },
371
+ },
372
+ required: ['report'],
373
+ },
374
+ },
375
+ ],
376
+ },
377
+ };
378
+
379
+ case 'tools/call':
380
+ return this.handleToolCall(id, req.params?.name, req.params?.arguments);
381
+
382
+ default:
383
+ return {
384
+ jsonrpc: '2.0',
385
+ id,
386
+ error: { code: -32601, message: `Method '${req.method}' not found` },
387
+ };
388
+ }
389
+ }
390
+
391
+ private async handleToolCall(id: number | string | null, toolName: string, args: any): Promise<JsonRpcResponse> {
392
+ try {
393
+ if (!toolName) {
394
+ return {
395
+ jsonrpc: '2.0',
396
+ id,
397
+ error: { code: -32602, message: 'Missing tool name' },
398
+ };
399
+ }
400
+
401
+ if (toolName === 'diagnose_trace') {
402
+ const tracePathRaw = args?.tracePath;
403
+ if (!tracePathRaw || typeof tracePathRaw !== 'string') {
404
+ return {
405
+ jsonrpc: '2.0',
406
+ id,
407
+ error: { code: -32000, message: 'tracePath argument must be a non-empty string' },
408
+ };
409
+ }
410
+
411
+ const tracePath = this.assertPathInWorkspace(tracePathRaw);
412
+ if (!fs.existsSync(tracePath)) {
413
+ throw new Error(`Trace file not found: '${tracePath}'`);
414
+ }
415
+
416
+ const { traceEntryName, networkEntryName, traceEntryNames, networkEntryNames } = ArchiveReader.findTraceFileEntries(tracePath);
417
+ if (!traceEntryName) {
418
+ throw new Error(`No .trace event stream found in archive '${tracePath}'`);
419
+ }
420
+
421
+ const traceText = await ArchiveReader.readEntriesAsText(tracePath, traceEntryNames ?? [traceEntryName]);
422
+ const networkText = (networkEntryNames ?? (networkEntryName ? [networkEntryName] : [])).length > 0
423
+ ? await ArchiveReader.readEntriesAsText(tracePath, networkEntryNames ?? [networkEntryName!])
424
+ : '';
425
+
426
+ const traceLines = traceText.split('\n');
427
+ const networkLines = networkText.split('\n');
428
+ const versionInfo = VersionDetector.detectFromLines(traceLines);
429
+ const adapter = TraceAdapterRegistry.getAdapter(versionInfo.traceFormatVersion);
430
+ const manifest = {
431
+ archivePath: tracePath,
432
+ entryNames: [traceEntryName, networkEntryName].filter(Boolean) as string[],
433
+ traceEntryName,
434
+ networkEntryName,
435
+ };
436
+ let context = await adapter.parse(manifest, traceLines, networkLines);
437
+ if (args?.errorContextPath) {
438
+ const errorContextPath = this.assertPathInWorkspace(args.errorContextPath);
439
+ const errorContext = await fs.promises.readFile(errorContextPath, 'utf8');
440
+ context = supplementDiagnosticContext(context, parseExternalFailureEvidence(errorContext));
441
+ }
442
+ const correlated = EvidenceCorrelator.correlate(context);
443
+ const intelligence = await bootstrapProjectIntelligence(this.workspaceRoot);
444
+ await recordProjectFailure(this.workspaceRoot, context.failedAction.selector, correlated.classification.category);
445
+ const report = DiagnosticReportGenerator.generateTerminalReport(correlated, undefined, intelligence);
446
+ const canonicalClassification = {
447
+ ...correlated.classification,
448
+ category: normalizeFailureCategory(correlated.classification.category),
449
+ };
450
+
451
+ return {
452
+ jsonrpc: '2.0',
453
+ id,
454
+ result: {
455
+ content: [{ type: 'text', text: report }],
456
+ classification: canonicalClassification,
457
+ rawClassification: correlated.classification.category,
458
+ provenance: getRuntimeProvenance(this.workspaceRoot),
459
+ failureFingerprint: correlated.failureFingerprint,
460
+ failureObservation: correlated.failureObservation,
461
+ causalGraph: correlated.classification.causalGraph,
462
+ },
463
+ };
464
+ }
465
+
466
+ if (toolName === 'repair_trace') {
467
+ const tracePath = args?.tracePath;
468
+ if (typeof tracePath !== 'string' || !tracePath.trim()) {
469
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'tracePath argument must be a non-empty string' } };
470
+ }
471
+
472
+ const result = await runRepairWorkflow({
473
+ tracePath,
474
+ workspaceRoot: this.workspaceRoot,
475
+ errorContextPath: typeof args?.errorContextPath === 'string' ? args.errorContextPath : undefined,
476
+ testFilePath: typeof args?.testPath === 'string' ? args.testPath : undefined,
477
+ pomFilePath: typeof args?.pomPath === 'string' ? args.pomPath : undefined,
478
+ className: typeof args?.className === 'string' ? args.className : undefined,
479
+ memberName: typeof args?.memberName === 'string' ? args.memberName : undefined,
480
+ configPath: typeof args?.configPath === 'string' ? args.configPath : undefined,
481
+ execute: args?.execute === true,
482
+ worktreeId: typeof args?.worktreeId === 'string' ? args.worktreeId : undefined,
483
+ operation: args?.operation,
484
+ });
485
+
486
+ const response = {
487
+ status: result.status,
488
+ classification: {
489
+ ...result.correlated.classification,
490
+ category: normalizeFailureCategory(result.correlated.classification.category),
491
+ },
492
+ provenance: getRuntimeProvenance(this.workspaceRoot),
493
+ failureFingerprint: result.correlated.failureFingerprint,
494
+ failureObservation: result.correlated.failureObservation,
495
+ failedAction: result.correlated.context.failedAction,
496
+ proposedLocator: result.proposedLocator,
497
+ candidate: result.candidate
498
+ ? { locatorExpression: result.candidate.locatorExpression, score: result.candidate.score }
499
+ : undefined,
500
+ proposal: result.proposal
501
+ ? {
502
+ pattern: result.proposal.pattern,
503
+ replacementSelector: result.proposal.replacementSelector,
504
+ fullDiff: result.proposal.fullDiff,
505
+ target: {
506
+ testFilePath: result.proposal.testFilePath,
507
+ pomFilePath: result.proposal.pomFilePath,
508
+ className: result.proposal.className,
509
+ memberName: result.proposal.memberName,
510
+ },
511
+ }
512
+ : undefined,
513
+ proposalId: result.stagedProposal?.proposalId,
514
+ worktree: result.worktree,
515
+ verification: result.verification
516
+ ? {
517
+ isReadyForApproval: result.verification.isReadyForApproval,
518
+ state: result.verification.state,
519
+ execution: result.verification.executionProof,
520
+ intentValidation: result.verification.intentValidation,
521
+ }
522
+ : undefined,
523
+ reason: result.reason,
524
+ };
525
+
526
+ return {
527
+ jsonrpc: '2.0',
528
+ id,
529
+ result: {
530
+ content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
531
+ ...response,
532
+ },
533
+ };
534
+ }
535
+
536
+ if (toolName === 'propose_repair') {
537
+ if (typeof args?.tracePath !== 'string' || !args.tracePath.trim()) {
538
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'tracePath argument must be a non-empty string' } };
539
+ }
540
+ const result = await runTraceProposalWorkflow({
541
+ tracePath: args.tracePath,
542
+ workspaceRoot: this.workspaceRoot,
543
+ errorContextPath: typeof args?.errorContextPath === 'string' ? args.errorContextPath : undefined,
544
+ executionId: typeof args?.executionId === 'string' ? args.executionId : undefined,
545
+ testIdentity: typeof args?.testIdentity === 'string' ? args.testIdentity : undefined,
546
+ enableBrowserInvestigation: args?.enableBrowserInvestigation === true,
547
+ browserUrl: typeof args?.browserUrl === 'string' ? args.browserUrl : undefined,
548
+ browserAllowedHosts: Array.isArray(args?.browserAllowedHosts) ? args.browserAllowedHosts.filter((host: unknown): host is string => typeof host === 'string') : undefined,
549
+ });
550
+ return {
551
+ jsonrpc: '2.0',
552
+ id,
553
+ result: {
554
+ content: [{ type: 'text', text: JSON.stringify({ state: result.agent.state, classification: result.agent.classification, proposal: result.agent.proposal, errors: result.agent.errors }, null, 2) }],
555
+ state: result.agent.state,
556
+ modelInvoked: result.agent.modelInvoked,
557
+ classification: result.agent.classification,
558
+ proposal: result.agent.proposal,
559
+ errors: result.agent.errors,
560
+ evidence: {
561
+ bundleId: result.bundle.bundleId,
562
+ redactionComplete: result.bundle.redactionComplete,
563
+ limitations: result.bundle.limitations,
564
+ artifactCount: result.bundle.artifacts.length,
565
+ },
566
+ },
567
+ };
568
+ }
569
+
570
+ if (toolName === 'autonomous_repair') {
571
+ if (typeof args?.tracePath !== 'string' || !args.tracePath.trim()) {
572
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'tracePath argument must be a non-empty string' } };
573
+ }
574
+ const result = await runAutonomousRepairWorkflow({
575
+ tracePath: args.tracePath,
576
+ workspaceRoot: this.workspaceRoot,
577
+ errorContextPath: typeof args?.errorContextPath === 'string' ? args.errorContextPath : undefined,
578
+ testFilePath: typeof args?.testPath === 'string' ? args.testPath : undefined,
579
+ pomFilePath: typeof args?.pomPath === 'string' ? args.pomPath : undefined,
580
+ className: typeof args?.className === 'string' ? args.className : undefined,
581
+ memberName: typeof args?.memberName === 'string' ? args.memberName : undefined,
582
+ configPath: typeof args?.configPath === 'string' ? args.configPath : undefined,
583
+ worktreeId: typeof args?.worktreeId === 'string' ? args.worktreeId : undefined,
584
+ execute: args?.execute === true,
585
+ autoPromote: args?.autoPromote === true,
586
+ enableBrowserInvestigation: args?.enableBrowserInvestigation === true,
587
+ browserUrl: typeof args?.browserUrl === 'string' ? args.browserUrl : undefined,
588
+ browserAllowedHosts: Array.isArray(args?.browserAllowedHosts) ? args.browserAllowedHosts.filter((host: unknown): host is string => typeof host === 'string') : undefined,
589
+ enableTestExecution: args?.enableTestExecution === true,
590
+ });
591
+ const response = {
592
+ status: result.status,
593
+ reason: result.reason,
594
+ modelInvoked: result.proposalRun.agent.modelInvoked,
595
+ state: result.proposalRun.agent.state,
596
+ classification: result.proposalRun.agent.classification,
597
+ proposal: result.proposal,
598
+ verification: result.verification,
599
+ promotion: result.promotion,
600
+ };
601
+ return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: JSON.stringify(response, null, 2) }], ...response } };
602
+ }
603
+
604
+ if (toolName === 'initialize_project') {
605
+ const initialized = await initProjectConfig(this.workspaceRoot);
606
+ return { jsonrpc: '2.0', id, result: { status: initialized.created ? 'CREATED' : 'EXISTING', configPath: initialized.configPath, config: initialized.config } };
607
+ }
608
+
609
+ if (toolName === 'profile_repository') {
610
+ const profile = await buildRepositoryProfile(this.workspaceRoot);
611
+ const written = await writeRepositoryProfile(this.workspaceRoot, profile);
612
+ return { jsonrpc: '2.0', id, result: { status: 'PROFILE_READY', profilePath: written.profilePath, profile } };
613
+ }
614
+
615
+ if (toolName === 'cluster_failures') {
616
+ const observations = args?.observations;
617
+ if (!Array.isArray(observations)) {
618
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'observations must be an array' } };
619
+ }
620
+ const clusters = clusterFailures(observations as FailureObservation[]);
621
+ return { jsonrpc: '2.0', id, result: { observationCount: observations.length, clusterCount: clusters.length, clusters } };
622
+ }
623
+
624
+ if (toolName === 'suite_health') {
625
+ const runs = args?.runs;
626
+ if (!Array.isArray(runs)) {
627
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'runs must be an array' } };
628
+ }
629
+ const tests = analyzeTestStability(runs as TestRunObservation[]);
630
+ return { jsonrpc: '2.0', id, result: { runCount: runs.length, testCount: tests.length, flakyTestCount: tests.filter((test) => test.flaky).length, tests } };
631
+ }
632
+
633
+ if (toolName === 'build_team_dashboard') {
634
+ if (!Array.isArray(args?.runs)) {
635
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'runs must be an array of TeamEvidenceRun objects' } };
636
+ }
637
+ return { jsonrpc: '2.0', id, result: buildTeamDashboard(args.runs as TeamEvidenceRun[], args?.policy ?? {}) };
638
+ }
639
+
640
+ if (toolName === 'analyze_repository_impact') {
641
+ if (!Array.isArray(args?.changedFiles) || args.changedFiles.some((file: unknown) => typeof file !== 'string')) {
642
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'changedFiles must be an array of strings' } };
643
+ }
644
+ return { jsonrpc: '2.0', id, result: await analyzeRepositoryImpact(this.workspaceRoot, args.changedFiles as string[]) };
645
+ }
646
+
647
+ if (toolName === 'compile_repair_operation') {
648
+ const operation = compileSafeRepairOperation(args?.operation);
649
+ return { jsonrpc: '2.0', id, result: operation };
650
+ }
651
+
652
+ if (toolName === 'evaluate_quality_gate') {
653
+ return { jsonrpc: '2.0', id, result: evaluateQualityGate((args ?? {}) as QualityGateInput) };
654
+ }
655
+
656
+ if (toolName === 'ingest_playwright_report') {
657
+ if (!args?.report || typeof args.report !== 'object') {
658
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'report must be a Playwright JSON report object' } };
659
+ }
660
+ const evidence = buildCiEvidenceReport(args.report, { repository: args.repository, runId: args.runId });
661
+ await recordCiWorkflow(this.workspaceRoot, evidence);
662
+ return {
663
+ jsonrpc: '2.0',
664
+ id,
665
+ result: { ...evidence, sarif: buildSarifReport(evidence, PACKAGE_VERSION) },
666
+ };
667
+ }
668
+
669
+ if (toolName === 'repair_page_object') {
670
+ const { pomPath: pomRaw, testPath: testRaw, className, memberName, replacementSelector, approvalToken } = args ?? {};
671
+ if (!pomRaw || !testRaw || !className || !memberName || !replacementSelector) {
672
+ return {
673
+ jsonrpc: '2.0',
674
+ id,
675
+ error: {
676
+ code: -32000,
677
+ message: 'Missing required arguments: pomPath, testPath, className, memberName, replacementSelector',
678
+ },
679
+ };
680
+ }
681
+
682
+ const pomPath = this.assertPathInWorkspace(pomRaw);
683
+ const testPath = this.assertPathInWorkspace(testRaw);
684
+
685
+ if (!fs.existsSync(pomPath)) throw new Error(`Page Object file not found: '${pomPath}'`);
686
+ if (!fs.existsSync(testPath)) throw new Error(`Test spec file not found: '${testPath}'`);
687
+
688
+ // Validate locator expression grammar upfront recursively
689
+ const grammar = DiffAllowlistValidator.validateLocatorGrammar(replacementSelector);
690
+ if (!grammar.isValid) {
691
+ throw new Error(`Security Violation: Disallowed replacement expression '${replacementSelector}'. ${grammar.reason}`);
692
+ }
693
+
694
+ const origPomSource = await fs.promises.readFile(pomPath, 'utf-8');
695
+ const origTestSource = await fs.promises.readFile(testPath, 'utf-8');
696
+ const initialFingerprint = AssertionHasher.computeFingerprint(testPath);
697
+
698
+ // Pre-validate diff allowlist in-memory before writing to disk
699
+ const patcher = new AstPatcher();
700
+ const inMemPatch = patcher.patchPageObjectInMemory(origPomSource, {
701
+ className,
702
+ memberName,
703
+ replacementExpression: replacementSelector,
704
+ });
705
+
706
+ const diffValidation = DiffAllowlistValidator.validate({
707
+ originalSource: origPomSource,
708
+ patchedSource: inMemPatch.patchedSource,
709
+ targetClassName: className,
710
+ targetMemberName: memberName,
711
+ });
712
+
713
+ if (!diffValidation.isAllowed) {
714
+ throw new Error(`Diff Allowlist Rejected: ${diffValidation.reason}`);
715
+ }
716
+
717
+ const fullDiff = inMemPatch.diff ?? '';
718
+
719
+ // If an approvalToken is provided, promote atomically via WorkspacePromoter under lock
720
+ if (approvalToken) {
721
+ const tokenPayload = ApprovalService.getInstance().getTokenPayload(approvalToken);
722
+ if (!tokenPayload) {
723
+ return {
724
+ jsonrpc: '2.0',
725
+ id,
726
+ error: {
727
+ code: -32000,
728
+ message: `Repair Authorization Denied: Approval token '${approvalToken}' not found or already consumed/expired.`,
729
+ },
730
+ };
731
+ }
732
+
733
+ // Promote verified patch atomically via WorkspacePromoter (which validates CAS and consumes token under lock)
734
+ const promoResult = await WorkspacePromoter.promote({
735
+ targetFilePath: pomPath,
736
+ workspaceRoot: this.workspaceRoot,
737
+ patchedContent: inMemPatch.patchedSource,
738
+ approvalTokenPayload: tokenPayload,
739
+ });
740
+
741
+ if (!promoResult.success) {
742
+ return {
743
+ jsonrpc: '2.0',
744
+ id,
745
+ error: {
746
+ code: -32000,
747
+ message: `Workspace Promotion Failed: ${promoResult.error}`,
748
+ },
749
+ };
750
+ }
751
+
752
+ await recordProjectRepairAccepted(this.workspaceRoot, replacementSelector).catch(() => {});
753
+
754
+ const postFingerprint = AssertionHasher.computeFingerprint(testPath);
755
+ const assertionIntact = initialFingerprint === postFingerprint;
756
+
757
+ if (!assertionIntact) {
758
+ // Rollback immediately if assertion fingerprint altered
759
+ await fs.promises.writeFile(pomPath, origPomSource, 'utf8');
760
+ return {
761
+ jsonrpc: '2.0',
762
+ id,
763
+ error: {
764
+ code: -32000,
765
+ message: 'Safety Invariant Violation: Assertion AST SHA-256 fingerprint altered by repair. Mutation rolled back.',
766
+ },
767
+ };
768
+ }
769
+
770
+ return {
771
+ jsonrpc: '2.0',
772
+ id,
773
+ result: {
774
+ content: [
775
+ {
776
+ type: 'text',
777
+ text: `Successfully applied authorized repair to ${className}.${memberName} via atomic WorkspacePromoter.\nAssertion AST fingerprint verified intact: ${assertionIntact}`,
778
+ },
779
+ ],
780
+ status: 'APPLIED',
781
+ patchResult: {
782
+ filePath: pomPath,
783
+ className,
784
+ memberName,
785
+ pattern: inMemPatch.pattern,
786
+ originalSelector: '',
787
+ replacementSelector,
788
+ success: true,
789
+ },
790
+ assertionIntact: true,
791
+ },
792
+ };
793
+ }
794
+
795
+ // When approvalToken is omitted: stage proposal ONLY as a draft. Never leak usable bearer token or fabricate execution verification.
796
+ const staged = ApprovalService.getInstance().stageProposal({
797
+ targetFilePath: pomPath,
798
+ targetClassName: className,
799
+ targetMemberName: memberName,
800
+ originalSourceContent: origPomSource,
801
+ replacementSelector,
802
+ fullDiff,
803
+ patchedSource: inMemPatch.patchedSource,
804
+ testFilePath: testPath,
805
+ testFileContent: origTestSource,
806
+ worktreeId: 'staged-draft',
807
+ });
808
+
809
+ return {
810
+ jsonrpc: '2.0',
811
+ id,
812
+ result: {
813
+ content: [
814
+ {
815
+ type: 'text',
816
+ text: `Repair proposal staged in-memory. Isolated AST diff validated.\nProposal ID: ${staged.proposalId}\nPattern: ${inMemPatch.pattern}\n\nTo review and authorize promotion, a human operator must run:\n pw-intel approve ${staged.proposalId}`,
817
+ },
818
+ ],
819
+ status: 'PROPOSAL_READY_FOR_APPROVAL',
820
+ proposalId: staged.proposalId,
821
+ pattern: inMemPatch.pattern,
822
+ diff: inMemPatch.diff,
823
+ target: { className, memberName, replacementSelector },
824
+ },
825
+ };
826
+ }
827
+
828
+ if (toolName === 'generate_playwright_test') {
829
+ const { featureName, baseUrl, steps } = args ?? {};
830
+ if (!featureName || !Array.isArray(steps)) {
831
+ return {
832
+ jsonrpc: '2.0',
833
+ id,
834
+ error: { code: -32000, message: 'Missing required arguments: featureName (string) and steps (array)' },
835
+ };
836
+ }
837
+
838
+ const generated = TestGenerator.generateSuite(featureName, steps, baseUrl);
839
+ return {
840
+ jsonrpc: '2.0',
841
+ id,
842
+ result: {
843
+ content: [
844
+ {
845
+ type: 'text',
846
+ text: `// Page Object: ${generated.pageObjectName}.ts\n${generated.pageObjectCode}\n\n// Test Spec\n${generated.specCode}`,
847
+ },
848
+ ],
849
+ generated,
850
+ },
851
+ };
852
+ }
853
+
854
+ if (toolName === 'plan_test_architecture') {
855
+ const { featureName, mode, baseUrl, requirements, steps, write } = args ?? {};
856
+ if (typeof featureName !== 'string' || !featureName.trim() || (mode !== 'greenfield' && mode !== 'brownfield')) {
857
+ return { jsonrpc: '2.0', id, error: { code: -32602, message: 'featureName and mode (greenfield|brownfield) are required' } };
858
+ }
859
+ const profile = mode === 'brownfield' ? await buildRepositoryProfile(this.workspaceRoot) : undefined;
860
+ const plan = planArchitecture({ featureName, mode: mode as ArchitectureMode, baseUrl, requirements, steps, profile });
861
+ const writeResult = write === true ? await writeArchitecturePlan(this.workspaceRoot, plan) : undefined;
862
+ await recordArchitectureWorkflow(this.workspaceRoot, plan, writeResult);
863
+ return { jsonrpc: '2.0', id, result: { plan, writeResult } };
864
+ }
865
+
866
+ if (toolName === 'run_qa_pipeline') {
867
+ const {
868
+ featureName,
869
+ workspaceRoot,
870
+ baseUrl,
871
+ prompt,
872
+ markdown,
873
+ jsonRequirements,
874
+ featureText,
875
+ editedFeatureText,
876
+ author,
877
+ outArtifactDir,
878
+ allowMutatingActions,
879
+ write,
880
+ verify,
881
+ runMutations,
882
+ } = args ?? {};
883
+ const targetWorkspace = typeof workspaceRoot === 'string' && workspaceRoot.trim()
884
+ ? path.resolve(workspaceRoot)
885
+ : this.workspaceRoot;
886
+ const resolvedAuthor: AuthorKind | undefined =
887
+ author === 'template' || author === 'hybrid' || author === 'llm' ? author : undefined;
888
+ const result = await runEvidenceDrivenGeneration({
889
+ workspaceRoot: targetWorkspace,
890
+ featureName: typeof featureName === 'string' ? featureName : undefined,
891
+ baseUrl: typeof baseUrl === 'string' ? baseUrl : undefined,
892
+ prompt: typeof prompt === 'string' ? prompt : undefined,
893
+ markdown: typeof markdown === 'string' ? markdown : undefined,
894
+ jsonRequirements,
895
+ featureText: typeof featureText === 'string' ? featureText : undefined,
896
+ editedFeatureText: typeof editedFeatureText === 'string' ? editedFeatureText : undefined,
897
+ author: resolvedAuthor,
898
+ outArtifactDir: typeof outArtifactDir === 'string' ? outArtifactDir : undefined,
899
+ allowMutatingActions: allowMutatingActions === true,
900
+ write: write !== false,
901
+ verify: verify !== false,
902
+ runMutations: runMutations !== false,
903
+ });
904
+ return {
905
+ jsonrpc: '2.0',
906
+ id,
907
+ result: {
908
+ qaReport: result.qaReport,
909
+ workflowPlan: result.workflowPlan,
910
+ featureText: result.featureText,
911
+ },
912
+ };
913
+ }
914
+
915
+ if (toolName === 'get_product_status') {
916
+ return {
917
+ jsonrpc: '2.0',
918
+ id,
919
+ result: {
920
+ packageVersion: PACKAGE_VERSION,
921
+ engineeringMilestone: ENGINE_MILESTONE,
922
+ provenance: getRuntimeProvenance(this.workspaceRoot),
923
+ safetyMode: 'fail-closed',
924
+ mutationPolicy: 'approval-required',
925
+ llmPolicy: 'provider-neutral-bounded-agent-with-deterministic-verification',
926
+ capabilities: {
927
+ traceDiagnosis: true,
928
+ liveReproduction: true,
929
+ astPageObjectRepair: true,
930
+ traceToRepairWorkflow: true,
931
+ isolatedWorktreeVerification: true,
932
+ workflowRepairExecution: true,
933
+ allowlistedOperationWorkflow: true,
934
+ browserOperationExecutor: true,
935
+ workspacePromotion: 'explicit-auto-promote-policy',
936
+ builtInLlmProvider: false,
937
+ boundedModelProposalWorkflow: true,
938
+ boundedAutonomousRepairWorkflow: true,
939
+ structuredGenerationAgent: true,
940
+ repositoryInspection: true,
941
+ repositoryBaselineRunner: true,
942
+ externalRepositoryEvaluation: false,
943
+ projectIntelligence: true,
944
+ failureClustering: true,
945
+ suiteHealth: true,
946
+ safeOperationCompiler: true,
947
+ qualityGate: true,
948
+ sarifOutput: true,
949
+ teamDashboard: true,
950
+ architectureGeneration: true,
951
+ firstPartySkills: true,
952
+ },
953
+ },
954
+ };
955
+ }
956
+
957
+ return {
958
+ jsonrpc: '2.0',
959
+ id,
960
+ error: { code: -32602, message: `Unknown tool '${toolName}'` },
961
+ };
962
+ } catch (err: any) {
963
+ return {
964
+ jsonrpc: '2.0',
965
+ id,
966
+ error: { code: -32000, message: err.message },
967
+ };
968
+ }
969
+ }
970
+ }