@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.
- package/README.md +2 -2
- package/dist/api/AgentsApi.d.ts +1 -0
- package/dist/api/AgentsApi.d.ts.map +1 -1
- package/dist/api/AgentsApi.js +136 -11
- package/dist/api/QaTasksApi.d.ts.map +1 -1
- package/dist/api/QaTasksApi.js +4 -0
- package/dist/prompts/PdrPrompts.d.ts.map +1 -1
- package/dist/prompts/PdrPrompts.js +6 -0
- package/dist/prompts/SdsPrompts.d.ts.map +1 -1
- package/dist/prompts/SdsPrompts.js +7 -0
- package/dist/services/agents/AgentRatingService.d.ts +19 -0
- package/dist/services/agents/AgentRatingService.d.ts.map +1 -1
- package/dist/services/agents/AgentRatingService.js +66 -2
- package/dist/services/agents/GatewayAgentService.d.ts +8 -0
- package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
- package/dist/services/agents/GatewayAgentService.js +462 -65
- package/dist/services/agents/GatewayHandoff.d.ts +5 -1
- package/dist/services/agents/GatewayHandoff.d.ts.map +1 -1
- package/dist/services/agents/GatewayHandoff.js +65 -32
- package/dist/services/agents/RoutingService.d.ts +1 -0
- package/dist/services/agents/RoutingService.d.ts.map +1 -1
- package/dist/services/agents/RoutingService.js +4 -4
- package/dist/services/backlog/BacklogService.d.ts +23 -0
- package/dist/services/backlog/BacklogService.d.ts.map +1 -1
- package/dist/services/backlog/BacklogService.js +62 -7
- package/dist/services/backlog/TaskOrderingHeuristics.d.ts +12 -0
- package/dist/services/backlog/TaskOrderingHeuristics.d.ts.map +1 -0
- package/dist/services/backlog/TaskOrderingHeuristics.js +56 -0
- package/dist/services/backlog/TaskOrderingService.d.ts +16 -4
- package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
- package/dist/services/backlog/TaskOrderingService.js +529 -73
- package/dist/services/docs/DocInventory.d.ts +11 -0
- package/dist/services/docs/DocInventory.d.ts.map +1 -0
- package/dist/services/docs/DocInventory.js +230 -0
- package/dist/services/docs/DocgenRunContext.d.ts +59 -0
- package/dist/services/docs/DocgenRunContext.d.ts.map +1 -0
- package/dist/services/docs/DocgenRunContext.js +4 -0
- package/dist/services/docs/DocsService.d.ts +59 -2
- package/dist/services/docs/DocsService.d.ts.map +1 -1
- package/dist/services/docs/DocsService.js +1701 -48
- package/dist/services/docs/alignment/DocAlignmentGraph.d.ts +23 -0
- package/dist/services/docs/alignment/DocAlignmentGraph.d.ts.map +1 -0
- package/dist/services/docs/alignment/DocAlignmentGraph.js +78 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts +19 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts.map +1 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.js +222 -0
- package/dist/services/docs/patch/DocPatchEngine.d.ts +57 -0
- package/dist/services/docs/patch/DocPatchEngine.d.ts.map +1 -0
- package/dist/services/docs/patch/DocPatchEngine.js +331 -0
- package/dist/services/docs/review/Glossary.d.ts +16 -0
- package/dist/services/docs/review/Glossary.d.ts.map +1 -0
- package/dist/services/docs/review/Glossary.js +47 -0
- package/dist/services/docs/review/ReviewReportRenderer.d.ts +3 -0
- package/dist/services/docs/review/ReviewReportRenderer.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewReportRenderer.js +133 -0
- package/dist/services/docs/review/ReviewReportSchema.d.ts +39 -0
- package/dist/services/docs/review/ReviewReportSchema.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewReportSchema.js +47 -0
- package/dist/services/docs/review/ReviewTypes.d.ts +76 -0
- package/dist/services/docs/review/ReviewTypes.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewTypes.js +94 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts +7 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.js +93 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts +7 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.js +308 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts +8 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.js +278 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts +8 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.js +487 -0
- package/dist/services/docs/review/gates/NoMaybesGate.d.ts +8 -0
- package/dist/services/docs/review/gates/NoMaybesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/NoMaybesGate.js +145 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.js +266 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.js +59 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.js +200 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts +7 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.js +159 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts +8 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.js +129 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts +7 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.js +169 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts +10 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.js +261 -0
- package/dist/services/docs/review/gates/RfpConsentGate.d.ts +6 -0
- package/dist/services/docs/review/gates/RfpConsentGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/RfpConsentGate.js +127 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts +7 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.js +173 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.js +196 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.js +89 -0
- package/dist/services/docs/review/gates/SdsOpsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsOpsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsOpsGate.js +162 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.js +166 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.js +273 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.js +203 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts +9 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.js +217 -0
- package/dist/services/docs/review/glossary.json +47 -0
- package/dist/services/estimate/EstimateService.d.ts +2 -0
- package/dist/services/estimate/EstimateService.d.ts.map +1 -1
- package/dist/services/estimate/EstimateService.js +66 -18
- package/dist/services/estimate/VelocityService.d.ts +4 -0
- package/dist/services/estimate/VelocityService.d.ts.map +1 -1
- package/dist/services/estimate/VelocityService.js +179 -36
- package/dist/services/estimate/types.d.ts +1 -0
- package/dist/services/estimate/types.d.ts.map +1 -1
- package/dist/services/execution/GatewayTrioService.d.ts +71 -4
- package/dist/services/execution/GatewayTrioService.d.ts.map +1 -1
- package/dist/services/execution/GatewayTrioService.js +1695 -328
- package/dist/services/execution/QaApiRunner.d.ts +30 -0
- package/dist/services/execution/QaApiRunner.d.ts.map +1 -0
- package/dist/services/execution/QaApiRunner.js +881 -0
- package/dist/services/execution/QaFollowupService.d.ts +1 -0
- package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
- package/dist/services/execution/QaFollowupService.js +8 -2
- package/dist/services/execution/QaPlanValidator.d.ts +10 -0
- package/dist/services/execution/QaPlanValidator.d.ts.map +1 -0
- package/dist/services/execution/QaPlanValidator.js +128 -0
- package/dist/services/execution/QaProfileService.d.ts +21 -1
- package/dist/services/execution/QaProfileService.d.ts.map +1 -1
- package/dist/services/execution/QaProfileService.js +214 -29
- package/dist/services/execution/QaTasksService.d.ts +41 -1
- package/dist/services/execution/QaTasksService.d.ts.map +1 -1
- package/dist/services/execution/QaTasksService.js +2851 -500
- package/dist/services/execution/QaTestCommandBuilder.d.ts +51 -0
- package/dist/services/execution/QaTestCommandBuilder.d.ts.map +1 -0
- package/dist/services/execution/QaTestCommandBuilder.js +495 -0
- package/dist/services/execution/TaskSelectionService.d.ts +4 -2
- package/dist/services/execution/TaskSelectionService.d.ts.map +1 -1
- package/dist/services/execution/TaskSelectionService.js +144 -28
- package/dist/services/execution/TaskStateService.d.ts +19 -6
- package/dist/services/execution/TaskStateService.d.ts.map +1 -1
- package/dist/services/execution/TaskStateService.js +128 -13
- package/dist/services/execution/WorkOnTasksService.d.ts +19 -2
- package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
- package/dist/services/execution/WorkOnTasksService.js +3913 -1225
- package/dist/services/jobs/JobInsightsService.d.ts +4 -0
- package/dist/services/jobs/JobInsightsService.d.ts.map +1 -1
- package/dist/services/jobs/JobInsightsService.js +51 -5
- package/dist/services/jobs/JobResumeService.d.ts.map +1 -1
- package/dist/services/jobs/JobResumeService.js +23 -10
- package/dist/services/jobs/JobService.d.ts +56 -4
- package/dist/services/jobs/JobService.d.ts.map +1 -1
- package/dist/services/jobs/JobService.js +232 -1
- package/dist/services/openapi/OpenApiService.d.ts +41 -0
- package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
- package/dist/services/openapi/OpenApiService.js +889 -98
- package/dist/services/planning/CreateTasksService.d.ts +15 -0
- package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
- package/dist/services/planning/CreateTasksService.js +311 -6
- package/dist/services/planning/RefineTasksService.d.ts +4 -0
- package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
- package/dist/services/planning/RefineTasksService.js +225 -24
- package/dist/services/review/CodeReviewService.d.ts +4 -0
- package/dist/services/review/CodeReviewService.d.ts.map +1 -1
- package/dist/services/review/CodeReviewService.js +778 -232
- package/dist/services/review/ReviewNormalizer.d.ts +9 -0
- package/dist/services/review/ReviewNormalizer.d.ts.map +1 -0
- package/dist/services/review/ReviewNormalizer.js +147 -0
- package/dist/services/shared/AuthErrors.d.ts +3 -0
- package/dist/services/shared/AuthErrors.d.ts.map +1 -0
- package/dist/services/shared/AuthErrors.js +17 -0
- package/dist/services/shared/DocdexGuidance.d.ts +7 -0
- package/dist/services/shared/DocdexGuidance.d.ts.map +1 -0
- package/dist/services/shared/DocdexGuidance.js +12 -0
- package/dist/services/shared/ProjectGuidance.d.ts +12 -1
- package/dist/services/shared/ProjectGuidance.d.ts.map +1 -1
- package/dist/services/shared/ProjectGuidance.js +64 -7
- package/dist/services/system/ToolDenylist.d.ts +13 -0
- package/dist/services/system/ToolDenylist.d.ts.map +1 -0
- package/dist/services/system/ToolDenylist.js +85 -0
- package/dist/services/telemetry/TelemetryService.d.ts.map +1 -1
- package/dist/services/telemetry/TelemetryService.js +39 -7
- package/dist/workspace/WorkspaceManager.d.ts +22 -0
- package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
- package/dist/workspace/WorkspaceManager.js +203 -32
- 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;
|
|
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.
|
|
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:
|
|
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
|
-
|
|
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;
|
|
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
|
-
|
|
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 (
|
|
228
|
+
if (mobileHints.some((hint) => normalized.includes(hint)))
|
|
128
229
|
return true;
|
|
129
|
-
if (
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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.
|
|
257
|
+
return path.join(this.mcodaDir, 'qa-profiles.json');
|
|
142
258
|
}
|
|
143
259
|
get workspaceConfigPath() {
|
|
144
|
-
return path.join(this.
|
|
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
|
-
|
|
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'
|
|
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":"
|
|
1
|
+
{"version":3,"file":"QaTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaTasksService.ts"],"names":[],"mappings":"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"}
|