@mcoda/core 0.1.9 → 0.1.12

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 (204) hide show
  1. package/README.md +2 -2
  2. package/dist/api/AgentsApi.d.ts +1 -0
  3. package/dist/api/AgentsApi.d.ts.map +1 -1
  4. package/dist/api/AgentsApi.js +136 -11
  5. package/dist/api/QaTasksApi.d.ts.map +1 -1
  6. package/dist/api/QaTasksApi.js +4 -0
  7. package/dist/prompts/PdrPrompts.d.ts.map +1 -1
  8. package/dist/prompts/PdrPrompts.js +6 -0
  9. package/dist/prompts/SdsPrompts.d.ts.map +1 -1
  10. package/dist/prompts/SdsPrompts.js +7 -0
  11. package/dist/services/agents/AgentRatingService.d.ts +19 -0
  12. package/dist/services/agents/AgentRatingService.d.ts.map +1 -1
  13. package/dist/services/agents/AgentRatingService.js +66 -2
  14. package/dist/services/agents/GatewayAgentService.d.ts +8 -0
  15. package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
  16. package/dist/services/agents/GatewayAgentService.js +462 -65
  17. package/dist/services/agents/GatewayHandoff.d.ts +5 -1
  18. package/dist/services/agents/GatewayHandoff.d.ts.map +1 -1
  19. package/dist/services/agents/GatewayHandoff.js +65 -32
  20. package/dist/services/agents/RoutingService.d.ts +1 -0
  21. package/dist/services/agents/RoutingService.d.ts.map +1 -1
  22. package/dist/services/agents/RoutingService.js +4 -4
  23. package/dist/services/backlog/BacklogService.d.ts +23 -0
  24. package/dist/services/backlog/BacklogService.d.ts.map +1 -1
  25. package/dist/services/backlog/BacklogService.js +62 -7
  26. package/dist/services/backlog/TaskOrderingHeuristics.d.ts +12 -0
  27. package/dist/services/backlog/TaskOrderingHeuristics.d.ts.map +1 -0
  28. package/dist/services/backlog/TaskOrderingHeuristics.js +56 -0
  29. package/dist/services/backlog/TaskOrderingService.d.ts +16 -4
  30. package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
  31. package/dist/services/backlog/TaskOrderingService.js +529 -73
  32. package/dist/services/docs/DocInventory.d.ts +11 -0
  33. package/dist/services/docs/DocInventory.d.ts.map +1 -0
  34. package/dist/services/docs/DocInventory.js +230 -0
  35. package/dist/services/docs/DocgenRunContext.d.ts +59 -0
  36. package/dist/services/docs/DocgenRunContext.d.ts.map +1 -0
  37. package/dist/services/docs/DocgenRunContext.js +4 -0
  38. package/dist/services/docs/DocsService.d.ts +59 -2
  39. package/dist/services/docs/DocsService.d.ts.map +1 -1
  40. package/dist/services/docs/DocsService.js +1701 -48
  41. package/dist/services/docs/alignment/DocAlignmentGraph.d.ts +23 -0
  42. package/dist/services/docs/alignment/DocAlignmentGraph.d.ts.map +1 -0
  43. package/dist/services/docs/alignment/DocAlignmentGraph.js +78 -0
  44. package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts +19 -0
  45. package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts.map +1 -0
  46. package/dist/services/docs/alignment/DocAlignmentPatcher.js +222 -0
  47. package/dist/services/docs/patch/DocPatchEngine.d.ts +57 -0
  48. package/dist/services/docs/patch/DocPatchEngine.d.ts.map +1 -0
  49. package/dist/services/docs/patch/DocPatchEngine.js +331 -0
  50. package/dist/services/docs/review/Glossary.d.ts +16 -0
  51. package/dist/services/docs/review/Glossary.d.ts.map +1 -0
  52. package/dist/services/docs/review/Glossary.js +47 -0
  53. package/dist/services/docs/review/ReviewReportRenderer.d.ts +3 -0
  54. package/dist/services/docs/review/ReviewReportRenderer.d.ts.map +1 -0
  55. package/dist/services/docs/review/ReviewReportRenderer.js +133 -0
  56. package/dist/services/docs/review/ReviewReportSchema.d.ts +39 -0
  57. package/dist/services/docs/review/ReviewReportSchema.d.ts.map +1 -0
  58. package/dist/services/docs/review/ReviewReportSchema.js +47 -0
  59. package/dist/services/docs/review/ReviewTypes.d.ts +76 -0
  60. package/dist/services/docs/review/ReviewTypes.d.ts.map +1 -0
  61. package/dist/services/docs/review/ReviewTypes.js +94 -0
  62. package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts +7 -0
  63. package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts.map +1 -0
  64. package/dist/services/docs/review/gates/AdminOpenApiSpecGate.js +93 -0
  65. package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts +7 -0
  66. package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts.map +1 -0
  67. package/dist/services/docs/review/gates/ApiPathConsistencyGate.js +308 -0
  68. package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts +8 -0
  69. package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts.map +1 -0
  70. package/dist/services/docs/review/gates/BuildReadyCompletenessGate.js +278 -0
  71. package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts +8 -0
  72. package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts.map +1 -0
  73. package/dist/services/docs/review/gates/DeploymentBlueprintGate.js +487 -0
  74. package/dist/services/docs/review/gates/NoMaybesGate.d.ts +8 -0
  75. package/dist/services/docs/review/gates/NoMaybesGate.d.ts.map +1 -0
  76. package/dist/services/docs/review/gates/NoMaybesGate.js +145 -0
  77. package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts +7 -0
  78. package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts.map +1 -0
  79. package/dist/services/docs/review/gates/OpenApiCoverageGate.js +266 -0
  80. package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts +7 -0
  81. package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts.map +1 -0
  82. package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.js +59 -0
  83. package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts +7 -0
  84. package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts.map +1 -0
  85. package/dist/services/docs/review/gates/OpenQuestionsGate.js +200 -0
  86. package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts +7 -0
  87. package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts.map +1 -0
  88. package/dist/services/docs/review/gates/PdrInterfacesGate.js +159 -0
  89. package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts +8 -0
  90. package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts.map +1 -0
  91. package/dist/services/docs/review/gates/PdrOpenQuestionsGate.js +129 -0
  92. package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts +7 -0
  93. package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts.map +1 -0
  94. package/dist/services/docs/review/gates/PdrOwnershipGate.js +169 -0
  95. package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts +10 -0
  96. package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts.map +1 -0
  97. package/dist/services/docs/review/gates/PlaceholderArtifactGate.js +261 -0
  98. package/dist/services/docs/review/gates/RfpConsentGate.d.ts +6 -0
  99. package/dist/services/docs/review/gates/RfpConsentGate.d.ts.map +1 -0
  100. package/dist/services/docs/review/gates/RfpConsentGate.js +127 -0
  101. package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts +7 -0
  102. package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts.map +1 -0
  103. package/dist/services/docs/review/gates/RfpDefinitionGate.js +173 -0
  104. package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts +7 -0
  105. package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts.map +1 -0
  106. package/dist/services/docs/review/gates/SdsAdaptersGate.js +196 -0
  107. package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts +7 -0
  108. package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts.map +1 -0
  109. package/dist/services/docs/review/gates/SdsDecisionsGate.js +89 -0
  110. package/dist/services/docs/review/gates/SdsOpsGate.d.ts +7 -0
  111. package/dist/services/docs/review/gates/SdsOpsGate.d.ts.map +1 -0
  112. package/dist/services/docs/review/gates/SdsOpsGate.js +162 -0
  113. package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts +7 -0
  114. package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts.map +1 -0
  115. package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.js +166 -0
  116. package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts +7 -0
  117. package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts.map +1 -0
  118. package/dist/services/docs/review/gates/SqlRequiredTablesGate.js +273 -0
  119. package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts +7 -0
  120. package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts.map +1 -0
  121. package/dist/services/docs/review/gates/SqlSyntaxGate.js +203 -0
  122. package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts +9 -0
  123. package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts.map +1 -0
  124. package/dist/services/docs/review/gates/TerminologyNormalizationGate.js +217 -0
  125. package/dist/services/docs/review/glossary.json +47 -0
  126. package/dist/services/estimate/EstimateService.d.ts +2 -0
  127. package/dist/services/estimate/EstimateService.d.ts.map +1 -1
  128. package/dist/services/estimate/EstimateService.js +66 -18
  129. package/dist/services/estimate/VelocityService.d.ts +4 -0
  130. package/dist/services/estimate/VelocityService.d.ts.map +1 -1
  131. package/dist/services/estimate/VelocityService.js +179 -36
  132. package/dist/services/estimate/types.d.ts +1 -0
  133. package/dist/services/estimate/types.d.ts.map +1 -1
  134. package/dist/services/execution/GatewayTrioService.d.ts +71 -4
  135. package/dist/services/execution/GatewayTrioService.d.ts.map +1 -1
  136. package/dist/services/execution/GatewayTrioService.js +1695 -328
  137. package/dist/services/execution/QaApiRunner.d.ts +30 -0
  138. package/dist/services/execution/QaApiRunner.d.ts.map +1 -0
  139. package/dist/services/execution/QaApiRunner.js +881 -0
  140. package/dist/services/execution/QaFollowupService.d.ts +1 -0
  141. package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
  142. package/dist/services/execution/QaFollowupService.js +8 -2
  143. package/dist/services/execution/QaPlanValidator.d.ts +10 -0
  144. package/dist/services/execution/QaPlanValidator.d.ts.map +1 -0
  145. package/dist/services/execution/QaPlanValidator.js +128 -0
  146. package/dist/services/execution/QaProfileService.d.ts +21 -1
  147. package/dist/services/execution/QaProfileService.d.ts.map +1 -1
  148. package/dist/services/execution/QaProfileService.js +214 -29
  149. package/dist/services/execution/QaTasksService.d.ts +41 -1
  150. package/dist/services/execution/QaTasksService.d.ts.map +1 -1
  151. package/dist/services/execution/QaTasksService.js +2851 -500
  152. package/dist/services/execution/QaTestCommandBuilder.d.ts +51 -0
  153. package/dist/services/execution/QaTestCommandBuilder.d.ts.map +1 -0
  154. package/dist/services/execution/QaTestCommandBuilder.js +495 -0
  155. package/dist/services/execution/TaskSelectionService.d.ts +4 -2
  156. package/dist/services/execution/TaskSelectionService.d.ts.map +1 -1
  157. package/dist/services/execution/TaskSelectionService.js +144 -28
  158. package/dist/services/execution/TaskStateService.d.ts +19 -6
  159. package/dist/services/execution/TaskStateService.d.ts.map +1 -1
  160. package/dist/services/execution/TaskStateService.js +128 -13
  161. package/dist/services/execution/WorkOnTasksService.d.ts +19 -2
  162. package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
  163. package/dist/services/execution/WorkOnTasksService.js +3913 -1225
  164. package/dist/services/jobs/JobInsightsService.d.ts +4 -0
  165. package/dist/services/jobs/JobInsightsService.d.ts.map +1 -1
  166. package/dist/services/jobs/JobInsightsService.js +51 -5
  167. package/dist/services/jobs/JobResumeService.d.ts.map +1 -1
  168. package/dist/services/jobs/JobResumeService.js +23 -10
  169. package/dist/services/jobs/JobService.d.ts +56 -4
  170. package/dist/services/jobs/JobService.d.ts.map +1 -1
  171. package/dist/services/jobs/JobService.js +232 -1
  172. package/dist/services/openapi/OpenApiService.d.ts +41 -0
  173. package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
  174. package/dist/services/openapi/OpenApiService.js +889 -98
  175. package/dist/services/planning/CreateTasksService.d.ts +15 -0
  176. package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
  177. package/dist/services/planning/CreateTasksService.js +311 -6
  178. package/dist/services/planning/RefineTasksService.d.ts +4 -0
  179. package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
  180. package/dist/services/planning/RefineTasksService.js +225 -24
  181. package/dist/services/review/CodeReviewService.d.ts +4 -0
  182. package/dist/services/review/CodeReviewService.d.ts.map +1 -1
  183. package/dist/services/review/CodeReviewService.js +778 -232
  184. package/dist/services/review/ReviewNormalizer.d.ts +9 -0
  185. package/dist/services/review/ReviewNormalizer.d.ts.map +1 -0
  186. package/dist/services/review/ReviewNormalizer.js +147 -0
  187. package/dist/services/shared/AuthErrors.d.ts +3 -0
  188. package/dist/services/shared/AuthErrors.d.ts.map +1 -0
  189. package/dist/services/shared/AuthErrors.js +17 -0
  190. package/dist/services/shared/DocdexGuidance.d.ts +7 -0
  191. package/dist/services/shared/DocdexGuidance.d.ts.map +1 -0
  192. package/dist/services/shared/DocdexGuidance.js +12 -0
  193. package/dist/services/shared/ProjectGuidance.d.ts +12 -1
  194. package/dist/services/shared/ProjectGuidance.d.ts.map +1 -1
  195. package/dist/services/shared/ProjectGuidance.js +64 -7
  196. package/dist/services/system/ToolDenylist.d.ts +13 -0
  197. package/dist/services/system/ToolDenylist.d.ts.map +1 -0
  198. package/dist/services/system/ToolDenylist.js +85 -0
  199. package/dist/services/telemetry/TelemetryService.d.ts.map +1 -1
  200. package/dist/services/telemetry/TelemetryService.js +39 -7
  201. package/dist/workspace/WorkspaceManager.d.ts +22 -0
  202. package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
  203. package/dist/workspace/WorkspaceManager.js +203 -32
  204. package/package.json +6 -5
