@supatest/cli 0.0.32 → 0.0.34

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 +838 -619
  2. package/package.json +7 -6
package/dist/index.js CHANGED
@@ -336,11 +336,78 @@ function getModelById(id) {
336
336
  const baseId = normalizeModelId(id);
337
337
  return AVAILABLE_MODELS.find((m) => m.id === baseId);
338
338
  }
339
+ function getTierFromProviderModel(providerModel) {
340
+ if (providerModel === "glm-4.7" || providerModel.startsWith("glm-4.7")) {
341
+ return "premium";
342
+ }
343
+ return null;
344
+ }
345
+ function getModelCostLabel(modelId) {
346
+ if (modelId === "small") {
347
+ return SMALL_COST_LABEL;
348
+ }
349
+ if (modelId === "medium") {
350
+ return MEDIUM_COST_LABEL;
351
+ }
352
+ if (modelId === "premium") {
353
+ return PREMIUM_COST_LABEL;
354
+ }
355
+ const model = getModelById(modelId);
356
+ if (model) {
357
+ if (model.costMultiplier === SMALL_COST_MULTIPLIER) {
358
+ return SMALL_COST_LABEL;
359
+ }
360
+ if (model.costMultiplier === MEDIUM_COST_MULTIPLIER) {
361
+ return MEDIUM_COST_LABEL;
362
+ }
363
+ if (model.costMultiplier === PREMIUM_COST_MULTIPLIER) {
364
+ return PREMIUM_COST_LABEL;
365
+ }
366
+ }
367
+ return MEDIUM_COST_LABEL;
368
+ }
339
369
  function getModelDisplayName(id) {
340
- const model = getModelById(id);
341
- return model?.name ?? id;
370
+ if (MODEL_TIERS.includes(id)) {
371
+ const tierNames = {
372
+ small: "Small",
373
+ medium: "Medium",
374
+ premium: "Premium"
375
+ };
376
+ return tierNames[id] || id;
377
+ }
378
+ const anthropicModel = getModelById(id);
379
+ if (anthropicModel) {
380
+ return anthropicModel.name;
381
+ }
382
+ const tier = getTierFromProviderModel(id);
383
+ if (tier && !id.startsWith("claude-")) {
384
+ const tierNames = {
385
+ small: "Small",
386
+ medium: "Medium",
387
+ premium: "Premium"
388
+ };
389
+ return tierNames[tier];
390
+ }
391
+ return id;
392
+ }
393
+ function resolveTierToAnthropicModel(tier) {
394
+ const tierToModel = {
395
+ small: "claude-haiku-4-5",
396
+ medium: "claude-sonnet-4-5",
397
+ premium: "claude-opus-4-5"
398
+ };
399
+ return tierToModel[tier];
400
+ }
401
+ function resolveToAnthropicModel(model) {
402
+ if (MODEL_TIERS.includes(model)) {
403
+ return resolveTierToAnthropicModel(model);
404
+ }
405
+ return model;
342
406
  }
343
407
  function isValidModelId(id) {
408
+ if (MODEL_TIERS.includes(id)) {
409
+ return true;
410
+ }
344
411
  return AVAILABLE_MODELS.some((m) => id === m.id || id.startsWith(`${m.id}-`));
345
412
  }
346
413
  function getErrorMap() {
@@ -538,7 +605,31 @@ function getToolDisplayName(toolName) {
538
605
  };
539
606
  return displayNameMap[toolName] || toolName;
540
607
  }
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;
608
+ function getToolCategory(toolName) {
609
+ const name = toolName.toLowerCase();
610
+ if (name.includes("read")) return "Read";
611
+ if (name.includes("write")) return "Write";
612
+ if (name.includes("edit")) return "Edit";
613
+ if (name.includes("bash") || name.includes("command")) return "Bash";
614
+ if (name.includes("glob")) return "Glob";
615
+ if (name.includes("grep")) return "Grep";
616
+ if (name.includes("task")) return "Task";
617
+ if (name.includes("todo")) return "Todo";
618
+ return getToolDisplayName(toolName);
619
+ }
620
+ function getToolGroupCounts(tools) {
621
+ const groups = tools.reduce(
622
+ (acc, tool) => {
623
+ const toolName = tool.toolName || tool.name || "";
624
+ const category = getToolCategory(toolName);
625
+ acc[category] = (acc[category] || 0) + 1;
626
+ return acc;
627
+ },
628
+ {}
629
+ );
630
+ return Object.entries(groups).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
631
+ }
632
+ 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;
542
633
  var init_shared_es = __esm({
543
634
  "../shared/dist/shared.es.mjs"() {
544
635
  "use strict";
@@ -547,23 +638,32 @@ var init_shared_es = __esm({
547
638
  id: "claude-sonnet-4-5",
548
639
  name: "Sonnet 4.5",
549
640
  description: "Fast & capable",
550
- contextWindow: 2e5
641
+ contextWindow: 2e5,
642
+ costMultiplier: 1
551
643
  },
552
644
  {
553
645
  id: "claude-opus-4-5",
554
646
  name: "Opus 4.5",
555
647
  description: "Most capable",
556
- contextWindow: 2e5
648
+ contextWindow: 2e5,
649
+ costMultiplier: 2
557
650
  },
558
651
  {
559
652
  id: "claude-haiku-4-5",
560
653
  name: "Haiku 4.5",
561
654
  description: "Lightweight",
562
- contextWindow: 2e5
655
+ contextWindow: 2e5,
656
+ costMultiplier: 0.5
563
657
  }
564
658
  ];
565
- DEFAULT_MODEL_ID = "claude-sonnet-4-5";
566
659
  DATE_SUFFIX_REGEX = /-\d{8}$/;
660
+ SMALL_COST_MULTIPLIER = 0.5;
661
+ MEDIUM_COST_MULTIPLIER = 1;
662
+ PREMIUM_COST_MULTIPLIER = 2;
663
+ SMALL_COST_LABEL = "0.5x";
664
+ MEDIUM_COST_LABEL = "1x";
665
+ PREMIUM_COST_LABEL = "2x";
666
+ MODEL_TIERS = ["small", "medium", "premium"];
567
667
  CONTEXT_WINDOWS = Object.fromEntries(
568
668
  AVAILABLE_MODELS.map((m) => [m.id, m.contextWindow])
569
669
  );
@@ -5003,263 +5103,6 @@ var init_shared_es = __esm({
5003
5103
  days: numberType()
5004
5104
  })
5005
5105
  });
5006
- runSummaryEmailFailureSchema = objectType({
5007
- testRunId: stringType(),
5008
- testId: stringType(),
5009
- title: stringType(),
5010
- file: stringType(),
5011
- errorMessage: stringType().nullable(),
5012
- errorStack: stringType().nullable()
5013
- });
5014
- runSummaryEmailReportSchema = objectType({
5015
- runId: stringType(),
5016
- readableId: stringType().optional(),
5017
- runDetailsUrl: stringType(),
5018
- startedAt: stringType(),
5019
- endedAt: stringType().optional(),
5020
- durationMs: numberType(),
5021
- branch: stringType().optional(),
5022
- commit: stringType().optional(),
5023
- commitMessage: stringType().optional(),
5024
- totalTests: numberType(),
5025
- passedTests: numberType(),
5026
- failedTests: numberType(),
5027
- flakyTests: numberType(),
5028
- skippedTests: numberType(),
5029
- passRate: numberType(),
5030
- topFailures: arrayType(runSummaryEmailFailureSchema)
5031
- });
5032
- sendRunReportRequestSchema = objectType({
5033
- runId: stringType(),
5034
- emails: arrayType(stringType().email())
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
- });
5263
5106
  }
5264
5107
  });
5265
5108
 
@@ -5522,7 +5365,7 @@ var CLI_VERSION;
5522
5365
  var init_version = __esm({
5523
5366
  "src/version.ts"() {
5524
5367
  "use strict";
5525
- CLI_VERSION = "0.0.32";
5368
+ CLI_VERSION = "0.0.34";
5526
5369
  }
5527
5370
  });
5528
5371
 
