@supatest/cli 0.0.42 → 0.0.44

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 (2) hide show
  1. package/dist/index.js +380 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -32,6 +32,34 @@ If no: Run discovery once, then write findings to .supatest/SUPATEST.md:
32
32
  This ensures discovery happens once and persists across sessions.
33
33
  </context>
34
34
 
35
+ <test_tagging>
36
+ Tag tests with metadata for organization and filtering on the Supatest platform:
37
+
38
+ **Platform Tags** (indexed, fast filtering):
39
+ - @feature:name - Feature area (e.g., auth, checkout, dashboard)
40
+ - @owner:email - Test owner/maintainer
41
+ - @priority:critical|high|medium|low - Test priority
42
+ - @test_type:smoke|e2e|regression|integration|unit - Test category
43
+ - @ticket:PROJ-123 - Related ticket/issue
44
+ - @slow - Flag for long-running tests
45
+ - @flaky - Flag for known flaky tests
46
+
47
+ **Custom Tags** (flexible metadata):
48
+ - @key:value - Any custom metadata (e.g., @browser:chrome, @viewport:mobile)
49
+
50
+ **Playwright - Use native tag property (preferred):**
51
+ test("User can complete purchase", {
52
+ tag: ['@feature:checkout', '@priority:high', '@test_type:e2e', '@owner:qa@example.com']
53
+ }, async ({ page }) => {
54
+ // test code
55
+ });
56
+
57
+ **WebdriverIO/Other frameworks - Use title tags:**
58
+ it("@feature:checkout @priority:high @test_type:e2e User can complete purchase", async () => {
59
+ // test code
60
+ });
61
+ </test_tagging>
62
+
35
63
  <workflow>
36
64
  For each test:
37
65
  1. **Write** - Create test using the project's framework and patterns
@@ -163,6 +191,34 @@ You are a Test Fixer Agent that debugs failing tests and fixes issues. You work
163
191
  Continue until all tests pass.
164
192
  </workflow>
165
193
 
194
+ <test_tagging>
195
+ When creating or fixing tests, add metadata tags for organization and filtering:
196
+
197
+ **Platform Tags** (indexed, fast filtering):
198
+ - @feature:name - Feature area (e.g., auth, checkout, dashboard)
199
+ - @owner:email - Test owner/maintainer
200
+ - @priority:critical|high|medium|low - Test priority
201
+ - @test_type:smoke|e2e|regression|integration|unit - Test category
202
+ - @ticket:PROJ-123 - Related ticket/issue
203
+ - @slow - Flag for long-running tests
204
+ - @flaky - Flag for known flaky tests
205
+
206
+ **Custom Tags** (flexible metadata):
207
+ - @key:value - Any custom metadata (e.g., @browser:chrome, @viewport:mobile)
208
+
209
+ **Playwright - Use native tag property (preferred):**
210
+ test("User can complete purchase", {
211
+ tag: ['@feature:checkout', '@priority:high', '@test_type:e2e', '@owner:qa@example.com']
212
+ }, async ({ page }) => {
213
+ // test code
214
+ });
215
+
216
+ **WebdriverIO/Other frameworks - Use title tags:**
217
+ it("@feature:checkout @priority:high @test_type:e2e User can complete purchase", async () => {
218
+ // test code
219
+ });
220
+ </test_tagging>
221
+
166
222
  <root_causes>
167
223
  **Selector** - Element changed or locator is fragile \u2192 update selector, add wait, make more specific
168
224
 
@@ -190,6 +246,20 @@ Continue until all tests pass.
190
246
  - Don't skip or remove tests without understanding the failure
191
247
  </fixing_principles>
192
248
 
249
+ <browser_inspection>
250
+ If available in /mcp commands, use Playwright MCP for live debugging when the failure is unclear from all available assets:
251
+ - Test code, error logs, and stack traces
252
+ - Application code and related files in the repo
253
+ - Configuration and test setup files
254
+
255
+ Execute the test flow with MCP to observe actual behavior:
256
+ - Navigate and interact as the test does
257
+ - Verify element states, attributes, and content
258
+ - Check console errors and runtime issues
259
+ - Test selectors and locators against live DOM
260
+ - Inspect page state at each step
261
+ </browser_inspection>
262
+
193
263
  <flakiness>