@@ -20,6 +20,7 @@ export declare class QaFollowupService {
20
20
  private workspaceRepo;
21
21
  private workspaceRoot;
22
22
  constructor(workspaceRepo: WorkspaceRepository, workspaceRoot: string);
23
+ private get mcodaDir();
23
24
  private get cachePath();
24
25
  private readCache;
25
26
  private writeCache;
@@ -1 +1 @@
1
- {"version":3,"file":"QaFollowupService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaFollowupService.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,OAAO,EACP,mBAAmB,EACpB,MAAM,WAAW,CAAC;AAMnB,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgCD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,aAAa;IAAuB,OAAO,CAAC,aAAa;gBAAzD,aAAa,EAAE,mBAAmB,EAAU,aAAa,EAAE,MAAM;IAErF,OAAO,KAAK,SAAS,GAEpB;YAEa,SAAS;YAST,UAAU;YAKV,kBAAkB;IA+C1B,kBAAkB,CACtB,UAAU,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAC7D,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,GAAG;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;YA8EnG,sBAAsB;CA+ErC"}
1
+ {"version":3,"file":"QaFollowupService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaFollowupService.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,OAAO,EACP,mBAAmB,EACpB,MAAM,WAAW,CAAC;AAMnB,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgCD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,aAAa;IAAuB,OAAO,CAAC,aAAa;gBAAzD,aAAa,EAAE,mBAAmB,EAAU,aAAa,EAAE,MAAM;IAErF,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,SAAS,GAEpB;YAEa,SAAS;YAST,UAAU;YAKV,kBAAkB;IA+C1B,kBAAkB,CACtB,UAAU,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAC7D,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,GAAG;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;YAiFnG,sBAAsB;CA+ErC"}
@@ -30,8 +30,11 @@ export class QaFollowupService {
30
30
  this.workspaceRepo = workspaceRepo;
31
31
  this.workspaceRoot = workspaceRoot;
32
32
  }
33
+ get mcodaDir() {
34
+ return PathHelper.getWorkspaceDir(this.workspaceRoot);
35
+ }
33
36
  get cachePath() {
34
- return path.join(this.workspaceRoot, '.mcoda', 'qa-containers.json');
37
+ return path.join(this.mcodaDir, 'qa-containers.json');
35
38
  }
36
39
  async readCache() {
37
40
  try {
@@ -94,9 +97,12 @@ export class QaFollowupService {
94
97
  const keyGen = createTaskKeyGenerator(storyKeyBase, existingKeys);
95
98
  const followupKey = keyGen();
96
99
  const now = new Date().toISOString();
100
+ const storyPoints = suggestion.storyPoints ?? 1;
101
+ const boundedPoints = Math.min(10, Math.max(1, Math.round(storyPoints)));
97
102
  const metadata = {
98
103
  tags: ['qa-found', 'auto-created', 'ready-for-ai-dev', 'source=qa', ...(suggestion.tags ?? [])],
99
104
  source_task: sourceTask.key,
105
+ complexity: boundedPoints,
100
106
  ...(suggestion.followupSlug ? { qa_followup_slug: suggestion.followupSlug } : {}),
101
107
  ...(suggestion.components ? { components: suggestion.components } : {}),
102
108
  ...(suggestion.docLinks ? { doc_links: suggestion.docLinks } : {}),
@@ -124,7 +130,7 @@ export class QaFollowupService {
124
130
  description,
125
131
  type: suggestion.type ?? 'bug',
126
132
  status: 'not_started',
127
- storyPoints: suggestion.storyPoints ?? 1,
133
+ storyPoints: boundedPoints,
128
134
  priority: suggestion.priority ?? 99,
129
135
  metadata,
130
136
  };
@@ -0,0 +1,10 @@
1
+ import { QaTaskPlan } from '@mcoda/shared';
2
+ type NormalizedQaPlan = {
3
+ taskProfiles: Record<string, string[]>;
4
+ taskPlans: Record<string, QaTaskPlan>;
5
+ notes?: string;
6
+ warnings: string[];
7
+ };
8
+ export declare const normalizeQaPlanOutput: (value: unknown) => NormalizedQaPlan;
9
+ export {};
10
+ //# sourceMappingURL=QaPlanValidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QaPlanValidator.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaPlanValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,UAAU,EAAE,MAAM,eAAe,CAAC;AAGnD,KAAK,gBAAgB,GAAG;IACtB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAwGF,eAAO,MAAM,qBAAqB,GAAI,OAAO,OAAO,KAAG,gBAoCtD,CAAC"}
@@ -0,0 +1,128 @@
1
+ const toStringList = (value) => {
2
+ if (typeof value === 'string')
3
+ return value.trim() ? [value.trim()] : [];
4
+ if (!Array.isArray(value))
5
+ return [];
6
+ return value
7
+ .filter((entry) => typeof entry === 'string')
8
+ .map((entry) => entry.trim())
9
+ .filter(Boolean);
10
+ };
11
+ const ASSERT_TEXT_OK_MARKER = '__MCODA_ASSERT_OK__';
12
+ const buildAssertTextExpression = (params) => {
13
+ const textExpression = params.selector
14
+ ? `(() => { const el = document.querySelector(${JSON.stringify(params.selector)}); return el ? (el.innerText || el.textContent || '') : ''; })()`
15
+ : `document.body ? (document.body.innerText || document.body.textContent || '') : ''`;
16
+ const expected = JSON.stringify(params.text);
17
+ const comparison = params.contains ? 'actual.includes(expected)' : 'actual.trim() === expected';
18
+ return `(() => { const actual = ${textExpression}; const expected = ${expected}; const ok = ${comparison}; return ok ? ${JSON.stringify(ASSERT_TEXT_OK_MARKER)} : actual; })()`;
19
+ };
20
+ const normalizeBrowserActions = (entries, warnings, taskKey) => {
21
+ const actions = [];
22
+ const context = taskKey ? ` for ${taskKey}` : '';
23
+ for (const entry of entries) {
24
+ if (!entry || typeof entry !== 'object')
25
+ continue;
26
+ const action = entry;
27
+ const rawType = typeof action.type === 'string' ? action.type : '';
28
+ if (rawType === 'assertText' || rawType === 'assert_text') {
29
+ const text = typeof action.text === 'string' ? action.text.trim() : '';
30
+ if (!text) {
31
+ warnings.push(`QA plan browser action ${rawType} missing text${context}.`);
32
+ continue;
33
+ }
34
+ const selector = typeof action.selector === 'string' ? action.selector : undefined;
35
+ const contains = typeof action.contains === 'boolean' ? action.contains : true;
36
+ actions.push({
37
+ type: 'script',
38
+ expression: buildAssertTextExpression({ selector, text, contains }),
39
+ expect: ASSERT_TEXT_OK_MARKER,
40
+ });
41
+ continue;
42
+ }
43
+ actions.push(action);
44
+ }
45
+ return actions;
46
+ };
47
+ const normalizePlanEntry = (value, warnings, taskKey) => {
48
+ if (!value || typeof value !== 'object')
49
+ return undefined;
50
+ const raw = value;
51
+ const profiles = toStringList(raw.profiles);
52
+ const cliCommands = toStringList(raw.cli?.commands);
53
+ const apiRequests = Array.isArray(raw.api?.requests)
54
+ ? raw.api.requests.filter((entry) => typeof entry === 'object' && entry)
55
+ : [];
56
+ const rawBrowserActions = Array.isArray(raw.browser?.actions)
57
+ ? raw.browser.actions.filter((entry) => typeof entry === 'object' && entry)
58
+ : [];
59
+ const browserActions = normalizeBrowserActions(rawBrowserActions, warnings, taskKey);
60
+ const stressApi = Array.isArray(raw.stress?.api)
61
+ ? raw.stress.api.filter((entry) => typeof entry === 'object' && entry)
62
+ : [];
63
+ const stressBrowser = Array.isArray(raw.stress?.browser)
64
+ ? raw.stress.browser.filter((entry) => typeof entry === 'object' && entry)
65
+ : [];
66
+ const plan = {};
67
+ if (profiles.length)
68
+ plan.profiles = profiles;
69
+ if (cliCommands.length)
70
+ plan.cli = { commands: cliCommands };
71
+ if (apiRequests.length || typeof raw.api?.base_url === 'string') {
72
+ plan.api = {
73
+ base_url: typeof raw.api?.base_url === 'string' ? raw.api.base_url : undefined,
74
+ requests: apiRequests,
75
+ };
76
+ }
77
+ if (browserActions.length || typeof raw.browser?.base_url === 'string') {
78
+ plan.browser = {
79
+ base_url: typeof raw.browser?.base_url === 'string' ? raw.browser.base_url : undefined,
80
+ actions: browserActions.length ? browserActions : undefined,
81
+ };
82
+ }
83
+ if (stressApi.length || stressBrowser.length) {
84
+ plan.stress = {
85
+ api: stressApi,
86
+ browser: stressBrowser,
87
+ };
88
+ }
89
+ return Object.keys(plan).length ? plan : undefined;
90
+ };
91
+ export const normalizeQaPlanOutput = (value) => {
92
+ const warnings = [];
93
+ if (!value || typeof value !== 'object') {
94
+ warnings.push('QA plan output is not an object.');
95
+ return { taskProfiles: {}, taskPlans: {}, warnings };
96
+ }
97
+ const raw = value;
98
+ const taskProfilesRaw = raw.task_profiles ?? raw.taskProfiles;
99
+ const taskPlansRaw = raw.task_plans ?? raw.taskPlans ?? raw.tasks;
100
+ const taskProfiles = {};
101
+ if (taskProfilesRaw && typeof taskProfilesRaw === 'object') {
102
+ for (const [key, entry] of Object.entries(taskProfilesRaw)) {
103
+ const list = toStringList(entry);
104
+ if (list.length)
105
+ taskProfiles[key] = list;
106
+ }
107
+ }
108
+ else if (taskProfilesRaw !== undefined) {
109
+ warnings.push('QA plan task_profiles is not an object.');
110
+ }
111
+ const taskPlans = {};
112
+ if (taskPlansRaw && typeof taskPlansRaw === 'object') {
113
+ for (const [key, entry] of Object.entries(taskPlansRaw)) {
114
+ const normalized = normalizePlanEntry(entry, warnings, key);
115
+ if (normalized)
116
+ taskPlans[key] = normalized;
117
+ }
118
+ }
119
+ else if (taskPlansRaw !== undefined) {
120
+ warnings.push('QA plan task_plans is not an object.');
121
+ }
122
+ return {
123
+ taskProfiles,
124
+ taskPlans,
125
+ notes: typeof raw.notes === 'string' ? raw.notes : undefined,
126
+ warnings,
127
+ };
128
+ };
@@ -4,17 +4,33 @@ export interface QaProfileResolutionOptions {
4
4
  profileName?: string;
5
5
  level?: string;
6
6
  defaultLevel?: string;
7
+ runnerPreference?: 'cli' | 'chromium' | 'maestro';
7
8
  }
9
+ type QaRunner = 'cli' | 'chromium' | 'maestro';
8
10
  export declare class QaProfileService {
9
11
  private workspaceRoot;
10
12
  private cache?;
11
13
  private webInterfaceCache?;
12
14
  private routingCache?;
13
- constructor(workspaceRoot: string);
15
+ private noRepoWrites;
16
+ constructor(workspaceRoot: string, options?: {
17
+ noRepoWrites?: boolean;
18
+ });
19
+ private get mcodaDir();
14
20
  private fileExists;
15
21
  private readPackageJson;
16
22
  private detectWebInterface;
17
23
  private detectUiTask;
24
+ private detectMobileTask;
25
+ private resolveRunnerPlan;
26
+ getRunnerPlan(task: TaskRow & {
27
+ metadata?: any;
28
+ }): Promise<{
29
+ runners: QaRunner[];
30
+ hasWebInterface: boolean;
31
+ uiTask: boolean;
32
+ mobileTask: boolean;
33
+ }>;
18
34
  private resolveRunnerPreference;
19
35
  private get profilePath();
20
36
  private get workspaceConfigPath();
@@ -24,5 +40,9 @@ export declare class QaProfileService {
24
40
  resolveProfileForTask(task: TaskRow & {
25
41
  metadata?: any;
26
42
  }, options?: QaProfileResolutionOptions): Promise<QaProfile | undefined>;
43
+ resolveProfilesForTask(task: TaskRow & {
44
+ metadata?: any;
45
+ }, options?: QaProfileResolutionOptions): Promise<QaProfile[]>;
27
46
  }
47
+ export {};
28
48
  //# sourceMappingURL=QaProfileService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QaProfileService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaProfileService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG1D,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAcD,qBAAa,gBAAgB;IAUf,OAAO,CAAC,aAAa;IATjC,OAAO,CAAC,KAAK,CAAC,CAAc;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAU;IACpC,OAAO,CAAC,YAAY,CAAC,CAKnB;gBAEkB,aAAa,EAAE,MAAM;YAE3B,UAAU;YASV,eAAe;YAUf,kBAAkB;IAuDhC,OAAO,CAAC,YAAY;YAuCN,uBAAuB;IAMrC,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,mBAAmB,GAE9B;YAEa,+BAA+B;YAU/B,gBAAgB;IAwBxB,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAyBpC,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;KAAE,EAAE,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAgG1I"}
1
+ {"version":3,"file":"QaProfileService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaProfileService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI1D,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;CACnD;AAED,KAAK,QAAQ,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAc/C,qBAAa,gBAAgB;IAWf,OAAO,CAAC,aAAa;IAVjC,OAAO,CAAC,KAAK,CAAC,CAAc;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAU;IACpC,OAAO,CAAC,YAAY,CAAC,CAKnB;IACF,OAAO,CAAC,YAAY,CAAU;gBAEV,aAAa,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAO;IAInF,OAAO,KAAK,QAAQ,GAEnB;YAEa,UAAU;YASV,eAAe;YAUf,kBAAkB;IAyDhC,OAAO,CAAC,YAAY;IAwGpB,OAAO,CAAC,gBAAgB;YAqBV,iBAAiB;IAezB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC;QAC/D,OAAO,EAAE,QAAQ,EAAE,CAAC;QACpB,eAAe,EAAE,OAAO,CAAC;QACzB,MAAM,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;YAIY,uBAAuB;IAQrC,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,mBAAmB,GAE9B;YAEa,+BAA+B;YAU/B,gBAAgB;IAwBxB,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA2BpC,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;KAAE,EAAE,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAoGnI,sBAAsB,CAC1B,IAAI,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;KAAE,EAClC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,SAAS,EAAE,CAAC;CA8DxB"}
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { PathHelper } from '@mcoda/shared';
3
+ import { classifyTask } from '../backlog/TaskOrderingHeuristics.js';
3
4
  import fs from 'node:fs/promises';
4
5
  const DEFAULT_QA_PROFILES = [
5
6
  {
@@ -13,8 +14,12 @@ const DEFAULT_QA_PROFILES = [
13
14
  },
14
15
  ];
15
16
  export class QaProfileService {
16
- constructor(workspaceRoot) {
17
+ constructor(workspaceRoot, options = {}) {
17
18
  this.workspaceRoot = workspaceRoot;
19
+ this.noRepoWrites = Boolean(options.noRepoWrites);
20
+ }
21
+ get mcodaDir() {
22
+ return PathHelper.getWorkspaceDir(this.workspaceRoot);
18
23
  }
19
24
  async fileExists(targetPath) {
20
25
  try {
@@ -47,6 +52,8 @@ export class QaProfileService {
47
52
  'apps/client',
48
53
  'packages/web',
49
54
  'packages/client',
55
+ 'src/public',
56
+ 'src/public/index.html',
50
57
  'public/index.html',
51
58
  'index.html',
52
59
  'src/App.tsx',
@@ -92,24 +99,41 @@ export class QaProfileService {
92
99
  }
93
100
  detectUiTask(task) {
94
101
  const metadata = task.metadata ?? {};
95
- const tags = Array.isArray(metadata.tags) ? metadata.tags.map((t) => t.toLowerCase()) : [];
96
- const uiTags = new Set([
97
- 'ui',
98
- 'frontend',
99
- 'front-end',
100
- 'client',
101
- 'web',
102
- 'react',
103
- 'vue',
104
- 'svelte',
105
- 'angular',
106
- 'next',
107
- 'nuxt',
108
- 'astro',
109
- ]);
110
- if (tags.some((tag) => uiTags.has(tag)))
111
- return true;
112
102
  const files = Array.isArray(metadata.files) ? metadata.files : [];
103
+ const reviewFiles = Array.isArray(metadata.last_review_changed_paths)
104
+ ? metadata.last_review_changed_paths
105
+ : [];
106
+ const key = String(task.key ?? '').toLowerCase();
107
+ const isUiKey = key.startsWith('web-') ||
108
+ key.startsWith('ui-') ||
109
+ key.startsWith('fe-') ||
110
+ key.startsWith('ux-') ||
111
+ key.includes('-web-') ||
112
+ key.includes('-ui-') ||
113
+ key.includes('-fe-') ||
114
+ key.includes('-ux-');
115
+ if (isUiKey)
116
+ return true;
117
+ const isBackendKey = key.startsWith('bck-') ||
118
+ key.startsWith('backend-') ||
119
+ key.startsWith('api-') ||
120
+ key.startsWith('ops-') ||
121
+ key.startsWith('infra-') ||
122
+ key.includes('-bck-') ||
123
+ key.includes('-backend-') ||
124
+ key.includes('-api-') ||
125
+ key.includes('-ops-') ||
126
+ key.includes('-infra-');
127
+ const tags = Array.isArray(metadata.tags)
128
+ ? metadata.tags.map((tag) => String(tag).toLowerCase())
129
+ : [];
130
+ const tagHints = new Set(['ui', 'ux', 'frontend', 'front-end', 'web', 'client']);
131
+ const hasUiTag = tags.some((tag) => tagHints.has(tag));
132
+ const components = Array.isArray(metadata.components)
133
+ ? metadata.components.map((component) => String(component).toLowerCase())
134
+ : [];
135
+ const componentHints = new Set(['ui', 'ux', 'frontend', 'front-end', 'web', 'client']);
136
+ const hasUiComponent = components.some((component) => componentHints.has(component));
113
137
  const uiHints = [
114
138
  '/ui/',
115
139
  '/frontend/',
@@ -122,26 +146,118 @@ export class QaProfileService {
122
146
  '/styles/',
123
147
  ];
124
148
  const uiExtensions = ['.tsx', '.jsx', '.vue', '.svelte', '.astro', '.html', '.css', '.scss', '.less'];
125
- for (const file of files) {
149
+ const hasUiFileHint = (paths, options = {}) => {
150
+ for (const file of paths) {
151
+ const normalized = String(file).toLowerCase();
152
+ const extensionMatch = uiExtensions.some((ext) => normalized.endsWith(ext));
153
+ if (extensionMatch)
154
+ return true;
155
+ if (options.requireExtension)
156
+ continue;
157
+ if (uiHints.some((hint) => normalized.includes(hint)))
158
+ return true;
159
+ }
160
+ return false;
161
+ };
162
+ const type = typeof task.type === 'string' ? task.type.toLowerCase() : '';
163
+ const hasUiType = ['frontend', 'front-end', 'ui', 'web', 'client'].some((hint) => type.includes(hint));
164
+ if (hasUiTag || hasUiComponent || hasUiType)
165
+ return true;
166
+ if (hasUiFileHint(files, { requireExtension: isBackendKey }))
167
+ return true;
168
+ if (isBackendKey)
169
+ return false;
170
+ if (hasUiFileHint(reviewFiles))
171
+ return true;
172
+ const acceptance = Array.isArray(task.acceptanceCriteria)
173
+ ? task.acceptanceCriteria
174
+ : [];
175
+ const text = [task.key, task.title, task.description, task.type, ...acceptance]
176
+ .filter(Boolean)
177
+ .join(' ')
178
+ .toLowerCase();
179
+ if (text) {
180
+ const uiPhrases = [
181
+ 'user interface',
182
+ 'front end',
183
+ 'frontend',
184
+ 'front-end',
185
+ 'web ui',
186
+ 'web-',
187
+ 'ui-',
188
+ 'ui ',
189
+ 'page',
190
+ 'screen',
191
+ 'view',
192
+ 'component',
193
+ 'browser',
194
+ 'html',
195
+ 'css',
196
+ 'responsive',
197
+ 'accessibility',
198
+ ];
199
+ if (uiPhrases.some((phrase) => text.includes(phrase)))
200
+ return true;
201
+ }
202
+ const classification = classifyTask({
203
+ title: task.title,
204
+ description: task.description,
205
+ type: task.type ?? undefined,
206
+ });
207
+ if (classification.stage === 'frontend')
208
+ return true;
209
+ return false;
210
+ }
211
+ detectMobileTask(task) {
212
+ const metadata = task.metadata ?? {};
213
+ const tags = Array.isArray(metadata.tags) ? metadata.tags.map((t) => t.toLowerCase()) : [];
214
+ const type = typeof task.type === 'string' ? task.type.toLowerCase() : '';
215
+ const mobileTags = new Set(['mobile', 'ios', 'android', 'maestro', 'react-native', 'rn']);
216
+ if (tags.some((tag) => mobileTags.has(tag)))
217
+ return true;
218
+ if (mobileTags.has(type))
219
+ return true;
220
+ const files = Array.isArray(metadata.files) ? metadata.files : [];
221
+ const reviewFiles = Array.isArray(metadata.last_review_changed_paths)
222
+ ? metadata.last_review_changed_paths
223
+ : [];
224
+ const combined = [...files, ...reviewFiles];
225
+ const mobileHints = ['/ios/', '/android/', '/mobile/'];
226
+ for (const file of combined) {
126
227
  const normalized = String(file).toLowerCase();
127
- if (uiExtensions.some((ext) => normalized.endsWith(ext)))
228
+ if (mobileHints.some((hint) => normalized.includes(hint)))
128
229
  return true;
129
- if (uiHints.some((hint) => normalized.includes(hint)))
230
+ if (normalized.endsWith('.maestro.yml') || normalized.endsWith('.maestro.yaml'))
130
231
  return true;
131
232
  }
132
233
  return false;
133
234
  }
235
+ async resolveRunnerPlan(task) {
236
+ const hasWebInterface = await this.detectWebInterface();
237
+ const uiTask = this.detectUiTask(task);
238
+ const mobileTask = this.detectMobileTask(task);
239
+ const runners = ['cli'];
240
+ if (uiTask && hasWebInterface)
241
+ runners.push('chromium');
242
+ if (mobileTask)
243
+ runners.push('maestro');
244
+ return { runners, hasWebInterface, uiTask, mobileTask };
245
+ }
246
+ async getRunnerPlan(task) {
247
+ return this.resolveRunnerPlan(task);
248
+ }
134
249
  async resolveRunnerPreference(task) {
135
- if (task && this.detectUiTask(task))
136
- return 'chromium';
137
- const hasUi = await this.detectWebInterface();
138
- return hasUi ? 'chromium' : 'cli';
250
+ if (task && this.detectUiTask(task)) {
251
+ const hasUi = await this.detectWebInterface();
252
+ return hasUi ? 'chromium' : 'cli';
253
+ }
254
+ return 'cli';
139
255
  }
140
256
  get profilePath() {
141
- return path.join(this.workspaceRoot, '.mcoda', 'qa-profiles.json');
257
+ return path.join(this.mcodaDir, 'qa-profiles.json');
142
258
  }
143
259
  get workspaceConfigPath() {
144
- return path.join(this.workspaceRoot, '.mcoda', 'config.json');
260
+ return path.join(this.mcodaDir, 'config.json');
145
261
  }
146
262
  async getConfiguredDefaultProfileName() {
147
263
  try {
@@ -176,7 +292,9 @@ export class QaProfileService {
176
292
  async loadProfiles() {
177
293
  if (this.cache)
178
294
  return this.cache;
179
- await PathHelper.ensureDir(path.join(this.workspaceRoot, '.mcoda'));
295
+ if (!this.noRepoWrites) {
296
+ await PathHelper.ensureDir(this.mcodaDir);
297
+ }
180
298
  try {
181
299
  const raw = await fs.readFile(this.profilePath, 'utf8');
182
300
  const parsed = JSON.parse(raw);
@@ -205,7 +323,7 @@ export class QaProfileService {
205
323
  return undefined;
206
324
  const envProfile = process.env.MCODA_QA_PROFILE;
207
325
  const routing = await this.getRoutingConfig();
208
- const runnerPreference = await this.resolveRunnerPreference(task);
326
+ const runnerPreference = options.runnerPreference ?? (await this.resolveRunnerPreference(task));
209
327
  const normalizeRunner = (profile) => profile.runner ?? 'cli';
210
328
  const matchRunner = (profile) => normalizeRunner(profile) === runnerPreference || profile.name === runnerPreference;
211
329
  const pickByRunner = () => {
@@ -229,6 +347,9 @@ export class QaProfileService {
229
347
  };
230
348
  const explicit = pickByName(configuredDefault);
231
349
  if (explicit) {
350
+ if (options.profileName) {
351
+ return explicit;
352
+ }
232
353
  if (normalizeRunner(explicit) !== runnerPreference) {
233
354
  const fallback = pickByRunner();
234
355
  if (fallback)
@@ -301,4 +422,68 @@ export class QaProfileService {
301
422
  }
302
423
  return undefined;
303
424
  }
425
+ async resolveProfilesForTask(task, options = {}) {
426
+ if (options.profileName) {
427
+ const explicit = await this.resolveProfileForTask(task, options);
428
+ return explicit ? [explicit] : [];
429
+ }
430
+ const qaProfiles = Array.isArray(task.metadata?.qa?.profiles_expected)
431
+ ? task.metadata.qa.profiles_expected
432
+ .map((value) => String(value).trim())
433
+ .filter(Boolean)
434
+ : [];
435
+ if (qaProfiles.length > 0) {
436
+ const profiles = await this.loadProfiles();
437
+ const byName = new Map(profiles.map((profile) => [profile.name.toLowerCase(), profile]));
438
+ const pickByRunner = (runner) => {
439
+ const matches = profiles.filter((profile) => (profile.runner ?? 'cli') === runner);
440
+ if (!matches.length)
441
+ return undefined;
442
+ const defaults = matches.filter((profile) => profile.default);
443
+ if (defaults.length === 1)
444
+ return defaults[0];
445
+ return matches[0];
446
+ };
447
+ const runnerAliases = {
448
+ api: 'cli',
449
+ cli: 'cli',
450
+ browser: 'chromium',
451
+ web: 'chromium',
452
+ ui: 'chromium',
453
+ chromium: 'chromium',
454
+ maestro: 'maestro',
455
+ mobile: 'maestro',
456
+ };
457
+ const resolved = [];
458
+ const seen = new Set();
459
+ for (const profileName of qaProfiles) {
460
+ const normalized = profileName.toLowerCase();
461
+ let profile = byName.get(normalized);
462
+ if (!profile) {
463
+ const runner = runnerAliases[normalized];
464
+ if (runner) {
465
+ profile = pickByRunner(runner);
466
+ }
467
+ }
468
+ if (profile && !seen.has(profile.name)) {
469
+ resolved.push(profile);
470
+ seen.add(profile.name);
471
+ }
472
+ }
473
+ if (resolved.length > 0) {
474
+ return resolved;
475
+ }
476
+ }
477
+ const plan = await this.resolveRunnerPlan(task);
478
+ const profiles = [];
479
+ const seen = new Set();
480
+ for (const runner of plan.runners) {
481
+ const profile = await this.resolveProfileForTask(task, { ...options, runnerPreference: runner });
482
+ if (profile && !seen.has(profile.name)) {
483
+ profiles.push(profile);
484
+ seen.add(profile.name);
485
+ }
486
+ }
487
+ return profiles;
488
+ }
304
489
  }
@@ -23,10 +23,11 @@ export interface QaTasksRequest extends TaskSelectionFilters {
23
23
  rateAgents?: boolean;
24
24
  createFollowupTasks?: 'auto' | 'none' | 'prompt';
25
25
  dryRun?: boolean;
26
- result?: 'pass' | 'fail' | 'blocked';
26
+ result?: 'pass' | 'fail';
27
27
  notes?: string;
28
28
  evidenceUrl?: string;
29
29
  allowDirty?: boolean;
30
+ cleanIgnorePaths?: string[];
30
31
  abortSignal?: AbortSignal;
31
32
  }
32
33
  export interface QaTaskResult {
@@ -61,6 +62,8 @@ export declare class QaTasksService {
61
62
  private routingService?;
62
63
  private ratingService?;
63
64
  private dryRunGuard;
65
+ private qaProfilePlan?;
66
+ private qaTaskPlans?;
64
67
  constructor(workspace: WorkspaceResolution, deps: {
65
68
  workspaceRepo: WorkspaceRepository;
66
69
  jobService: JobService;
@@ -79,13 +82,20 @@ export declare class QaTasksService {
79
82
  noTelemetry?: boolean;
80
83
  }): Promise<QaTasksService>;
81
84
  close(): Promise<void>;
85
+ setDocdexAvailability(available: boolean, reason?: string): void;
82
86
  private readPromptFiles;
83
87
  private loadPrompts;
84
88
  private checkpoint;
85
89
  private ensureTaskBranch;
86
90
  private ensureMcoda;
91
+ private buildCleanIgnorePaths;
87
92
  private adapterForProfile;
88
93
  private mapOutcome;
94
+ private shouldUseAgentInterpretation;
95
+ private buildDeterministicInterpretation;
96
+ private buildRunnerFailureMessage;
97
+ private createRunnerFailureComments;
98
+ private resolveRunAllMarkerPolicy;
89
99
  private adjustOutcomeForSkippedTests;
90
100
  private combineOutcome;
91
101
  private gatherDocContext;
@@ -97,8 +107,37 @@ export declare class QaTasksService {
97
107
  private readPackageJson;
98
108
  private detectPackageManager;
99
109
  private resolveTestCommand;
110
+ private isCliTask;
111
+ private findCliBinCommand;
112
+ private resolveCliChecklistCommands;
113
+ private softenOptionalNpmScripts;
114
+ private usesCliBrowserTools;
115
+ private ensureCypressChromium;
116
+ private applyChromiumForCli;
117
+ private buildScriptCommand;
118
+ private resolveDevServerCommand;
119
+ private shouldInstallQaDeps;
120
+ private hasFileWithExtension;
121
+ private resolveInstallCommands;
122
+ private runShellCommand;
123
+ private commitInstallChanges;
124
+ private isBranchInUseError;
125
+ private buildQaInstallBranch;
126
+ private prepareQaWorkspace;
127
+ private isUrlReachable;
128
+ private waitForUrlReady;
129
+ private startQaServer;
130
+ private checkQaPreflight;
131
+ private isHttpUrl;
132
+ private loadAvailableProfiles;
133
+ private pickDefaultProfile;
134
+ private planProfilesWithAgent;
135
+ private resolveProfilesForRequest;
136
+ private isApprovedReviewDecision;
137
+ private shouldSkipQaForNoChanges;
100
138
  private extractJsonCandidate;
101
139
  private normalizeAgentOutput;
140
+ private validateInterpretation;
102
141
  private interpretResult;
103
142
  private loadCommentContext;
104
143
  private resolveFailureSlug;
@@ -106,6 +145,7 @@ export declare class QaTasksService {
106
145
  private createTaskRun;
107
146
  private finishTaskRun;
108
147
  private logTask;
148
+ private createQaComment;
109
149
  private applyStateTransition;
110
150
  private buildFollowupSuggestion;
111
151
  private buildManualQaFollowup;
@@ -1 +1 @@
1
- {"version":3,"file":"QaTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaTasksService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"QaTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaTasksService.ts"],"names":[],"mappings":"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"}