@@ -6463,6 +6306,7 @@ var CoreAgent;
6463
6306
  var init_agent = __esm({
6464
6307
  async "src/core/agent.ts"() {
6465
6308
  "use strict";
6309
+ init_shared_es();
6466
6310
  await init_config();
6467
6311
  init_command_discovery();
6468
6312
  init_error_logger();
@@ -6531,6 +6375,8 @@ ${projectInstructions}`,
6531
6375
  "ANTHROPIC_API_KEY",
6532
6376
  "ANTHROPIC_BASE_URL",
6533
6377
  "ANTHROPIC_AUTH_TOKEN",
6378
+ "ZAI_API_KEY",
6379
+ "ZAI_BASE_URL",
6534
6380
  "CLAUDE_CODE_AUTH_TOKEN",
6535
6381
  "CLAUDE_CODE_OAUTH_TOKEN",
6536
6382
  "CLAUDE_API_KEY"
@@ -6549,15 +6395,17 @@ ${projectInstructions}`,
6549
6395
  if (config2.oauthToken) {
6550
6396
  cleanEnv.ANTHROPIC_API_KEY = "";
6551
6397
  cleanEnv.ANTHROPIC_BASE_URL = "";
6398
+ cleanEnv.ZAI_API_KEY = "";
6399
+ cleanEnv.ZAI_BASE_URL = "";
6552
6400
  this.presenter.onLog(`Auth: Using Claude Max (default Claude Code credentials)`);
6553
- logger.debug("[agent] Claude Max mode: Using default ~/.claude/ config, cleared ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL");
6401
+ logger.debug("[agent] Claude Max mode: Using default ~/.claude/ config, cleared provider credentials");
6554
6402
  } else {
6555
6403
  const internalConfigDir = join6(homedir2(), ".supatest", "claude-internal");
6556
6404
  cleanEnv.CLAUDE_CONFIG_DIR = internalConfigDir;
6557
6405
  cleanEnv.ANTHROPIC_API_KEY = config2.supatestApiKey || "";
6558
6406
  cleanEnv.ANTHROPIC_BASE_URL = process.env.ANTHROPIC_BASE_URL || "";
6559
- this.presenter.onLog(`Auth: Using Supatest API key${process.env.ANTHROPIC_BASE_URL ? ` (base: ${process.env.ANTHROPIC_BASE_URL})` : ""}`);
6560
- logger.debug("[agent] API key mode: Set ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, and CLAUDE_CONFIG_DIR");
6407
+ this.presenter.onLog(`Auth: Using Supatest API (provider determined by backend)${process.env.ANTHROPIC_BASE_URL ? ` (base: ${process.env.ANTHROPIC_BASE_URL})` : ""}`);
6408
+ logger.debug("[agent] API mode: Set ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, and CLAUDE_CONFIG_DIR");
6561
6409
  }
6562
6410
  cleanEnv.ANTHROPIC_AUTH_TOKEN = "";
6563
6411
  cleanEnv.CLAUDE_CODE_AUTH_TOKEN = "";
@@ -6567,12 +6415,14 @@ ${projectInstructions}`,
6567
6415
  CLAUDE_CONFIG_DIR: cleanEnv.CLAUDE_CONFIG_DIR || "(using default ~/.claude/)"
6568
6416
  });
6569
6417
  cleanEnv.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "1";
6418
+ const selectedModel = config2.selectedModel || "premium";
6419
+ const defaultModel = resolveToAnthropicModel(selectedModel);
6570
6420
  const queryOptions = {
6571
6421
  // AbortController for cancellation support
6572
6422
  abortController: this.abortController,
6573
6423
  maxTurns: config2.maxIterations,
6574
6424
  cwd,
6575
- model: config2.selectedModel || config.anthropicModelName,
6425
+ model: defaultModel,
6576
6426
  permissionMode: isPlanMode ? "plan" : "bypassPermissions",
6577
6427
  allowDangerouslySkipPermissions: !isPlanMode,
6578
6428
  pathToClaudeCodeExecutable: claudeCodePath,
@@ -6965,6 +6815,7 @@ var init_react = __esm({
6965
6815
  toolInput: input,
6966
6816
  toolResult: void 0,
6967
6817
  isExpanded: false,
6818
+ isPending: true,
6968
6819
  toolUseId: toolId
6969
6820
  };
6970
6821
  this.callbacks.addMessage(message);
@@ -7010,7 +6861,8 @@ var init_react = __esm({
7010
6861
  }
7011
6862
  onToolResult(toolId, result) {
7012
6863
  this.callbacks.updateMessageByToolId(toolId, {
7013
- toolResult: result
6864
+ toolResult: result,
6865
+ isPending: false
7014
6866
  });
7015
6867
  streamEventAsync(this.apiClient, this.sessionId, {
7016
6868
  type: "tool_result",
@@ -7124,16 +6976,16 @@ var init_react = __esm({
7124
6976
  });
7125
6977
 
7126
6978
  // src/ui/contexts/SessionContext.tsx
7127
- import React, { createContext, useCallback, useContext, useState } from "react";
6979
+ import React, { createContext, useCallback, useContext, useMemo, useState } from "react";
7128
6980
  var SessionContext, SessionProvider, useSession;
7129
6981
  var init_SessionContext = __esm({
7130
6982
  "src/ui/contexts/SessionContext.tsx"() {
7131
6983
  "use strict";
7132
- init_shared_es();
7133
6984
  SessionContext = createContext(null);
7134
6985
  SessionProvider = ({
7135
6986
  children,
7136
- initialModel
6987
+ initialModel,
6988
+ initialLlmProvider = "supatest-managed"
7137
6989
  }) => {
7138
6990
  const [messages, setMessages] = useState([]);
7139
6991
  const [todos, setTodos] = useState([]);
@@ -7150,8 +7002,10 @@ var init_SessionContext = __esm({
7150
7002
  const [webUrl, setWebUrl] = useState();
7151
7003
  const [agentMode, setAgentMode] = useState("build");
7152
7004
  const [planFilePath, setPlanFilePath] = useState();
7153
- const [selectedModel, setSelectedModel] = useState(initialModel || DEFAULT_MODEL_ID);
7005
+ const [selectedModel, setSelectedModel] = useState(initialModel || "premium");
7006
+ const [llmProvider, setLlmProvider] = useState(initialLlmProvider);
7154
7007
  const [allToolsExpanded, setAllToolsExpanded] = useState(true);
7008
+ const [toolGroupsExpanded, setToolGroupsExpanded] = useState(false);
7155
7009
  const [staticRemountKey, setStaticRemountKey] = useState(0);
7156
7010
  const addMessage = useCallback(
7157
7011
  (message) => {
@@ -7234,7 +7088,10 @@ var init_SessionContext = __esm({
7234
7088
  return newValue;
7235
7089
  });
7236
7090
  }, []);
7237
- const value = {
7091
+ const toggleToolGroups = useCallback(() => {
7092
+ setToolGroupsExpanded((prev) => !prev);
7093
+ }, []);
7094
+ const value = useMemo(() => ({
7238
7095
  messages,
7239
7096
  addMessage,
7240
7097
  updateLastMessage,
@@ -7244,6 +7101,8 @@ var init_SessionContext = __esm({
7244
7101
  loadMessages,
7245
7102
  toggleAllToolOutputs,
7246
7103
  allToolsExpanded,
7104
+ toolGroupsExpanded,
7105
+ toggleToolGroups,
7247
7106
  todos,
7248
7107
  setTodos,
7249
7108
  stats,
@@ -7264,9 +7123,37 @@ var init_SessionContext = __esm({
7264
7123
  setPlanFilePath,
7265
7124
  selectedModel,
7266
7125
  setSelectedModel,
7126
+ llmProvider,
7127
+ setLlmProvider,
7267
7128
  staticRemountKey,
7268
7129
  refreshStatic
7269
- };
7130
+ }), [
7131
+ messages,
7132
+ addMessage,
7133
+ updateLastMessage,
7134
+ updateMessageById,
7135
+ updateMessageByToolId,
7136
+ clearMessages,
7137
+ loadMessages,
7138
+ toggleAllToolOutputs,
7139
+ allToolsExpanded,
7140
+ toolGroupsExpanded,
7141
+ toggleToolGroups,
7142
+ todos,
7143
+ stats,
7144
+ updateStats,
7145
+ usageStats,
7146
+ isAgentRunning,
7147
+ shouldInterruptAgent,
7148
+ sessionId,
7149
+ webUrl,
7150
+ agentMode,
7151
+ planFilePath,
7152
+ selectedModel,
7153
+ llmProvider,
7154
+ staticRemountKey,
7155
+ refreshStatic
7156
+ ]);
7270
7157
  return /* @__PURE__ */ React.createElement(SessionContext.Provider, { value }, children);
7271
7158
  };
7272
7159
  useSession = () => {
@@ -7305,7 +7192,7 @@ var init_theme = __esm({
7305
7192
  text: {
7306
7193
  primary: "#FFFFFF",
7307
7194
  secondary: "#A0AEC0",
7308
- dim: "#4A5568",
7195
+ dim: "#8C99B2",
7309
7196
  accent: "#38B2AC",
7310
7197
  // Cyan/teal accent
7311
7198
  success: "#48BB78",
@@ -7321,7 +7208,7 @@ var init_theme = __esm({
7321
7208
  },
7322
7209
  // Borders
7323
7210
  border: {
7324
- default: "#4A5568",
7211
+ default: "#8C99B2",
7325
7212
  accent: "#38B2AC",
7326
7213
  error: "#F56565"
7327
7214
  },
@@ -7353,7 +7240,6 @@ var init_theme = __esm({
7353
7240
 
7354
7241
  // src/ui/components/Header.tsx
7355
7242
  import { Box, Text } from "ink";
7356
- import Gradient from "ink-gradient";
7357
7243
  import React2 from "react";
7358
7244
  var Header;
7359
7245
  var init_Header = __esm({
@@ -7362,7 +7248,7 @@ var init_Header = __esm({
7362
7248
  init_banner();
7363
7249
  init_version();
7364
7250
  init_theme();
7365
- Header = ({ currentFolder, gitBranch, headless = false }) => {
7251
+ Header = React2.memo(({ currentFolder, gitBranch, headless = false }) => {
7366
7252
  const version = CLI_VERSION;
7367
7253
  const banner = getBanner();
7368
7254
  const infoParts = [`v${version}`];
@@ -7383,11 +7269,11 @@ var init_Header = __esm({
7383
7269
  marginTop: 5,
7384
7270
  width: "100%"
7385
7271
  },
7386
- /* @__PURE__ */ React2.createElement(Gradient, { colors: ["#C96868", "#FF8C94"] }, /* @__PURE__ */ React2.createElement(Text, null, banner)),
7272
+ /* @__PURE__ */ React2.createElement(Text, { color: theme.text.accent }, banner),
7387
7273
  /* @__PURE__ */ React2.createElement(Box, { justifyContent: "center", marginTop: 0 }, /* @__PURE__ */ React2.createElement(Text, { color: theme.text.dim }, infoLine)),
7388
7274
  !headless && /* @__PURE__ */ React2.createElement(Box, { flexDirection: "column", marginTop: 1, paddingX: 2, width: "100%" }, /* @__PURE__ */ React2.createElement(Box, { flexDirection: "column", marginBottom: 0 }, /* @__PURE__ */ React2.createElement(Text, { color: theme.text.dim }, "\u{1F4A1} ", /* @__PURE__ */ React2.createElement(Text, { color: theme.text.secondary }, "Tip:"), " Use ", /* @__PURE__ */ React2.createElement(Text, { bold: true, color: theme.text.accent }, "@filename"), " to reference files, or ", /* @__PURE__ */ React2.createElement(Text, { bold: true, color: theme.text.accent }, "/help"), " for commands")), /* @__PURE__ */ React2.createElement(Box, { flexDirection: "column", marginTop: 0 }, /* @__PURE__ */ React2.createElement(Text, { color: theme.text.dim }, "\u2328\uFE0F ", /* @__PURE__ */ React2.createElement(Text, { color: theme.text.secondary }, "Shortcuts:"), " ", /* @__PURE__ */ React2.createElement(Text, { bold: true, color: theme.text.accent }, "Ctrl+H"), " help, ", /* @__PURE__ */ React2.createElement(Text, { bold: true, color: theme.text.accent }, "Ctrl+C"), " exit, ", /* @__PURE__ */ React2.createElement(Text, { bold: true, color: theme.text.accent }, "ESC"), " interrupt")), /* @__PURE__ */ React2.createElement(Box, { flexDirection: "column", marginTop: 0 }, /* @__PURE__ */ React2.createElement(Text, { color: theme.text.dim }, "\u{1F680} ", /* @__PURE__ */ React2.createElement(Text, { color: theme.text.secondary }, "Prompt Tips:"), " Be explicit with instructions, provide context, use examples, and think step-by-step")))
7389
7275
  );
7390
- };
7276
+ });
7391
7277
  }
7392
7278
  });
7393
7279
 
@@ -7395,7 +7281,7 @@ var init_Header = __esm({
7395
7281
  import chalk2 from "chalk";
7396
7282
  import { Box as Box2, Text as Text2 } from "ink";
7397
7283
  import { all, createLowlight } from "lowlight";
7398
- import React3, { useMemo } from "react";
7284
+ import React3, { useMemo as useMemo2 } from "react";
7399
7285
  function parseMarkdownSections(text) {
7400
7286
  const sections = [];
7401
7287
  const lines = text.split(/\r?\n/);
@@ -7555,7 +7441,7 @@ var init_markdown = __esm({
7555
7441
  text,
7556
7442
  isPending = false
7557
7443
  }) => {
7558
- const sections = useMemo(() => parseMarkdownSections(text), [text]);
7444
+ const sections = useMemo2(() => parseMarkdownSections(text), [text]);
7559
7445
  const elements = sections.map((section, index) => {
7560
7446
  if (section.type === "table" && section.tableRows) {
7561
7447
  return /* @__PURE__ */ React3.createElement(Table, { key: `table-${index}`, rows: section.tableRows });
@@ -8088,32 +7974,66 @@ var init_ToolMessage = __esm({
8088
7974
  }
8089
7975
  });
8090
7976
 
8091
- // src/ui/components/messages/UserMessage.tsx
7977
+ // src/ui/components/messages/ToolGroup.tsx
8092
7978
  import { Box as Box9, Text as Text9 } from "ink";
8093
7979
  import React10 from "react";
7980
+ var ToolGroup;
7981
+ var init_ToolGroup = __esm({
7982
+ "src/ui/components/messages/ToolGroup.tsx"() {
7983
+ "use strict";
7984
+ init_shared_es();
7985
+ init_theme();
7986
+ init_ToolMessage();
7987
+ ToolGroup = ({
7988
+ tools,
7989
+ isExpanded,
7990
+ onToggle,
7991
+ onToggleTool
7992
+ }) => {
7993
+ const toolGroups = getToolGroupCounts(tools);
7994
+ return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Text9, { color: theme.text.dim }, isExpanded ? "\u25BC " : "\u25B6 "), /* @__PURE__ */ React10.createElement(Text9, { color: theme.text.dim }, toolGroups.length > 0 ? toolGroups.map((group) => `${group.name} ${group.count}`).join(", ") : `${tools.length} tool${tools.length !== 1 ? "s" : ""}`), !isExpanded && /* @__PURE__ */ React10.createElement(Text9, { color: theme.text.dim }, " (ctrl+o to expand)")), isExpanded && /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginLeft: 2 }, tools.map((tool) => /* @__PURE__ */ React10.createElement(
7995
+ ToolMessage,
7996
+ {
7997
+ description: tool.description,
7998
+ id: tool.id,
7999
+ input: tool.input,
8000
+ isExpanded: tool.isExpanded,
8001
+ key: tool.id,
8002
+ onToggle: onToggleTool,
8003
+ result: tool.result,
8004
+ toolName: tool.toolName
8005
+ }
8006
+ ))));
8007
+ };
8008
+ }
8009
+ });
8010
+
8011
+ // src/ui/components/messages/UserMessage.tsx
8012
+ import { Box as Box10, Text as Text10 } from "ink";
8013
+ import React11 from "react";
8094
8014
  var UserMessage;
8095
8015
  var init_UserMessage = __esm({
8096
8016
  "src/ui/components/messages/UserMessage.tsx"() {
8097
8017
  "use strict";
8098
8018
  init_theme();
8099
8019
  UserMessage = ({ text }) => {
8100
- return /* @__PURE__ */ React10.createElement(Box9, { alignItems: "center", flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: theme.text.info }, "\u{1F464} "), /* @__PURE__ */ React10.createElement(
8101
- Box9,
8020
+ return /* @__PURE__ */ React11.createElement(Box10, { alignItems: "center", flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: theme.text.info }, "\u{1F464} "), /* @__PURE__ */ React11.createElement(
8021
+ Box10,
8102
8022
  {
8103
8023
  borderColor: theme.text.dim,
8104
8024
  borderStyle: "round",
8105
8025
  paddingLeft: 1,
8106
8026
  paddingRight: 1
8107
8027
  },
8108
- /* @__PURE__ */ React10.createElement(Text9, { color: theme.text.secondary }, text)
8028
+ /* @__PURE__ */ React11.createElement(Text10, { color: theme.text.secondary }, text)
8109
8029
  ));
8110
8030
  };
8111
8031
  }
8112
8032
  });
8113
8033
 
8114
8034
  // src/ui/components/QueuedMessageDisplay.tsx
8115
- import { Box as Box10, Text as Text10 } from "ink";
8116
- import React11 from "react";
8035
+ import { Box as Box11, Text as Text11 } from "ink";
8036
+ import React12 from "react";
8117
8037
  var MAX_DISPLAYED_QUEUED_MESSAGES, QueuedMessageDisplay;
8118
8038
  var init_QueuedMessageDisplay = __esm({
8119
8039
  "src/ui/components/QueuedMessageDisplay.tsx"() {
@@ -8126,8 +8046,8 @@ var init_QueuedMessageDisplay = __esm({
8126
8046
  if (messageQueue.length === 0) {
8127
8047
  return null;
8128
8048
  }
8129
- return /* @__PURE__ */ React11.createElement(
8130
- Box10,
8049
+ return /* @__PURE__ */ React12.createElement(
8050
+ Box11,
8131
8051
  {
8132
8052
  borderColor: theme.border.default,
8133
8053
  borderStyle: "round",
@@ -8136,20 +8056,20 @@ var init_QueuedMessageDisplay = __esm({
8136
8056
  marginTop: 0,
8137
8057
  paddingX: 1
8138
8058
  },
8139
- /* @__PURE__ */ React11.createElement(Box10, { marginBottom: 0 }, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: theme.text.secondary }, "Queued (", messageQueue.length, ")")),
8059
+ /* @__PURE__ */ React12.createElement(Box11, { marginBottom: 0 }, /* @__PURE__ */ React12.createElement(Text11, { bold: true, color: theme.text.secondary }, "Queued (", messageQueue.length, ")")),
8140
8060
  messageQueue.slice(0, MAX_DISPLAYED_QUEUED_MESSAGES).map((message, index) => {
8141
8061
  const preview = message.replace(/\s+/g, " ");
8142
- return /* @__PURE__ */ React11.createElement(Box10, { key: index, width: "100%" }, /* @__PURE__ */ React11.createElement(Text10, { color: theme.text.dim }, " ", index + 1, ". "), /* @__PURE__ */ React11.createElement(Text10, { color: theme.text.primary, wrap: "truncate" }, preview));
8062
+ return /* @__PURE__ */ React12.createElement(Box11, { key: index, width: "100%" }, /* @__PURE__ */ React12.createElement(Text11, { color: theme.text.dim }, " ", index + 1, ". "), /* @__PURE__ */ React12.createElement(Text11, { color: theme.text.primary, wrap: "truncate" }, preview));
8143
8063
  }),
8144
- messageQueue.length > MAX_DISPLAYED_QUEUED_MESSAGES && /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { color: theme.text.dim, italic: true }, "... (+", messageQueue.length - MAX_DISPLAYED_QUEUED_MESSAGES, " more)"))
8064
+ messageQueue.length > MAX_DISPLAYED_QUEUED_MESSAGES && /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { color: theme.text.dim, italic: true }, "... (+", messageQueue.length - MAX_DISPLAYED_QUEUED_MESSAGES, " more)"))
8145
8065
  );
8146
8066
  };
8147
8067
  }
8148
8068
  });
8149
8069
 
8150
8070
  // src/ui/components/MessageList.tsx
8151
- import { Box as Box11, Static } from "ink";
8152
- import React12, { useMemo as useMemo3 } from "react";
8071
+ import { Box as Box12, Static } from "ink";
8072
+ import React13, { useMemo as useMemo4, useRef } from "react";
8153
8073
  var MessageList;
8154
8074
  var init_MessageList = __esm({
8155
8075
  "src/ui/components/MessageList.tsx"() {
@@ -8161,17 +8081,18 @@ var init_MessageList = __esm({
8161
8081
  init_LoadingMessage();
8162
8082
  init_ThinkingMessage();
8163
8083
  init_TodoMessage();
8084
+ init_ToolGroup();
8164
8085
  init_ToolMessage();
8165
8086
  init_UserMessage();
8166
8087
  init_QueuedMessageDisplay();
8167
8088
  MessageList = ({ terminalWidth, currentFolder, gitBranch, headless = false, queuedTasks = [] }) => {
8168
- const { messages, updateMessageById, isAgentRunning, staticRemountKey } = useSession();
8169
- const renderMessage = (message) => {
8089
+ const { messages, updateMessageById, isAgentRunning, staticRemountKey, toolGroupsExpanded, toggleToolGroups } = useSession();
8090
+ const renderMessage = (message, isInGroup = false) => {
8170
8091
  switch (message.type) {
8171
8092
  case "user":
8172
- return /* @__PURE__ */ React12.createElement(UserMessage, { key: message.id, text: message.content });
8093
+ return /* @__PURE__ */ React13.createElement(UserMessage, { key: message.id, text: message.content });
8173
8094
  case "assistant":
8174
- return /* @__PURE__ */ React12.createElement(
8095
+ return /* @__PURE__ */ React13.createElement(
8175
8096
  AssistantMessage,
8176
8097
  {
8177
8098
  isPending: message.isPending,
@@ -8181,7 +8102,22 @@ var init_MessageList = __esm({
8181
8102
  }
8182
8103
  );
8183
8104
  case "tool":
8184
- return /* @__PURE__ */ React12.createElement(
8105
+ if (isInGroup) {
8106
+ return /* @__PURE__ */ React13.createElement(
8107
+ ToolMessage,
8108
+ {
8109
+ description: message.content,
8110
+ id: message.id,
8111
+ input: message.toolInput,
8112
+ isExpanded: message.isExpanded,
8113
+ key: message.id,
8114
+ onToggle: (id) => updateMessageById(id, { isExpanded: !message.isExpanded }),
8115
+ result: message.toolResult,
8116
+ toolName: message.toolName || "Unknown"
8117
+ }
8118
+ );
8119
+ }
8120
+ return /* @__PURE__ */ React13.createElement(
8185
8121
  ToolMessage,
8186
8122
  {
8187
8123
  description: message.content,
@@ -8195,7 +8131,7 @@ var init_MessageList = __esm({
8195
8131
  }
8196
8132
  );
8197
8133
  case "thinking":
8198
- return /* @__PURE__ */ React12.createElement(
8134
+ return /* @__PURE__ */ React13.createElement(
8199
8135
  ThinkingMessage,
8200
8136
  {
8201
8137
  content: message.content,
@@ -8206,7 +8142,7 @@ var init_MessageList = __esm({
8206
8142
  }
8207
8143
  );
8208
8144
  case "error":
8209
- return /* @__PURE__ */ React12.createElement(
8145
+ return /* @__PURE__ */ React13.createElement(
8210
8146
  ErrorMessage,
8211
8147
  {
8212
8148
  key: message.id,
@@ -8215,37 +8151,134 @@ var init_MessageList = __esm({
8215
8151
  }
8216
8152
  );
8217
8153
  case "todo":
8218
- return /* @__PURE__ */ React12.createElement(TodoMessage, { key: message.id, todos: message.todos || [] });
8154
+ return /* @__PURE__ */ React13.createElement(TodoMessage, { key: message.id, todos: message.todos || [] });
8219
8155
  default:
8220
8156
  return null;
8221
8157
  }
8222
8158
  };
8223
- const { completedMessages, pendingMessages } = useMemo3(() => {
8159
+ const renderGroupedMessage = (group) => {
8160
+ if (group.type === "group") {
8161
+ return /* @__PURE__ */ React13.createElement(
8162
+ ToolGroup,
8163
+ {
8164
+ isExpanded: toolGroupsExpanded,
8165
+ key: `group-${group.messages[0].id}`,
8166
+ onToggle: toggleToolGroups,
8167
+ onToggleTool: (id) => {
8168
+ const msg = group.messages.find((m) => m.id === id);
8169
+ if (msg) {
8170
+ updateMessageById(id, { isExpanded: !msg.isExpanded });
8171
+ }
8172
+ },
8173
+ tools: group.messages.map((msg) => ({
8174
+ id: msg.id,
8175
+ toolName: msg.toolName || "Unknown",
8176
+ description: msg.content,
8177
+ input: msg.toolInput,
8178
+ result: msg.toolResult,
8179
+ isExpanded: msg.isExpanded
8180
+ }))
8181
+ }
8182
+ );
8183
+ }
8184
+ return renderMessage(group.messages[0]);
8185
+ };
8186
+ const lastUserMessageIndex = useMemo4(() => {
8187
+ for (let i = messages.length - 1; i >= 0; i--) {
8188
+ if (messages[i].type === "user") {
8189
+ return i;
8190
+ }
8191
+ }
8192
+ return -1;
8193
+ }, [messages]);
8194
+ const hasPendingAssistant = useMemo4(
8195
+ () => messages.some((m) => m.type === "assistant" && m.isPending),
8196
+ [messages]
8197
+ );
8198
+ const completedBoundaryRef = useRef(-1);
8199
+ const completedBoundaryKey = useMemo4(() => {
8200
+ const currentBoundary = lastUserMessageIndex;
8201
+ if (currentBoundary !== completedBoundaryRef.current) {
8202
+ completedBoundaryRef.current = currentBoundary;
8203
+ return `boundary-${currentBoundary}`;
8204
+ }
8205
+ return `boundary-${completedBoundaryRef.current}`;
8206
+ }, [lastUserMessageIndex]);
8207
+ const { completedGroups, currentTurnGroups } = useMemo4(() => {
8224
8208
  const completed = [];
8225
- const pending = [];
8226
- for (const msg of messages) {
8227
- if (msg.isPending) {
8228
- pending.push(msg);
8209
+ const currentTurn = [];
8210
+ const processTurn = (turnMessages2, targetArray) => {
8211
+ let currentToolGroup = [];
8212
+ const flushToolGroup = () => {
8213
+ if (currentToolGroup.length === 0) return;
8214
+ if (currentToolGroup.length === 1) {
8215
+ targetArray.push({ type: "single", messages: [...currentToolGroup] });
8216
+ } else {
8217
+ targetArray.push({ type: "group", messages: [...currentToolGroup] });
8218
+ }
8219
+ currentToolGroup = [];
8220
+ };
8221
+ for (const msg of turnMessages2) {
8222
+ if (msg.type === "tool") {
8223
+ currentToolGroup.push(msg);
8224
+ } else {
8225
+ flushToolGroup();
8226
+ targetArray.push({ type: "single", messages: [msg] });
8227
+ }
8228
+ }
8229
+ flushToolGroup();
8230
+ };
8231
+ let turnMessages = [];
8232
+ for (let i = 0; i < lastUserMessageIndex; i++) {
8233
+ const msg = messages[i];
8234
+ if (msg.type === "user") {
8235
+ processTurn(turnMessages, completed);
8236
+ turnMessages = [];
8237
+ completed.push({ type: "single", messages: [msg] });
8229
8238
  } else {
8230
- completed.push(msg);
8239
+ turnMessages.push(msg);
8231
8240
  }
8232
8241
  }
8233
- return { completedMessages: completed, pendingMessages: pending };
8234
- }, [messages]);
8235
- const staticItems = useMemo3(() => [
8242
+ processTurn(turnMessages, completed);
8243
+ if (lastUserMessageIndex >= 0) {
8244
+ completed.push({ type: "single", messages: [messages[lastUserMessageIndex]] });
8245
+ }
8246
+ const currentTurnMessages = lastUserMessageIndex >= 0 ? messages.slice(lastUserMessageIndex + 1) : messages;
8247
+ processTurn(currentTurnMessages, currentTurn);
8248
+ return { completedGroups: completed, currentTurnGroups: currentTurn };
8249
+ }, [messages, lastUserMessageIndex, completedBoundaryKey]);
8250
+ const staticItems = useMemo4(() => [
8236
8251
  { id: "header", type: "header" },
8237
- ...completedMessages.map((msg) => ({ ...msg, _isMessage: true }))
8238
- ], [completedMessages]);
8239
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Static, { items: staticItems, key: staticRemountKey }, (item) => {
8252
+ ...completedGroups.map((group, idx) => {
8253
+ if (group.type === "group") {
8254
+ return { ...group, _isGroup: true, id: `group-${idx}` };
8255
+ }
8256
+ return { ...group.messages[0], _isMessage: true };
8257
+ })
8258
+ ], [completedGroups]);
8259
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Static, { items: staticItems, key: staticRemountKey }, (item) => {
8240
8260
  if (item.type === "header") {
8241
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", key: "header" }, /* @__PURE__ */ React12.createElement(Header, { currentFolder, gitBranch, headless }));
8261
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: "header" }, /* @__PURE__ */ React13.createElement(Header, { currentFolder, gitBranch, headless }));
8262
+ }
8263
+ if (item._isGroup) {
8264
+ const content2 = renderGroupedMessage(item);
8265
+ if (!content2) {
8266
+ return null;
8267
+ }
8268
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: item.id, width: "100%" }, content2);
8242
8269
  }
8243
8270
  const content = renderMessage(item);
8244
8271
  if (!content) {
8245
8272
  return null;
8246
8273
  }
8247
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", key: item.id, width: "100%" }, content);
8248
- }), pendingMessages.map((message) => /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", key: message.id, width: "100%" }, renderMessage(message))), /* @__PURE__ */ React12.createElement(QueuedMessageDisplay, { messageQueue: queuedTasks }), isAgentRunning && !messages.some((m) => m.type === "assistant" && m.isPending) && /* @__PURE__ */ React12.createElement(LoadingMessage, { headless, key: "loading" }));
8274
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: item.id, width: "100%" }, content);
8275
+ }), currentTurnGroups.map((group, idx) => {
8276
+ const content = renderGroupedMessage(group);
8277
+ if (!content) {
8278
+ return null;
8279
+ }
8280
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: group.type === "group" ? `current-group-${idx}` : group.messages[0].id, width: "100%" }, content);
8281
+ }), /* @__PURE__ */ React13.createElement(QueuedMessageDisplay, { messageQueue: queuedTasks }), isAgentRunning && !hasPendingAssistant && /* @__PURE__ */ React13.createElement(LoadingMessage, { headless, key: "loading" }));
8249
8282
  };
8250
8283
  }
8251
8284
  });
@@ -8372,21 +8405,21 @@ var init_encryption = __esm({
8372
8405
  });
8373
8406
 
8374
8407
  // src/utils/token-storage.ts
8375
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync } from "fs";
8376
- import { homedir as homedir5 } from "os";
8377
- import { join as join8 } from "path";
8408
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync } from "fs";
8409
+ import { homedir as homedir4 } from "os";
8410
+ import { join as join7 } from "path";
8378
8411
  function getTokenFilePath() {
8379
8412
  const apiUrl = process.env.SUPATEST_API_URL || PRODUCTION_API_URL;
8380
8413
  if (apiUrl === PRODUCTION_API_URL) {
8381
- return join8(CONFIG_DIR, "token.json");
8414
+ return join7(CONFIG_DIR, "token.json");
8382
8415
  }
8383
- return join8(CONFIG_DIR, "token.local.json");
8416
+ return join7(CONFIG_DIR, "token.local.json");
8384
8417
  }
8385
8418
  function isV2Format(stored) {
8386
8419
  return "version" in stored && stored.version === 2;
8387
8420
  }
8388
8421
  function ensureConfigDir() {
8389
- if (!existsSync6(CONFIG_DIR)) {
8422
+ if (!existsSync5(CONFIG_DIR)) {
8390
8423
  mkdirSync2(CONFIG_DIR, { recursive: true, mode: 448 });
8391
8424
  }
8392
8425
  }
@@ -8406,11 +8439,11 @@ function saveToken(token, expiresAt) {
8406
8439
  }
8407
8440
  function loadToken() {
8408
8441
  const tokenFile = getTokenFilePath();
8409
- if (!existsSync6(tokenFile)) {
8442
+ if (!existsSync5(tokenFile)) {
8410
8443
  return null;
8411
8444
  }
8412
8445
  try {
8413
- const data = readFileSync5(tokenFile, "utf8");
8446
+ const data = readFileSync4(tokenFile, "utf8");
8414
8447
  const stored = JSON.parse(data);
8415
8448
  let payload;
8416
8449
  if (isV2Format(stored)) {
@@ -8439,7 +8472,7 @@ function loadToken() {
8439
8472
  }
8440
8473
  function removeToken() {
8441
8474
  const tokenFile = getTokenFilePath();
8442
- if (existsSync6(tokenFile)) {
8475
+ if (existsSync5(tokenFile)) {
8443
8476
  unlinkSync2(tokenFile);
8444
8477
  }
8445
8478
  }
@@ -8448,10 +8481,10 @@ var init_token_storage = __esm({
8448
8481
  "src/utils/token-storage.ts"() {
8449
8482
  "use strict";
8450
8483
  init_encryption();
8451
- CONFIG_DIR = join8(homedir5(), ".supatest");
8484
+ CONFIG_DIR = join7(homedir4(), ".supatest");
8452
8485
  PRODUCTION_API_URL = "https://code-api.supatest.ai";
8453
8486
  STORAGE_VERSION = 2;
8454
- TOKEN_FILE = join8(CONFIG_DIR, "token.json");
8487
+ TOKEN_FILE = join7(CONFIG_DIR, "token.json");
8455
8488
  }
8456
8489
  });
8457
8490
 
@@ -8920,6 +8953,128 @@ var init_login = __esm({
8920
8953
  }
8921
8954
  });
8922
8955
 
8956
+ // src/utils/claude-max.ts
8957
+ import { execSync as execSync5 } from "child_process";
8958
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
8959
+ import { homedir as homedir5 } from "os";
8960
+ import { join as join8 } from "path";
8961
+ function isClaudeMaxAvailable() {
8962
+ const platform2 = process.platform;
8963
+ logger.debug("[claude-max] Checking Claude Code credentials", { platform: platform2 });
8964
+ if (platform2 === "darwin") {
8965
+ return checkMacOSKeychain();
8966
+ } else {
8967
+ return checkCredentialsFile();
8968
+ }
8969
+ }
8970
+ function checkMacOSKeychain() {
8971
+ try {
8972
+ const credentialsJson = execSync5(
8973
+ 'security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null',
8974
+ { encoding: "utf-8" }
8975
+ ).trim();
8976
+ if (!credentialsJson) {
8977
+ logger.debug("[claude-max] No credentials found in macOS keychain");
8978
+ return false;
8979
+ }
8980
+ const credentials = JSON.parse(credentialsJson);
8981
+ const hasOauth = !!credentials.claudeAiOauth?.accessToken;
8982
+ logger.debug("[claude-max] macOS keychain credentials check", {
8983
+ hasOauth,
8984
+ hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
8985
+ });
8986
+ return hasOauth;
8987
+ } catch (error) {
8988
+ logger.debug("[claude-max] Error checking macOS keychain", {
8989
+ error: error instanceof Error ? error.message : String(error)
8990
+ });
8991
+ return false;
8992
+ }
8993
+ }
8994
+ function checkCredentialsFile() {
8995
+ try {
8996
+ const credentialsPath = join8(homedir5(), ".claude", ".credentials.json");
8997
+ if (!existsSync6(credentialsPath)) {
8998
+ logger.debug("[claude-max] Credentials file not found", { path: credentialsPath });
8999
+ return false;
9000
+ }
9001
+ const credentialsJson = readFileSync5(credentialsPath, "utf-8");
9002
+ const credentials = JSON.parse(credentialsJson);
9003
+ const hasOauth = !!credentials.claudeAiOauth?.accessToken;
9004
+ logger.debug("[claude-max] Credentials file check", {
9005
+ path: credentialsPath,
9006
+ hasOauth,
9007
+ hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
9008
+ });
9009
+ return hasOauth;
9010
+ } catch (error) {
9011
+ logger.debug("[claude-max] Error checking credentials file", {
9012
+ error: error instanceof Error ? error.message : String(error)
9013
+ });
9014
+ return false;
9015
+ }
9016
+ }
9017
+ var init_claude_max = __esm({
9018
+ "src/utils/claude-max.ts"() {
9019
+ "use strict";
9020
+ init_logger();
9021
+ }
9022
+ });
9023
+
9024
+ // src/utils/settings-loader.ts
9025
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
9026
+ import { join as join9 } from "path";
9027
+ function loadSupatestSettings(cwd) {
9028
+ const settingsPath = join9(cwd, ".supatest", "settings.json");
9029
+ if (!existsSync7(settingsPath)) {
9030
+ return {};
9031
+ }
9032
+ try {
9033
+ const content = readFileSync6(settingsPath, "utf-8");
9034
+ return JSON.parse(content);
9035
+ } catch (error) {
9036
+ console.warn(
9037
+ `Warning: Failed to load settings from ${settingsPath}:`,
9038
+ error instanceof Error ? error.message : String(error)
9039
+ );
9040
+ return {};
9041
+ }
9042
+ }
9043
+ function saveSupatestSettings(cwd, settings) {
9044
+ const settingsDir = join9(cwd, ".supatest");
9045
+ const settingsPath = join9(settingsDir, "settings.json");
9046
+ try {
9047
+ if (!existsSync7(settingsDir)) {
9048
+ mkdirSync3(settingsDir, { recursive: true });
9049
+ }
9050
+ const existingSettings = loadSupatestSettings(cwd);
9051
+ const mergedSettings = {
9052
+ ...existingSettings,
9053
+ ...settings,
9054
+ // Preserve nested objects like permissions and hooks
9055
+ permissions: {
9056
+ ...existingSettings.permissions,
9057
+ ...settings.permissions
9058
+ },
9059
+ hooks: {
9060
+ ...existingSettings.hooks,
9061
+ ...settings.hooks
9062
+ }
9063
+ };
9064
+ writeFileSync2(settingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
9065
+ } catch (error) {
9066
+ console.warn(
9067
+ `Warning: Failed to save settings to ${settingsPath}:`,
9068
+ error instanceof Error ? error.message : String(error)
9069
+ );
9070
+ }
9071
+ }
9072
+ var init_settings_loader = __esm({
9073
+ "src/utils/settings-loader.ts"() {
9074
+ "use strict";
9075
+ }
9076
+ });
9077
+
8923
9078
  // src/ui/types/auth.ts
8924
9079
  var init_auth = __esm({
8925
9080
  "src/ui/types/auth.ts"() {
@@ -8928,8 +9083,8 @@ var init_auth = __esm({
8928
9083
  });
8929
9084
 
8930
9085
  // src/ui/components/AuthBanner.tsx
8931
- import { Box as Box13, Text as Text11 } from "ink";
8932
- import React15 from "react";
9086
+ import { Box as Box14, Text as Text12 } from "ink";
9087
+ import React16 from "react";
8933
9088
  var AuthBanner;
8934
9089
  var init_AuthBanner = __esm({
8935
9090
  "src/ui/components/AuthBanner.tsx"() {
@@ -8941,10 +9096,10 @@ var init_AuthBanner = __esm({
8941
9096
  return null;
8942
9097
  }
8943
9098
  if (authState === "authenticating" /* Authenticating */) {
8944
- return /* @__PURE__ */ React15.createElement(Box13, { marginBottom: 0, paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text11, { color: theme.text.info }, "Authenticating..."));
9099
+ return /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 0, paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text12, { color: theme.text.info }, "Authenticating..."));
8945
9100
  }
8946
- return /* @__PURE__ */ React15.createElement(
8947
- Box13,
9101
+ return /* @__PURE__ */ React16.createElement(
9102
+ Box14,
8948
9103
  {
8949
9104
  borderColor: theme.text.warning,
8950
9105
  borderStyle: "round",
@@ -8952,10 +9107,10 @@ var init_AuthBanner = __esm({
8952
9107
  paddingX: 1,
8953
9108
  paddingY: 0
8954
9109
  },
8955
- /* @__PURE__ */ React15.createElement(Text11, { bold: true, color: theme.text.warning }, "Not logged in"),
8956
- /* @__PURE__ */ React15.createElement(Text11, { color: theme.text.dim }, " - Type "),
8957
- /* @__PURE__ */ React15.createElement(Text11, { color: theme.text.info }, "/login"),
8958
- /* @__PURE__ */ React15.createElement(Text11, { color: theme.text.dim }, " to authenticate")
9110
+ /* @__PURE__ */ React16.createElement(Text12, { bold: true, color: theme.text.warning }, "Not logged in"),
9111
+ /* @__PURE__ */ React16.createElement(Text12, { color: theme.text.dim }, " - Type "),
9112
+ /* @__PURE__ */ React16.createElement(Text12, { color: theme.text.info }, "/login"),
9113
+ /* @__PURE__ */ React16.createElement(Text12, { color: theme.text.dim }, " to authenticate")
8959
9114
  );
8960
9115
  };
8961
9116
  }
@@ -9177,12 +9332,12 @@ var init_mouse = __esm({
9177
9332
 
9178
9333
  // src/ui/contexts/KeypressContext.tsx
9179
9334
  import { useStdin as useStdin2 } from "ink";
9180
- import React16, {
9335
+ import React17, {
9181
9336
  createContext as createContext2,
9182
9337
  useCallback as useCallback2,
9183
9338
  useContext as useContext2,
9184
9339
  useEffect as useEffect4,
9185
- useRef as useRef2
9340
+ useRef as useRef3
9186
9341
  } from "react";
9187
9342
  function charLengthAt(str, i) {
9188
9343
  if (str.length <= i) {
@@ -9469,7 +9624,7 @@ function KeypressProvider({
9469
9624
  debugKeystrokeLogging
9470
9625
  }) {
9471
9626
  const { stdin, setRawMode } = useStdin2();
9472
- const subscribers = useRef2(/* @__PURE__ */ new Set()).current;
9627
+ const subscribers = useRef3(/* @__PURE__ */ new Set()).current;
9473
9628
  const subscribe = useCallback2(
9474
9629
  (handler) => subscribers.add(handler),
9475
9630
  [subscribers]
@@ -9500,7 +9655,7 @@ function KeypressProvider({
9500
9655
  }
9501
9656
  };
9502
9657
  }, [stdin, setRawMode, config2, debugKeystrokeLogging, broadcast]);
9503
- return /* @__PURE__ */ React16.createElement(KeypressContext.Provider, { value: { subscribe, unsubscribe } }, children);
9658
+ return /* @__PURE__ */ React17.createElement(KeypressContext.Provider, { value: { subscribe, unsubscribe } }, children);
9504
9659
  }
9505
9660
  var BACKSLASH_ENTER_TIMEOUT, ESC_TIMEOUT, PASTE_TIMEOUT, KEY_INFO_MAP, kUTF16SurrogateThreshold, MAC_ALT_KEY_CHARACTER_MAP, KeypressContext;
9506
9661
  var init_KeypressContext = __esm({
@@ -9632,8 +9787,8 @@ var init_useKeypress = __esm({
9632
9787
  });
9633
9788
 
9634
9789
  // src/ui/components/AuthDialog.tsx
9635
- import { Box as Box14, Text as Text12 } from "ink";
9636
- import React17 from "react";
9790
+ import { Box as Box15, Text as Text13 } from "ink";
9791
+ import React18 from "react";
9637
9792
  var AuthDialog;
9638
9793
  var init_AuthDialog = __esm({
9639
9794
  "src/ui/components/AuthDialog.tsx"() {
@@ -9649,8 +9804,8 @@ var init_AuthDialog = __esm({
9649
9804
  },
9650
9805
  { isActive: true }
9651
9806
  );
9652
- return /* @__PURE__ */ React17.createElement(
9653
- Box14,
9807
+ return /* @__PURE__ */ React18.createElement(
9808
+ Box15,
9654
9809
  {
9655
9810
  borderColor: theme.border.accent,
9656
9811
  borderStyle: "round",
@@ -9658,18 +9813,18 @@ var init_AuthDialog = __esm({
9658
9813
  paddingX: 2,
9659
9814
  paddingY: 1
9660
9815
  },
9661
- /* @__PURE__ */ React17.createElement(Text12, { bold: true, color: theme.text.primary }, "Welcome to Supatest CLI"),
9662
- /* @__PURE__ */ React17.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text12, { color: theme.text.secondary }, "Authentication is required to use Supatest CLI.")),
9663
- /* @__PURE__ */ React17.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React17.createElement(Box14, null, /* @__PURE__ */ React17.createElement(Text12, { color: theme.text.accent }, ">", " "), /* @__PURE__ */ React17.createElement(Text12, { color: theme.text.primary }, "[L] Login with browser"))),
9664
- /* @__PURE__ */ React17.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text12, { color: theme.text.dim, italic: true }, "Press Enter or L to login"))
9816
+ /* @__PURE__ */ React18.createElement(Text13, { bold: true, color: theme.text.primary }, "Welcome to Supatest CLI"),
9817
+ /* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.secondary }, "Authentication is required to use Supatest CLI.")),
9818
+ /* @__PURE__ */ React18.createElement(Box15, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React18.createElement(Box15, null, /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.accent }, ">", " "), /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.primary }, "[L] Login with browser"))),
9819
+ /* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.dim, italic: true }, "Press Enter or L to login"))
9665
9820
  );
9666
9821
  };
9667
9822
  }
9668
9823
  });
9669
9824
 
9670
9825
  // src/ui/components/FeedbackDialog.tsx
9671
- import { Box as Box15, Text as Text13, useInput } from "ink";
9672
- import React18, { useState as useState5 } from "react";
9826
+ import { Box as Box16, Text as Text14, useInput } from "ink";
9827
+ import React19, { useState as useState5 } from "react";
9673
9828
  var CATEGORY_ORDER, FeedbackDialog;
9674
9829
  var init_FeedbackDialog = __esm({
9675
9830
  "src/ui/components/FeedbackDialog.tsx"() {
@@ -9764,21 +9919,21 @@ var init_FeedbackDialog = __esm({
9764
9919
  });
9765
9920
  const renderDescription = () => {
9766
9921
  if (!description && focus !== "description") {
9767
- return /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.dim, italic: true }, "Enter your feedback...");
9922
+ return /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim, italic: true }, "Enter your feedback...");
9768
9923
  }
9769
9924
  if (focus === "description") {
9770
9925
  const before = description.slice(0, cursorPosition);
9771
9926
  const charAtCursor = description[cursorPosition] || " ";
9772
9927
  const after = description.slice(cursorPosition + 1);
9773
9928
  if (!description) {
9774
- return /* @__PURE__ */ React18.createElement(Text13, null, /* @__PURE__ */ React18.createElement(Text13, { inverse: true }, " "), /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.dim, italic: true }, "Enter your feedback..."));
9929
+ return /* @__PURE__ */ React19.createElement(Text14, null, /* @__PURE__ */ React19.createElement(Text14, { inverse: true }, " "), /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim, italic: true }, "Enter your feedback..."));
9775
9930
  }
9776
- return /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.primary }, before, /* @__PURE__ */ React18.createElement(Text13, { inverse: true }, charAtCursor), after);
9931
+ return /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.primary }, before, /* @__PURE__ */ React19.createElement(Text14, { inverse: true }, charAtCursor), after);
9777
9932
  }
9778
- return /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.primary }, description);
9933
+ return /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.primary }, description);
9779
9934
  };
9780
- return /* @__PURE__ */ React18.createElement(
9781
- Box15,
9935
+ return /* @__PURE__ */ React19.createElement(
9936
+ Box16,
9782
9937
  {
9783
9938
  borderColor: theme.border.accent,
9784
9939
  borderStyle: "round",
@@ -9786,18 +9941,18 @@ var init_FeedbackDialog = __esm({
9786
9941
  paddingX: 2,
9787
9942
  paddingY: 1
9788
9943
  },
9789
- /* @__PURE__ */ React18.createElement(Text13, { bold: true, color: theme.text.accent }, "Report Issue"),
9790
- /* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }),
9791
- /* @__PURE__ */ React18.createElement(Text13, { bold: true, color: theme.text.secondary }, "Category:"),
9792
- /* @__PURE__ */ React18.createElement(Box15, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, CATEGORY_ORDER.map((category) => {
9944
+ /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: theme.text.accent }, "Report Issue"),
9945
+ /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }),
9946
+ /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: theme.text.secondary }, "Category:"),
9947
+ /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, CATEGORY_ORDER.map((category) => {
9793
9948
  const isSelected = selectedCategory === category;
9794
9949
  const info = FEEDBACK_CATEGORIES[category];
9795
- return /* @__PURE__ */ React18.createElement(Box15, { flexDirection: "row", key: category }, /* @__PURE__ */ React18.createElement(Text13, { color: isSelected && focus === "category" ? theme.text.accent : theme.text.dim }, isSelected ? "\u25B6 " : " "), /* @__PURE__ */ React18.createElement(Text13, { color: isSelected ? theme.text.primary : theme.text.dim }, info.label), /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.dim }, " ", info.description));
9950
+ return /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "row", key: category }, /* @__PURE__ */ React19.createElement(Text14, { color: isSelected && focus === "category" ? theme.text.accent : theme.text.dim }, isSelected ? "\u25B6 " : " "), /* @__PURE__ */ React19.createElement(Text14, { color: isSelected ? theme.text.primary : theme.text.dim }, info.label), /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, " ", info.description));
9796
9951
  })),
9797
- /* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }),
9798
- /* @__PURE__ */ React18.createElement(Text13, { bold: true, color: theme.text.secondary }, "Description:"),
9799
- /* @__PURE__ */ React18.createElement(
9800
- Box15,
9952
+ /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }),
9953
+ /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: theme.text.secondary }, "Description:"),
9954
+ /* @__PURE__ */ React19.createElement(
9955
+ Box16,
9801
9956
  {
9802
9957
  borderColor: focus === "description" ? theme.border.accent : theme.border.default,
9803
9958
  borderStyle: "round",
@@ -9808,8 +9963,8 @@ var init_FeedbackDialog = __esm({
9808
9963
  },
9809
9964
  renderDescription()
9810
9965
  ),
9811
- /* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }),
9812
- /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.dim }, /* @__PURE__ */ React18.createElement(Text13, { bold: true }, "\u2191\u2193"), " category \u2022", " ", /* @__PURE__ */ React18.createElement(Text13, { bold: true }, "Tab"), " to description \u2022", " ", /* @__PURE__ */ React18.createElement(Text13, { bold: true }, "Enter"), " submit \u2022", " ", /* @__PURE__ */ React18.createElement(Text13, { bold: true }, "ESC"), " cancel")
9966
+ /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }),
9967
+ /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "\u2191\u2193"), " category \u2022", " ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "Tab"), " to description \u2022", " ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "Enter"), " submit \u2022", " ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "ESC"), " cancel")
9813
9968
  );
9814
9969
  };
9815
9970
  }
@@ -9918,8 +10073,8 @@ var init_context_builder = __esm({
9918
10073
  });
9919
10074
 
9920
10075
  // src/ui/components/RunSelector.tsx
9921
- import { Box as Box16, Text as Text14, useInput as useInput2 } from "ink";
9922
- import React19, { useEffect as useEffect6, useState as useState6 } from "react";
10076
+ import { Box as Box17, Text as Text15, useInput as useInput2 } from "ink";
10077
+ import React20, { useEffect as useEffect6, useState as useState6 } from "react";
9923
10078
  function formatRelativeTime(date) {
9924
10079
  const now = /* @__PURE__ */ new Date();
9925
10080
  const diffMs = now.getTime() - date.getTime();
@@ -10013,13 +10168,13 @@ var init_RunSelector = __esm({
10013
10168
  }
10014
10169
  });
10015
10170
  if (error) {
10016
- return /* @__PURE__ */ React19.createElement(Box16, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: "red" }, "Error Loading Runs"), /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, error), /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "ESC"), " to cancel")));
10171
+ return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "red" }, "Error Loading Runs"), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, error), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "ESC"), " to cancel")));
10017
10172
  }
10018
10173
  if (allRuns.length === 0 && isLoading) {
10019
- return /* @__PURE__ */ React19.createElement(Box16, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: "cyan" }, "Loading Runs..."), /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, "Fetching test runs from the server"));
10174
+ return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "cyan" }, "Loading Runs..."), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Fetching test runs from the server"));
10020
10175
  }
10021
10176
  if (allRuns.length === 0 && !isLoading) {
10022
- return /* @__PURE__ */ React19.createElement(Box16, { borderColor: "yellow", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: "yellow" }, "No Runs Found"), /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, "No test runs available. Run your tests with the Supatest reporter first."), /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "ESC"), " to cancel")));
10177
+ return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "yellow", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "yellow" }, "No Runs Found"), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "No test runs available. Run your tests with the Supatest reporter first."), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "ESC"), " to cancel")));
10023
10178
  }
10024
10179
  let startIndex;
10025
10180
  let endIndex;
@@ -10036,7 +10191,7 @@ var init_RunSelector = __esm({
10036
10191
  }
10037
10192
  }
10038
10193
  const visibleRuns = allRuns.slice(startIndex, endIndex);
10039
- return /* @__PURE__ */ React19.createElement(Box16, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React19.createElement(Box16, { marginBottom: 1 }, /* @__PURE__ */ React19.createElement(Text14, { bold: true, color: "cyan" }, "Select a Run to Fix")), /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column" }, visibleRuns.map((run, index) => {
10194
+ return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "cyan" }, "Select a Run to Fix")), /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column" }, visibleRuns.map((run, index) => {
10040
10195
  const actualIndex = startIndex + index;
10041
10196
  const isSelected = actualIndex === selectedIndex;
10042
10197
  const branch = run.git?.branch || "unknown";
@@ -10048,15 +10203,15 @@ var init_RunSelector = __esm({
10048
10203
  const hasFailures = failed > 0;
10049
10204
  const indicator = isSelected ? "\u25B6 " : " ";
10050
10205
  const bgColor = isSelected ? theme.text.accent : void 0;
10051
- return /* @__PURE__ */ React19.createElement(Box16, { key: run.id, width: "100%" }, /* @__PURE__ */ React19.createElement(Text14, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, indicator), /* @__PURE__ */ React19.createElement(Text14, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, branch, commit && /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, " @ ", commit)), /* @__PURE__ */ React19.createElement(Text14, null, " "), /* @__PURE__ */ React19.createElement(Text14, { backgroundColor: bgColor, color: hasFailures ? isSelected ? "black" : "red" : isSelected ? "black" : "green" }, failed, " failed"), /* @__PURE__ */ React19.createElement(Text14, { backgroundColor: bgColor, color: isSelected ? "black" : theme.text.dim }, " / ", total, " total"), /* @__PURE__ */ React19.createElement(Text14, null, " "), /* @__PURE__ */ React19.createElement(Text14, { backgroundColor: bgColor, color: isSelected ? "black" : theme.text.dim }, timeAgo), /* @__PURE__ */ React19.createElement(Text14, null, " "), /* @__PURE__ */ React19.createElement(Text14, { backgroundColor: bgColor, color: isSelected ? "black" : theme.text.dim }, source));
10052
- })), /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column", marginTop: 1 }, (allRuns.length > VISIBLE_ITEMS || totalRuns > allRuns.length) && /* @__PURE__ */ React19.createElement(Box16, { marginBottom: 1 }, /* @__PURE__ */ React19.createElement(Text14, { color: "yellow" }, "Showing ", startIndex + 1, "-", endIndex, " of ", totalRuns || allRuns.length, " runs", hasMore && !isLoading && /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, " \u2022 Scroll for more"))), /* @__PURE__ */ React19.createElement(Box16, null, /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim }, "Use ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "\u2191\u2193"), " to navigate \u2022 ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "Enter"), " to select \u2022 ", /* @__PURE__ */ React19.createElement(Text14, { bold: true }, "ESC"), " to cancel")), isLoading && /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text14, { color: "cyan" }, "Loading more runs..."))));
10206
+ return /* @__PURE__ */ React20.createElement(Box17, { key: run.id, width: "100%" }, /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, indicator), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, branch, commit && /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, " @ ", commit)), /* @__PURE__ */ React20.createElement(Text15, null, " "), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, color: hasFailures ? isSelected ? "black" : "red" : isSelected ? "black" : "green" }, failed, " failed"), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, color: isSelected ? "black" : theme.text.dim }, " / ", total, " total"), /* @__PURE__ */ React20.createElement(Text15, null, " "), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, color: isSelected ? "black" : theme.text.dim }, timeAgo), /* @__PURE__ */ React20.createElement(Text15, null, " "), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, color: isSelected ? "black" : theme.text.dim }, source));
10207
+ })), /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column", marginTop: 1 }, (allRuns.length > VISIBLE_ITEMS || totalRuns > allRuns.length) && /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: "yellow" }, "Showing ", startIndex + 1, "-", endIndex, " of ", totalRuns || allRuns.length, " runs", hasMore && !isLoading && /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, " \u2022 Scroll for more"))), /* @__PURE__ */ React20.createElement(Box17, null, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Use ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "\u2191\u2193"), " to navigate \u2022 ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "Enter"), " to select \u2022 ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "ESC"), " to cancel")), isLoading && /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: "cyan" }, "Loading more runs..."))));
10053
10208
  };
10054
10209
  }
10055
10210
  });
10056
10211
 
10057
10212
  // src/ui/components/TestSelector.tsx
10058
- import { Box as Box17, Text as Text15, useInput as useInput3 } from "ink";
10059
- import React20, { useEffect as useEffect7, useState as useState7 } from "react";
10213
+ import { Box as Box18, Text as Text16, useInput as useInput3 } from "ink";
10214
+ import React21, { useEffect as useEffect7, useState as useState7 } from "react";
10060
10215
  var PAGE_SIZE2, VISIBLE_ITEMS2, TestSelector;
10061
10216
  var init_TestSelector = __esm({
10062
10217
  "src/ui/components/TestSelector.tsx"() {
@@ -10168,13 +10323,13 @@ var init_TestSelector = __esm({
10168
10323
  }
10169
10324
  });
10170
10325
  if (error) {
10171
- return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "red" }, "Error Loading Tests"), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, error), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "ESC"), " to go back")));
10326
+ return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "red" }, "Error Loading Tests"), /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, error), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "ESC"), " to go back")));
10172
10327
  }
10173
10328
  if (allTests.length === 0 && isLoading) {
10174
- return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "cyan" }, "Loading Failed Tests..."), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Fetching failed tests for this run"));
10329
+ return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "cyan" }, "Loading Failed Tests..."), /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "Fetching failed tests for this run"));
10175
10330
  }
10176
10331
  if (allTests.length === 0 && !isLoading) {
10177
- return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "green", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "green" }, "No Failed Tests"), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "All tests passed in this run. Nothing to fix!"), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "ESC"), " to go back")));
10332
+ return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "green", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "green" }, "No Failed Tests"), /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "All tests passed in this run. Nothing to fix!"), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "ESC"), " to go back")));
10178
10333
  }
10179
10334
  const testStartIndex = Math.max(0, cursorIndex - 1);
10180
10335
  const adjustedStart = isOnFixAll ? 0 : Math.max(0, testStartIndex - Math.floor(VISIBLE_ITEMS2 / 2));
@@ -10182,8 +10337,8 @@ var init_TestSelector = __esm({
10182
10337
  const visibleTests = allTests.slice(adjustedStart, adjustedEnd);
10183
10338
  const branch = run.git?.branch || "unknown";
10184
10339
  const commit = run.git?.commit?.slice(0, 7) || "";
10185
- return /* @__PURE__ */ React20.createElement(Box17, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text15, { bold: true, color: "cyan" }, "Run: ", branch, commit && /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, " @ ", commit), /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, " \u2022 "), /* @__PURE__ */ React20.createElement(Text15, { color: "red" }, allTests.length, " failed test", allTests.length !== 1 ? "s" : ""))), /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(
10186
- Text15,
10340
+ return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "cyan" }, "Run: ", branch, commit && /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " @ ", commit), /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " \u2022 "), /* @__PURE__ */ React21.createElement(Text16, { color: "red" }, allTests.length, " failed test", allTests.length !== 1 ? "s" : ""))), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column" }, /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(
10341
+ Text16,
10187
10342
  {
10188
10343
  backgroundColor: isOnFixAll ? theme.text.accent : void 0,
10189
10344
  bold: isOnFixAll,
@@ -10195,7 +10350,7 @@ var init_TestSelector = __esm({
10195
10350
  " Failed Test",
10196
10351
  allTests.length !== 1 ? "s" : "",
10197
10352
  "]"
10198
- )), /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")), visibleTests.map((test, index) => {
10353
+ )), /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")), visibleTests.map((test, index) => {
10199
10354
  const actualIndex = adjustedStart + index;
10200
10355
  const itemIndex = actualIndex + 1;
10201
10356
  const isSelected = itemIndex === cursorIndex;
@@ -10206,15 +10361,15 @@ var init_TestSelector = __esm({
10206
10361
  const title = test.title;
10207
10362
  const indicator = isSelected ? "\u25B6 " : " ";
10208
10363
  const bgColor = isSelected ? theme.text.accent : void 0;
10209
- return /* @__PURE__ */ React20.createElement(Box17, { key: test.id, marginBottom: 0 }, /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, indicator), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, color: isChecked ? "green" : isSelected ? "black" : theme.text.dim }, checkbox), /* @__PURE__ */ React20.createElement(Text15, null, " "), /* @__PURE__ */ React20.createElement(Text15, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, file, line && /* @__PURE__ */ React20.createElement(Text15, { color: isSelected ? "black" : theme.text.dim }, ":", line), /* @__PURE__ */ React20.createElement(Text15, { color: isSelected ? "black" : theme.text.dim }, " - "), title));
10210
- })), /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column", marginTop: 1 }, allTests.length > VISIBLE_ITEMS2 && /* @__PURE__ */ React20.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: "yellow" }, "Showing ", adjustedStart + 1, "-", adjustedEnd, " of ", totalTests || allTests.length, " failed tests", hasMore && !isLoading && /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, " \u2022 Scroll for more"))), /* @__PURE__ */ React20.createElement(Box17, null, /* @__PURE__ */ React20.createElement(Text15, { color: theme.text.dim }, /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "Space"), " toggle \u2022 ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "a"), " all \u2022 ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "n"), " none \u2022 ", /* @__PURE__ */ React20.createElement(Text15, { bold: true }, "Enter"), " fix selected")), selectedTests.size > 0 && /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: "green" }, selectedTests.size, " test", selectedTests.size !== 1 ? "s" : "", " selected")), isLoading && /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text15, { color: "cyan" }, "Loading more tests..."))));
10364
+ return /* @__PURE__ */ React21.createElement(Box18, { key: test.id, marginBottom: 0 }, /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, indicator), /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, color: isChecked ? "green" : isSelected ? "black" : theme.text.dim }, checkbox), /* @__PURE__ */ React21.createElement(Text16, null, " "), /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, file, line && /* @__PURE__ */ React21.createElement(Text16, { color: isSelected ? "black" : theme.text.dim }, ":", line), /* @__PURE__ */ React21.createElement(Text16, { color: isSelected ? "black" : theme.text.dim }, " - "), title));
10365
+ })), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column", marginTop: 1 }, allTests.length > VISIBLE_ITEMS2 && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", adjustedStart + 1, "-", adjustedEnd, " of ", totalTests || allTests.length, " failed tests", hasMore && !isLoading && /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " \u2022 Scroll for more"))), /* @__PURE__ */ React21.createElement(Box18, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Space"), " toggle \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "a"), " all \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "n"), " none \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Enter"), " fix selected")), selectedTests.size > 0 && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "green" }, selectedTests.size, " test", selectedTests.size !== 1 ? "s" : "", " selected")), isLoading && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "cyan" }, "Loading more tests..."))));
10211
10366
  };
10212
10367
  }
10213
10368
  });
10214
10369
 
10215
10370
  // src/ui/components/FixFlow.tsx
10216
- import { Box as Box18, Text as Text16, useInput as useInput4 } from "ink";
10217
- import React21, { useState as useState8 } from "react";
10371
+ import { Box as Box19, Text as Text17, useInput as useInput4 } from "ink";
10372
+ import React22, { useState as useState8 } from "react";
10218
10373
  var FixFlow;
10219
10374
  var init_FixFlow = __esm({
10220
10375
  "src/ui/components/FixFlow.tsx"() {
@@ -10285,7 +10440,7 @@ var init_FixFlow = __esm({
10285
10440
  };
10286
10441
  switch (step) {
10287
10442
  case "select-run":
10288
- return /* @__PURE__ */ React21.createElement(
10443
+ return /* @__PURE__ */ React22.createElement(
10289
10444
  RunSelector,
10290
10445
  {
10291
10446
  apiClient,
@@ -10298,7 +10453,7 @@ var init_FixFlow = __esm({
10298
10453
  if (!selectedRun) {
10299
10454
  return null;
10300
10455
  }
10301
- return /* @__PURE__ */ React21.createElement(
10456
+ return /* @__PURE__ */ React22.createElement(
10302
10457
  TestSelector,
10303
10458
  {
10304
10459
  apiClient,
@@ -10309,13 +10464,13 @@ var init_FixFlow = __esm({
10309
10464
  );
10310
10465
  case "loading-details":
10311
10466
  if (loadError) {
10312
- return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "red" }, "Error Loading Test Details"), /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, loadError), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "ESC"), " to go back")));
10467
+ return /* @__PURE__ */ React22.createElement(Box19, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: "red" }, "Error Loading Test Details"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, loadError), /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React22.createElement(Text17, { bold: true }, "ESC"), " to go back")));
10313
10468
  }
10314
- return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "cyan" }, "Loading Test Details..."), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "Fetching error messages, stack traces, and execution steps...")), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, loadingProgress.current, " / ", loadingProgress.total, " tests loaded")));
10469
+ return /* @__PURE__ */ React22.createElement(Box19, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: "cyan" }, "Loading Test Details..."), /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "Fetching error messages, stack traces, and execution steps...")), /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text17, { color: "yellow" }, loadingProgress.current, " / ", loadingProgress.total, " tests loaded")));
10315
10470
  case "fixing":
10316
- return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "cyan" }, "Fixing ", selectedTests.length, " Test", selectedTests.length !== 1 ? "s" : "", "..."), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, selectedTests.map((test, index) => /* @__PURE__ */ React21.createElement(Box18, { key: test.id }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, index + 1, ". ", test.file.split("/").pop(), ":", test.location?.line || "", " - ", test.title)))), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "The agent will now analyze and fix each test...")));
10471
+ return /* @__PURE__ */ React22.createElement(Box19, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: "cyan" }, "Fixing ", selectedTests.length, " Test", selectedTests.length !== 1 ? "s" : "", "..."), /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }, selectedTests.map((test, index) => /* @__PURE__ */ React22.createElement(Box19, { key: test.id }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, index + 1, ". ", test.file.split("/").pop(), ":", test.location?.line || "", " - ", test.title)))), /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "The agent will now analyze and fix each test...")));
10317
10472
  case "complete":
10318
- return /* @__PURE__ */ React21.createElement(Box18, { borderColor: "green", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Text16, { bold: true, color: "green" }, "Fix Complete"), /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, "Press any key to continue..."));
10473
+ return /* @__PURE__ */ React22.createElement(Box19, { borderColor: "green", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: "green" }, "Fix Complete"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "Press any key to continue..."));
10319
10474
  default:
10320
10475
  return null;
10321
10476
  }
@@ -10324,8 +10479,8 @@ var init_FixFlow = __esm({
10324
10479
  });
10325
10480
 
10326
10481
  // src/ui/components/HelpMenu.tsx
10327
- import { Box as Box19, Text as Text17, useInput as useInput5 } from "ink";
10328
- import React22, { useEffect as useEffect9, useState as useState9 } from "react";
10482
+ import { Box as Box20, Text as Text18, useInput as useInput5 } from "ink";
10483
+ import React23, { useEffect as useEffect9, useState as useState9 } from "react";
10329
10484
  var HelpMenu;
10330
10485
  var init_HelpMenu = __esm({
10331
10486
  "src/ui/components/HelpMenu.tsx"() {
@@ -10344,8 +10499,8 @@ var init_HelpMenu = __esm({
10344
10499
  onClose();
10345
10500
  }
10346
10501
  });
10347
- return /* @__PURE__ */ React22.createElement(
10348
- Box19,
10502
+ return /* @__PURE__ */ React23.createElement(
10503
+ Box20,
10349
10504
  {
10350
10505
  borderColor: theme.border.accent,
10351
10506
  borderStyle: "round",
@@ -10353,21 +10508,21 @@ var init_HelpMenu = __esm({
10353
10508
  paddingX: 2,
10354
10509
  paddingY: 1
10355
10510
  },
10356
- /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.accent }, "\u{1F4D6} Supatest AI CLI - Help"),
10357
- /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }),
10358
- /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "Slash Commands:"),
10359
- /* @__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"))),
10360
- 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)"))),
10361
- /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }),
10362
- /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "Keyboard Shortcuts:"),
10363
- /* @__PURE__ */ React22.createElement(Box19, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "?"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " ", "- Toggle help (when input is empty)")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Ctrl+H"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Toggle help")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Ctrl+C"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " ", "- Exit (or clear input if not empty)")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Ctrl+D"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Exit immediately")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Ctrl+L"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Clear terminal screen")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Ctrl+U"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Clear current input line")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "ESC"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Interrupt running agent")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Shift+Enter"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Add new line in input")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "ctrl+o"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Toggle tool outputs")), /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "Ctrl+M"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " - Cycle through models"))),
10364
- /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }),
10365
- /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "File References:"),
10366
- /* @__PURE__ */ React22.createElement(Box19, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React22.createElement(Text17, null, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.accent }, "@filename"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, " ", "- Reference a file (autocomplete with Tab)")), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, 'Example: "Fix the bug in @src/app.ts"')),
10367
- /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }),
10368
- /* @__PURE__ */ React22.createElement(Text17, { bold: true, color: theme.text.secondary }, "Tips:"),
10369
- /* @__PURE__ */ React22.createElement(Box19, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "\u2022 Press Enter to submit your task"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "\u2022 Use Shift+Enter to write multi-line prompts"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "\u2022 Drag and drop files into the terminal to add file paths"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "\u2022 The agent will automatically run tools and fix issues"), /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "\u2022 Use Ctrl+L to clear the terminal screen without clearing the messages history")),
10370
- /* @__PURE__ */ React22.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text17, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React22.createElement(Text17, { bold: true }, "ESC"), " or ", /* @__PURE__ */ React22.createElement(Text17, { bold: true }, "?"), " to close"))
10511
+ /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.accent }, "\u{1F4D6} Supatest AI CLI - Help"),
10512
+ /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
10513
+ /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Slash Commands:"),
10514
+ /* @__PURE__ */ React23.createElement(Box20, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/help"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " or "), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/?"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Toggle this help menu")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/resume"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Resume a previous session")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/clear"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Clear message history")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/model"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Cycle through available models")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/provider"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Select LLM provider (Supatest Managed or Claude Max)")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/setup"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Initial setup for Supatest CLI")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/discover"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Discover test framework and write to SUPATEST.md")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/feedback"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Report an issue or request a feature")), isAuthenticated ? /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/logout"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Log out of Supatest")) : /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/login"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Authenticate with Supatest")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/exit"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Exit the CLI"))),
10515
+ customCommands.length > 0 && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }), /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Project Commands:"), /* @__PURE__ */ React23.createElement(Box20, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, customCommands.slice(0, 5).map((cmd) => /* @__PURE__ */ React23.createElement(Text18, { key: cmd.name }, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "/", cmd.name), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, cmd.description ? ` - ${cmd.description}` : ""))), customCommands.length > 5 && /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "...and ", customCommands.length - 5, " more (use Tab to autocomplete)"))),
10516
+ /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
10517
+ /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Keyboard Shortcuts:"),
10518
+ /* @__PURE__ */ React23.createElement(Box20, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "?"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " ", "- Toggle help (when input is empty)")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Ctrl+H"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Toggle help")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Ctrl+C"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " ", "- Exit (or clear input if not empty)")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Ctrl+D"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Exit immediately")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Ctrl+L"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Clear terminal screen")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Ctrl+U"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Clear current input line")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "ESC"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Interrupt running agent")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Shift+Enter"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Add new line in input")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "ctrl+o"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Toggle tool outputs")), /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "Ctrl+M"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " - Cycle through models"))),
10519
+ /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
10520
+ /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "File References:"),
10521
+ /* @__PURE__ */ React23.createElement(Box20, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React23.createElement(Text18, null, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.accent }, "@filename"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, " ", "- Reference a file (autocomplete with Tab)")), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, 'Example: "Fix the bug in @src/app.ts"')),
10522
+ /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
10523
+ /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Tips:"),
10524
+ /* @__PURE__ */ React23.createElement(Box20, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "\u2022 Press Enter to submit your task"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "\u2022 Use Shift+Enter to write multi-line prompts"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "\u2022 Drag and drop files into the terminal to add file paths"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "\u2022 The agent will automatically run tools and fix issues"), /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "\u2022 Use Ctrl+L to clear the terminal screen without clearing the messages history")),
10525
+ /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React23.createElement(Text18, { bold: true }, "ESC"), " or ", /* @__PURE__ */ React23.createElement(Text18, { bold: true }, "?"), " to close"))
10371
10526
  );
10372
10527
  };
10373
10528
  }
@@ -10456,12 +10611,27 @@ var init_file_completion = __esm({
10456
10611
  });
10457
10612
 
10458
10613
  // src/ui/components/ModelSelector.tsx
10459
- import { Box as Box20, Text as Text18, useInput as useInput6 } from "ink";
10460
- import React23, { useState as useState10 } from "react";
10461
- function getNextModel(currentModel) {
10462
- const currentIndex = AVAILABLE_MODELS.findIndex((m) => m.id === currentModel);
10463
- const nextIndex = (currentIndex + 1) % AVAILABLE_MODELS.length;
10464
- return AVAILABLE_MODELS[nextIndex].id;
10614
+ import { Box as Box21, Text as Text19, useInput as useInput6 } from "ink";
10615
+ import React24, { useState as useState10 } from "react";
10616
+ function getAvailableModels(isClaudeMax) {
10617
+ if (isClaudeMax) {
10618
+ return AVAILABLE_MODELS.map((m) => ({
10619
+ id: m.id,
10620
+ name: m.name,
10621
+ description: m.description
10622
+ }));
10623
+ }
10624
+ return MODEL_TIERS.map((tier) => ({
10625
+ id: tier,
10626
+ name: getModelDisplayName(tier),
10627
+ description: tier === "small" ? "Fast & lightweight" : tier === "medium" ? "Balanced performance" : "Most capable"
10628
+ }));
10629
+ }
10630
+ function getNextModel(currentModel, isClaudeMax = false) {
10631
+ const models = getAvailableModels(isClaudeMax);
10632
+ const currentIndex = models.findIndex((m) => m.id === currentModel);
10633
+ const nextIndex = (currentIndex + 1) % models.length;
10634
+ return models[nextIndex].id;
10465
10635
  }
10466
10636
  var ModelSelector;
10467
10637
  var init_ModelSelector = __esm({
@@ -10472,27 +10642,29 @@ var init_ModelSelector = __esm({
10472
10642
  ModelSelector = ({
10473
10643
  currentModel,
10474
10644
  onSelect,
10475
- onCancel
10645
+ onCancel,
10646
+ isClaudeMax = false
10476
10647
  }) => {
10477
- const currentIndex = AVAILABLE_MODELS.findIndex((m) => m.id === currentModel);
10648
+ const models = getAvailableModels(isClaudeMax);
10649
+ const currentIndex = models.findIndex((m) => m.id === currentModel);
10478
10650
  const [selectedIndex, setSelectedIndex] = useState10(currentIndex >= 0 ? currentIndex : 0);
10479
10651
  useInput6((input, key) => {
10480
10652
  if (key.upArrow) {
10481
- setSelectedIndex((prev) => prev > 0 ? prev - 1 : AVAILABLE_MODELS.length - 1);
10653
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : models.length - 1);
10482
10654
  } else if (key.downArrow) {
10483
- setSelectedIndex((prev) => prev < AVAILABLE_MODELS.length - 1 ? prev + 1 : 0);
10655
+ setSelectedIndex((prev) => prev < models.length - 1 ? prev + 1 : 0);
10484
10656
  } else if (key.return) {
10485
- onSelect(AVAILABLE_MODELS[selectedIndex].id);
10657
+ onSelect(models[selectedIndex].id);
10486
10658
  } else if (key.escape || input === "q") {
10487
10659
  onCancel();
10488
10660
  }
10489
10661
  });
10490
- return /* @__PURE__ */ React23.createElement(Box20, { borderColor: theme.border.accent, borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React23.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.accent }, "Select Model")), /* @__PURE__ */ React23.createElement(Box20, { flexDirection: "column" }, AVAILABLE_MODELS.map((model, index) => {
10662
+ return /* @__PURE__ */ React24.createElement(Box21, { borderColor: theme.border.accent, borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React24.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React24.createElement(Text19, { bold: true, color: theme.text.accent }, "Select Model")), /* @__PURE__ */ React24.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim }, "Cost: ", /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.info }, "0.5x"), " (Small) \u2022 ", /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.info }, "1x"), " (Medium) \u2022 ", /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.info }, "2x"), " (Premium)")), /* @__PURE__ */ React24.createElement(Box21, { flexDirection: "column" }, models.map((model, index) => {
10491
10663
  const isSelected = index === selectedIndex;
10492
10664
  const isCurrent = model.id === currentModel;
10493
10665
  const indicator = isSelected ? "\u25B6 " : " ";
10494
- return /* @__PURE__ */ React23.createElement(Box20, { gap: 1, key: model.id }, /* @__PURE__ */ React23.createElement(
10495
- Text18,
10666
+ return /* @__PURE__ */ React24.createElement(Box21, { gap: 1, key: model.id }, /* @__PURE__ */ React24.createElement(
10667
+ Text19,
10496
10668
  {
10497
10669
  backgroundColor: isSelected ? theme.text.accent : void 0,
10498
10670
  bold: isSelected,
@@ -10500,15 +10672,15 @@ var init_ModelSelector = __esm({
10500
10672
  },
10501
10673
  indicator,
10502
10674
  model.name.padEnd(12)
10503
- ), /* @__PURE__ */ React23.createElement(
10504
- Text18,
10675
+ ), /* @__PURE__ */ React24.createElement(
10676
+ Text19,
10505
10677
  {
10506
10678
  backgroundColor: isSelected ? theme.text.accent : void 0,
10507
10679
  color: isSelected ? "black" : theme.text.dim
10508
10680
  },
10509
10681
  model.description
10510
- ), isCurrent && /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.success }, " (current)"));
10511
- })), /* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text18, { color: theme.text.dim }, /* @__PURE__ */ React23.createElement(Text18, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React23.createElement(Text18, { bold: true }, "Enter"), " select \u2022 ", /* @__PURE__ */ React23.createElement(Text18, { bold: true }, "ESC"), " cancel")));
10682
+ ), isCurrent && /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.success }, " (current)"));
10683
+ })), /* @__PURE__ */ React24.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim }, /* @__PURE__ */ React24.createElement(Text19, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React24.createElement(Text19, { bold: true }, "Enter"), " select \u2022 ", /* @__PURE__ */ React24.createElement(Text19, { bold: true }, "ESC"), " cancel")));
10512
10684
  };
10513
10685
  }
10514
10686
  });
@@ -10516,8 +10688,8 @@ var init_ModelSelector = __esm({
10516
10688
  // src/ui/components/InputPrompt.tsx
10517
10689
  import path5 from "path";
10518
10690
  import chalk4 from "chalk";
10519
- import { Box as Box21, Text as Text19 } from "ink";
10520
- import React24, { forwardRef, useEffect as useEffect10, useImperativeHandle, useState as useState11 } from "react";
10691
+ import { Box as Box22, Text as Text20 } from "ink";
10692
+ import React25, { forwardRef, useEffect as useEffect10, useImperativeHandle, useState as useState11 } from "react";
10521
10693
  var InputPrompt;
10522
10694
  var init_InputPrompt = __esm({
10523
10695
  "src/ui/components/InputPrompt.tsx"() {
@@ -10537,7 +10709,8 @@ var init_InputPrompt = __esm({
10537
10709
  cwd,
10538
10710
  currentFolder,
10539
10711
  gitBranch,
10540
- onInputChange
10712
+ onInputChange,
10713
+ isClaudeMax = false
10541
10714
  }, ref) => {
10542
10715
  const { messages, agentMode, selectedModel, setSelectedModel, isAgentRunning, usageStats } = useSession();
10543
10716
  const [value, setValue] = useState11("");
@@ -10552,6 +10725,7 @@ var init_InputPrompt = __esm({
10552
10725
  { name: "/resume", desc: "Resume session" },
10553
10726
  { name: "/clear", desc: "Clear history" },
10554
10727
  { name: "/model", desc: "Change model" },
10728
+ { name: "/provider", desc: "Select LLM provider" },
10555
10729
  { name: "/fix", desc: "Fix failing tests" },
10556
10730
  { name: "/feedback", desc: "Report an issue" },
10557
10731
  { name: "/setup", desc: "Install Playwright browsers" },
@@ -10694,7 +10868,7 @@ var init_InputPrompt = __esm({
10694
10868
  }
10695
10869
  }
10696
10870
  if (key.shift && key.name === "m" && !isAgentRunning) {
10697
- setSelectedModel(getNextModel(selectedModel));
10871
+ setSelectedModel(getNextModel(selectedModel, isClaudeMax));
10698
10872
  return;
10699
10873
  }
10700
10874
  if (input === "?" && value.length === 0 && onHelpToggle) {
@@ -10783,8 +10957,8 @@ var init_InputPrompt = __esm({
10783
10957
  }
10784
10958
  charCount += lineLength + 1;
10785
10959
  }
10786
- return /* @__PURE__ */ React24.createElement(Box21, { flexDirection: "column", width: "100%" }, showSuggestions && /* @__PURE__ */ React24.createElement(
10787
- Box21,
10960
+ return /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "column", width: "100%" }, showSuggestions && /* @__PURE__ */ React25.createElement(
10961
+ Box22,
10788
10962
  {
10789
10963
  borderColor: theme.border.default,
10790
10964
  borderStyle: "round",
@@ -10795,12 +10969,12 @@ var init_InputPrompt = __esm({
10795
10969
  suggestions.map((item, idx) => {
10796
10970
  const isSeparator = item.startsWith("\u2500\u2500\u2500\u2500\u2500");
10797
10971
  if (isSeparator) {
10798
- return /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim, key: item }, " ", item);
10972
+ return /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim, key: item }, " ", item);
10799
10973
  }
10800
- return /* @__PURE__ */ React24.createElement(Text19, { color: idx === activeSuggestion ? theme.text.accent : theme.text.dim, key: item }, idx === activeSuggestion ? "\u276F " : " ", item);
10974
+ return /* @__PURE__ */ React25.createElement(Text20, { color: idx === activeSuggestion ? theme.text.accent : theme.text.dim, key: item }, idx === activeSuggestion ? "\u276F " : " ", item);
10801
10975
  })
10802
- ), /* @__PURE__ */ React24.createElement(
10803
- Box21,
10976
+ ), /* @__PURE__ */ React25.createElement(
10977
+ Box22,
10804
10978
  {
10805
10979
  borderColor: disabled ? theme.border.default : theme.border.accent,
10806
10980
  borderStyle: "round",
@@ -10810,24 +10984,96 @@ var init_InputPrompt = __esm({
10810
10984
  paddingX: 1,
10811
10985
  width: "100%"
10812
10986
  },
10813
- /* @__PURE__ */ React24.createElement(Box21, { flexDirection: "row" }, /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.accent }, "\u276F "), /* @__PURE__ */ React24.createElement(Box21, { flexDirection: "column", flexGrow: 1 }, !hasContent && !disabled && /* @__PURE__ */ React24.createElement(Text19, null, chalk4.inverse(placeholder.slice(0, 1)), /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim, italic: true }, placeholder.slice(1))), lines.length > 0 && /* @__PURE__ */ React24.createElement(Box21, { flexDirection: "column" }, lines.map((line, idx) => {
10987
+ /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "row" }, /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.accent }, "\u276F "), /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "column", flexGrow: 1 }, !hasContent && !disabled && /* @__PURE__ */ React25.createElement(Text20, null, chalk4.inverse(placeholder.slice(0, 1)), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim, italic: true }, placeholder.slice(1))), lines.length > 0 && /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "column" }, lines.map((line, idx) => {
10814
10988
  if (idx === cursorLine && !disabled) {
10815
10989
  const before = line.slice(0, cursorCol);
10816
10990
  const charAtCursor = line[cursorCol] || " ";
10817
10991
  const after = line.slice(cursorCol + 1);
10818
- return /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.primary, key: idx }, before, chalk4.inverse(charAtCursor), after);
10992
+ return /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.primary, key: idx }, before, chalk4.inverse(charAtCursor), after);
10819
10993
  }
10820
- return /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.primary, key: idx }, line);
10821
- })), !hasContent && disabled && /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim, italic: true }, "Waiting for agent to complete...")))
10822
- ), /* @__PURE__ */ React24.createElement(Box21, { justifyContent: "space-between", paddingX: 1 }, /* @__PURE__ */ React24.createElement(Box21, { gap: 2 }, /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text19, { color: agentMode === "plan" ? theme.status.inProgress : theme.text.dim }, agentMode === "plan" ? "\u23F8 plan" : "\u25B6 build"), /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim }, " (shift+tab)")), /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim }, "model:"), /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.info }, getModelDisplayName(selectedModel)), /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim }, " (shift+m)"))), /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text19, { color: usageStats && usageStats.contextPct >= 90 ? theme.text.error : usageStats && usageStats.contextPct >= 75 ? theme.text.warning : theme.text.dim }, usageStats?.contextPct ?? 0, "% context used"), /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.dim }, " ", "(", usageStats ? usageStats.inputTokens >= 1e3 ? `${(usageStats.inputTokens / 1e3).toFixed(1)}K` : usageStats.inputTokens : 0, " / ", usageStats ? usageStats.contextWindow >= 1e3 ? `${(usageStats.contextWindow / 1e3).toFixed(0)}K` : usageStats.contextWindow : "200K", ")"))));
10994
+ return /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.primary, key: idx }, line);
10995
+ })), !hasContent && disabled && /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim, italic: true }, "Waiting for agent to complete...")))
10996
+ ), /* @__PURE__ */ React25.createElement(Box22, { justifyContent: "space-between", paddingX: 1 }, /* @__PURE__ */ React25.createElement(Box22, { gap: 2 }, /* @__PURE__ */ React25.createElement(Box22, null, /* @__PURE__ */ React25.createElement(Text20, { color: agentMode === "plan" ? theme.status.inProgress : theme.text.dim }, agentMode === "plan" ? "\u23F8 plan" : "\u25B6 build"), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, " (shift+tab)")), /* @__PURE__ */ React25.createElement(Box22, null, /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, "model:"), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.info }, getModelDisplayName(selectedModel)), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, " (Cost: "), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.info }, getModelCostLabel(selectedModel)), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, ") (shift+m)"))), /* @__PURE__ */ React25.createElement(Box22, null, /* @__PURE__ */ React25.createElement(Text20, { color: usageStats && usageStats.contextPct >= 90 ? theme.text.error : usageStats && usageStats.contextPct >= 75 ? theme.text.warning : theme.text.dim }, usageStats?.contextPct ?? 0, "% context used"), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, " ", "(", usageStats ? usageStats.inputTokens >= 1e3 ? `${(usageStats.inputTokens / 1e3).toFixed(1)}K` : usageStats.inputTokens : 0, " / ", usageStats ? usageStats.contextWindow >= 1e3 ? `${(usageStats.contextWindow / 1e3).toFixed(0)}K` : usageStats.contextWindow : "200K", ")"))));
10823
10997
  });
10824
10998
  InputPrompt.displayName = "InputPrompt";
10825
10999
  }
10826
11000
  });
10827
11001
 
11002
+ // src/ui/components/ProviderSelector.tsx
11003
+ import { Box as Box23, Text as Text21, useInput as useInput7 } from "ink";
11004
+ import React26, { useState as useState12 } from "react";
11005
+ var PROVIDERS, ProviderSelector;
11006
+ var init_ProviderSelector = __esm({
11007
+ "src/ui/components/ProviderSelector.tsx"() {
11008
+ "use strict";
11009
+ init_theme();
11010
+ PROVIDERS = [
11011
+ {
11012
+ id: "supatest-managed",
11013
+ name: "Supatest Managed",
11014
+ description: "Uses Supatest API with available models"
11015
+ },
11016
+ {
11017
+ id: "claude-max",
11018
+ name: "Claude Max",
11019
+ description: "Direct Claude Max subscription (requires Claude Code login)"
11020
+ }
11021
+ ];
11022
+ ProviderSelector = ({
11023
+ currentProvider,
11024
+ onSelect,
11025
+ onCancel,
11026
+ claudeMaxAvailable
11027
+ }) => {
11028
+ const availableProviders = PROVIDERS.filter(
11029
+ (p) => p.id !== "claude-max" || claudeMaxAvailable
11030
+ );
11031
+ const currentIndex = availableProviders.findIndex(
11032
+ (p) => p.id === currentProvider
11033
+ );
11034
+ const [selectedIndex, setSelectedIndex] = useState12(
11035
+ currentIndex >= 0 ? currentIndex : 0
11036
+ );
11037
+ useInput7((input, key) => {
11038
+ if (key.upArrow) {
11039
+ setSelectedIndex(
11040
+ (prev) => prev > 0 ? prev - 1 : availableProviders.length - 1
11041
+ );
11042
+ } else if (key.downArrow) {
11043
+ setSelectedIndex(
11044
+ (prev) => prev < availableProviders.length - 1 ? prev + 1 : 0
11045
+ );
11046
+ } else if (key.return) {
11047
+ onSelect(availableProviders[selectedIndex].id);
11048
+ } else if (key.escape || input === "q") {
11049
+ onCancel();
11050
+ }
11051
+ });
11052
+ return /* @__PURE__ */ React26.createElement(Box23, { borderColor: theme.border.accent, borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React26.createElement(Box23, { marginBottom: 1 }, /* @__PURE__ */ React26.createElement(Text21, { bold: true, color: theme.text.accent }, "Select LLM Provider")), /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column" }, availableProviders.map((provider, index) => {
11053
+ const isSelected = index === selectedIndex;
11054
+ const isCurrent = provider.id === currentProvider;
11055
+ const indicator = isSelected ? "\u25B6 " : " ";
11056
+ return /* @__PURE__ */ React26.createElement(
11057
+ Text21,
11058
+ {
11059
+ backgroundColor: isSelected ? theme.text.accent : void 0,
11060
+ bold: isSelected,
11061
+ color: isSelected ? "black" : theme.text.primary,
11062
+ key: provider.id
11063
+ },
11064
+ indicator,
11065
+ provider.name,
11066
+ isCurrent && /* @__PURE__ */ React26.createElement(Text21, { color: isSelected ? "black" : theme.text.success }, " (current)"),
11067
+ /* @__PURE__ */ React26.createElement(Text21, { color: isSelected ? "black" : theme.text.dim }, " - ", provider.description)
11068
+ );
11069
+ })), /* @__PURE__ */ React26.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text21, { color: theme.text.dim }, /* @__PURE__ */ React26.createElement(Text21, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React26.createElement(Text21, { bold: true }, "Enter"), " select \u2022", " ", /* @__PURE__ */ React26.createElement(Text21, { bold: true }, "ESC"), " cancel")));
11070
+ };
11071
+ }
11072
+ });
11073
+
10828
11074
  // src/ui/components/SessionSelector.tsx
10829
- import { Box as Box22, Text as Text20, useInput as useInput7 } from "ink";
10830
- import React25, { useEffect as useEffect11, useState as useState12 } from "react";
11075
+ import { Box as Box24, Text as Text22, useInput as useInput8 } from "ink";
11076
+ import React27, { useEffect as useEffect11, useState as useState13 } from "react";
10831
11077
  function getSessionPrefix(authMethod) {
10832
11078
  return authMethod === "api-key" ? "[Team]" : "[Me]";
10833
11079
  }
@@ -10842,12 +11088,12 @@ var init_SessionSelector = __esm({
10842
11088
  onSelect,
10843
11089
  onCancel
10844
11090
  }) => {
10845
- const [allSessions, setAllSessions] = useState12([]);
10846
- const [selectedIndex, setSelectedIndex] = useState12(0);
10847
- const [isLoading, setIsLoading] = useState12(false);
10848
- const [hasMore, setHasMore] = useState12(true);
10849
- const [totalSessions, setTotalSessions] = useState12(0);
10850
- const [error, setError] = useState12(null);
11091
+ const [allSessions, setAllSessions] = useState13([]);
11092
+ const [selectedIndex, setSelectedIndex] = useState13(0);
11093
+ const [isLoading, setIsLoading] = useState13(false);
11094
+ const [hasMore, setHasMore] = useState13(true);
11095
+ const [totalSessions, setTotalSessions] = useState13(0);
11096
+ const [error, setError] = useState13(null);
10851
11097
  useEffect11(() => {
10852
11098
  loadMoreSessions();
10853
11099
  }, []);
@@ -10874,7 +11120,7 @@ var init_SessionSelector = __esm({
10874
11120
  setIsLoading(false);
10875
11121
  }
10876
11122
  };
10877
- useInput7((input, key) => {
11123
+ useInput8((input, key) => {
10878
11124
  if (allSessions.length === 0) {
10879
11125
  if (key.escape || input === "q") {
10880
11126
  onCancel();
@@ -10898,13 +11144,13 @@ var init_SessionSelector = __esm({
10898
11144
  }
10899
11145
  });
10900
11146
  if (error) {
10901
- return /* @__PURE__ */ React25.createElement(Box22, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "red" }, "Error Loading Sessions"), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, error), /* @__PURE__ */ React25.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React25.createElement(Text20, { bold: true }, "ESC"), " to cancel")));
11147
+ return /* @__PURE__ */ React27.createElement(Box24, { borderColor: "red", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React27.createElement(Text22, { bold: true, color: "red" }, "Error Loading Sessions"), /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, error), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React27.createElement(Text22, { bold: true }, "ESC"), " to cancel")));
10902
11148
  }
10903
11149
  if (allSessions.length === 0 && isLoading) {
10904
- return /* @__PURE__ */ React25.createElement(Box22, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "cyan" }, "Loading Sessions..."), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, "Fetching your sessions from the server"));
11150
+ return /* @__PURE__ */ React27.createElement(Box24, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React27.createElement(Text22, { bold: true, color: "cyan" }, "Loading Sessions..."), /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, "Fetching your sessions from the server"));
10905
11151
  }
10906
11152
  if (allSessions.length === 0 && !isLoading) {
10907
- return /* @__PURE__ */ React25.createElement(Box22, { borderColor: "yellow", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "yellow" }, "No Sessions Found"), /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, "No previous sessions available. Start a new conversation!"), /* @__PURE__ */ React25.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React25.createElement(Text20, { bold: true }, "ESC"), " to cancel")));
11153
+ return /* @__PURE__ */ React27.createElement(Box24, { borderColor: "yellow", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React27.createElement(Text22, { bold: true, color: "yellow" }, "No Sessions Found"), /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, "No previous sessions available. Start a new conversation!"), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, "Press ", /* @__PURE__ */ React27.createElement(Text22, { bold: true }, "ESC"), " to cancel")));
10908
11154
  }
10909
11155
  const VISIBLE_ITEMS3 = 10;
10910
11156
  let startIndex;
@@ -10924,7 +11170,7 @@ var init_SessionSelector = __esm({
10924
11170
  const visibleSessions = allSessions.slice(startIndex, endIndex);
10925
11171
  const MAX_TITLE_WIDTH = 50;
10926
11172
  const PREFIX_WIDTH = 6;
10927
- return /* @__PURE__ */ React25.createElement(Box22, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React25.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "cyan" }, "Select a Session to Resume")), /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "column" }, visibleSessions.map((item, index) => {
11173
+ return /* @__PURE__ */ React27.createElement(Box24, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React27.createElement(Box24, { marginBottom: 1 }, /* @__PURE__ */ React27.createElement(Text22, { bold: true, color: "cyan" }, "Select a Session to Resume")), /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column" }, visibleSessions.map((item, index) => {
10928
11174
  const actualIndex = startIndex + index;
10929
11175
  const isSelected = actualIndex === selectedIndex;
10930
11176
  const title = item.session.title || "Untitled session";
@@ -10948,8 +11194,8 @@ var init_SessionSelector = __esm({
10948
11194
  const prefixColor = item.prefix === "[Me]" ? "cyan" : "yellow";
10949
11195
  const indicator = isSelected ? "\u25B6 " : " ";
10950
11196
  const bgColor = isSelected ? theme.text.accent : void 0;
10951
- return /* @__PURE__ */ React25.createElement(Box22, { key: item.session.id, width: "100%" }, /* @__PURE__ */ React25.createElement(Text20, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, indicator), /* @__PURE__ */ React25.createElement(Text20, { backgroundColor: bgColor, bold: isSelected, color: prefixColor }, prefix), /* @__PURE__ */ React25.createElement(Text20, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, displayTitle), /* @__PURE__ */ React25.createElement(Text20, { backgroundColor: bgColor, color: theme.text.dim }, "(", dateStr, ")"));
10952
- })), /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "column", marginTop: 1 }, (allSessions.length > VISIBLE_ITEMS3 || totalSessions > allSessions.length) && /* @__PURE__ */ React25.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React25.createElement(Text20, { color: "yellow" }, "Showing ", startIndex + 1, "-", endIndex, " of ", totalSessions || allSessions.length, " sessions", hasMore && !isLoading && /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, " \u2022 Scroll for more"))), /* @__PURE__ */ React25.createElement(Box22, null, /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim }, "Use ", /* @__PURE__ */ React25.createElement(Text20, { bold: true }, "\u2191\u2193"), " to navigate \u2022 ", /* @__PURE__ */ React25.createElement(Text20, { bold: true }, "Enter"), " to select \u2022 ", /* @__PURE__ */ React25.createElement(Text20, { bold: true }, "ESC"), " to cancel")), isLoading && /* @__PURE__ */ React25.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { color: "cyan" }, "Loading more sessions..."))));
11197
+ return /* @__PURE__ */ React27.createElement(Box24, { key: item.session.id, width: "100%" }, /* @__PURE__ */ React27.createElement(Text22, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, indicator), /* @__PURE__ */ React27.createElement(Text22, { backgroundColor: bgColor, bold: isSelected, color: prefixColor }, prefix), /* @__PURE__ */ React27.createElement(Text22, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : theme.text.primary }, displayTitle), /* @__PURE__ */ React27.createElement(Text22, { backgroundColor: bgColor, color: theme.text.dim }, "(", dateStr, ")"));
11198
+ })), /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", marginTop: 1 }, (allSessions.length > VISIBLE_ITEMS3 || totalSessions > allSessions.length) && /* @__PURE__ */ React27.createElement(Box24, { marginBottom: 1 }, /* @__PURE__ */ React27.createElement(Text22, { color: "yellow" }, "Showing ", startIndex + 1, "-", endIndex, " of ", totalSessions || allSessions.length, " sessions", hasMore && !isLoading && /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, " \u2022 Scroll for more"))), /* @__PURE__ */ React27.createElement(Box24, null, /* @__PURE__ */ React27.createElement(Text22, { color: theme.text.dim }, "Use ", /* @__PURE__ */ React27.createElement(Text22, { bold: true }, "\u2191\u2193"), " to navigate \u2022 ", /* @__PURE__ */ React27.createElement(Text22, { bold: true }, "Enter"), " to select \u2022 ", /* @__PURE__ */ React27.createElement(Text22, { bold: true }, "ESC"), " to cancel")), isLoading && /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text22, { color: "cyan" }, "Loading more sessions..."))));
10953
11199
  };
10954
11200
  }
10955
11201
  });
@@ -10980,18 +11226,18 @@ var init_useModeToggle = __esm({
10980
11226
  });
10981
11227
 
10982
11228
  // src/ui/hooks/useOverlayEscapeGuard.ts
10983
- import { useCallback as useCallback3, useMemo as useMemo4, useRef as useRef3 } from "react";
11229
+ import { useCallback as useCallback3, useMemo as useMemo5, useRef as useRef4 } from "react";
10984
11230
  var useOverlayEscapeGuard;
10985
11231
  var init_useOverlayEscapeGuard = __esm({
10986
11232
  "src/ui/hooks/useOverlayEscapeGuard.ts"() {
10987
11233
  "use strict";
10988
11234
  useOverlayEscapeGuard = ({ overlays, suppressionMs = 250 }) => {
10989
- const suppressUntilRef = useRef3(0);
11235
+ const suppressUntilRef = useRef4(0);
10990
11236
  const markOverlayClosed = useCallback3(() => {
10991
11237
  suppressUntilRef.current = Date.now() + suppressionMs;
10992
11238
  }, [suppressionMs]);
10993
11239
  const isCancelSuppressed = useCallback3(() => Date.now() < suppressUntilRef.current, []);
10994
- const isOverlayOpen = useMemo4(() => overlays.some(Boolean), [overlays]);
11240
+ const isOverlayOpen = useMemo5(() => overlays.some(Boolean), [overlays]);
10995
11241
  return { isOverlayOpen, isCancelSuppressed, markOverlayClosed };
10996
11242
  };
10997
11243
  }
@@ -11000,9 +11246,9 @@ var init_useOverlayEscapeGuard = __esm({
11000
11246
  // src/ui/App.tsx
11001
11247
  import { execSync as execSync6 } from "child_process";
11002
11248
  import { homedir as homedir6 } from "os";
11003
- import { Box as Box23, Text as Text21, useApp as useApp2, useStdout as useStdout2 } from "ink";
11249
+ import { Box as Box25, Text as Text23, useApp as useApp2, useStdout as useStdout2 } from "ink";
11004
11250
  import Spinner3 from "ink-spinner";
11005
- import React26, { useEffect as useEffect13, useRef as useRef4, useState as useState13 } from "react";
11251
+ import React28, { useEffect as useEffect13, useRef as useRef5, useState as useState14 } from "react";
11006
11252
  var getGitBranch2, getCurrentFolder2, AppContent, App;
11007
11253
  var init_App = __esm({
11008
11254
  "src/ui/App.tsx"() {
@@ -11011,7 +11257,9 @@ var init_App = __esm({
11011
11257
  init_login();
11012
11258
  init_setup();
11013
11259
  init_prompts();
11260
+ init_claude_max();
11014
11261
  init_command_discovery();
11262
+ init_settings_loader();
11015
11263
  init_stdio();
11016
11264
  init_token_storage();
11017
11265
  init_version();
@@ -11023,6 +11271,7 @@ var init_App = __esm({
11023
11271
  init_InputPrompt();
11024
11272
  init_MessageList();
11025
11273
  init_ModelSelector();
11274
+ init_ProviderSelector();
11026
11275
  init_SessionSelector();
11027
11276
  init_SessionContext();
11028
11277
  init_useKeypress();
@@ -11048,28 +11297,29 @@ var init_App = __esm({
11048
11297
  AppContent = ({ config: config2, sessionId, webUrl, queuedTasks = [], onExit, onSubmitTask, apiClient, onResumeSession, onClearSession }) => {
11049
11298
  const { exit } = useApp2();
11050
11299
  const { stdout } = useStdout2();
11051
- const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel, refreshStatic } = useSession();
11300
+ const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel, refreshStatic, toggleToolGroups, llmProvider, setLlmProvider } = useSession();
11052
11301
  useModeToggle();
11053
- const [terminalWidth, setTerminalWidth] = useState13(process.stdout.columns || 80);
11054
- const [showHelp, setShowHelp] = useState13(false);
11055
- const [showInput, setShowInput] = useState13(true);
11056
- const [gitBranch] = useState13(() => getGitBranch2());
11057
- const [currentFolder] = useState13(() => getCurrentFolder2(config2.cwd));
11058
- const [hasInputContent, setHasInputContent] = useState13(false);
11059
- const [exitWarning, setExitWarning] = useState13(null);
11060
- const inputPromptRef = useRef4(null);
11061
- const [showSessionSelector, setShowSessionSelector] = useState13(false);
11062
- const [showModelSelector, setShowModelSelector] = useState13(false);
11063
- const [showFeedbackDialog, setShowFeedbackDialog] = useState13(false);
11064
- const [isLoadingSession, setIsLoadingSession] = useState13(false);
11065
- const [showFixFlow, setShowFixFlow] = useState13(false);
11066
- const [fixRunId, setFixRunId] = useState13(void 0);
11067
- const [authState, setAuthState] = useState13(
11302
+ const [terminalWidth, setTerminalWidth] = useState14(process.stdout.columns || 80);
11303
+ const [showHelp, setShowHelp] = useState14(false);
11304
+ const [showInput, setShowInput] = useState14(true);
11305
+ const [gitBranch] = useState14(() => getGitBranch2());
11306
+ const [currentFolder] = useState14(() => getCurrentFolder2(config2.cwd));
11307
+ const [hasInputContent, setHasInputContent] = useState14(false);
11308
+ const [exitWarning, setExitWarning] = useState14(null);
11309
+ const inputPromptRef = useRef5(null);
11310
+ const [showSessionSelector, setShowSessionSelector] = useState14(false);
11311
+ const [showModelSelector, setShowModelSelector] = useState14(false);
11312
+ const [showProviderSelector, setShowProviderSelector] = useState14(false);
11313
+ const [showFeedbackDialog, setShowFeedbackDialog] = useState14(false);
11314
+ const [isLoadingSession, setIsLoadingSession] = useState14(false);
11315
+ const [showFixFlow, setShowFixFlow] = useState14(false);
11316
+ const [fixRunId, setFixRunId] = useState14(void 0);
11317
+ const [authState, setAuthState] = useState14(
11068
11318
  () => config2.supatestApiKey ? "authenticated" /* Authenticated */ : "unauthenticated" /* Unauthenticated */
11069
11319
  );
11070
- const [showAuthDialog, setShowAuthDialog] = useState13(false);
11320
+ const [showAuthDialog, setShowAuthDialog] = useState14(false);
11071
11321
  const { isOverlayOpen, isCancelSuppressed, markOverlayClosed } = useOverlayEscapeGuard({
11072
- overlays: [showHelp, showSessionSelector, showAuthDialog, showModelSelector, showFeedbackDialog, showFixFlow]
11322
+ overlays: [showHelp, showSessionSelector, showAuthDialog, showModelSelector, showProviderSelector, showFeedbackDialog, showFixFlow]
11073
11323
  });
11074
11324
  useEffect13(() => {
11075
11325
  if (!config2.supatestApiKey) {
@@ -11184,6 +11434,10 @@ var init_App = __esm({
11184
11434
  setShowModelSelector(true);
11185
11435
  return;
11186
11436
  }
11437
+ if (command === "/provider") {
11438
+ setShowProviderSelector(true);
11439
+ return;
11440
+ }
11187
11441
  if (command === "/fix" || command.startsWith("/fix ")) {
11188
11442
  if (authState !== "authenticated" /* Authenticated */) {
11189
11443
  addMessage({
@@ -11319,6 +11573,20 @@ var init_App = __esm({
11319
11573
  markOverlayClosed();
11320
11574
  setShowModelSelector(false);
11321
11575
  };
11576
+ const handleProviderSelect = (provider) => {
11577
+ setShowProviderSelector(false);
11578
+ markOverlayClosed();
11579
+ setLlmProvider(provider);
11580
+ saveSupatestSettings(config2.cwd || process.cwd(), { llmProvider: provider });
11581
+ addMessage({
11582
+ type: "assistant",
11583
+ content: `LLM Provider changed to: ${provider === "claude-max" ? "Claude Max" : "Supatest Managed"}. This setting has been saved and will persist across sessions.`
11584
+ });
11585
+ };
11586
+ const handleProviderSelectorCancel = () => {
11587
+ markOverlayClosed();
11588
+ setShowProviderSelector(false);
11589
+ };
11322
11590
  const handleFeedbackSubmit = async (category, description) => {
11323
11591
  setShowFeedbackDialog(false);
11324
11592
  markOverlayClosed();
@@ -11394,7 +11662,7 @@ var init_App = __esm({
11394
11662
  markOverlayClosed();
11395
11663
  setShowHelp(false);
11396
11664
  };
11397
- const isInitialMount = useRef4(true);
11665
+ const isInitialMount = useRef5(true);
11398
11666
  useEffect13(() => {
11399
11667
  const handleResize = () => {
11400
11668
  setTerminalWidth(process.stdout.columns || 80);
@@ -11463,7 +11731,7 @@ var init_App = __esm({
11463
11731
  clearTerminalViewportAndScrollback();
11464
11732
  }
11465
11733
  if (key.ctrl && key.name === "o") {
11466
- toggleAllToolOutputs();
11734
+ toggleToolGroups();
11467
11735
  }
11468
11736
  },
11469
11737
  { isActive: !isOverlayOpen }
@@ -11476,21 +11744,21 @@ var init_App = __esm({
11476
11744
  });
11477
11745
  }
11478
11746
  }, []);
11479
- return /* @__PURE__ */ React26.createElement(
11480
- Box23,
11747
+ return /* @__PURE__ */ React28.createElement(
11748
+ Box25,
11481
11749
  {
11482
11750
  flexDirection: "column",
11483
11751
  paddingX: 1
11484
11752
  },
11485
- /* @__PURE__ */ React26.createElement(MessageList, { currentFolder, gitBranch, queuedTasks, terminalWidth }),
11486
- showHelp && /* @__PURE__ */ React26.createElement(
11753
+ /* @__PURE__ */ React28.createElement(MessageList, { currentFolder, gitBranch, queuedTasks, terminalWidth }),
11754
+ showHelp && /* @__PURE__ */ React28.createElement(
11487
11755
  HelpMenu,
11488
11756
  {
11489
11757
  isAuthenticated: authState === "authenticated" /* Authenticated */,
11490
11758
  onClose: handleHelpClose
11491
11759
  }
11492
11760
  ),
11493
- showSessionSelector && apiClient && /* @__PURE__ */ React26.createElement(
11761
+ showSessionSelector && apiClient && /* @__PURE__ */ React28.createElement(
11494
11762
  SessionSelector,
11495
11763
  {
11496
11764
  apiClient,
@@ -11498,29 +11766,39 @@ var init_App = __esm({
11498
11766
  onSelect: handleSessionSelect
11499
11767
  }
11500
11768
  ),
11501
- isLoadingSession && /* @__PURE__ */ React26.createElement(Box23, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "row" }, /* @__PURE__ */ React26.createElement(Box23, { width: 2 }, /* @__PURE__ */ React26.createElement(Text21, { color: theme.text.accent }, /* @__PURE__ */ React26.createElement(Spinner3, { type: "dots" }))), /* @__PURE__ */ React26.createElement(Text21, { bold: true, color: "cyan" }, "Loading session...")), /* @__PURE__ */ React26.createElement(Text21, { color: theme.text.dim }, "Fetching queries and context")),
11502
- showModelSelector && /* @__PURE__ */ React26.createElement(
11769
+ isLoadingSession && /* @__PURE__ */ React28.createElement(Box25, { borderColor: "cyan", borderStyle: "round", flexDirection: "column", padding: 1 }, /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "row" }, /* @__PURE__ */ React28.createElement(Box25, { width: 2 }, /* @__PURE__ */ React28.createElement(Text23, { color: theme.text.accent }, /* @__PURE__ */ React28.createElement(Spinner3, { type: "dots" }))), /* @__PURE__ */ React28.createElement(Text23, { bold: true, color: "cyan" }, "Loading session...")), /* @__PURE__ */ React28.createElement(Text23, { color: theme.text.dim }, "Fetching queries and context")),
11770
+ showModelSelector && /* @__PURE__ */ React28.createElement(
11503
11771
  ModelSelector,
11504
11772
  {
11505
11773
  currentModel: selectedModel,
11774
+ isClaudeMax: !!config2.oauthToken,
11506
11775
  onCancel: handleModelSelectorCancel,
11507
11776
  onSelect: handleModelSelect
11508
11777
  }
11509
11778
  ),
11510
- showAuthDialog && /* @__PURE__ */ React26.createElement(
11779
+ showProviderSelector && /* @__PURE__ */ React28.createElement(
11780
+ ProviderSelector,
11781
+ {
11782
+ claudeMaxAvailable: isClaudeMaxAvailable(),
11783
+ currentProvider: llmProvider,
11784
+ onCancel: handleProviderSelectorCancel,
11785
+ onSelect: handleProviderSelect
11786
+ }
11787
+ ),
11788
+ showAuthDialog && /* @__PURE__ */ React28.createElement(
11511
11789
  AuthDialog,
11512
11790
  {
11513
11791
  onLogin: handleLogin
11514
11792
  }
11515
11793
  ),
11516
- showFeedbackDialog && /* @__PURE__ */ React26.createElement(
11794
+ showFeedbackDialog && /* @__PURE__ */ React28.createElement(
11517
11795
  FeedbackDialog,
11518
11796
  {
11519
11797
  onCancel: handleFeedbackCancel,
11520
11798
  onSubmit: handleFeedbackSubmit
11521
11799
  }
11522
11800
  ),
11523
- showFixFlow && apiClient && /* @__PURE__ */ React26.createElement(
11801
+ showFixFlow && apiClient && /* @__PURE__ */ React28.createElement(
11524
11802
  FixFlow,
11525
11803
  {
11526
11804
  apiClient,
@@ -11530,12 +11808,13 @@ var init_App = __esm({
11530
11808
  onStartFix: handleFixStart
11531
11809
  }
11532
11810
  ),
11533
- /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column" }, !showAuthDialog && /* @__PURE__ */ React26.createElement(AuthBanner, { authState }), showInput && !showSessionSelector && !showAuthDialog && !showHelp && !showModelSelector && !showFeedbackDialog && !showFixFlow && !isLoadingSession && /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column", marginTop: 0, width: "100%" }, exitWarning && /* @__PURE__ */ React26.createElement(Box23, { marginBottom: 0, paddingX: 1 }, /* @__PURE__ */ React26.createElement(Text21, { color: "yellow" }, exitWarning)), /* @__PURE__ */ React26.createElement(
11811
+ /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "column" }, !showAuthDialog && /* @__PURE__ */ React28.createElement(AuthBanner, { authState }), showInput && !showSessionSelector && !showAuthDialog && !showHelp && !showModelSelector && !showProviderSelector && !showFeedbackDialog && !showFixFlow && !isLoadingSession && /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "column", marginTop: 0, width: "100%" }, exitWarning && /* @__PURE__ */ React28.createElement(Box25, { marginBottom: 0, paddingX: 1 }, /* @__PURE__ */ React28.createElement(Text23, { color: "yellow" }, exitWarning)), /* @__PURE__ */ React28.createElement(
11534
11812
  InputPrompt,
11535
11813
  {
11536
11814
  currentFolder,
11537
11815
  cwd: config2.cwd,
11538
11816
  gitBranch,
11817
+ isClaudeMax: !!config2.oauthToken,
11539
11818
  onHelpToggle: () => setShowHelp((prev) => !prev),
11540
11819
  onInputChange: (val) => setHasInputContent(val.trim().length > 0),
11541
11820
  onSubmit: handleSubmitTask,
@@ -11546,7 +11825,7 @@ var init_App = __esm({
11546
11825
  );
11547
11826
  };
11548
11827
  App = (props) => {
11549
- return /* @__PURE__ */ React26.createElement(AppContent, { ...props });
11828
+ return /* @__PURE__ */ React28.createElement(AppContent, { ...props });
11550
11829
  };
11551
11830
  }
11552
11831
  });
@@ -11582,7 +11861,7 @@ __export(interactive_exports, {
11582
11861
  runInteractive: () => runInteractive
11583
11862
  });
11584
11863
  import { render as render2 } from "ink";
11585
- import React27, { useEffect as useEffect15, useRef as useRef5 } from "react";
11864
+ import React29, { useEffect as useEffect15, useRef as useRef6 } from "react";
11586
11865
  function getToolDescription2(toolName, input) {
11587
11866
  switch (toolName) {
11588
11867
  case "Read":
@@ -11715,7 +11994,7 @@ async function runInteractive(config2) {
11715
11994
  webUrl = session.webUrl;
11716
11995
  }
11717
11996
  const { unmount, waitUntilExit } = render2(
11718
- /* @__PURE__ */ React27.createElement(
11997
+ /* @__PURE__ */ React29.createElement(
11719
11998
  InteractiveApp,
11720
11999
  {
11721
12000
  apiClient,
@@ -11770,7 +12049,9 @@ var init_interactive = __esm({
11770
12049
  init_SessionContext();
11771
12050
  init_useBracketedPaste();
11772
12051
  init_mouse();
12052
+ init_claude_max();
11773
12053
  init_logger();
12054
+ init_settings_loader();
11774
12055
  init_stdio();
11775
12056
  init_version();
11776
12057
  AgentRunner = ({ config: config2, sessionId, apiClient, messageBridge, onComplete, onTurnComplete }) => {
@@ -11787,9 +12068,10 @@ var init_interactive = __esm({
11787
12068
  agentMode,
11788
12069
  setAgentMode,
11789
12070
  planFilePath,
11790
- selectedModel
12071
+ selectedModel,
12072
+ llmProvider
11791
12073
  } = useSession();
11792
- const agentRef = useRef5(null);
12074
+ const agentRef = useRef6(null);
11793
12075
  useEffect15(() => {
11794
12076
  if (shouldInterruptAgent && agentRef.current) {
11795
12077
  agentRef.current.abort();
@@ -11803,7 +12085,7 @@ var init_interactive = __esm({
11803
12085
  try {
11804
12086
  const supatestApiKey = apiClient.getApiKey?.() || config2.supatestApiKey || "";
11805
12087
  const proxyUrl = config2.supatestApiUrl || "https://code-api.supatest.ai";
11806
- const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}/anthropic`;
12088
+ const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}`;
11807
12089
  process.env.ANTHROPIC_BASE_URL = baseUrl;
11808
12090
  process.env.ANTHROPIC_API_KEY = supatestApiKey;
11809
12091
  const presenter = new ReactPresenter(
@@ -11844,12 +12126,22 @@ var init_interactive = __esm({
11844
12126
  sessionId,
11845
12127
  config2.verbose
11846
12128
  );
12129
+ let oauthToken;
12130
+ if (llmProvider === "claude-max") {
12131
+ if (isClaudeMaxAvailable()) {
12132
+ oauthToken = "use-claude-max";
12133
+ logger.info("Using Claude Max subscription for LLM calls");
12134
+ } else {
12135
+ logger.warn("Claude Max selected but not available. Falling back to Supatest Managed.");
12136
+ }
12137
+ }
11847
12138
  const runConfig = {
11848
12139
  ...config2,
11849
12140
  supatestApiKey,
11850
12141
  mode: agentMode,
11851
12142
  planFilePath,
11852
12143
  selectedModel,
12144
+ oauthToken,
11853
12145
  systemPromptAppend: agentMode === "plan" ? config.planSystemPrompt : config2.systemPromptAppend
11854
12146
  };
11855
12147
  const agent2 = new CoreAgent(presenter, messageBridge);
@@ -11894,17 +12186,17 @@ var init_interactive = __esm({
11894
12186
  setIsAgentRunning,
11895
12187
  setUsageStats
11896
12188
  } = useSession();
11897
- const [sessionId, setSessionId] = React27.useState(initialSessionId);
11898
- const [currentTask, setCurrentTask] = React27.useState(config2.task);
11899
- const [taskId, setTaskId] = React27.useState(0);
11900
- const [shouldRunAgent, setShouldRunAgent] = React27.useState(!!config2.task);
11901
- const [taskQueue, setTaskQueue] = React27.useState([]);
11902
- const [providerSessionId, setProviderSessionId] = React27.useState();
11903
- const messageBridgeRef = React27.useRef(null);
11904
- const lastSubmitRef = React27.useRef(null);
11905
- const [pendingInjected, setPendingInjected] = React27.useState([]);
11906
- const pendingInjectedRef = React27.useRef([]);
11907
- React27.useEffect(() => {
12189
+ const [sessionId, setSessionId] = React29.useState(initialSessionId);
12190
+ const [currentTask, setCurrentTask] = React29.useState(config2.task);
12191
+ const [taskId, setTaskId] = React29.useState(0);
12192
+ const [shouldRunAgent, setShouldRunAgent] = React29.useState(!!config2.task);
12193
+ const [taskQueue, setTaskQueue] = React29.useState([]);
12194
+ const [providerSessionId, setProviderSessionId] = React29.useState();
12195
+ const messageBridgeRef = React29.useRef(null);
12196
+ const lastSubmitRef = React29.useRef(null);
12197
+ const [pendingInjected, setPendingInjected] = React29.useState([]);
12198
+ const pendingInjectedRef = React29.useRef([]);
12199
+ React29.useEffect(() => {
11908
12200
  pendingInjectedRef.current = pendingInjected;
11909
12201
  }, [pendingInjected]);
11910
12202
  const handleSubmitTask = async (task) => {
@@ -11967,7 +12259,7 @@ var init_interactive = __esm({
11967
12259
  if (shouldRunAgent && !messageBridgeRef.current) {
11968
12260
  messageBridgeRef.current = new MessageBridge(providerSessionId || "");
11969
12261
  }
11970
- React27.useEffect(() => {
12262
+ React29.useEffect(() => {
11971
12263
  if (!shouldRunAgent && taskQueue.length > 0) {
11972
12264
  const [nextTask, ...remaining] = taskQueue;
11973
12265
  setTaskQueue(remaining);
@@ -11981,14 +12273,14 @@ var init_interactive = __esm({
11981
12273
  setShouldRunAgent(true);
11982
12274
  }
11983
12275
  }, [shouldRunAgent, taskQueue, addMessage, providerSessionId]);
11984
- const handleClearSession = React27.useCallback(() => {
12276
+ const handleClearSession = React29.useCallback(() => {
11985
12277
  setSessionId(void 0);
11986
12278
  setContextSessionId(void 0);
11987
12279
  setProviderSessionId(void 0);
11988
12280
  setTaskQueue([]);
11989
12281
  setPendingInjected([]);
11990
12282
  }, [setContextSessionId]);
11991
- return /* @__PURE__ */ React27.createElement(React27.Fragment, null, /* @__PURE__ */ React27.createElement(
12283
+ return /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement(
11992
12284
  App,
11993
12285
  {
11994
12286
  apiClient,
@@ -12051,7 +12343,7 @@ var init_interactive = __esm({
12051
12343
  sessionId,
12052
12344
  webUrl
12053
12345
  }
12054
- ), shouldRunAgent && currentTask && sessionId && messageBridgeRef.current && /* @__PURE__ */ React27.createElement(
12346
+ ), shouldRunAgent && currentTask && sessionId && messageBridgeRef.current && /* @__PURE__ */ React29.createElement(
12055
12347
  AgentRunner,
12056
12348
  {
12057
12349
  apiClient,
@@ -12074,7 +12366,9 @@ var init_interactive = __esm({
12074
12366
  };
12075
12367
  InteractiveApp = (props) => {
12076
12368
  useBracketedPaste();
12077
- return /* @__PURE__ */ React27.createElement(KeypressProvider, null, /* @__PURE__ */ React27.createElement(SessionProvider, { initialModel: props.config.selectedModel }, /* @__PURE__ */ React27.createElement(InteractiveAppContent, { ...props })));
12369
+ const settings = loadSupatestSettings(props.config.cwd || process.cwd());
12370
+ const initialProvider = settings.llmProvider || "supatest-managed";
12371
+ return /* @__PURE__ */ React29.createElement(KeypressProvider, null, /* @__PURE__ */ React29.createElement(SessionProvider, { initialLlmProvider: initialProvider, initialModel: props.config.selectedModel }, /* @__PURE__ */ React29.createElement(InteractiveAppContent, { ...props })));
12078
12372
  };
12079
12373
  }
12080
12374
  });
@@ -12090,7 +12384,7 @@ import { Command } from "commander";
12090
12384
  init_api_client();
12091
12385
  import chalk3 from "chalk";
12092
12386
  import { render } from "ink";
12093
- import React14 from "react";
12387
+ import React15 from "react";
12094
12388
 
12095
12389
  // src/ui/HeadlessApp.tsx
12096
12390
  await init_agent();
@@ -12099,8 +12393,8 @@ init_MessageList();
12099
12393
  init_SessionContext();
12100
12394
  import { execSync as execSync2 } from "child_process";
12101
12395
  import { homedir as homedir3 } from "os";
12102
- import { Box as Box12, useApp } from "ink";
12103
- import React13, { useEffect as useEffect2, useRef, useState as useState3 } from "react";
12396
+ import { Box as Box13, useApp } from "ink";
12397
+ import React14, { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
12104
12398
  var getGitBranch = () => {
12105
12399
  try {
12106
12400
  return execSync2("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
@@ -12126,14 +12420,14 @@ var HeadlessAgentRunner = ({ config: config2, sessionId, apiClient, onComplete }
12126
12420
  setTodos,
12127
12421
  setUsageStats
12128
12422
  } = useSession();
12129
- const agentRef = useRef(null);
12423
+ const agentRef = useRef2(null);
12130
12424
  useEffect2(() => {
12131
12425
  let isMounted = true;
12132
12426
  const runAgent2 = async () => {
12133
12427
  setIsAgentRunning(true);
12134
12428
  try {
12135
12429
  const proxyUrl = config2.supatestApiUrl || "https://code-api.supatest.ai";
12136
- const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}/anthropic`;
12430
+ const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}`;
12137
12431
  process.env.ANTHROPIC_BASE_URL = baseUrl;
12138
12432
  process.env.ANTHROPIC_API_KEY = config2.supatestApiKey;
12139
12433
  const presenter = new ReactPresenter(
@@ -12214,7 +12508,7 @@ var HeadlessAppContent = ({
12214
12508
  const [gitBranch] = useState3(() => getGitBranch());
12215
12509
  const [currentFolder] = useState3(() => getCurrentFolder());
12216
12510
  const [terminalWidth, setTerminalWidth] = useState3(process.stdout.columns || 80);
12217
- const hasCompletedRef = useRef(false);
12511
+ const hasCompletedRef = useRef2(false);
12218
12512
  useEffect2(() => {
12219
12513
  setSessionId(sessionId);
12220
12514
  if (webUrl) {
@@ -12244,7 +12538,7 @@ var HeadlessAppContent = ({
12244
12538
  onComplete(success, providerSessionId);
12245
12539
  exit();
12246
12540
  };
12247
- return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React13.createElement(
12541
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React14.createElement(
12248
12542
  MessageList,
12249
12543
  {
12250
12544
  currentFolder,
@@ -12252,7 +12546,7 @@ var HeadlessAppContent = ({
12252
12546
  headless: true,
12253
12547
  terminalWidth
12254
12548
  }
12255
- ), /* @__PURE__ */ React13.createElement(
12549
+ ), /* @__PURE__ */ React14.createElement(
12256
12550
  HeadlessAgentRunner,
12257
12551
  {
12258
12552
  apiClient,
@@ -12263,7 +12557,7 @@ var HeadlessAppContent = ({
12263
12557
  ));
12264
12558
  };
12265
12559
  var HeadlessApp = (props) => {
12266
- return /* @__PURE__ */ React13.createElement(SessionProvider, { initialModel: props.config.selectedModel }, /* @__PURE__ */ React13.createElement(HeadlessAppContent, { ...props }));
12560
+ return /* @__PURE__ */ React14.createElement(SessionProvider, { initialModel: props.config.selectedModel }, /* @__PURE__ */ React14.createElement(HeadlessAppContent, { ...props }));
12267
12561
  };
12268
12562
 
12269
12563
  // src/modes/headless.ts
@@ -12332,7 +12626,7 @@ async function runAgent(config2) {
12332
12626
  }
12333
12627
  };
12334
12628
  const { unmount, waitUntilExit } = render(
12335
- React14.createElement(HeadlessApp, {
12629
+ React15.createElement(HeadlessApp, {
12336
12630
  config: config2,
12337
12631
  sessionId,
12338
12632
  webUrl,
@@ -12407,77 +12701,12 @@ Updating Supatest CLI ${CLI_VERSION} \u2192 ${latest}...`);
12407
12701
 