194
264
  After fixing, verify stability by running 2-3 times. Watch for:
195
265
  - Inconsistent pass/fail results
@@ -760,10 +830,39 @@ Never ask about routing, data scope, UI interactions, empty states, or error han
760
830
  <output_format>
761
831
  **Risk Assessment**: [HIGH/MEDIUM/LOW] - one line justification
762
832
  **User Journeys**: "User can [action] to [achieve goal]"
763
- **Test Cases**: Name, assertions, test data needs
833
+ **Test Cases**: Name, assertions, test data needs, suggested tags
764
834
  **Not Testing**: What you're skipping and why (shows judgment)
765
835
  </output_format>
766
836
 
837
+ <test_tagging>
838
+ Include metadata tags in test plans for organization and filtering:
839
+
840
+ **Platform Tags** (indexed, fast filtering):
841
+ - @feature:name - Feature area (e.g., auth, checkout, dashboard)
842
+ - @owner:email - Test owner/maintainer
843
+ - @priority:critical|high|medium|low - Test priority (align with risk assessment)
844
+ - @test_type:smoke|e2e|regression|integration|unit - Test category
845
+ - @ticket:PROJ-123 - Related ticket/issue
846
+ - @slow - Flag for long-running tests
847
+ - @flaky - Flag for known flaky tests
848
+
849
+ **Custom Tags** (flexible metadata):
850
+ - @key:value - Any custom metadata (e.g., @browser:chrome, @viewport:mobile)
851
+
852
+ Map risk levels to priority tags:
853
+ - HIGH risk \u2192 @priority:critical or @priority:high
854
+ - MEDIUM risk \u2192 @priority:medium
855
+ - LOW risk \u2192 @priority:low
856
+
857
+ **Playwright - Use native tag property (preferred):**
858
+ test("User can complete purchase", {
859
+ tag: ['@feature:checkout', '@priority:high', '@test_type:e2e']
860
+ }, async ({ page }) => { });
861
+
862
+ **WebdriverIO/Other frameworks - Use title tags:**
863
+ it("@feature:checkout @priority:high @test_type:e2e User can complete purchase", async () => { });
864
+ </test_tagging>
865
+
767
866
  <example>
768
867
  **Scenario**: Read-only analytics dashboard
769
868
 
@@ -1155,7 +1254,7 @@ function getToolGroupCounts(tools) {
1155
1254
  );
1156
1255
  return Object.entries(groups).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
1157
1256
  }
