@supatest/cli 0.0.27 → 0.0.29
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 +35 -9
- package/dist/index.js +306 -10
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -15,9 +15,11 @@ Supatest AI is an AI-powered CLI that helps you write and maintain E2E tests. Us
|
|
|
15
15
|
## Requirements
|
|
16
16
|
|
|
17
17
|
- **Node.js 18+** - [Download Node.js](https://nodejs.org/)
|
|
18
|
-
- **Supatest
|
|
18
|
+
- **Supatest Account** - [Sign up at supatest.ai](https://supatest.ai)
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Getting Started
|
|
21
|
+
|
|
22
|
+
### 1. Install
|
|
21
23
|
|
|
22
24
|
```bash
|
|
23
25
|
npm install -g @supatest/cli
|
|
@@ -29,19 +31,43 @@ Or use npx without installing:
|
|
|
29
31
|
npx @supatest/cli
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
### Interactive Mode
|
|
34
|
+
### 2. Login
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Start the CLI and authenticate:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
supatest
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
```
|
|
43
|
+
> /login
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This opens your browser to authenticate with your Supatest account.
|
|
47
|
+
|
|
48
|
+
### 3. Setup
|
|
49
|
+
|
|
50
|
+
Check that your environment has the required tools:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
> /setup
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This verifies prerequisites like browsers and test frameworks are properly configured.
|
|
57
|
+
|
|
58
|
+
### 4. Discover
|
|
59
|
+
|
|
60
|
+
Scan your project to detect existing test files and configuration:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
> /discover
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This helps Supatest understand your test structure so it can work with your existing setup.
|
|
67
|
+
|
|
68
|
+
### 5. Start Testing
|
|
43
69
|
|
|
44
|
-
|
|
70
|
+
Now describe what you want to test:
|
|
45
71
|
|
|
46
72
|
```
|
|
47
73
|
> Write a test for the login flow
|
|
@@ -113,7 +139,7 @@ test:
|
|
|
113
139
|
## Support
|
|
114
140
|
|
|
115
141
|
- [Documentation](https://supatest.ai/docs)
|
|
116
|
-
- [GitHub Issues](https://github.com/
|
|
142
|
+
- [GitHub Issues](https://github.com/supatest-ai/supatest/issues)
|
|
117
143
|
|
|
118
144
|
## License
|
|
119
145
|
|
package/dist/index.js
CHANGED
|
@@ -19,15 +19,15 @@ You are Supatest AI, an E2E test builder that iteratively creates, runs, and fix
|
|
|
19
19
|
</role>
|
|
20
20
|
|
|
21
21
|
<context>
|
|
22
|
-
First, check if SUPATEST.md contains test framework information.
|
|
22
|
+
First, check if .supatest/SUPATEST.md contains test framework information.
|
|
23
23
|
|
|
24
24
|
If yes: Read it and use the documented framework, patterns, and conventions.
|
|
25
25
|
|
|
26
|
-
If no: Run discovery once, then write findings to SUPATEST.md:
|
|
26
|
+
If no: Run discovery once, then write findings to .supatest/SUPATEST.md:
|
|
27
27
|
- Detect framework from package.json dependencies
|
|
28
28
|
- Find test command from package.json scripts
|
|
29
29
|
- Read 2-3 existing tests to learn patterns (structure, page objects, selectors, test data setup)
|
|
30
|
-
- Write a "Test Framework" section to SUPATEST.md with your findings
|
|
30
|
+
- Write a "Test Framework" section to .supatest/SUPATEST.md with your findings
|
|
31
31
|
|
|
32
32
|
This ensures discovery happens once and persists across sessions.
|
|
33
33
|
</context>
|
|
@@ -82,6 +82,66 @@ A test is complete when it passes 2+ times consistently with resilient selectors
|
|
|
82
82
|
}
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
// src/prompts/discover.ts
|
|
86
|
+
var discoverPrompt;
|
|
87
|
+
var init_discover = __esm({
|
|
88
|
+
"src/prompts/discover.ts"() {
|
|
89
|
+
"use strict";
|
|
90
|
+
discoverPrompt = `Discover and document the test framework setup for this project.
|
|
91
|
+
|
|
92
|
+
**Your task:**
|
|
93
|
+
1. Read package.json to identify the test framework (Playwright, WebDriverIO, Cypress, Cucumber, etc.)
|
|
94
|
+
2. Find the test command in package.json scripts
|
|
95
|
+
3. Locate existing tests and read 3-5 files to understand:
|
|
96
|
+
- Test file structure and naming conventions
|
|
97
|
+
- Page objects, fixtures, or helper utilities
|
|
98
|
+
- Selector strategies used (data-testid, roles, CSS, XPath)
|
|
99
|
+
- Test data setup patterns (API calls vs UI setup)
|
|
100
|
+
- Assertion patterns and custom matchers
|
|
101
|
+
- Wait strategies and timing patterns
|
|
102
|
+
4. Identify best practices and patterns used in the codebase:
|
|
103
|
+
- How are tests organized (by feature, by page, by user flow)?
|
|
104
|
+
- Are there shared utilities or custom commands?
|
|
105
|
+
- How is authentication handled in tests?
|
|
106
|
+
- Are there environment-specific configurations?
|
|
107
|
+
5. Write your findings to .supatest/SUPATEST.md in a "Test Framework" section
|
|
108
|
+
|
|
109
|
+
**Example SUPATEST.md output:**
|
|
110
|
+
|
|
111
|
+
## Test Framework
|
|
112
|
+
|
|
113
|
+
- **Framework:** WebDriverIO + Cucumber
|
|
114
|
+
- **Config:** wdio.conf.js
|
|
115
|
+
- **Test command:** \`yarn start -- --provider browser --tags @tag_name\`
|
|
116
|
+
|
|
117
|
+
### Project Structure
|
|
118
|
+
- Features: src/features/
|
|
119
|
+
- Step definitions: src/step_definitions/ui/
|
|
120
|
+
- Page objects: src/pages/common/
|
|
121
|
+
- API utilities: src/utils/endpoints/
|
|
122
|
+
|
|
123
|
+
### Conventions
|
|
124
|
+
- Selectors: data-testid preferred, fallback to aria selectors
|
|
125
|
+
- Test data: Created via API endpoints before tests run
|
|
126
|
+
- Naming: snake_case for feature files, camelCase for step definitions
|
|
127
|
+
- Tags: @smoke for critical paths, @regression for full suite
|
|
128
|
+
|
|
129
|
+
### Patterns
|
|
130
|
+
- Page Object Model with lazy element initialization
|
|
131
|
+
- API helpers for test data setup/teardown
|
|
132
|
+
- Custom wait utilities in src/utils/waits.js
|
|
133
|
+
- Shared authentication flow via login.task.js
|
|
134
|
+
|
|
135
|
+
### Best Practices
|
|
136
|
+
- Each test creates isolated test data
|
|
137
|
+
- Cleanup in afterEach hooks
|
|
138
|
+
- No hard-coded waits, use explicit element conditions
|
|
139
|
+
- Screenshots on failure via reporter config
|
|
140
|
+
|
|
141
|
+
If .supatest/SUPATEST.md already has a "Test Framework" section, report what's there and ask if the user wants to refresh it.`;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
85
145
|
// src/prompts/fixer.ts
|
|
86
146
|
var fixerPrompt;
|
|
87
147
|
var init_fixer = __esm({
|
|
@@ -228,6 +288,7 @@ var init_prompts = __esm({
|
|
|
228
288
|
"src/prompts/index.ts"() {
|
|
229
289
|
"use strict";
|
|
230
290
|
init_builder();
|
|
291
|
+
init_discover();
|
|
231
292
|
init_fixer();
|
|
232
293
|
init_planner();
|
|
233
294
|
}
|
|
@@ -477,7 +538,7 @@ function getToolDisplayName(toolName) {
|
|
|
477
538
|
};
|
|
478
539
|
return displayNameMap[toolName] || toolName;
|
|
479
540
|
}
|
|
480
|
-
var AVAILABLE_MODELS, DEFAULT_MODEL_ID, DATE_SUFFIX_REGEX, CONTEXT_WINDOWS, util, objectUtil, ZodParsedType, getParsedType, ZodIssueCode, ZodError, errorMap, overrideErrorMap, makeIssue, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync, errorUtil, ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, ZodBranded, ZodPipeline, ZodReadonly, ZodFirstPartyTypeKind, stringType, numberType, booleanType, dateType, unknownType, arrayType, objectType, unionType, discriminatedUnionType, recordType, functionType, lazyType, literalType, enumType, promiseType, coerce, MAX_API_KEY_NAME_LENGTH, apiKeySchema, apiKeyUsageSchema, createApiKeyRequestSchema, apiKeyResponseSchema, apiKeyUsageSummarySchema, genericErrorSchema, validationErrorSchema, feedbackCategorySchema, FEEDBACK_CATEGORIES, createFeedbackSchema, feedbackResponseSchema, listFeedbackQuerySchema, feedbackListResponseSchema, healthMetricSchema, healthMetricDailyItemSchema, healthMetricsWithDailySchema, healthAnalyticsPeriodSchema, healthAnalyticsDailyItemSchema, healthAnalyticsResponseSchema, MAX_TIMEZONE_CHAR_LENGTH, organizationSchema, organizationSettingsSchema, textBlockSchema, toolUseBlockSchema, toolResultBlockSchema, thinkingBlockSchema, imageBlockSchema, contentBlockSchema, sessionSchema, createSessionRequestSchema, updateSessionRequestSchema, messageSchema, createMessageRequestSchema, cliEventSchema, createCLISessionRequestSchema, queryResultSchema, queryTurnSchema, queryContentSchema, queryUsageSchema, querySchema, runStatusSchema, testResultStatusSchema, testOutcomeSchema, attachmentKindSchema, stepCategorySchema, runSummarySchema, ciMetadataSchema, gitMetadataSchema, playwrightConfigSchema, errorInfoSchema, locationSchema, sourceSnippetSchema, runSchema, annotationSchema, testSchema, testResultSchema, baseStepSchema, stepSchema, attachmentSchema, listRunsQuerySchema, listTestsQuerySchema, runsListResponseSchema, runDetailResponseSchema, testsListResponseSchema, testDetailResponseSchema, testHistoryItemSchema, testHistoryResponseSchema, topOffenderSchema, topOffendersResponseSchema, trendPointSchema, trendsResponseSchema, errorCategorySchema, failureClusterSchema, newFailureSchema, runInsightsResponseSchema, FailureCategoryEnum, SelectorTypeEnum, FailureCategoryStatsSchema, FailureCategoriesResponseSchema, FailingSelectorStatsSchema, FailingSelectorsResponseSchema, newFailureItemSchema, newFailuresResponseSchema, flakyTestItemSchema, flakyTestsResponseSchema, slowestTestItemSchema, slowestTestsResponseSchema, runSummaryEmailFailureSchema, runSummaryEmailReportSchema, sendRunReportRequestSchema;
|
|
541
|
+
var AVAILABLE_MODELS, DEFAULT_MODEL_ID, DATE_SUFFIX_REGEX, CONTEXT_WINDOWS, util, objectUtil, ZodParsedType, getParsedType, ZodIssueCode, ZodError, errorMap, overrideErrorMap, makeIssue, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync, errorUtil, ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, ZodBranded, ZodPipeline, ZodReadonly, ZodFirstPartyTypeKind, stringType, numberType, booleanType, dateType, unknownType, arrayType, objectType, unionType, discriminatedUnionType, recordType, functionType, lazyType, literalType, enumType, promiseType, coerce, MAX_API_KEY_NAME_LENGTH, apiKeySchema, apiKeyUsageSchema, createApiKeyRequestSchema, apiKeyResponseSchema, apiKeyUsageSummarySchema, genericErrorSchema, validationErrorSchema, feedbackCategorySchema, FEEDBACK_CATEGORIES, createFeedbackSchema, feedbackResponseSchema, listFeedbackQuerySchema, feedbackListResponseSchema, healthMetricSchema, healthMetricDailyItemSchema, healthMetricsWithDailySchema, healthAnalyticsPeriodSchema, healthAnalyticsDailyItemSchema, healthAnalyticsResponseSchema, MAX_TIMEZONE_CHAR_LENGTH, organizationSchema, organizationSettingsSchema, textBlockSchema, toolUseBlockSchema, toolResultBlockSchema, thinkingBlockSchema, imageBlockSchema, contentBlockSchema, sessionSchema, createSessionRequestSchema, updateSessionRequestSchema, messageSchema, createMessageRequestSchema, cliEventSchema, createCLISessionRequestSchema, queryResultSchema, queryTurnSchema, queryContentSchema, queryUsageSchema, querySchema, runStatusSchema, testResultStatusSchema, testOutcomeSchema, attachmentKindSchema, stepCategorySchema, runSummarySchema, ciMetadataSchema, gitMetadataSchema, playwrightConfigSchema, errorInfoSchema, locationSchema, sourceSnippetSchema, runSchema, annotationSchema, testSchema, testResultSchema, baseStepSchema, stepSchema, attachmentSchema, listRunsQuerySchema, listTestsQuerySchema, runsListResponseSchema, runDetailResponseSchema, testsListResponseSchema, testDetailResponseSchema, testHistoryItemSchema, testHistoryResponseSchema, topOffenderSchema, topOffendersResponseSchema, trendPointSchema, trendsResponseSchema, errorCategorySchema, failureClusterSchema, newFailureSchema, runInsightsResponseSchema, FailureCategoryEnum, SelectorTypeEnum, FailureCategoryStatsSchema, FailureCategoriesResponseSchema, FailingSelectorStatsSchema, FailingSelectorsResponseSchema, newFailureItemSchema, newFailuresResponseSchema, flakyTestItemSchema, flakyTestsResponseSchema, slowestTestItemSchema, slowestTestsResponseSchema, runSummaryEmailFailureSchema, runSummaryEmailReportSchema, sendRunReportRequestSchema, metricWithTrendSchema, weekOverWeekMetricsSchema, ciComputeTimeSchema, investigationCandidateSchema, failureCategoryBreakdownSchema, stabilityTrendSchema, folderStabilitySchema, managerReportSchema, managerReportQuerySchema, sendManagerReportRequestSchema, reportAttachmentLinkSchema, developerReportRegressionSchema, developerReportFlakyTestSchema, developerReportSlowTestSchema, developerRunSummaryReportSchema, executiveReportStatusSchema, executiveMetricSchema, executiveKeyMetricsSchema, executiveTrendPointSchema, executiveTrendsSchema, executiveFlakyOffenderSchema, executiveSlowestOffenderSchema, executiveTopOffendersSchema, executiveReportSchema, executiveReportQuerySchema, sendExecutiveReportRequestSchema;
|
|
481
542
|
var init_shared_es = __esm({
|
|
482
543
|
"../shared/dist/shared.es.mjs"() {
|
|
483
544
|
"use strict";
|
|
@@ -4957,24 +5018,248 @@ var init_shared_es = __esm({
|
|
|
4957
5018
|
startedAt: stringType(),
|
|
4958
5019
|
endedAt: stringType().optional(),
|
|
4959
5020
|
durationMs: numberType(),
|
|
4960
|
-
// Git info
|
|
4961
5021
|
branch: stringType().optional(),
|
|
4962
5022
|
commit: stringType().optional(),
|
|
4963
5023
|
commitMessage: stringType().optional(),
|
|
4964
|
-
// Summary stats
|
|
4965
5024
|
totalTests: numberType(),
|
|
4966
5025
|
passedTests: numberType(),
|
|
4967
5026
|
failedTests: numberType(),
|
|
4968
5027
|
flakyTests: numberType(),
|
|
4969
5028
|
skippedTests: numberType(),
|
|
4970
5029
|
passRate: numberType(),
|
|
4971
|
-
// Top failures
|
|
4972
5030
|
topFailures: arrayType(runSummaryEmailFailureSchema)
|
|
4973
5031
|
});
|
|
4974
5032
|
sendRunReportRequestSchema = objectType({
|
|
4975
5033
|
runId: stringType(),
|
|
4976
5034
|
emails: arrayType(stringType().email())
|
|
4977
5035
|
});
|
|
5036
|
+
metricWithTrendSchema = objectType({
|
|
5037
|
+
current: numberType(),
|
|
5038
|
+
previous: numberType(),
|
|
5039
|
+
change: numberType(),
|
|
5040
|
+
percentChange: numberType().nullable()
|
|
5041
|
+
});
|
|
5042
|
+
weekOverWeekMetricsSchema = objectType({
|
|
5043
|
+
passRate: metricWithTrendSchema,
|
|
5044
|
+
flakyTestCount: metricWithTrendSchema,
|
|
5045
|
+
newFailures: metricWithTrendSchema,
|
|
5046
|
+
totalRuns: metricWithTrendSchema
|
|
5047
|
+
});
|
|
5048
|
+
ciComputeTimeSchema = objectType({
|
|
5049
|
+
failedRunsMs: numberType(),
|
|
5050
|
+
retriedRunsMs: numberType(),
|
|
5051
|
+
totalWastedMs: numberType(),
|
|
5052
|
+
failedRunsHours: numberType(),
|
|
5053
|
+
retriedRunsHours: numberType(),
|
|
5054
|
+
totalWastedHours: numberType()
|
|
5055
|
+
});
|
|
5056
|
+
investigationCandidateSchema = objectType({
|
|
5057
|
+
testId: stringType(),
|
|
5058
|
+
testRunId: stringType(),
|
|
5059
|
+
runId: stringType(),
|
|
5060
|
+
file: stringType(),
|
|
5061
|
+
title: stringType(),
|
|
5062
|
+
flakeCount: numberType(),
|
|
5063
|
+
passRate: numberType(),
|
|
5064
|
+
avgDurationMs: numberType(),
|
|
5065
|
+
ciTimeImpactMs: numberType(),
|
|
5066
|
+
ciTimeImpactHours: numberType(),
|
|
5067
|
+
category: FailureCategoryEnum.nullable(),
|
|
5068
|
+
firstFlakyAt: stringType().nullable()
|
|
5069
|
+
});
|
|
5070
|
+
failureCategoryBreakdownSchema = objectType({
|
|
5071
|
+
category: FailureCategoryEnum,
|
|
5072
|
+
count: numberType(),
|
|
5073
|
+
percentage: numberType()
|
|
5074
|
+
});
|
|
5075
|
+
stabilityTrendSchema = enumType(["improving", "degrading", "stable"]);
|
|
5076
|
+
folderStabilitySchema = objectType({
|
|
5077
|
+
folder: stringType(),
|
|
5078
|
+
passRate: numberType(),
|
|
5079
|
+
previousPassRate: numberType(),
|
|
5080
|
+
trend: stabilityTrendSchema,
|
|
5081
|
+
testCount: numberType(),
|
|
5082
|
+
failureCount: numberType()
|
|
5083
|
+
});
|
|
5084
|
+
managerReportSchema = objectType({
|
|
5085
|
+
period: objectType({
|
|
5086
|
+
start: stringType(),
|
|
5087
|
+
end: stringType(),
|
|
5088
|
+
days: numberType()
|
|
5089
|
+
}),
|
|
5090
|
+
weekOverWeek: weekOverWeekMetricsSchema,
|
|
5091
|
+
ciComputeTime: ciComputeTimeSchema,
|
|
5092
|
+
investigationCandidates: arrayType(investigationCandidateSchema),
|
|
5093
|
+
failureCategories: arrayType(failureCategoryBreakdownSchema),
|
|
5094
|
+
folderStability: arrayType(folderStabilitySchema)
|
|
5095
|
+
});
|
|
5096
|
+
managerReportQuerySchema = objectType({
|
|
5097
|
+
startDate: stringType().regex(
|
|
5098
|
+
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
|
|
5099
|
+
"startDate must be in format YYYY-MM-DD or ISO datetime"
|
|
5100
|
+
),
|
|
5101
|
+
endDate: stringType().regex(
|
|
5102
|
+
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
|
|
5103
|
+
"endDate must be in format YYYY-MM-DD or ISO datetime"
|
|
5104
|
+
)
|
|
5105
|
+
});
|
|
5106
|
+
sendManagerReportRequestSchema = objectType({
|
|
5107
|
+
startDate: stringType(),
|
|
5108
|
+
endDate: stringType(),
|
|
5109
|
+
emails: arrayType(stringType().email())
|
|
5110
|
+
});
|
|
5111
|
+
reportAttachmentLinkSchema = objectType({
|
|
5112
|
+
name: stringType(),
|
|
5113
|
+
kind: attachmentKindSchema,
|
|
5114
|
+
url: stringType().optional()
|
|
5115
|
+
});
|
|
5116
|
+
developerReportRegressionSchema = objectType({
|
|
5117
|
+
testRunId: stringType(),
|
|
5118
|
+
testId: stringType(),
|
|
5119
|
+
title: stringType(),
|
|
5120
|
+
file: stringType(),
|
|
5121
|
+
errorMessage: stringType().nullable(),
|
|
5122
|
+
errorStack: stringType().nullable(),
|
|
5123
|
+
aiSummary: stringType().nullable(),
|
|
5124
|
+
attachments: arrayType(reportAttachmentLinkSchema),
|
|
5125
|
+
lastStableRun: objectType({
|
|
5126
|
+
runId: stringType(),
|
|
5127
|
+
date: stringType(),
|
|
5128
|
+
branch: stringType().optional()
|
|
5129
|
+
}).nullable()
|
|
5130
|
+
});
|
|
5131
|
+
developerReportFlakyTestSchema = objectType({
|
|
5132
|
+
testRunId: stringType(),
|
|
5133
|
+
testId: stringType(),
|
|
5134
|
+
title: stringType(),
|
|
5135
|
+
file: stringType(),
|
|
5136
|
+
passRate: numberType(),
|
|
5137
|
+
category: errorCategorySchema.nullable(),
|
|
5138
|
+
lastPassedRun: objectType({
|
|
5139
|
+
runId: stringType(),
|
|
5140
|
+
date: stringType()
|
|
5141
|
+
}).nullable()
|
|
5142
|
+
});
|
|
5143
|
+
developerReportSlowTestSchema = objectType({
|
|
5144
|
+
testRunId: stringType(),
|
|
5145
|
+
testId: stringType(),
|
|
5146
|
+
title: stringType(),
|
|
5147
|
+
file: stringType(),
|
|
5148
|
+
durationMs: numberType(),
|
|
5149
|
+
historicalAvgMs: numberType(),
|
|
5150
|
+
slowdownFactor: numberType()
|
|
5151
|
+
// how many times slower than average
|
|
5152
|
+
});
|
|
5153
|
+
developerRunSummaryReportSchema = objectType({
|
|
5154
|
+
runId: stringType(),
|
|
5155
|
+
readableId: stringType().optional(),
|
|
5156
|
+
runDetailsUrl: stringType(),
|
|
5157
|
+
startedAt: stringType(),
|
|
5158
|
+
endedAt: stringType().optional(),
|
|
5159
|
+
durationMs: numberType(),
|
|
5160
|
+
branch: stringType().optional(),
|
|
5161
|
+
commit: stringType().optional(),
|
|
5162
|
+
commitMessage: stringType().optional(),
|
|
5163
|
+
// Summary counts
|
|
5164
|
+
totalTests: numberType(),
|
|
5165
|
+
passedTests: numberType(),
|
|
5166
|
+
failedTests: numberType(),
|
|
5167
|
+
flakyTests: numberType(),
|
|
5168
|
+
skippedTests: numberType(),
|
|
5169
|
+
passRate: numberType(),
|
|
5170
|
+
// Sections
|
|
5171
|
+
newRegressions: arrayType(developerReportRegressionSchema),
|
|
5172
|
+
knownFlaky: arrayType(developerReportFlakyTestSchema),
|
|
5173
|
+
slowTests: arrayType(developerReportSlowTestSchema)
|
|
5174
|
+
});
|
|
5175
|
+
executiveReportStatusSchema = enumType([
|
|
5176
|
+
"healthy",
|
|
5177
|
+
"needs_attention",
|
|
5178
|
+
"critical"
|
|
5179
|
+
]);
|
|
5180
|
+
executiveMetricSchema = objectType({
|
|
5181
|
+
/** Current month's value */
|
|
5182
|
+
value: numberType(),
|
|
5183
|
+
/** Previous month's value */
|
|
5184
|
+
previousValue: numberType(),
|
|
5185
|
+
/** Percentage change from previous month (null if previous was 0) */
|
|
5186
|
+
change: numberType().nullable()
|
|
5187
|
+
});
|
|
5188
|
+
executiveKeyMetricsSchema = objectType({
|
|
5189
|
+
/** CI First-Try Pass Rate: COUNT(runs WHERE failed=0 AND flaky=0) / COUNT(runs) */
|
|
5190
|
+
ciFirstTryPassRate: executiveMetricSchema,
|
|
5191
|
+
/** Total Test Pass Rate from health analytics */
|
|
5192
|
+
testPassRate: executiveMetricSchema,
|
|
5193
|
+
/** Count of distinct tests with flaky outcomes */
|
|
5194
|
+
flakyTestCount: executiveMetricSchema,
|
|
5195
|
+
/** CI compute time lost on failed/retried runs in hours */
|
|
5196
|
+
ciComputeLostHours: executiveMetricSchema
|
|
5197
|
+
});
|
|
5198
|
+
executiveTrendPointSchema = objectType({
|
|
5199
|
+
date: stringType(),
|
|
5200
|
+
value: numberType()
|
|
5201
|
+
});
|
|
5202
|
+
executiveTrendsSchema = objectType({
|
|
5203
|
+
/** Daily pass rate values for sparkline */
|
|
5204
|
+
dailyPassRate: arrayType(executiveTrendPointSchema),
|
|
5205
|
+
/** Daily flaky count values for sparkline */
|
|
5206
|
+
dailyFlakyCount: arrayType(executiveTrendPointSchema)
|
|
5207
|
+
});
|
|
5208
|
+
executiveFlakyOffenderSchema = objectType({
|
|
5209
|
+
testId: stringType(),
|
|
5210
|
+
title: stringType(),
|
|
5211
|
+
file: stringType(),
|
|
5212
|
+
/** Number of flaky occurrences */
|
|
5213
|
+
flakyCount: numberType(),
|
|
5214
|
+
/** CI time impact in hours */
|
|
5215
|
+
ciTimeImpactHours: numberType()
|
|
5216
|
+
});
|
|
5217
|
+
executiveSlowestOffenderSchema = objectType({
|
|
5218
|
+
testId: stringType(),
|
|
5219
|
+
title: stringType(),
|
|
5220
|
+
file: stringType(),
|
|
5221
|
+
/** Average duration in milliseconds */
|
|
5222
|
+
avgDurationMs: numberType(),
|
|
5223
|
+
/** Trend percentage change from previous period (null if no previous data) */
|
|
5224
|
+
trend: numberType().nullable()
|
|
5225
|
+
});
|
|
5226
|
+
executiveTopOffendersSchema = objectType({
|
|
5227
|
+
/** Top 3 most flaky tests with CI time impact */
|
|
5228
|
+
mostFlaky: arrayType(executiveFlakyOffenderSchema),
|
|
5229
|
+
/** Top 3 slowest tests with trend */
|
|
5230
|
+
slowest: arrayType(executiveSlowestOffenderSchema)
|
|
5231
|
+
});
|
|
5232
|
+
executiveReportSchema = objectType({
|
|
5233
|
+
/** Month in format YYYY-MM */
|
|
5234
|
+
month: stringType(),
|
|
5235
|
+
/** When the report was generated */
|
|
5236
|
+
generatedAt: stringType(),
|
|
5237
|
+
/** URL to view full report in dashboard */
|
|
5238
|
+
reportUrl: stringType(),
|
|
5239
|
+
/** Overall status: healthy, needs_attention, or critical */
|
|
5240
|
+
status: executiveReportStatusSchema,
|
|
5241
|
+
/** 4 key metrics with month-over-month comparison */
|
|
5242
|
+
keyMetrics: executiveKeyMetricsSchema,
|
|
5243
|
+
/** 30-day trend data for sparklines */
|
|
5244
|
+
trends: executiveTrendsSchema,
|
|
5245
|
+
/** Top offenders (most flaky and slowest tests) */
|
|
5246
|
+
topOffenders: executiveTopOffendersSchema,
|
|
5247
|
+
/** Auto-generated signal messages based on thresholds */
|
|
5248
|
+
signals: arrayType(stringType())
|
|
5249
|
+
});
|
|
5250
|
+
executiveReportQuerySchema = objectType({
|
|
5251
|
+
month: stringType().regex(
|
|
5252
|
+
/^\d{4}-\d{2}$/,
|
|
5253
|
+
"month must be in format YYYY-MM"
|
|
5254
|
+
)
|
|
5255
|
+
});
|
|
5256
|
+
sendExecutiveReportRequestSchema = objectType({
|
|
5257
|
+
month: stringType().regex(
|
|
5258
|
+
/^\d{4}-\d{2}$/,
|
|
5259
|
+
"month must be in format YYYY-MM"
|
|
5260
|
+
),
|
|
5261
|
+
emails: arrayType(stringType().email())
|
|
5262
|
+
});
|
|
4978
5263
|
}
|
|
4979
5264
|
});
|
|
4980
5265
|
|
|
@@ -5233,7 +5518,7 @@ var CLI_VERSION;
|
|
|
5233
5518
|
var init_version = __esm({
|
|
5234
5519
|
"src/version.ts"() {
|
|
5235
5520
|
"use strict";
|
|
5236
|
-
CLI_VERSION = "0.0.
|
|
5521
|
+
CLI_VERSION = "0.0.29";
|
|
5237
5522
|
}
|
|
5238
5523
|
});
|
|
5239
5524
|
|
|
@@ -6199,6 +6484,9 @@ var init_agent = __esm({
|
|
|
6199
6484
|
async run(config2) {
|
|
6200
6485
|
this.abortController = new AbortController();
|
|
6201
6486
|
this.presenter.onStart(config2);
|
|
6487
|
+
if (config2.providerSessionId) {
|
|
6488
|
+
this.presenter.onLog(`Resuming with providerSessionId: ${config2.providerSessionId}`);
|
|
6489
|
+
}
|
|
6202
6490
|
const claudeCodePath = await this.resolveClaudeCodePath();
|
|
6203
6491
|
let prompt = config2.task;
|
|
6204
6492
|
if (config2.logs) {
|
|
@@ -10028,7 +10316,7 @@ var init_HelpMenu = __esm({
|
|
|
10028
10316
|
/* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.accent }, "\u{1F4D6} Supatest AI CLI - Help"),
|
|
10029
10317
|
/* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }),
|
|
10030
10318
|
/* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "Slash Commands:"),
|
|
10031
|
-
/* @__PURE__ */ React22.createElement(Box19, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/help"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " or "), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/?"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Toggle this help menu")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/resume"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Resume a previous session")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/clear"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Clear message history")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/model"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Cycle through available models")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/setup"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Initial setup for Supatest CLI")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/feedback"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Report an issue or request a feature")), isAuthenticated ? /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/logout"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Log out of Supatest")) : /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/login"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Authenticate with Supatest")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/exit"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Exit the CLI"))),
|
|
10319
|
+
/* @__PURE__ */ React22.createElement(Box19, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/help"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " or "), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/?"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Toggle this help menu")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/resume"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Resume a previous session")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/clear"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Clear message history")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/model"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Cycle through available models")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/setup"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Initial setup for Supatest CLI")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/discover"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Discover test framework and write to SUPATEST.md")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/feedback"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Report an issue or request a feature")), isAuthenticated ? /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/logout"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Log out of Supatest")) : /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/login"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Authenticate with Supatest")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/exit"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Exit the CLI"))),
|
|
10032
10320
|
customCommands.length > 0 && /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }), /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "Project Commands:"), /* @__PURE__ */ React22.createElement(Box19, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, customCommands.slice(0, 5).map((cmd) => /* @__PURE__ */ React22.createElement(Text17, { key: cmd.name }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "/", cmd.name), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, cmd.description ? ` - ${cmd.description}` : ""))), customCommands.length > 5 && /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "...and ", customCommands.length - 5, " more (use Tab to autocomplete)"))),
|
|
10033
10321
|
/* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }),
|
|
10034
10322
|
/* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "Keyboard Shortcuts:"),
|
|
@@ -10227,6 +10515,7 @@ var init_InputPrompt = __esm({
|
|
|
10227
10515
|
{ name: "/fix", desc: "Fix failing tests" },
|
|
10228
10516
|
{ name: "/feedback", desc: "Report an issue" },
|
|
10229
10517
|
{ name: "/setup", desc: "Install Playwright browsers" },
|
|
10518
|
+
{ name: "/discover", desc: "Discover test framework" },
|
|
10230
10519
|
{ name: "/login", desc: "Authenticate with Supatest" },
|
|
10231
10520
|
{ name: "/logout", desc: "Log out" },
|
|
10232
10521
|
{ name: "/exit", desc: "Exit CLI" }
|
|
@@ -10681,6 +10970,7 @@ var init_App = __esm({
|
|
|
10681
10970
|
init_shared_es();
|
|
10682
10971
|
init_login();
|
|
10683
10972
|
init_setup();
|
|
10973
|
+
init_prompts();
|
|
10684
10974
|
init_command_discovery();
|
|
10685
10975
|
init_stdio();
|
|
10686
10976
|
init_token_storage();
|
|
@@ -10918,6 +11208,10 @@ var init_App = __esm({
|
|
|
10918
11208
|
}
|
|
10919
11209
|
return;
|
|
10920
11210
|
}
|
|
11211
|
+
if (command === "/discover") {
|
|
11212
|
+
onSubmitTask?.(discoverPrompt);
|
|
11213
|
+
return;
|
|
11214
|
+
}
|
|
10921
11215
|
const projectDir = config2.cwd || process.cwd();
|
|
10922
11216
|
const spaceIndex = trimmedTask.indexOf(" ");
|
|
10923
11217
|
const commandName = spaceIndex > 0 ? trimmedTask.slice(1, spaceIndex) : trimmedTask.slice(1);
|
|
@@ -11676,7 +11970,9 @@ var init_interactive = __esm({
|
|
|
11676
11970
|
const uiMessages = convertQueriesToUIMessages(queries);
|
|
11677
11971
|
setSessionId(session.id);
|
|
11678
11972
|
setContextSessionId(session.id);
|
|
11679
|
-
|
|
11973
|
+
const resumeProviderSessionId = session.providerSessionId || void 0;
|
|
11974
|
+
logger.debug(`Resume session: ${session.id}, providerSessionId: ${resumeProviderSessionId || "NOT SET"}`);
|
|
11975
|
+
setProviderSessionId(resumeProviderSessionId);
|
|
11680
11976
|
const contextData = await apiClient.getSessionContext(session.id);
|
|
11681
11977
|
if (contextData.contextTokens > 0) {
|
|
11682
11978
|
const cacheRead = contextData.cacheReadTokens || 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supatest/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.29",
|
|
4
4
|
"description": "Supatest CLI - AI-powered task automation for CI/CD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@anthropic-ai/claude-agent-sdk": "^0.1
|
|
41
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.1",
|
|
42
42
|
"@anthropic-ai/sdk": "^0.71.2",
|
|
43
43
|
"@types/inquirer": "^9.0.0",
|
|
44
44
|
"ansi-escapes": "^7.0.0",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"ink-gradient": "^3.0.0",
|
|
53
53
|
"ink-spinner": "^5.0.0",
|
|
54
54
|
"inquirer": "^10.0.0",
|
|
55
|
+
"latest-version": "^9.0.0",
|
|
55
56
|
"lowlight": "^3.3.0",
|
|
56
57
|
"marked": "^15.0.0",
|
|
57
58
|
"marked-terminal": "^7.3.0",
|
|
@@ -59,18 +60,17 @@
|
|
|
59
60
|
"patch-package": "^8.0.1",
|
|
60
61
|
"postinstall-postinstall": "^2.1.0",
|
|
61
62
|
"react": "^19.0.0",
|
|
63
|
+
"semver": "^7.6.0",
|
|
62
64
|
"string-width": "^8.1.0",
|
|
63
65
|
"strip-ansi": "^7.1.2",
|
|
64
66
|
"undici": "^7.16.0",
|
|
65
|
-
"wrap-ansi": "^9.0.2"
|
|
66
|
-
"latest-version": "^9.0.0",
|
|
67
|
-
"semver": "^7.6.0"
|
|
67
|
+
"wrap-ansi": "^9.0.2"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/node": "^20.12.12",
|
|
71
|
-
"dotenv": "^16.6.1",
|
|
72
|
-
"@types/semver": "^7.5.8",
|
|
73
71
|
"@types/react": "^19.0.0",
|
|
72
|
+
"@types/semver": "^7.5.8",
|
|
73
|
+
"dotenv": "^16.6.1",
|
|
74
74
|
"nodemon": "^3.1.11",
|
|
75
75
|
"tsup": "^8.5.1",
|
|
76
76
|
"tsx": "^4.10.0",
|