12408
12702
  // src/index.ts
12409
12703
  init_banner();
12410
-
12411
- // src/utils/claude-max.ts
12412
- init_logger();
12413
- import { execSync as execSync4 } from "child_process";
12414
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
12415
- import { homedir as homedir4 } from "os";
12416
- import { join as join7 } from "path";
12417
- function isClaudeMaxAvailable() {
12418
- const platform2 = process.platform;
12419
- logger.debug("[claude-max] Checking Claude Code credentials", { platform: platform2 });
12420
- if (platform2 === "darwin") {
12421
- return checkMacOSKeychain();
12422
- } else {
12423
- return checkCredentialsFile();
12424
- }
12425
- }
12426
- function checkMacOSKeychain() {
12427
- try {
12428
- const credentialsJson = execSync4(
12429
- 'security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null',
12430
- { encoding: "utf-8" }
12431
- ).trim();
12432
- if (!credentialsJson) {
12433
- logger.debug("[claude-max] No credentials found in macOS keychain");
12434
- return false;
12435
- }
12436
- const credentials = JSON.parse(credentialsJson);
12437
- const hasOauth = !!credentials.claudeAiOauth?.accessToken;
12438
- logger.debug("[claude-max] macOS keychain credentials check", {
12439
- hasOauth,
12440
- hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
12441
- });
12442
- return hasOauth;
12443
- } catch (error) {
12444
- logger.debug("[claude-max] Error checking macOS keychain", {
12445
- error: error instanceof Error ? error.message : String(error)
12446
- });
12447
- return false;
12448
- }
12449
- }
12450
- function checkCredentialsFile() {
12451
- try {
12452
- const credentialsPath = join7(homedir4(), ".claude", ".credentials.json");
12453
- if (!existsSync5(credentialsPath)) {
12454
- logger.debug("[claude-max] Credentials file not found", { path: credentialsPath });
12455
- return false;
12456
- }
12457
- const credentialsJson = readFileSync4(credentialsPath, "utf-8");
12458
- const credentials = JSON.parse(credentialsJson);
12459
- const hasOauth = !!credentials.claudeAiOauth?.accessToken;
12460
- logger.debug("[claude-max] Credentials file check", {
12461
- path: credentialsPath,
12462
- hasOauth,
12463
- hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
12464
- });
12465
- return hasOauth;
12466
- } catch (error) {
12467
- logger.debug("[claude-max] Error checking credentials file", {
12468
- error: error instanceof Error ? error.message : String(error)
12469
- });
12470
- return false;
12471
- }
12472
- }
12473
-
12474
- // src/index.ts
12475
12704
  init_error_logger();