1158
- var AVAILABLE_MODELS, DATE_SUFFIX_REGEX, SMALL_COST_MULTIPLIER, MEDIUM_COST_MULTIPLIER, PREMIUM_COST_MULTIPLIER, SMALL_COST_LABEL, MEDIUM_COST_LABEL, PREMIUM_COST_LABEL, MODEL_TIERS, 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, fixAssignmentStatusSchema, fixAssignmentSchema, testWithAssignmentSchema, listAssignmentsQuerySchema, listTestsWithAssignmentsQuerySchema, assignmentsListResponseSchema, assigneeInfoSchema, assigneesListResponseSchema, assignTestsRequestSchema, assignTestRequestSchema, reassignTestRequestSchema, completeAssignmentsRequestSchema, completeAssignmentRequestSchema, bulkReassignRequestSchema, assignmentResponseSchema, assignTestsResponseSchema, testsWithAssignmentsResponseSchema, bulkReassignResponseSchema, userAssignmentStatsSchema, SECONDS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH, SECONDS_PER_YEAR;
1257
+ var AVAILABLE_MODELS, DATE_SUFFIX_REGEX, SMALL_COST_MULTIPLIER, MEDIUM_COST_MULTIPLIER, PREMIUM_COST_MULTIPLIER, SMALL_COST_LABEL, MEDIUM_COST_LABEL, PREMIUM_COST_LABEL, MODEL_TIERS, 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, coverageTestItemSchema, secondaryTagMetricSchema, tagCoverageSchema, coverageStatsSchema, coverageAlertSchema, coverageDashboardResponseSchema, coverageDashboardQuerySchema, 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, fixAssignmentStatusSchema, fixAssignmentSchema, testWithAssignmentSchema, listAssignmentsQuerySchema, listTestsWithAssignmentsQuerySchema, assignmentsListResponseSchema, assigneeInfoSchema, assigneesListResponseSchema, assignTestsRequestSchema, assignTestRequestSchema, reassignTestRequestSchema, completeAssignmentsRequestSchema, completeAssignmentRequestSchema, bulkReassignRequestSchema, assignmentResponseSchema, assignTestsResponseSchema, testsWithAssignmentsResponseSchema, bulkReassignResponseSchema, userAssignmentStatsSchema, testCatalogPrioritySchema, testCatalogTypeSchema, testCatalogAssignmentStatusSchema, testCatalogAssignmentSchema, testCatalogDefinitionSchema, testCatalogListItemSchema, testCatalogHistoryEntrySchema, testCatalogListQuerySchema, testCatalogListResponseSchema, testCatalogDetailResponseSchema, testCatalogFilterOptionsSchema, testCatalogAssigneeInfoSchema, testCatalogAssignRequestSchema, testCatalogUpdateAssignmentRequestSchema, testCatalogAssignmentResponseSchema, testCatalogFolderNodeSchema, testCatalogFolderTreeResponseSchema, testCatalogFolderTestsQuerySchema, SECONDS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH, SECONDS_PER_YEAR;
1159
1258
  var init_shared_es = __esm({
1160
1259
  "../shared/dist/shared.es.mjs"() {
1161
1260
  "use strict";
@@ -5423,7 +5522,18 @@ var init_shared_es = __esm({
5423
5522
  limit: coerce.number().min(1).max(100).default(50),
5424
5523
  status: testResultStatusSchema.optional(),
5425
5524
  isFlaky: coerce.boolean().optional(),
5426
- file: stringType().optional()
5525
+ file: stringType().optional(),
5526
+ groupByTestId: coerce.boolean().optional(),
5527
+ // When true, paginate by unique testId (grouped tests)
5528
+ // Tag filters
5529
+ owner: stringType().optional(),
5530
+ priority: stringType().optional(),
5531
+ // Will validate against testCatalogPrioritySchema in backend
5532
+ feature: stringType().optional(),
5533
+ testType: stringType().optional(),
5534
+ // Will validate against testCatalogTypeSchema in backend
5535
+ tags: stringType().optional()
5536
+ // Comma-separated custom tags
5427
5537
  });
5428
5538
  runsListResponseSchema = objectType({
5429
5539
  runs: arrayType(runSchema),
@@ -5435,11 +5545,93 @@ var init_shared_es = __esm({
5435
5545
  tests: arrayType(testSchema).optional(),
5436
5546
  testsTotal: numberType().optional()
5437
5547
  });
5548
+ coverageTestItemSchema = objectType({
5549
+ testId: stringType(),
5550
+ title: stringType(),
5551
+ file: stringType(),
5552
+ status: testResultStatusSchema.nullable(),
5553
+ passRate: numberType().nullable(),
5554
+ // 0-100
5555
+ lastRunAt: stringType().nullable()
5556
+ });
5557
+ secondaryTagMetricSchema = objectType({
5558
+ tag: stringType(),
5559
+ category: stringType(),
5560
+ // e.g., "type", "priority"
5561
+ testCount: numberType(),
5562
+ coverage: numberType()
5563
+ // 0-100 percentage
5564
+ });
5565
+ tagCoverageSchema = objectType({
5566
+ tag: stringType(),
5567
+ testCount: numberType(),
5568
+ passedCount: numberType(),
5569
+ failedCount: numberType(),
5570
+ coverage: numberType(),
5571
+ // 0-100 percentage
5572
+ tests: arrayType(coverageTestItemSchema),
5573
+ secondaryTags: arrayType(secondaryTagMetricSchema).optional()
5574
+ // Secondary metrics like type, priority
5575
+ });
5576
+ coverageStatsSchema = objectType({
5577
+ overallHealth: numberType(),
5578
+ // 0-100 percentage
5579
+ totalTests: numberType()
5580
+ });
5581
+ coverageAlertSchema = objectType({
5582
+ tag: stringType(),
5583
+ previousCoverage: numberType(),
5584
+ currentCoverage: numberType(),
5585
+ changePct: numberType()
5586
+ });
5587
+ coverageDashboardResponseSchema = objectType({
5588
+ stats: coverageStatsSchema,
5589
+ tagCoverages: arrayType(tagCoverageSchema),
5590
+ alerts: arrayType(coverageAlertSchema),
5591
+ period: objectType({
5592
+ start: stringType(),
5593
+ end: stringType(),
5594
+ days: numberType()
5595
+ })
5596
+ });
5597
+ coverageDashboardQuerySchema = objectType({
5598
+ // Option 1: Period-based (e.g., '7d', '14d', '30d')
5599
+ period: stringType().regex(/^\d+d$/, "Period must be in format '7d', '14d', '30d', etc.").optional(),
5600
+ // Option 2: Date range (YYYY-MM-DD format or ISO datetime strings)
5601
+ startDate: stringType().regex(
5602
+ /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
5603
+ "startDate must be in format YYYY-MM-DD or ISO datetime"
5604
+ ).optional(),
5605
+ endDate: stringType().regex(
5606
+ /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
5607
+ "endDate must be in format YYYY-MM-DD or ISO datetime"
5608
+ ).optional(),
5609
+ // Optional tag filter to drill down into specific tag
5610
+ tag: stringType().optional()
5611
+ }).refine(
5612
+ (data) => {
5613
+ const hasPeriod = !!data.period;
5614
+ const hasDateRange = !!data.startDate && !!data.endDate;
5615
+ const hasPartialDateRange = !!data.startDate && !data.endDate || !data.startDate && !!data.endDate;
5616
+ if (hasPartialDateRange) {
5617
+ return false;
5618
+ }
5619
+ if (hasPeriod && hasDateRange) {
5620
+ return false;
5621
+ }
5622
+ return true;
5623
+ },
5624
+ {
5625
+ message: "Provide either 'period' OR both 'startDate' and 'endDate', not a mix"
5626
+ }
5627
+ );
5438
5628
  testsListResponseSchema = objectType({
5439
5629
  tests: arrayType(testSchema),
5440
5630
  total: numberType(),
5441
5631
  page: numberType(),
5442
- limit: numberType()
5632
+ limit: numberType(),
5633
+ totalGroups: numberType().optional()
5634
+ // When groupByTestId=true, total unique test groups
5443
5635
  });
5444
5636
  testDetailResponseSchema = testSchema.extend({
5445
5637
  results: arrayType(
@@ -6045,6 +6237,173 @@ var init_shared_es = __esm({
6045
6237
  completed: numberType(),
6046
6238
  failed: numberType()
6047
6239
  });
6240
+ testCatalogPrioritySchema = enumType([
6241
+ "critical",
6242
+ "high",
6243
+ "medium",
6244
+ "low"
6245
+ ]);
6246
+ testCatalogTypeSchema = enumType([
6247
+ "smoke",
6248
+ "e2e",
6249
+ "regression",
6250
+ "integration",
6251
+ "unit"
6252
+ ]);
6253
+ testCatalogAssignmentStatusSchema = enumType([
6254
+ "assigned",
6255
+ "completed",
6256
+ "failed"
6257
+ ]);
6258
+ testCatalogAssignmentSchema = objectType({
6259
+ id: stringType().uuid(),
6260
+ assignedTo: stringType(),
6261
+ assignedAt: stringType(),
6262
+ status: testCatalogAssignmentStatusSchema
6263
+ });
6264
+ testCatalogDefinitionSchema = objectType({
6265
+ id: stringType().uuid(),
6266
+ readableId: stringType(),
6267
+ // TST-123
6268
+ testId: stringType(),
6269
+ // Stable ID from @id: tag or hash
6270
+ file: stringType(),
6271
+ title: stringType(),
6272
+ titlePath: arrayType(stringType()),
6273
+ projectName: stringType().nullable(),
6274
+ // Parsed metadata
6275
+ owner: stringType().nullable(),
6276
+ priority: testCatalogPrioritySchema.nullable(),
6277
+ feature: stringType().nullable(),
6278
+ ticketId: stringType().nullable(),
6279
+ testType: testCatalogTypeSchema.nullable(),
6280
+ isSlow: booleanType(),
6281
+ isFlakyTagged: booleanType(),
6282
+ // Raw data
6283
+ tags: arrayType(stringType()).nullable(),
6284
+ customMetadata: recordType(stringType()).nullable(),
6285
+ // Stats
6286
+ totalRuns: numberType(),
6287
+ passCount: numberType(),
6288
+ failCount: numberType(),
6289
+ flakyCount: numberType(),
6290
+ lastStatus: stringType().nullable(),
6291
+ lastRunAt: stringType().nullable(),
6292
+ lastRunId: stringType().nullable(),
6293
+ avgDurationMs: numberType().nullable(),
6294
+ passRate: numberType().nullable(),
6295
+ // 0-100
6296
+ // Assignment
6297
+ assignment: testCatalogAssignmentSchema.nullable(),
6298
+ // Timestamps
6299
+ createdAt: stringType(),
6300
+ updatedAt: stringType()
6301
+ });
6302
+ testCatalogListItemSchema = objectType({
6303
+ id: stringType().uuid(),
6304
+ readableId: stringType().optional(),
6305
+ testId: stringType(),
6306
+ file: stringType(),
6307
+ title: stringType(),
6308
+ projectName: stringType().nullable(),
6309
+ // Key metadata
6310
+ owner: stringType().nullable(),
6311
+ priority: testCatalogPrioritySchema.nullable(),
6312
+ feature: stringType().nullable(),
6313
+ isSlow: booleanType(),
6314
+ isFlakyTagged: booleanType(),
6315
+ // Stats
6316
+ totalRuns: numberType(),
6317
+ passRate: numberType().nullable(),
6318
+ flakyCount: numberType(),
6319
+ lastStatus: stringType().nullable(),
6320
+ lastRunAt: stringType().nullable(),
6321
+ avgDurationMs: numberType().nullable(),
6322
+ // Assignment
6323
+ assignment: testCatalogAssignmentSchema.nullable()
6324
+ });
6325
+ testCatalogHistoryEntrySchema = objectType({
6326
+ runId: stringType().uuid(),
6327
+ status: stringType(),
6328
+ durationMs: numberType(),
6329
+ date: stringType(),
6330
+ branch: stringType().optional(),
6331
+ errorSummary: stringType().optional()
6332
+ });
6333
+ testCatalogListQuerySchema = objectType({
6334
+ page: coerce.number().int().min(1).default(1),
6335
+ limit: coerce.number().int().min(1).max(100).default(20),
6336
+ status: enumType(["all", "passed", "failed", "flaky", "skipped"]).optional().default("all"),
6337
+ owner: stringType().optional(),
6338
+ assignee: stringType().optional(),
6339
+ feature: stringType().optional(),
6340
+ priority: testCatalogPrioritySchema.optional(),
6341
+ search: stringType().optional(),
6342
+ sortBy: enumType([
6343
+ "lastRunAt",
6344
+ "passRate",
6345
+ "flakyCount",
6346
+ "totalRuns",
6347
+ "title",
6348
+ "avgDurationMs"
6349
+ ]).optional().default("lastRunAt"),
6350
+ sortOrder: enumType(["asc", "desc"]).optional().default("desc")
6351
+ });
6352
+ testCatalogListResponseSchema = objectType({
6353
+ tests: arrayType(testCatalogListItemSchema),
6354
+ total: numberType(),
6355
+ page: numberType(),
6356
+ limit: numberType()
6357
+ });
6358
+ testCatalogDetailResponseSchema = objectType({
6359
+ test: testCatalogListItemSchema,
6360
+ history: arrayType(testCatalogHistoryEntrySchema)
6361
+ });
6362
+ testCatalogFilterOptionsSchema = objectType({
6363
+ owners: arrayType(stringType()),
6364
+ features: arrayType(stringType()),
6365
+ priorities: arrayType(testCatalogPrioritySchema),
6366
+ testTypes: arrayType(testCatalogTypeSchema)
6367
+ });
6368
+ testCatalogAssigneeInfoSchema = objectType({
6369
+ id: stringType(),
6370
+ name: stringType(),
6371
+ email: stringType().optional(),
6372
+ activeTests: numberType()
6373
+ });
6374
+ testCatalogAssignRequestSchema = objectType({
6375
+ assignedTo: stringType(),
6376
+ notes: stringType().optional()
6377
+ });
6378
+ testCatalogUpdateAssignmentRequestSchema = objectType({
6379
+ status: enumType(["completed", "failed"]),
6380
+ notes: stringType().optional()
6381
+ });
6382
+ testCatalogAssignmentResponseSchema = objectType({
6383
+ id: stringType().uuid(),
6384
+ testId: stringType().uuid(),
6385
+ assignedTo: stringType(),
6386
+ status: testCatalogAssignmentStatusSchema
6387
+ });
6388
+ testCatalogFolderNodeSchema = objectType({
6389
+ name: stringType(),
6390
+ path: stringType(),
6391
+ type: enumType(["folder", "file"]),
6392
+ testCount: numberType(),
6393
+ hasChildren: booleanType()
6394
+ });
6395
+ testCatalogFolderTreeResponseSchema = objectType({
6396
+ nodes: arrayType(testCatalogFolderNodeSchema)
6397
+ });
6398
+ testCatalogFolderTestsQuerySchema = objectType({
6399
+ folder: stringType(),
6400
+ status: enumType(["all", "passed", "failed", "flaky", "skipped"]).optional().default("all"),
6401
+ owner: stringType().optional(),
6402
+ assignee: stringType().optional(),
6403
+ feature: stringType().optional(),
6404
+ priority: testCatalogPrioritySchema.optional(),
6405
+ search: stringType().optional()
6406
+ });
6048
6407
  SECONDS_PER_MINUTE = 60;
6049
6408
  SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
6050
6409
  SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
@@ -6329,7 +6688,7 @@ var CLI_VERSION;
6329
6688
  var init_version = __esm({
6330
6689
  "src/version.ts"() {
6331
6690
  "use strict";
6332
- CLI_VERSION = "0.0.42";
6691
+ CLI_VERSION = "0.0.44";
6333
6692
  }
6334
6693
  });
6335
6694
 
@@ -9846,6 +10205,9 @@ async function exchangeCodeForToken(code, state) {
9846
10205
  const data = await response.json();
9847
10206
  return { token: data.token, expiresAt: data.expiresAt };
9848
10207
  }
10208
+ function escapeForCmd(value) {
10209
+ return value.replace(/[&^]/g, "^$&");
10210
+ }
9849
10211
  function openBrowser(url) {
9850
10212
  const os3 = platform();
9851
10213
  let command;
@@ -9856,14 +10218,14 @@ function openBrowser(url) {
9856
10218
  args = [url];
9857
10219
  break;
9858
10220
  case "win32":
9859
- command = "start";
9860
- args = ["", url];
10221
+ command = "cmd.exe";
10222
+ args = ["/c", "start", '""', escapeForCmd(url)];
9861
10223
  break;
9862
10224
  default:
9863
10225
  command = "xdg-open";
9864
10226
  args = [url];
9865
10227
  }
9866
- const options = { detached: true, stdio: "ignore", shell: os3 === "win32" };
10228
+ const options = { detached: true, stdio: "ignore" };
9867
10229
  spawn3(command, args, options).unref();
9868
10230
  }
9869
10231
  function startCallbackServer(port, expectedState) {
@@ -10535,6 +10897,13 @@ ${authUrl}
10535
10897
  codeChallenge: hash
10536
10898
  };
10537
10899
  }
10900
+ /**
10901
+ * Escape special characters for Windows cmd.exe
10902
+ * The ^ character is the escape character in cmd.exe
10903
+ */
10904
+ escapeForCmd(value) {
10905
+ return value.replace(/[&^]/g, "^$&");
10906
+ }
10538
10907
  /**
10539
10908
  * Open a URL in the default browser cross-platform
10540
10909
  */
@@ -10548,15 +10917,15 @@ ${authUrl}
10548
10917
  args = [url];
10549
10918
  break;
10550
10919
  case "win32":
10551
- command = "start";
10552
- args = ["", url];
10920
+ command = "cmd.exe";
10921
+ args = ["/c", "start", '""', this.escapeForCmd(url)];
10553
10922
  break;
10554
10923
  default:
10555
10924
  command = "xdg-open";
10556
10925
  args = [url];
10557
10926
  break;
10558
10927
  }
10559
- const options = { detached: true, stdio: "ignore", shell: os3 === "win32" };
10928
+ const options = { detached: true, stdio: "ignore" };
10560
10929
  spawn4(command, args, options).unref();
10561
10930
  }
10562
10931
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supatest/cli",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "description": "Supatest CLI - AI-powered task automation for CI/CD",
5
5
  "type": "module",
6
6
  "bin": {