12476
12705
  init_logger();
12477
12706
 
12478
12707
  // src/utils/node-version.ts
12479
12708
  init_logger();
12480
- import { execSync as execSync5 } from "child_process";
12709
+ import { execSync as execSync4 } from "child_process";
12481
12710
  var MINIMUM_NODE_VERSION2 = 18;
12482
12711
  function parseVersion2(versionString) {
12483
12712
  const cleaned = versionString.trim().replace(/^v/, "");
@@ -12494,7 +12723,7 @@ function parseVersion2(versionString) {
12494
12723
  }
12495
12724
  function getNodeVersion2() {
12496
12725
  try {
12497
- const versionOutput = execSync5("node --version", {
12726
+ const versionOutput = execSync4("node --version", {
12498
12727
  encoding: "utf-8",
12499
12728
  stdio: ["ignore", "pipe", "ignore"]
12500
12729
  });
@@ -12611,7 +12840,7 @@ program.name("supatest").description(
12611
12840
  "-m, --claude-max-iterations <number>",
12612
12841
  "Maximum number of iterations",
12613
12842
  "100"
12614
- ).option("--supatest-api-key <key>", "Supatest API key (or use SUPATEST_API_KEY env)").option("--supatest-api-url <url>", "Supatest API URL (or use SUPATEST_API_URL env, defaults to https://code-api.supatest.ai)").option("--headless", "Run in headless mode (for CI/CD, minimal output)").option("--verbose", "Enable verbose logging").option("--model <model>", "Claude model to use (or use ANTHROPIC_MODEL_NAME env)").option("--claude-max", "Use Claude Max subscription (requires Claude Code to be logged in)").action(async (task, options) => {
12843
+ ).option("--supatest-api-key <key>", "Supatest API key (or use SUPATEST_API_KEY env)").option("--supatest-api-url <url>", "Supatest API URL (or use SUPATEST_API_URL env, defaults to https://code-api.supatest.ai)").option("--headless", "Run in headless mode (for CI/CD, minimal output)").option("--verbose", "Enable verbose logging").option("--model <model>", "Model to use (or use ANTHROPIC_MODEL_NAME env). Use 'small', 'medium', or 'premium' for tier-based selection").action(async (task, options) => {
12615
12844
  try {
12616
12845
  checkNodeVersion2();
12617
12846
  await checkAndAutoUpdate();
@@ -12648,17 +12877,6 @@ program.name("supatest").description(
12648
12877
  let supatestApiKey;
12649
12878
  let oauthToken;
12650
12879
  const supatestApiUrl = options.supatestApiUrl || config.supatestApiUrl;
12651
- if (options.claudeMax) {
12652
- if (!isClaudeMaxAvailable()) {
12653
- logger.error("Claude Max not available. Please ensure:");
12654
- logger.error(" 1. Claude Code is installed");
12655
- logger.error(" 2. You are logged in with a Claude Max subscription");
12656
- logger.error(" 3. Run 'claude' and authenticate if needed");
12657
- process.exit(1);
12658
- }
12659
- oauthToken = "use-claude-max";
12660
- logger.info("Using Claude Max subscription for LLM calls");
12661
- }
12662
12880
  if (isHeadlessMode) {
12663
12881
  supatestApiKey = normalizeSupatestKey(
12664
12882
  options.supatestApiKey || config.supatestApiKey,
@@ -12684,15 +12902,16 @@ program.name("supatest").description(
12684
12902
  }
12685
12903
  }
12686
12904
  let selectedModel;
12687
- const modelOption = options.model || config.anthropicModelName;
12688
- if (modelOption) {
12689
- if (isValidModelId(modelOption)) {
12690
- selectedModel = modelOption;
12691
- } else {
12905
+ const modelOption = options.model || "medium";
12906
+ if (modelOption && isValidModelId(modelOption)) {
12907
+ selectedModel = modelOption;
12908
+ } else {
12909
+ if (modelOption && modelOption !== "medium") {
12692
12910
  const validModels = AVAILABLE_MODELS.map((m) => m.id).join(", ");
12693
- logger.warn(`Invalid model "${modelOption}". Valid models: ${validModels}`);
12911
+ logger.warn(`Invalid model "${modelOption}". Valid models: ${validModels} or tier names: small, medium, premium`);
12694
12912
  logger.warn("Using default model instead.");
12695
12913
  }
12914
+ selectedModel = "medium";
12696
12915
  }
12697
12916
  if (isHeadlessMode) {
12698
12917
  if (!prompt) {
@@ -12704,7 +12923,7 @@ program.name("supatest").description(
12704
12923
  logs,
12705
12924
  supatestApiKey,
12706
12925
  supatestApiUrl,
12707
- maxIterations: Number.parseInt(options.maxIterations || "1", 10),
12926
+ maxIterations: Number.parseInt(options.maxIterations || "100", 10),
12708
12927
  verbose: options.verbose || false,
12709
12928
  cwd: options.cwd,
12710
12929
  systemPromptAppend: config.headlessSystemPrompt,
@@ -12720,7 +12939,7 @@ program.name("supatest").description(
12720
12939
  logs,
12721
12940
  supatestApiKey,
12722
12941
  supatestApiUrl,
12723
- maxIterations: Number.parseInt(options.maxIterations || "1", 10),
12942
+ maxIterations: Number.parseInt(options.maxIterations || "100", 10),
12724
12943
  verbose: options.verbose || false,
12725
12944
  cwd: options.cwd,
12726
12945
  systemPromptAppend: config.interactiveSystemPrompt,