@supatest/cli 0.0.31 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +746 -555
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -336,11 +336,64 @@ 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") return "0.5x";
|
|
347
|
+
if (modelId === "medium") return "1x";
|
|
348
|
+
if (modelId === "premium") return "2x";
|
|
349
|
+
const model = getModelById(modelId);
|
|
350
|
+
if (model) {
|
|
351
|
+
return model.costMultiplier === 0.5 ? "0.5x" : model.costMultiplier === 1 ? "1x" : model.costMultiplier === 2 ? "2x" : "1x";
|
|
352
|
+
}
|
|
353
|
+
return "1x";
|
|
354
|
+
}
|
|
339
355
|
function getModelDisplayName(id) {
|
|
340
|
-
|
|
341
|
-
|
|
356
|
+
if (MODEL_TIERS.includes(id)) {
|
|
357
|
+
const tierNames = {
|
|
358
|
+
small: "Small",
|
|
359
|
+
medium: "Medium",
|
|
360
|
+
premium: "Premium"
|
|
361
|
+
};
|
|
362
|
+
return tierNames[id] || id;
|
|
363
|
+
}
|
|
364
|
+
const anthropicModel = getModelById(id);
|
|
365
|
+
if (anthropicModel) {
|
|
366
|
+
return anthropicModel.name;
|
|
367
|
+
}
|
|
368
|
+
const tier = getTierFromProviderModel(id);
|
|
369
|
+
if (tier && !id.startsWith("claude-")) {
|
|
370
|
+
const tierNames = {
|
|
371
|
+
small: "Small",
|
|
372
|
+
medium: "Medium",
|
|
373
|
+
premium: "Premium"
|
|
374
|
+
};
|
|
375
|
+
return tierNames[tier];
|
|
376
|
+
}
|
|
377
|
+
return id;
|
|
378
|
+
}
|
|
379
|
+
function resolveTierToAnthropicModel(tier) {
|
|
380
|
+
const tierToModel = {
|
|
381
|
+
small: "claude-haiku-4-5",
|
|
382
|
+
medium: "claude-sonnet-4-5",
|
|
383
|
+
premium: "claude-opus-4-5"
|
|
384
|
+
};
|
|
385
|
+
return tierToModel[tier];
|
|
386
|
+
}
|
|
387
|
+
function resolveToAnthropicModel(model) {
|
|
388
|
+
if (MODEL_TIERS.includes(model)) {
|
|
389
|
+
return resolveTierToAnthropicModel(model);
|
|
390
|
+
}
|
|
391
|
+
return model;
|
|
342
392
|
}
|
|
343
393
|
function isValidModelId(id) {
|
|
394
|
+
if (MODEL_TIERS.includes(id)) {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
344
397
|
return AVAILABLE_MODELS.some((m) => id === m.id || id.startsWith(`${m.id}-`));
|
|
345
398
|
}
|
|
346
399
|
function getErrorMap() {
|
|
@@ -538,7 +591,7 @@ function getToolDisplayName(toolName) {
|
|
|
538
591
|
};
|
|
539
592
|
return displayNameMap[toolName] || toolName;
|
|
540
593
|
}
|
|
541
|
-
var AVAILABLE_MODELS,
|
|
594
|
+
var AVAILABLE_MODELS, DATE_SUFFIX_REGEX, 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
595
|
var init_shared_es = __esm({
|
|
543
596
|
"../shared/dist/shared.es.mjs"() {
|
|
544
597
|
"use strict";
|
|
@@ -547,23 +600,26 @@ var init_shared_es = __esm({
|
|
|
547
600
|
id: "claude-sonnet-4-5",
|
|
548
601
|
name: "Sonnet 4.5",
|
|
549
602
|
description: "Fast & capable",
|
|
550
|
-
contextWindow: 2e5
|
|
603
|
+
contextWindow: 2e5,
|
|
604
|
+
costMultiplier: 1
|
|
551
605
|
},
|
|
552
606
|
{
|
|
553
607
|
id: "claude-opus-4-5",
|
|
554
608
|
name: "Opus 4.5",
|
|
555
609
|
description: "Most capable",
|
|
556
|
-
contextWindow: 2e5
|
|
610
|
+
contextWindow: 2e5,
|
|
611
|
+
costMultiplier: 2
|
|
557
612
|
},
|
|
558
613
|
{
|
|
559
614
|
id: "claude-haiku-4-5",
|
|
560
615
|
name: "Haiku 4.5",
|
|
561
616
|
description: "Lightweight",
|
|
562
|
-
contextWindow: 2e5
|
|
617
|
+
contextWindow: 2e5,
|
|
618
|
+
costMultiplier: 0.5
|
|
563
619
|
}
|
|
564
620
|
];
|
|
565
|
-
DEFAULT_MODEL_ID = "claude-sonnet-4-5";
|
|
566
621
|
DATE_SUFFIX_REGEX = /-\d{8}$/;
|
|
622
|
+
MODEL_TIERS = ["small", "medium", "premium"];
|
|
567
623
|
CONTEXT_WINDOWS = Object.fromEntries(
|
|
568
624
|
AVAILABLE_MODELS.map((m) => [m.id, m.contextWindow])
|
|
569
625
|
);
|
|
@@ -5003,263 +5059,6 @@ var init_shared_es = __esm({
|
|
|
5003
5059
|
days: numberType()
|
|
5004
5060
|
})
|
|
5005
5061
|
});
|
|
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
5062
|
}
|
|
5264
5063
|
});
|
|
5265
5064
|
|
|
@@ -5522,7 +5321,7 @@ var CLI_VERSION;
|
|
|
5522
5321
|
var init_version = __esm({
|
|
5523
5322
|
"src/version.ts"() {
|
|
5524
5323
|
"use strict";
|
|
5525
|
-
CLI_VERSION = "0.0.
|
|
5324
|
+
CLI_VERSION = "0.0.33";
|
|
5526
5325
|
}
|
|
5527
5326
|
});
|
|
5528
5327
|
|
|
@@ -6463,6 +6262,7 @@ var CoreAgent;
|
|
|
6463
6262
|
var init_agent = __esm({
|
|
6464
6263
|
async "src/core/agent.ts"() {
|
|
6465
6264
|
"use strict";
|
|
6265
|
+
init_shared_es();
|
|
6466
6266
|
await init_config();
|
|
6467
6267
|
init_command_discovery();
|
|
6468
6268
|
init_error_logger();
|
|
@@ -6531,6 +6331,8 @@ ${projectInstructions}`,
|
|
|
6531
6331
|
"ANTHROPIC_API_KEY",
|
|
6532
6332
|
"ANTHROPIC_BASE_URL",
|
|
6533
6333
|
"ANTHROPIC_AUTH_TOKEN",
|
|
6334
|
+
"ZAI_API_KEY",
|
|
6335
|
+
"ZAI_BASE_URL",
|
|
6534
6336
|
"CLAUDE_CODE_AUTH_TOKEN",
|
|
6535
6337
|
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
6536
6338
|
"CLAUDE_API_KEY"
|
|
@@ -6549,15 +6351,17 @@ ${projectInstructions}`,
|
|
|
6549
6351
|
if (config2.oauthToken) {
|
|
6550
6352
|
cleanEnv.ANTHROPIC_API_KEY = "";
|
|
6551
6353
|
cleanEnv.ANTHROPIC_BASE_URL = "";
|
|
6354
|
+
cleanEnv.ZAI_API_KEY = "";
|
|
6355
|
+
cleanEnv.ZAI_BASE_URL = "";
|
|
6552
6356
|
this.presenter.onLog(`Auth: Using Claude Max (default Claude Code credentials)`);
|
|
6553
|
-
logger.debug("[agent] Claude Max mode: Using default ~/.claude/ config, cleared
|
|
6357
|
+
logger.debug("[agent] Claude Max mode: Using default ~/.claude/ config, cleared provider credentials");
|
|
6554
6358
|
} else {
|
|
6555
6359
|
const internalConfigDir = join6(homedir2(), ".supatest", "claude-internal");
|
|
6556
6360
|
cleanEnv.CLAUDE_CONFIG_DIR = internalConfigDir;
|
|
6557
6361
|
cleanEnv.ANTHROPIC_API_KEY = config2.supatestApiKey || "";
|
|
6558
6362
|
cleanEnv.ANTHROPIC_BASE_URL = process.env.ANTHROPIC_BASE_URL || "";
|
|
6559
|
-
this.presenter.onLog(`Auth: Using Supatest API
|
|
6560
|
-
logger.debug("[agent] API
|
|
6363
|
+
this.presenter.onLog(`Auth: Using Supatest API (provider determined by backend)${process.env.ANTHROPIC_BASE_URL ? ` (base: ${process.env.ANTHROPIC_BASE_URL})` : ""}`);
|
|
6364
|
+
logger.debug("[agent] API mode: Set ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, and CLAUDE_CONFIG_DIR");
|
|
6561
6365
|
}
|
|
6562
6366
|
cleanEnv.ANTHROPIC_AUTH_TOKEN = "";
|
|
6563
6367
|
cleanEnv.CLAUDE_CODE_AUTH_TOKEN = "";
|
|
@@ -6567,12 +6371,14 @@ ${projectInstructions}`,
|
|
|
6567
6371
|
CLAUDE_CONFIG_DIR: cleanEnv.CLAUDE_CONFIG_DIR || "(using default ~/.claude/)"
|
|
6568
6372
|
});
|
|
6569
6373
|
cleanEnv.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "1";
|
|
6374
|
+
const selectedModel = config2.selectedModel || "premium";
|
|
6375
|
+
const defaultModel = resolveToAnthropicModel(selectedModel);
|
|
6570
6376
|
const queryOptions = {
|
|
6571
6377
|
// AbortController for cancellation support
|
|
6572
6378
|
abortController: this.abortController,
|
|
6573
6379
|
maxTurns: config2.maxIterations,
|
|
6574
6380
|
cwd,
|
|
6575
|
-
model:
|
|
6381
|
+
model: defaultModel,
|
|
6576
6382
|
permissionMode: isPlanMode ? "plan" : "bypassPermissions",
|
|
6577
6383
|
allowDangerouslySkipPermissions: !isPlanMode,
|
|
6578
6384
|
pathToClaudeCodeExecutable: claudeCodePath,
|
|
@@ -6965,6 +6771,7 @@ var init_react = __esm({
|
|
|
6965
6771
|
toolInput: input,
|
|
6966
6772
|
toolResult: void 0,
|
|
6967
6773
|
isExpanded: false,
|
|
6774
|
+
isPending: true,
|
|
6968
6775
|
toolUseId: toolId
|
|
6969
6776
|
};
|
|
6970
6777
|
this.callbacks.addMessage(message);
|
|
@@ -7010,7 +6817,8 @@ var init_react = __esm({
|
|
|
7010
6817
|
}
|
|
7011
6818
|
onToolResult(toolId, result) {
|
|
7012
6819
|
this.callbacks.updateMessageByToolId(toolId, {
|
|
7013
|
-
toolResult: result
|
|
6820
|
+
toolResult: result,
|
|
6821
|
+
isPending: false
|
|
7014
6822
|
});
|
|
7015
6823
|
streamEventAsync(this.apiClient, this.sessionId, {
|
|
7016
6824
|
type: "tool_result",
|
|
@@ -7129,11 +6937,11 @@ var SessionContext, SessionProvider, useSession;
|
|
|
7129
6937
|
var init_SessionContext = __esm({
|
|
7130
6938
|
"src/ui/contexts/SessionContext.tsx"() {
|
|
7131
6939
|
"use strict";
|
|
7132
|
-
init_shared_es();
|
|
7133
6940
|
SessionContext = createContext(null);
|
|
7134
6941
|
SessionProvider = ({
|
|
7135
6942
|
children,
|
|
7136
|
-
initialModel
|
|
6943
|
+
initialModel,
|
|
6944
|
+
initialLlmProvider = "supatest-managed"
|
|
7137
6945
|
}) => {
|
|
7138
6946
|
const [messages, setMessages] = useState([]);
|
|
7139
6947
|
const [todos, setTodos] = useState([]);
|
|
@@ -7150,8 +6958,10 @@ var init_SessionContext = __esm({
|
|
|
7150
6958
|
const [webUrl, setWebUrl] = useState();
|
|
7151
6959
|
const [agentMode, setAgentMode] = useState("build");
|
|
7152
6960
|
const [planFilePath, setPlanFilePath] = useState();
|
|
7153
|
-
const [selectedModel, setSelectedModel] = useState(initialModel ||
|
|
6961
|
+
const [selectedModel, setSelectedModel] = useState(initialModel || "premium");
|
|
6962
|
+
const [llmProvider, setLlmProvider] = useState(initialLlmProvider);
|
|
7154
6963
|
const [allToolsExpanded, setAllToolsExpanded] = useState(true);
|
|
6964
|
+
const [toolGroupsExpanded, setToolGroupsExpanded] = useState(false);
|
|
7155
6965
|
const [staticRemountKey, setStaticRemountKey] = useState(0);
|
|
7156
6966
|
const addMessage = useCallback(
|
|
7157
6967
|
(message) => {
|
|
@@ -7234,6 +7044,9 @@ var init_SessionContext = __esm({
|
|
|
7234
7044
|
return newValue;
|
|
7235
7045
|
});
|
|
7236
7046
|
}, []);
|
|
7047
|
+
const toggleToolGroups = useCallback(() => {
|
|
7048
|
+
setToolGroupsExpanded((prev) => !prev);
|
|
7049
|
+
}, []);
|
|
7237
7050
|
const value = {
|
|
7238
7051
|
messages,
|
|
7239
7052
|
addMessage,
|
|
@@ -7244,6 +7057,8 @@ var init_SessionContext = __esm({
|
|
|
7244
7057
|
loadMessages,
|
|
7245
7058
|
toggleAllToolOutputs,
|
|
7246
7059
|
allToolsExpanded,
|
|
7060
|
+
toolGroupsExpanded,
|
|
7061
|
+
toggleToolGroups,
|
|
7247
7062
|
todos,
|
|
7248
7063
|
setTodos,
|
|
7249
7064
|
stats,
|
|
@@ -7264,6 +7079,8 @@ var init_SessionContext = __esm({
|
|
|
7264
7079
|
setPlanFilePath,
|
|
7265
7080
|
selectedModel,
|
|
7266
7081
|
setSelectedModel,
|
|
7082
|
+
llmProvider,
|
|
7083
|
+
setLlmProvider,
|
|
7267
7084
|
staticRemountKey,
|
|
7268
7085
|
refreshStatic
|
|
7269
7086
|
};
|
|
@@ -7353,7 +7170,6 @@ var init_theme = __esm({
|
|
|
7353
7170
|
|
|
7354
7171
|
// src/ui/components/Header.tsx
|
|
7355
7172
|
import { Box, Text } from "ink";
|
|
7356
|
-
import Gradient from "ink-gradient";
|
|
7357
7173
|
import React2 from "react";
|
|
7358
7174
|
var Header;
|
|
7359
7175
|
var init_Header = __esm({
|
|
@@ -7383,7 +7199,7 @@ var init_Header = __esm({
|
|
|
7383
7199
|
marginTop: 5,
|
|
7384
7200
|
width: "100%"
|
|
7385
7201
|
},
|
|
7386
|
-
/* @__PURE__ */ React2.createElement(
|
|
7202
|
+
/* @__PURE__ */ React2.createElement(Text, { color: theme.text.accent }, banner),
|
|
7387
7203
|
/* @__PURE__ */ React2.createElement(Box, { justifyContent: "center", marginTop: 0 }, /* @__PURE__ */ React2.createElement(Text, { color: theme.text.dim }, infoLine)),
|
|
7388
7204
|
!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
7205
|
);
|
|
@@ -8088,32 +7904,88 @@ var init_ToolMessage = __esm({
|
|
|
8088
7904
|
}
|
|
8089
7905
|
});
|
|
8090
7906
|
|
|
8091
|
-
// src/ui/components/messages/
|
|
7907
|
+
// src/ui/components/messages/ToolGroup.tsx
|
|
8092
7908
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
8093
7909
|
import React10 from "react";
|
|
7910
|
+
function getToolCategory(toolName) {
|
|
7911
|
+
const name = toolName.toLowerCase();
|
|
7912
|
+
if (name.includes("read")) return "Read";
|
|
7913
|
+
if (name.includes("write")) return "Write";
|
|
7914
|
+
if (name.includes("edit")) return "Edit";
|
|
7915
|
+
if (name.includes("bash") || name.includes("command")) return "Bash";
|
|
7916
|
+
if (name.includes("glob")) return "Glob";
|
|
7917
|
+
if (name.includes("grep")) return "Grep";
|
|
7918
|
+
if (name.includes("task")) return "Task";
|
|
7919
|
+
if (name.includes("todo")) return "Todo";
|
|
7920
|
+
return toolName.charAt(0).toUpperCase() + toolName.slice(1).toLowerCase();
|
|
7921
|
+
}
|
|
7922
|
+
function getToolGroupCounts(tools) {
|
|
7923
|
+
const groups = tools.reduce(
|
|
7924
|
+
(acc, tool) => {
|
|
7925
|
+
const category = getToolCategory(tool.toolName);
|
|
7926
|
+
acc[category] = (acc[category] || 0) + 1;
|
|
7927
|
+
return acc;
|
|
7928
|
+
},
|
|
7929
|
+
{}
|
|
7930
|
+
);
|
|
7931
|
+
return Object.entries(groups).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
|
|
7932
|
+
}
|
|
7933
|
+
var ToolGroup;
|
|
7934
|
+
var init_ToolGroup = __esm({
|
|
7935
|
+
"src/ui/components/messages/ToolGroup.tsx"() {
|
|
7936
|
+
"use strict";
|
|
7937
|
+
init_theme();
|
|
7938
|
+
init_ToolMessage();
|
|
7939
|
+
ToolGroup = ({
|
|
7940
|
+
tools,
|
|
7941
|
+
isExpanded,
|
|
7942
|
+
onToggle,
|
|
7943
|
+
onToggleTool
|
|
7944
|
+
}) => {
|
|
7945
|
+
const toolGroups = getToolGroupCounts(tools);
|
|
7946
|
+
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(
|
|
7947
|
+
ToolMessage,
|
|
7948
|
+
{
|
|
7949
|
+
description: tool.description,
|
|
7950
|
+
id: tool.id,
|
|
7951
|
+
input: tool.input,
|
|
7952
|
+
isExpanded: tool.isExpanded,
|
|
7953
|
+
key: tool.id,
|
|
7954
|
+
onToggle: onToggleTool,
|
|
7955
|
+
result: tool.result,
|
|
7956
|
+
toolName: tool.toolName
|
|
7957
|
+
}
|
|
7958
|
+
))));
|
|
7959
|
+
};
|
|
7960
|
+
}
|
|
7961
|
+
});
|
|
7962
|
+
|
|
7963
|
+
// src/ui/components/messages/UserMessage.tsx
|
|
7964
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
7965
|
+
import React11 from "react";
|
|
8094
7966
|
var UserMessage;
|
|
8095
7967
|
var init_UserMessage = __esm({
|
|
8096
7968
|
"src/ui/components/messages/UserMessage.tsx"() {
|
|
8097
7969
|
"use strict";
|
|
8098
7970
|
init_theme();
|
|
8099
7971
|
UserMessage = ({ text }) => {
|
|
8100
|
-
return /* @__PURE__ */
|
|
8101
|
-
|
|
7972
|
+
return /* @__PURE__ */ React11.createElement(Box10, { alignItems: "center", flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: theme.text.info }, "\u{1F464} "), /* @__PURE__ */ React11.createElement(
|
|
7973
|
+
Box10,
|
|
8102
7974
|
{
|
|
8103
7975
|
borderColor: theme.text.dim,
|
|
8104
7976
|
borderStyle: "round",
|
|
8105
7977
|
paddingLeft: 1,
|
|
8106
7978
|
paddingRight: 1
|
|
8107
7979
|
},
|
|
8108
|
-
/* @__PURE__ */
|
|
7980
|
+
/* @__PURE__ */ React11.createElement(Text10, { color: theme.text.secondary }, text)
|
|
8109
7981
|
));
|
|
8110
7982
|
};
|
|
8111
7983
|
}
|
|
8112
7984
|
});
|
|
8113
7985
|
|
|
8114
7986
|
// src/ui/components/QueuedMessageDisplay.tsx
|
|
8115
|
-
import { Box as
|
|
8116
|
-
import
|
|
7987
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
7988
|
+
import React12 from "react";
|
|
8117
7989
|
var MAX_DISPLAYED_QUEUED_MESSAGES, QueuedMessageDisplay;
|
|
8118
7990
|
var init_QueuedMessageDisplay = __esm({
|
|
8119
7991
|
"src/ui/components/QueuedMessageDisplay.tsx"() {
|
|
@@ -8126,8 +7998,8 @@ var init_QueuedMessageDisplay = __esm({
|
|
|
8126
7998
|
if (messageQueue.length === 0) {
|
|
8127
7999
|
return null;
|
|
8128
8000
|
}
|
|
8129
|
-
return /* @__PURE__ */
|
|
8130
|
-
|
|
8001
|
+
return /* @__PURE__ */ React12.createElement(
|
|
8002
|
+
Box11,
|
|
8131
8003
|
{
|
|
8132
8004
|
borderColor: theme.border.default,
|
|
8133
8005
|
borderStyle: "round",
|
|
@@ -8136,20 +8008,20 @@ var init_QueuedMessageDisplay = __esm({
|
|
|
8136
8008
|
marginTop: 0,
|
|
8137
8009
|
paddingX: 1
|
|
8138
8010
|
},
|
|
8139
|
-
/* @__PURE__ */
|
|
8011
|
+
/* @__PURE__ */ React12.createElement(Box11, { marginBottom: 0 }, /* @__PURE__ */ React12.createElement(Text11, { bold: true, color: theme.text.secondary }, "Queued (", messageQueue.length, ")")),
|
|
8140
8012
|
messageQueue.slice(0, MAX_DISPLAYED_QUEUED_MESSAGES).map((message, index) => {
|
|
8141
8013
|
const preview = message.replace(/\s+/g, " ");
|
|
8142
|
-
return /* @__PURE__ */
|
|
8014
|
+
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
8015
|
}),
|
|
8144
|
-
messageQueue.length > MAX_DISPLAYED_QUEUED_MESSAGES && /* @__PURE__ */
|
|
8016
|
+
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
8017
|
);
|
|
8146
8018
|
};
|
|
8147
8019
|
}
|
|
8148
8020
|
});
|
|
8149
8021
|
|
|
8150
8022
|
// src/ui/components/MessageList.tsx
|
|
8151
|
-
import { Box as
|
|
8152
|
-
import
|
|
8023
|
+
import { Box as Box12, Static } from "ink";
|
|
8024
|
+
import React13, { useMemo as useMemo3 } from "react";
|
|
8153
8025
|
var MessageList;
|
|
8154
8026
|
var init_MessageList = __esm({
|
|
8155
8027
|
"src/ui/components/MessageList.tsx"() {
|
|
@@ -8161,17 +8033,18 @@ var init_MessageList = __esm({
|
|
|
8161
8033
|
init_LoadingMessage();
|
|
8162
8034
|
init_ThinkingMessage();
|
|
8163
8035
|
init_TodoMessage();
|
|
8036
|
+
init_ToolGroup();
|
|
8164
8037
|
init_ToolMessage();
|
|
8165
8038
|
init_UserMessage();
|
|
8166
8039
|
init_QueuedMessageDisplay();
|
|
8167
8040
|
MessageList = ({ terminalWidth, currentFolder, gitBranch, headless = false, queuedTasks = [] }) => {
|
|
8168
|
-
const { messages, updateMessageById, isAgentRunning, staticRemountKey } = useSession();
|
|
8169
|
-
const renderMessage = (message) => {
|
|
8041
|
+
const { messages, updateMessageById, isAgentRunning, staticRemountKey, toolGroupsExpanded, toggleToolGroups } = useSession();
|
|
8042
|
+
const renderMessage = (message, isInGroup = false) => {
|
|
8170
8043
|
switch (message.type) {
|
|
8171
8044
|
case "user":
|
|
8172
|
-
return /* @__PURE__ */
|
|
8045
|
+
return /* @__PURE__ */ React13.createElement(UserMessage, { key: message.id, text: message.content });
|
|
8173
8046
|
case "assistant":
|
|
8174
|
-
return /* @__PURE__ */
|
|
8047
|
+
return /* @__PURE__ */ React13.createElement(
|
|
8175
8048
|
AssistantMessage,
|
|
8176
8049
|
{
|
|
8177
8050
|
isPending: message.isPending,
|
|
@@ -8181,7 +8054,22 @@ var init_MessageList = __esm({
|
|
|
8181
8054
|
}
|
|
8182
8055
|
);
|
|
8183
8056
|
case "tool":
|
|
8184
|
-
|
|
8057
|
+
if (isInGroup) {
|
|
8058
|
+
return /* @__PURE__ */ React13.createElement(
|
|
8059
|
+
ToolMessage,
|
|
8060
|
+
{
|
|
8061
|
+
description: message.content,
|
|
8062
|
+
id: message.id,
|
|
8063
|
+
input: message.toolInput,
|
|
8064
|
+
isExpanded: message.isExpanded,
|
|
8065
|
+
key: message.id,
|
|
8066
|
+
onToggle: (id) => updateMessageById(id, { isExpanded: !message.isExpanded }),
|
|
8067
|
+
result: message.toolResult,
|
|
8068
|
+
toolName: message.toolName || "Unknown"
|
|
8069
|
+
}
|
|
8070
|
+
);
|
|
8071
|
+
}
|
|
8072
|
+
return /* @__PURE__ */ React13.createElement(
|
|
8185
8073
|
ToolMessage,
|
|
8186
8074
|
{
|
|
8187
8075
|
description: message.content,
|
|
@@ -8195,7 +8083,7 @@ var init_MessageList = __esm({
|
|
|
8195
8083
|
}
|
|
8196
8084
|
);
|
|
8197
8085
|
case "thinking":
|
|
8198
|
-
return /* @__PURE__ */
|
|
8086
|
+
return /* @__PURE__ */ React13.createElement(
|
|
8199
8087
|
ThinkingMessage,
|
|
8200
8088
|
{
|
|
8201
8089
|
content: message.content,
|
|
@@ -8206,7 +8094,7 @@ var init_MessageList = __esm({
|
|
|
8206
8094
|
}
|
|
8207
8095
|
);
|
|
8208
8096
|
case "error":
|
|
8209
|
-
return /* @__PURE__ */
|
|
8097
|
+
return /* @__PURE__ */ React13.createElement(
|
|
8210
8098
|
ErrorMessage,
|
|
8211
8099
|
{
|
|
8212
8100
|
key: message.id,
|
|
@@ -8215,37 +8103,120 @@ var init_MessageList = __esm({
|
|
|
8215
8103
|
}
|
|
8216
8104
|
);
|
|
8217
8105
|
case "todo":
|
|
8218
|
-
return /* @__PURE__ */
|
|
8106
|
+
return /* @__PURE__ */ React13.createElement(TodoMessage, { key: message.id, todos: message.todos || [] });
|
|
8219
8107
|
default:
|
|
8220
8108
|
return null;
|
|
8221
8109
|
}
|
|
8222
8110
|
};
|
|
8223
|
-
const
|
|
8111
|
+
const renderGroupedMessage = (group) => {
|
|
8112
|
+
if (group.type === "group") {
|
|
8113
|
+
return /* @__PURE__ */ React13.createElement(
|
|
8114
|
+
ToolGroup,
|
|
8115
|
+
{
|
|
8116
|
+
isExpanded: toolGroupsExpanded,
|
|
8117
|
+
key: `group-${group.messages[0].id}`,
|
|
8118
|
+
onToggle: toggleToolGroups,
|
|
8119
|
+
onToggleTool: (id) => {
|
|
8120
|
+
const msg = group.messages.find((m) => m.id === id);
|
|
8121
|
+
if (msg) {
|
|
8122
|
+
updateMessageById(id, { isExpanded: !msg.isExpanded });
|
|
8123
|
+
}
|
|
8124
|
+
},
|
|
8125
|
+
tools: group.messages.map((msg) => ({
|
|
8126
|
+
id: msg.id,
|
|
8127
|
+
toolName: msg.toolName || "Unknown",
|
|
8128
|
+
description: msg.content,
|
|
8129
|
+
input: msg.toolInput,
|
|
8130
|
+
result: msg.toolResult,
|
|
8131
|
+
isExpanded: msg.isExpanded
|
|
8132
|
+
}))
|
|
8133
|
+
}
|
|
8134
|
+
);
|
|
8135
|
+
}
|
|
8136
|
+
return renderMessage(group.messages[0]);
|
|
8137
|
+
};
|
|
8138
|
+
const { completedGroups, currentTurnGroups } = useMemo3(() => {
|
|
8224
8139
|
const completed = [];
|
|
8225
|
-
const
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8140
|
+
const currentTurn = [];
|
|
8141
|
+
const processTurn = (turnMessages2, targetArray) => {
|
|
8142
|
+
let currentToolGroup = [];
|
|
8143
|
+
const flushToolGroup = () => {
|
|
8144
|
+
if (currentToolGroup.length === 0) return;
|
|
8145
|
+
if (currentToolGroup.length === 1) {
|
|
8146
|
+
targetArray.push({ type: "single", messages: [...currentToolGroup] });
|
|
8147
|
+
} else {
|
|
8148
|
+
targetArray.push({ type: "group", messages: [...currentToolGroup] });
|
|
8149
|
+
}
|
|
8150
|
+
currentToolGroup = [];
|
|
8151
|
+
};
|
|
8152
|
+
for (const msg of turnMessages2) {
|
|
8153
|
+
if (msg.type === "tool") {
|
|
8154
|
+
currentToolGroup.push(msg);
|
|
8155
|
+
} else {
|
|
8156
|
+
flushToolGroup();
|
|
8157
|
+
targetArray.push({ type: "single", messages: [msg] });
|
|
8158
|
+
}
|
|
8159
|
+
}
|
|
8160
|
+
flushToolGroup();
|
|
8161
|
+
};
|
|
8162
|
+
let lastUserMessageIndex = -1;
|
|
8163
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
8164
|
+
if (messages[i].type === "user") {
|
|
8165
|
+
lastUserMessageIndex = i;
|
|
8166
|
+
break;
|
|
8167
|
+
}
|
|
8168
|
+
}
|
|
8169
|
+
let turnMessages = [];
|
|
8170
|
+
for (let i = 0; i < lastUserMessageIndex; i++) {
|
|
8171
|
+
const msg = messages[i];
|
|
8172
|
+
if (msg.type === "user") {
|
|
8173
|
+
processTurn(turnMessages, completed);
|
|
8174
|
+
turnMessages = [];
|
|
8175
|
+
completed.push({ type: "single", messages: [msg] });
|
|
8229
8176
|
} else {
|
|
8230
|
-
|
|
8177
|
+
turnMessages.push(msg);
|
|
8231
8178
|
}
|
|
8232
8179
|
}
|
|
8233
|
-
|
|
8180
|
+
processTurn(turnMessages, completed);
|
|
8181
|
+
if (lastUserMessageIndex >= 0) {
|
|
8182
|
+
completed.push({ type: "single", messages: [messages[lastUserMessageIndex]] });
|
|
8183
|
+
}
|
|
8184
|
+
const currentTurnMessages = lastUserMessageIndex >= 0 ? messages.slice(lastUserMessageIndex + 1) : messages;
|
|
8185
|
+
processTurn(currentTurnMessages, currentTurn);
|
|
8186
|
+
return { completedGroups: completed, currentTurnGroups: currentTurn };
|
|
8234
8187
|
}, [messages]);
|
|
8235
8188
|
const staticItems = useMemo3(() => [
|
|
8236
8189
|
{ id: "header", type: "header" },
|
|
8237
|
-
...
|
|
8238
|
-
|
|
8239
|
-
|
|
8190
|
+
...completedGroups.map((group, idx) => {
|
|
8191
|
+
if (group.type === "group") {
|
|
8192
|
+
return { ...group, _isGroup: true, id: `group-${idx}` };
|
|
8193
|
+
}
|
|
8194
|
+
return { ...group.messages[0], _isMessage: true };
|
|
8195
|
+
})
|
|
8196
|
+
], [completedGroups]);
|
|
8197
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Static, { items: staticItems, key: staticRemountKey }, (item) => {
|
|
8240
8198
|
if (item.type === "header") {
|
|
8241
|
-
return /* @__PURE__ */
|
|
8199
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: "header" }, /* @__PURE__ */ React13.createElement(Header, { currentFolder, gitBranch, headless }));
|
|
8200
|
+
}
|
|
8201
|
+
if (item._isGroup) {
|
|
8202
|
+
const content2 = renderGroupedMessage(item);
|
|
8203
|
+
if (!content2) {
|
|
8204
|
+
return null;
|
|
8205
|
+
}
|
|
8206
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: item.id, width: "100%" }, content2);
|
|
8242
8207
|
}
|
|
8243
8208
|
const content = renderMessage(item);
|
|
8244
8209
|
if (!content) {
|
|
8245
8210
|
return null;
|
|
8246
8211
|
}
|
|
8247
|
-
return /* @__PURE__ */
|
|
8248
|
-
}),
|
|
8212
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: item.id, width: "100%" }, content);
|
|
8213
|
+
}), currentTurnGroups.map((group, idx) => {
|
|
8214
|
+
const content = renderGroupedMessage(group);
|
|
8215
|
+
if (!content) {
|
|
8216
|
+
return null;
|
|
8217
|
+
}
|
|
8218
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", key: group.type === "group" ? `current-group-${idx}` : group.messages[0].id, width: "100%" }, content);
|
|
8219
|
+
}), /* @__PURE__ */ React13.createElement(QueuedMessageDisplay, { messageQueue: queuedTasks }), isAgentRunning && !messages.some((m) => m.type === "assistant" && m.isPending) && /* @__PURE__ */ React13.createElement(LoadingMessage, { headless, key: "loading" }));
|
|
8249
8220
|
};
|
|
8250
8221
|
}
|
|
8251
8222
|
});
|
|
@@ -8920,6 +8891,128 @@ var init_login = __esm({
|
|
|
8920
8891
|
}
|
|
8921
8892
|
});
|
|
8922
8893
|
|
|
8894
|
+
// src/utils/claude-max.ts
|
|
8895
|
+
import { execSync as execSync5 } from "child_process";
|
|
8896
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
8897
|
+
import { homedir as homedir5 } from "os";
|
|
8898
|
+
import { join as join8 } from "path";
|
|
8899
|
+
function isClaudeMaxAvailable() {
|
|
8900
|
+
const platform2 = process.platform;
|
|
8901
|
+
logger.debug("[claude-max] Checking Claude Code credentials", { platform: platform2 });
|
|
8902
|
+
if (platform2 === "darwin") {
|
|
8903
|
+
return checkMacOSKeychain();
|
|
8904
|
+
} else {
|
|
8905
|
+
return checkCredentialsFile();
|
|
8906
|
+
}
|
|
8907
|
+
}
|
|
8908
|
+
function checkMacOSKeychain() {
|
|
8909
|
+
try {
|
|
8910
|
+
const credentialsJson = execSync5(
|
|
8911
|
+
'security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null',
|
|
8912
|
+
{ encoding: "utf-8" }
|
|
8913
|
+
).trim();
|
|
8914
|
+
if (!credentialsJson) {
|
|
8915
|
+
logger.debug("[claude-max] No credentials found in macOS keychain");
|
|
8916
|
+
return false;
|
|
8917
|
+
}
|
|
8918
|
+
const credentials = JSON.parse(credentialsJson);
|
|
8919
|
+
const hasOauth = !!credentials.claudeAiOauth?.accessToken;
|
|
8920
|
+
logger.debug("[claude-max] macOS keychain credentials check", {
|
|
8921
|
+
hasOauth,
|
|
8922
|
+
hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
|
|
8923
|
+
});
|
|
8924
|
+
return hasOauth;
|
|
8925
|
+
} catch (error) {
|
|
8926
|
+
logger.debug("[claude-max] Error checking macOS keychain", {
|
|
8927
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8928
|
+
});
|
|
8929
|
+
return false;
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
8932
|
+
function checkCredentialsFile() {
|
|
8933
|
+
try {
|
|
8934
|
+
const credentialsPath = join8(homedir5(), ".claude", ".credentials.json");
|
|
8935
|
+
if (!existsSync6(credentialsPath)) {
|
|
8936
|
+
logger.debug("[claude-max] Credentials file not found", { path: credentialsPath });
|
|
8937
|
+
return false;
|
|
8938
|
+
}
|
|
8939
|
+
const credentialsJson = readFileSync5(credentialsPath, "utf-8");
|
|
8940
|
+
const credentials = JSON.parse(credentialsJson);
|
|
8941
|
+
const hasOauth = !!credentials.claudeAiOauth?.accessToken;
|
|
8942
|
+
logger.debug("[claude-max] Credentials file check", {
|
|
8943
|
+
path: credentialsPath,
|
|
8944
|
+
hasOauth,
|
|
8945
|
+
hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
|
|
8946
|
+
});
|
|
8947
|
+
return hasOauth;
|
|
8948
|
+
} catch (error) {
|
|
8949
|
+
logger.debug("[claude-max] Error checking credentials file", {
|
|
8950
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8951
|
+
});
|
|
8952
|
+
return false;
|
|
8953
|
+
}
|
|
8954
|
+
}
|
|
8955
|
+
var init_claude_max = __esm({
|
|
8956
|
+
"src/utils/claude-max.ts"() {
|
|
8957
|
+
"use strict";
|
|
8958
|
+
init_logger();
|
|
8959
|
+
}
|
|
8960
|
+
});
|
|
8961
|
+
|
|
8962
|
+
// src/utils/settings-loader.ts
|
|
8963
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
|
|
8964
|
+
import { join as join9 } from "path";
|
|
8965
|
+
function loadSupatestSettings(cwd) {
|
|
8966
|
+
const settingsPath = join9(cwd, ".supatest", "settings.json");
|
|
8967
|
+
if (!existsSync7(settingsPath)) {
|
|
8968
|
+
return {};
|
|
8969
|
+
}
|
|
8970
|
+
try {
|
|
8971
|
+
const content = readFileSync6(settingsPath, "utf-8");
|
|
8972
|
+
return JSON.parse(content);
|
|
8973
|
+
} catch (error) {
|
|
8974
|
+
console.warn(
|
|
8975
|
+
`Warning: Failed to load settings from ${settingsPath}:`,
|
|
8976
|
+
error instanceof Error ? error.message : String(error)
|
|
8977
|
+
);
|
|
8978
|
+
return {};
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
function saveSupatestSettings(cwd, settings) {
|
|
8982
|
+
const settingsDir = join9(cwd, ".supatest");
|
|
8983
|
+
const settingsPath = join9(settingsDir, "settings.json");
|
|
8984
|
+
try {
|
|
8985
|
+
if (!existsSync7(settingsDir)) {
|
|
8986
|
+
mkdirSync3(settingsDir, { recursive: true });
|
|
8987
|
+
}
|
|
8988
|
+
const existingSettings = loadSupatestSettings(cwd);
|
|
8989
|
+
const mergedSettings = {
|
|
8990
|
+
...existingSettings,
|
|
8991
|
+
...settings,
|
|
8992
|
+
// Preserve nested objects like permissions and hooks
|
|
8993
|
+
permissions: {
|
|
8994
|
+
...existingSettings.permissions,
|
|
8995
|
+
...settings.permissions
|
|
8996
|
+
},
|
|
8997
|
+
hooks: {
|
|
8998
|
+
...existingSettings.hooks,
|
|
8999
|
+
...settings.hooks
|
|
9000
|
+
}
|
|
9001
|
+
};
|
|
9002
|
+
writeFileSync2(settingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
|
|
9003
|
+
} catch (error) {
|
|
9004
|
+
console.warn(
|
|
9005
|
+
`Warning: Failed to save settings to ${settingsPath}:`,
|
|
9006
|
+
error instanceof Error ? error.message : String(error)
|
|
9007
|
+
);
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
var init_settings_loader = __esm({
|
|
9011
|
+
"src/utils/settings-loader.ts"() {
|
|
9012
|
+
"use strict";
|
|
9013
|
+
}
|
|
9014
|
+
});
|
|
9015
|
+
|
|
8923
9016
|
// src/ui/types/auth.ts
|
|
8924
9017
|
var init_auth = __esm({
|
|
8925
9018
|
"src/ui/types/auth.ts"() {
|
|
@@ -8928,8 +9021,8 @@ var init_auth = __esm({
|
|
|
8928
9021
|
});
|
|
8929
9022
|
|
|
8930
9023
|
// src/ui/components/AuthBanner.tsx
|
|
8931
|
-
import { Box as
|
|
8932
|
-
import
|
|
9024
|
+
import { Box as Box14, Text as Text12 } from "ink";
|
|
9025
|
+
import React16 from "react";
|
|
8933
9026
|
var AuthBanner;
|
|
8934
9027
|
var init_AuthBanner = __esm({
|
|
8935
9028
|
"src/ui/components/AuthBanner.tsx"() {
|
|
@@ -8941,10 +9034,10 @@ var init_AuthBanner = __esm({
|
|
|
8941
9034
|
return null;
|
|
8942
9035
|
}
|
|
8943
9036
|
if (authState === "authenticating" /* Authenticating */) {
|
|
8944
|
-
return /* @__PURE__ */
|
|
9037
|
+
return /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 0, paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text12, { color: theme.text.info }, "Authenticating..."));
|
|
8945
9038
|
}
|
|
8946
|
-
return /* @__PURE__ */
|
|
8947
|
-
|
|
9039
|
+
return /* @__PURE__ */ React16.createElement(
|
|
9040
|
+
Box14,
|
|
8948
9041
|
{
|
|
8949
9042
|
borderColor: theme.text.warning,
|
|
8950
9043
|
borderStyle: "round",
|
|
@@ -8952,10 +9045,10 @@ var init_AuthBanner = __esm({
|
|
|
8952
9045
|
paddingX: 1,
|
|
8953
9046
|
paddingY: 0
|
|
8954
9047
|
},
|
|
8955
|
-
/* @__PURE__ */
|
|
8956
|
-
/* @__PURE__ */
|
|
8957
|
-
/* @__PURE__ */
|
|
8958
|
-
/* @__PURE__ */
|
|
9048
|
+
/* @__PURE__ */ React16.createElement(Text12, { bold: true, color: theme.text.warning }, "Not logged in"),
|
|
9049
|
+
/* @__PURE__ */ React16.createElement(Text12, { color: theme.text.dim }, " - Type "),
|
|
9050
|
+
/* @__PURE__ */ React16.createElement(Text12, { color: theme.text.info }, "/login"),
|
|
9051
|
+
/* @__PURE__ */ React16.createElement(Text12, { color: theme.text.dim }, " to authenticate")
|
|
8959
9052
|
);
|
|
8960
9053
|
};
|
|
8961
9054
|
}
|
|
@@ -9177,7 +9270,7 @@ var init_mouse = __esm({
|
|
|
9177
9270
|
|
|
9178
9271
|
// src/ui/contexts/KeypressContext.tsx
|
|
9179
9272
|
import { useStdin as useStdin2 } from "ink";
|
|
9180
|
-
import
|
|
9273
|
+
import React17, {
|
|
9181
9274
|
createContext as createContext2,
|
|
9182
9275
|
useCallback as useCallback2,
|
|
9183
9276
|
useContext as useContext2,
|
|
@@ -9500,7 +9593,7 @@ function KeypressProvider({
|
|
|
9500
9593
|
}
|
|
9501
9594
|
};
|
|
9502
9595
|
}, [stdin, setRawMode, config2, debugKeystrokeLogging, broadcast]);
|
|
9503
|
-
return /* @__PURE__ */
|
|
9596
|
+
return /* @__PURE__ */ React17.createElement(KeypressContext.Provider, { value: { subscribe, unsubscribe } }, children);
|
|
9504
9597
|
}
|
|
9505
9598
|
var BACKSLASH_ENTER_TIMEOUT, ESC_TIMEOUT, PASTE_TIMEOUT, KEY_INFO_MAP, kUTF16SurrogateThreshold, MAC_ALT_KEY_CHARACTER_MAP, KeypressContext;
|
|
9506
9599
|
var init_KeypressContext = __esm({
|
|
@@ -9632,8 +9725,8 @@ var init_useKeypress = __esm({
|
|
|
9632
9725
|
});
|
|
9633
9726
|
|
|
9634
9727
|
// src/ui/components/AuthDialog.tsx
|
|
9635
|
-
import { Box as
|
|
9636
|
-
import
|
|
9728
|
+
import { Box as Box15, Text as Text13 } from "ink";
|
|
9729
|
+
import React18 from "react";
|
|
9637
9730
|
var AuthDialog;
|
|
9638
9731
|
var init_AuthDialog = __esm({
|
|
9639
9732
|
"src/ui/components/AuthDialog.tsx"() {
|
|
@@ -9649,8 +9742,8 @@ var init_AuthDialog = __esm({
|
|
|
9649
9742
|
},
|
|
9650
9743
|
{ isActive: true }
|
|
9651
9744
|
);
|
|
9652
|
-
return /* @__PURE__ */
|
|
9653
|
-
|
|
9745
|
+
return /* @__PURE__ */ React18.createElement(
|
|
9746
|
+
Box15,
|
|
9654
9747
|
{
|
|
9655
9748
|
borderColor: theme.border.accent,
|
|
9656
9749
|
borderStyle: "round",
|
|
@@ -9658,18 +9751,18 @@ var init_AuthDialog = __esm({
|
|
|
9658
9751
|
paddingX: 2,
|
|
9659
9752
|
paddingY: 1
|
|
9660
9753
|
},
|
|
9661
|
-
/* @__PURE__ */
|
|
9662
|
-
/* @__PURE__ */
|
|
9663
|
-
/* @__PURE__ */
|
|
9664
|
-
/* @__PURE__ */
|
|
9754
|
+
/* @__PURE__ */ React18.createElement(Text13, { bold: true, color: theme.text.primary }, "Welcome to Supatest CLI"),
|
|
9755
|
+
/* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.secondary }, "Authentication is required to use Supatest CLI.")),
|
|
9756
|
+
/* @__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"))),
|
|
9757
|
+
/* @__PURE__ */ React18.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text13, { color: theme.text.dim, italic: true }, "Press Enter or L to login"))
|
|
9665
9758
|
);
|
|
9666
9759
|
};
|
|
9667
9760
|
}
|
|
9668
9761
|
});
|
|
9669
9762
|
|
|
9670
9763
|
// src/ui/components/FeedbackDialog.tsx
|
|
9671
|
-
import { Box as
|
|
9672
|
-
import
|
|
9764
|
+
import { Box as Box16, Text as Text14, useInput } from "ink";
|
|
9765
|
+
import React19, { useState as useState5 } from "react";
|
|
9673
9766
|
var CATEGORY_ORDER, FeedbackDialog;
|
|
9674
9767
|
var init_FeedbackDialog = __esm({
|
|
9675
9768
|
"src/ui/components/FeedbackDialog.tsx"() {
|
|
@@ -9764,21 +9857,21 @@ var init_FeedbackDialog = __esm({
|
|
|
9764
9857
|
});
|
|
9765
9858
|
const renderDescription = () => {
|
|
9766
9859
|
if (!description && focus !== "description") {
|
|
9767
|
-
return /* @__PURE__ */
|
|
9860
|
+
return /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.dim, italic: true }, "Enter your feedback...");
|
|
9768
9861
|
}
|
|
9769
9862
|
if (focus === "description") {
|
|
9770
9863
|
const before = description.slice(0, cursorPosition);
|
|
9771
9864
|
const charAtCursor = description[cursorPosition] || " ";
|
|
9772
9865
|
const after = description.slice(cursorPosition + 1);
|
|
9773
9866
|
if (!description) {
|
|
9774
|
-
return /* @__PURE__ */
|
|
9867
|
+
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
9868
|
}
|
|
9776
|
-
return /* @__PURE__ */
|
|
9869
|
+
return /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.primary }, before, /* @__PURE__ */ React19.createElement(Text14, { inverse: true }, charAtCursor), after);
|
|
9777
9870
|
}
|
|
9778
|
-
return /* @__PURE__ */
|
|
9871
|
+
return /* @__PURE__ */ React19.createElement(Text14, { color: theme.text.primary }, description);
|
|
9779
9872
|
};
|
|
9780
|
-
return /* @__PURE__ */
|
|
9781
|
-
|
|
9873
|
+
return /* @__PURE__ */ React19.createElement(
|
|
9874
|
+
Box16,
|
|
9782
9875
|
{
|
|
9783
9876
|
borderColor: theme.border.accent,
|
|
9784
9877
|
borderStyle: "round",
|
|
@@ -9786,18 +9879,18 @@ var init_FeedbackDialog = __esm({
|
|
|
9786
9879
|
paddingX: 2,
|
|
9787
9880
|
paddingY: 1
|
|
9788
9881
|
},
|
|
9789
|
-
/* @__PURE__ */
|
|
9790
|
-
/* @__PURE__ */
|
|
9791
|
-
/* @__PURE__ */
|
|
9792
|
-
/* @__PURE__ */
|
|
9882
|
+
/* @__PURE__ */ React19.createElement(Text14, { bold: true, color: theme.text.accent }, "Report Issue"),
|
|
9883
|
+
/* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }),
|
|
9884
|
+
/* @__PURE__ */ React19.createElement(Text14, { bold: true, color: theme.text.secondary }, "Category:"),
|
|
9885
|
+
/* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column", marginLeft: 2, marginTop: 0 }, CATEGORY_ORDER.map((category) => {
|
|
9793
9886
|
const isSelected = selectedCategory === category;
|
|
9794
9887
|
const info = FEEDBACK_CATEGORIES[category];
|
|
9795
|
-
return /* @__PURE__ */
|
|
9888
|
+
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
9889
|
})),
|
|
9797
|
-
/* @__PURE__ */
|
|
9798
|
-
/* @__PURE__ */
|
|
9799
|
-
/* @__PURE__ */
|
|
9800
|
-
|
|
9890
|
+
/* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }),
|
|
9891
|
+
/* @__PURE__ */ React19.createElement(Text14, { bold: true, color: theme.text.secondary }, "Description:"),
|
|
9892
|
+
/* @__PURE__ */ React19.createElement(
|
|
9893
|
+
Box16,
|
|
9801
9894
|
{
|
|
9802
9895
|
borderColor: focus === "description" ? theme.border.accent : theme.border.default,
|
|
9803
9896
|
borderStyle: "round",
|
|
@@ -9808,8 +9901,8 @@ var init_FeedbackDialog = __esm({
|
|
|
9808
9901
|
},
|
|
9809
9902
|
renderDescription()
|
|
9810
9903
|
),
|
|
9811
|
-
/* @__PURE__ */
|
|
9812
|
-
/* @__PURE__ */
|
|
9904
|
+
/* @__PURE__ */ React19.createElement(Box16, { marginTop: 1 }),
|
|
9905
|
+
/* @__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
9906
|
);
|
|
9814
9907
|
};
|
|
9815
9908
|
}
|
|
@@ -9918,8 +10011,8 @@ var init_context_builder = __esm({
|
|
|
9918
10011
|
});
|
|
9919
10012
|
|
|
9920
10013
|
// src/ui/components/RunSelector.tsx
|
|
9921
|
-
import { Box as
|
|
9922
|
-
import
|
|
10014
|
+
import { Box as Box17, Text as Text15, useInput as useInput2 } from "ink";
|
|
10015
|
+
import React20, { useEffect as useEffect6, useState as useState6 } from "react";
|
|
9923
10016
|
function formatRelativeTime(date) {
|
|
9924
10017
|
const now = /* @__PURE__ */ new Date();
|
|
9925
10018
|
const diffMs = now.getTime() - date.getTime();
|
|
@@ -10013,13 +10106,13 @@ var init_RunSelector = __esm({
|
|
|
10013
10106
|
}
|
|
10014
10107
|
});
|
|
10015
10108
|
if (error) {
|
|
10016
|
-
return /* @__PURE__ */
|
|
10109
|
+
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
10110
|
}
|
|
10018
10111
|
if (allRuns.length === 0 && isLoading) {
|
|
10019
|
-
return /* @__PURE__ */
|
|
10112
|
+
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
10113
|
}
|
|
10021
10114
|
if (allRuns.length === 0 && !isLoading) {
|
|
10022
|
-
return /* @__PURE__ */
|
|
10115
|
+
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
10116
|
}
|
|
10024
10117
|
let startIndex;
|
|
10025
10118
|
let endIndex;
|
|
@@ -10036,7 +10129,7 @@ var init_RunSelector = __esm({
|
|
|
10036
10129
|
}
|
|
10037
10130
|
}
|
|
10038
10131
|
const visibleRuns = allRuns.slice(startIndex, endIndex);
|
|
10039
|
-
return /* @__PURE__ */
|
|
10132
|
+
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
10133
|
const actualIndex = startIndex + index;
|
|
10041
10134
|
const isSelected = actualIndex === selectedIndex;
|
|
10042
10135
|
const branch = run.git?.branch || "unknown";
|
|
@@ -10048,15 +10141,15 @@ var init_RunSelector = __esm({
|
|
|
10048
10141
|
const hasFailures = failed > 0;
|
|
10049
10142
|
const indicator = isSelected ? "\u25B6 " : " ";
|
|
10050
10143
|
const bgColor = isSelected ? theme.text.accent : void 0;
|
|
10051
|
-
return /* @__PURE__ */
|
|
10052
|
-
})), /* @__PURE__ */
|
|
10144
|
+
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));
|
|
10145
|
+
})), /* @__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
10146
|
};
|
|
10054
10147
|
}
|
|
10055
10148
|
});
|
|
10056
10149
|
|
|
10057
10150
|
// src/ui/components/TestSelector.tsx
|
|
10058
|
-
import { Box as
|
|
10059
|
-
import
|
|
10151
|
+
import { Box as Box18, Text as Text16, useInput as useInput3 } from "ink";
|
|
10152
|
+
import React21, { useEffect as useEffect7, useState as useState7 } from "react";
|
|
10060
10153
|
var PAGE_SIZE2, VISIBLE_ITEMS2, TestSelector;
|
|
10061
10154
|
var init_TestSelector = __esm({
|
|
10062
10155
|
"src/ui/components/TestSelector.tsx"() {
|
|
@@ -10168,13 +10261,13 @@ var init_TestSelector = __esm({
|
|
|
10168
10261
|
}
|
|
10169
10262
|
});
|
|
10170
10263
|
if (error) {
|
|
10171
|
-
return /* @__PURE__ */
|
|
10264
|
+
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
10265
|
}
|
|
10173
10266
|
if (allTests.length === 0 && isLoading) {
|
|
10174
|
-
return /* @__PURE__ */
|
|
10267
|
+
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
10268
|
}
|
|
10176
10269
|
if (allTests.length === 0 && !isLoading) {
|
|
10177
|
-
return /* @__PURE__ */
|
|
10270
|
+
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
10271
|
}
|
|
10179
10272
|
const testStartIndex = Math.max(0, cursorIndex - 1);
|
|
10180
10273
|
const adjustedStart = isOnFixAll ? 0 : Math.max(0, testStartIndex - Math.floor(VISIBLE_ITEMS2 / 2));
|
|
@@ -10182,8 +10275,8 @@ var init_TestSelector = __esm({
|
|
|
10182
10275
|
const visibleTests = allTests.slice(adjustedStart, adjustedEnd);
|
|
10183
10276
|
const branch = run.git?.branch || "unknown";
|
|
10184
10277
|
const commit = run.git?.commit?.slice(0, 7) || "";
|
|
10185
|
-
return /* @__PURE__ */
|
|
10186
|
-
|
|
10278
|
+
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(
|
|
10279
|
+
Text16,
|
|
10187
10280
|
{
|
|
10188
10281
|
backgroundColor: isOnFixAll ? theme.text.accent : void 0,
|
|
10189
10282
|
bold: isOnFixAll,
|
|
@@ -10195,7 +10288,7 @@ var init_TestSelector = __esm({
|
|
|
10195
10288
|
" Failed Test",
|
|
10196
10289
|
allTests.length !== 1 ? "s" : "",
|
|
10197
10290
|
"]"
|
|
10198
|
-
)), /* @__PURE__ */
|
|
10291
|
+
)), /* @__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
10292
|
const actualIndex = adjustedStart + index;
|
|
10200
10293
|
const itemIndex = actualIndex + 1;
|
|
10201
10294
|
const isSelected = itemIndex === cursorIndex;
|
|
@@ -10206,15 +10299,15 @@ var init_TestSelector = __esm({
|
|
|
10206
10299
|
const title = test.title;
|
|
10207
10300
|
const indicator = isSelected ? "\u25B6 " : " ";
|
|
10208
10301
|
const bgColor = isSelected ? theme.text.accent : void 0;
|
|
10209
|
-
return /* @__PURE__ */
|
|
10210
|
-
})), /* @__PURE__ */
|
|
10302
|
+
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));
|
|
10303
|
+
})), /* @__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
10304
|
};
|
|
10212
10305
|
}
|
|
10213
10306
|
});
|
|
10214
10307
|
|
|
10215
10308
|
// src/ui/components/FixFlow.tsx
|
|
10216
|
-
import { Box as
|
|
10217
|
-
import
|
|
10309
|
+
import { Box as Box19, Text as Text17, useInput as useInput4 } from "ink";
|
|
10310
|
+
import React22, { useState as useState8 } from "react";
|
|
10218
10311
|
var FixFlow;
|
|
10219
10312
|
var init_FixFlow = __esm({
|
|
10220
10313
|
"src/ui/components/FixFlow.tsx"() {
|
|
@@ -10285,7 +10378,7 @@ var init_FixFlow = __esm({
|
|
|
10285
10378
|
};
|
|
10286
10379
|
switch (step) {
|
|
10287
10380
|
case "select-run":
|
|
10288
|
-
return /* @__PURE__ */
|
|
10381
|
+
return /* @__PURE__ */ React22.createElement(
|
|
10289
10382
|
RunSelector,
|
|
10290
10383
|
{
|
|
10291
10384
|
apiClient,
|
|
@@ -10298,7 +10391,7 @@ var init_FixFlow = __esm({
|
|
|
10298
10391
|
if (!selectedRun) {
|
|
10299
10392
|
return null;
|
|
10300
10393
|
}
|
|
10301
|
-
return /* @__PURE__ */
|
|
10394
|
+
return /* @__PURE__ */ React22.createElement(
|
|
10302
10395
|
TestSelector,
|
|
10303
10396
|
{
|
|
10304
10397
|
apiClient,
|
|
@@ -10309,13 +10402,13 @@ var init_FixFlow = __esm({
|
|
|
10309
10402
|
);
|
|
10310
10403
|
case "loading-details":
|
|
10311
10404
|
if (loadError) {
|
|
10312
|
-
return /* @__PURE__ */
|
|
10405
|
+
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
10406
|
}
|
|
10314
|
-
return /* @__PURE__ */
|
|
10407
|
+
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
10408
|
case "fixing":
|
|
10316
|
-
return /* @__PURE__ */
|
|
10409
|
+
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
10410
|
case "complete":
|
|
10318
|
-
return /* @__PURE__ */
|
|
10411
|
+
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
10412
|
default:
|
|
10320
10413
|
return null;
|
|
10321
10414
|
}
|
|
@@ -10324,8 +10417,8 @@ var init_FixFlow = __esm({
|
|
|
10324
10417
|
});
|
|
10325
10418
|
|
|
10326
10419
|
// src/ui/components/HelpMenu.tsx
|
|
10327
|
-
import { Box as
|
|
10328
|
-
import
|
|
10420
|
+
import { Box as Box20, Text as Text18, useInput as useInput5 } from "ink";
|
|
10421
|
+
import React23, { useEffect as useEffect9, useState as useState9 } from "react";
|
|
10329
10422
|
var HelpMenu;
|
|
10330
10423
|
var init_HelpMenu = __esm({
|
|
10331
10424
|
"src/ui/components/HelpMenu.tsx"() {
|
|
@@ -10344,8 +10437,8 @@ var init_HelpMenu = __esm({
|
|
|
10344
10437
|
onClose();
|
|
10345
10438
|
}
|
|
10346
10439
|
});
|
|
10347
|
-
return /* @__PURE__ */
|
|
10348
|
-
|
|
10440
|
+
return /* @__PURE__ */ React23.createElement(
|
|
10441
|
+
Box20,
|
|
10349
10442
|
{
|
|
10350
10443
|
borderColor: theme.border.accent,
|
|
10351
10444
|
borderStyle: "round",
|
|
@@ -10353,21 +10446,21 @@ var init_HelpMenu = __esm({
|
|
|
10353
10446
|
paddingX: 2,
|
|
10354
10447
|
paddingY: 1
|
|
10355
10448
|
},
|
|
10356
|
-
/* @__PURE__ */
|
|
10357
|
-
/* @__PURE__ */
|
|
10358
|
-
/* @__PURE__ */
|
|
10359
|
-
/* @__PURE__ */
|
|
10360
|
-
customCommands.length > 0 && /* @__PURE__ */
|
|
10361
|
-
/* @__PURE__ */
|
|
10362
|
-
/* @__PURE__ */
|
|
10363
|
-
/* @__PURE__ */
|
|
10364
|
-
/* @__PURE__ */
|
|
10365
|
-
/* @__PURE__ */
|
|
10366
|
-
/* @__PURE__ */
|
|
10367
|
-
/* @__PURE__ */
|
|
10368
|
-
/* @__PURE__ */
|
|
10369
|
-
/* @__PURE__ */
|
|
10370
|
-
/* @__PURE__ */
|
|
10449
|
+
/* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.accent }, "\u{1F4D6} Supatest AI CLI - Help"),
|
|
10450
|
+
/* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
|
|
10451
|
+
/* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Slash Commands:"),
|
|
10452
|
+
/* @__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"))),
|
|
10453
|
+
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)"))),
|
|
10454
|
+
/* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
|
|
10455
|
+
/* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Keyboard Shortcuts:"),
|
|
10456
|
+
/* @__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"))),
|
|
10457
|
+
/* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
|
|
10458
|
+
/* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "File References:"),
|
|
10459
|
+
/* @__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"')),
|
|
10460
|
+
/* @__PURE__ */ React23.createElement(Box20, { marginTop: 1 }),
|
|
10461
|
+
/* @__PURE__ */ React23.createElement(Text18, { bold: true, color: theme.text.secondary }, "Tips:"),
|
|
10462
|
+
/* @__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")),
|
|
10463
|
+
/* @__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
10464
|
);
|
|
10372
10465
|
};
|
|
10373
10466
|
}
|
|
@@ -10456,12 +10549,27 @@ var init_file_completion = __esm({
|
|
|
10456
10549
|
});
|
|
10457
10550
|
|
|
10458
10551
|
// src/ui/components/ModelSelector.tsx
|
|
10459
|
-
import { Box as
|
|
10460
|
-
import
|
|
10461
|
-
function
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10552
|
+
import { Box as Box21, Text as Text19, useInput as useInput6 } from "ink";
|
|
10553
|
+
import React24, { useState as useState10 } from "react";
|
|
10554
|
+
function getAvailableModels(isClaudeMax) {
|
|
10555
|
+
if (isClaudeMax) {
|
|
10556
|
+
return AVAILABLE_MODELS.map((m) => ({
|
|
10557
|
+
id: m.id,
|
|
10558
|
+
name: m.name,
|
|
10559
|
+
description: m.description
|
|
10560
|
+
}));
|
|
10561
|
+
}
|
|
10562
|
+
return MODEL_TIERS.map((tier) => ({
|
|
10563
|
+
id: tier,
|
|
10564
|
+
name: getModelDisplayName(tier),
|
|
10565
|
+
description: tier === "small" ? "Fast & lightweight" : tier === "medium" ? "Balanced performance" : "Most capable"
|
|
10566
|
+
}));
|
|
10567
|
+
}
|
|
10568
|
+
function getNextModel(currentModel, isClaudeMax = false) {
|
|
10569
|
+
const models = getAvailableModels(isClaudeMax);
|
|
10570
|
+
const currentIndex = models.findIndex((m) => m.id === currentModel);
|
|
10571
|
+
const nextIndex = (currentIndex + 1) % models.length;
|
|
10572
|
+
return models[nextIndex].id;
|
|
10465
10573
|
}
|
|
10466
10574
|
var ModelSelector;
|
|
10467
10575
|
var init_ModelSelector = __esm({
|
|
@@ -10472,27 +10580,29 @@ var init_ModelSelector = __esm({
|
|
|
10472
10580
|
ModelSelector = ({
|
|
10473
10581
|
currentModel,
|
|
10474
10582
|
onSelect,
|
|
10475
|
-
onCancel
|
|
10583
|
+
onCancel,
|
|
10584
|
+
isClaudeMax = false
|
|
10476
10585
|
}) => {
|
|
10477
|
-
const
|
|
10586
|
+
const models = getAvailableModels(isClaudeMax);
|
|
10587
|
+
const currentIndex = models.findIndex((m) => m.id === currentModel);
|
|
10478
10588
|
const [selectedIndex, setSelectedIndex] = useState10(currentIndex >= 0 ? currentIndex : 0);
|
|
10479
10589
|
useInput6((input, key) => {
|
|
10480
10590
|
if (key.upArrow) {
|
|
10481
|
-
setSelectedIndex((prev) => prev > 0 ? prev - 1 :
|
|
10591
|
+
setSelectedIndex((prev) => prev > 0 ? prev - 1 : models.length - 1);
|
|
10482
10592
|
} else if (key.downArrow) {
|
|
10483
|
-
setSelectedIndex((prev) => prev <
|
|
10593
|
+
setSelectedIndex((prev) => prev < models.length - 1 ? prev + 1 : 0);
|
|
10484
10594
|
} else if (key.return) {
|
|
10485
|
-
onSelect(
|
|
10595
|
+
onSelect(models[selectedIndex].id);
|
|
10486
10596
|
} else if (key.escape || input === "q") {
|
|
10487
10597
|
onCancel();
|
|
10488
10598
|
}
|
|
10489
10599
|
});
|
|
10490
|
-
return /* @__PURE__ */
|
|
10600
|
+
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
10601
|
const isSelected = index === selectedIndex;
|
|
10492
10602
|
const isCurrent = model.id === currentModel;
|
|
10493
10603
|
const indicator = isSelected ? "\u25B6 " : " ";
|
|
10494
|
-
return /* @__PURE__ */
|
|
10495
|
-
|
|
10604
|
+
return /* @__PURE__ */ React24.createElement(Box21, { gap: 1, key: model.id }, /* @__PURE__ */ React24.createElement(
|
|
10605
|
+
Text19,
|
|
10496
10606
|
{
|
|
10497
10607
|
backgroundColor: isSelected ? theme.text.accent : void 0,
|
|
10498
10608
|
bold: isSelected,
|
|
@@ -10500,15 +10610,15 @@ var init_ModelSelector = __esm({
|
|
|
10500
10610
|
},
|
|
10501
10611
|
indicator,
|
|
10502
10612
|
model.name.padEnd(12)
|
|
10503
|
-
), /* @__PURE__ */
|
|
10504
|
-
|
|
10613
|
+
), /* @__PURE__ */ React24.createElement(
|
|
10614
|
+
Text19,
|
|
10505
10615
|
{
|
|
10506
10616
|
backgroundColor: isSelected ? theme.text.accent : void 0,
|
|
10507
10617
|
color: isSelected ? "black" : theme.text.dim
|
|
10508
10618
|
},
|
|
10509
10619
|
model.description
|
|
10510
|
-
), isCurrent && /* @__PURE__ */
|
|
10511
|
-
})), /* @__PURE__ */
|
|
10620
|
+
), isCurrent && /* @__PURE__ */ React24.createElement(Text19, { color: theme.text.success }, " (current)"));
|
|
10621
|
+
})), /* @__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
10622
|
};
|
|
10513
10623
|
}
|
|
10514
10624
|
});
|
|
@@ -10516,8 +10626,8 @@ var init_ModelSelector = __esm({
|
|
|
10516
10626
|
// src/ui/components/InputPrompt.tsx
|
|
10517
10627
|
import path5 from "path";
|
|
10518
10628
|
import chalk4 from "chalk";
|
|
10519
|
-
import { Box as
|
|
10520
|
-
import
|
|
10629
|
+
import { Box as Box22, Text as Text20 } from "ink";
|
|
10630
|
+
import React25, { forwardRef, useEffect as useEffect10, useImperativeHandle, useState as useState11 } from "react";
|
|
10521
10631
|
var InputPrompt;
|
|
10522
10632
|
var init_InputPrompt = __esm({
|
|
10523
10633
|
"src/ui/components/InputPrompt.tsx"() {
|
|
@@ -10537,7 +10647,8 @@ var init_InputPrompt = __esm({
|
|
|
10537
10647
|
cwd,
|
|
10538
10648
|
currentFolder,
|
|
10539
10649
|
gitBranch,
|
|
10540
|
-
onInputChange
|
|
10650
|
+
onInputChange,
|
|
10651
|
+
isClaudeMax = false
|
|
10541
10652
|
}, ref) => {
|
|
10542
10653
|
const { messages, agentMode, selectedModel, setSelectedModel, isAgentRunning, usageStats } = useSession();
|
|
10543
10654
|
const [value, setValue] = useState11("");
|
|
@@ -10552,6 +10663,7 @@ var init_InputPrompt = __esm({
|
|
|
10552
10663
|
{ name: "/resume", desc: "Resume session" },
|
|
10553
10664
|
{ name: "/clear", desc: "Clear history" },
|
|
10554
10665
|
{ name: "/model", desc: "Change model" },
|
|
10666
|
+
{ name: "/provider", desc: "Select LLM provider" },
|
|
10555
10667
|
{ name: "/fix", desc: "Fix failing tests" },
|
|
10556
10668
|
{ name: "/feedback", desc: "Report an issue" },
|
|
10557
10669
|
{ name: "/setup", desc: "Install Playwright browsers" },
|
|
@@ -10694,7 +10806,7 @@ var init_InputPrompt = __esm({
|
|
|
10694
10806
|
}
|
|
10695
10807
|
}
|
|
10696
10808
|
if (key.shift && key.name === "m" && !isAgentRunning) {
|
|
10697
|
-
setSelectedModel(getNextModel(selectedModel));
|
|
10809
|
+
setSelectedModel(getNextModel(selectedModel, isClaudeMax));
|
|
10698
10810
|
return;
|
|
10699
10811
|
}
|
|
10700
10812
|
if (input === "?" && value.length === 0 && onHelpToggle) {
|
|
@@ -10783,8 +10895,8 @@ var init_InputPrompt = __esm({
|
|
|
10783
10895
|
}
|
|
10784
10896
|
charCount += lineLength + 1;
|
|
10785
10897
|
}
|
|
10786
|
-
return /* @__PURE__ */
|
|
10787
|
-
|
|
10898
|
+
return /* @__PURE__ */ React25.createElement(Box22, { flexDirection: "column", width: "100%" }, showSuggestions && /* @__PURE__ */ React25.createElement(
|
|
10899
|
+
Box22,
|
|
10788
10900
|
{
|
|
10789
10901
|
borderColor: theme.border.default,
|
|
10790
10902
|
borderStyle: "round",
|
|
@@ -10795,12 +10907,12 @@ var init_InputPrompt = __esm({
|
|
|
10795
10907
|
suggestions.map((item, idx) => {
|
|
10796
10908
|
const isSeparator = item.startsWith("\u2500\u2500\u2500\u2500\u2500");
|
|
10797
10909
|
if (isSeparator) {
|
|
10798
|
-
return /* @__PURE__ */
|
|
10910
|
+
return /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim, key: item }, " ", item);
|
|
10799
10911
|
}
|
|
10800
|
-
return /* @__PURE__ */
|
|
10912
|
+
return /* @__PURE__ */ React25.createElement(Text20, { color: idx === activeSuggestion ? theme.text.accent : theme.text.dim, key: item }, idx === activeSuggestion ? "\u276F " : " ", item);
|
|
10801
10913
|
})
|
|
10802
|
-
), /* @__PURE__ */
|
|
10803
|
-
|
|
10914
|
+
), /* @__PURE__ */ React25.createElement(
|
|
10915
|
+
Box22,
|
|
10804
10916
|
{
|
|
10805
10917
|
borderColor: disabled ? theme.border.default : theme.border.accent,
|
|
10806
10918
|
borderStyle: "round",
|
|
@@ -10810,24 +10922,96 @@ var init_InputPrompt = __esm({
|
|
|
10810
10922
|
paddingX: 1,
|
|
10811
10923
|
width: "100%"
|
|
10812
10924
|
},
|
|
10813
|
-
/* @__PURE__ */
|
|
10925
|
+
/* @__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
10926
|
if (idx === cursorLine && !disabled) {
|
|
10815
10927
|
const before = line.slice(0, cursorCol);
|
|
10816
10928
|
const charAtCursor = line[cursorCol] || " ";
|
|
10817
10929
|
const after = line.slice(cursorCol + 1);
|
|
10818
|
-
return /* @__PURE__ */
|
|
10930
|
+
return /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.primary, key: idx }, before, chalk4.inverse(charAtCursor), after);
|
|
10819
10931
|
}
|
|
10820
|
-
return /* @__PURE__ */
|
|
10821
|
-
})), !hasContent && disabled && /* @__PURE__ */
|
|
10822
|
-
), /* @__PURE__ */
|
|
10932
|
+
return /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.primary, key: idx }, line);
|
|
10933
|
+
})), !hasContent && disabled && /* @__PURE__ */ React25.createElement(Text20, { color: theme.text.dim, italic: true }, "Waiting for agent to complete...")))
|
|
10934
|
+
), /* @__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
10935
|
});
|
|
10824
10936
|
InputPrompt.displayName = "InputPrompt";
|
|
10825
10937
|
}
|
|
10826
10938
|
});
|
|
10827
10939
|
|
|
10940
|
+
// src/ui/components/ProviderSelector.tsx
|
|
10941
|
+
import { Box as Box23, Text as Text21, useInput as useInput7 } from "ink";
|
|
10942
|
+
import React26, { useState as useState12 } from "react";
|
|
10943
|
+
var PROVIDERS, ProviderSelector;
|
|
10944
|
+
var init_ProviderSelector = __esm({
|
|
10945
|
+
"src/ui/components/ProviderSelector.tsx"() {
|
|
10946
|
+
"use strict";
|
|
10947
|
+
init_theme();
|
|
10948
|
+
PROVIDERS = [
|
|
10949
|
+
{
|
|
10950
|
+
id: "supatest-managed",
|
|
10951
|
+
name: "Supatest Managed",
|
|
10952
|
+
description: "Uses Supatest API with available models"
|
|
10953
|
+
},
|
|
10954
|
+
{
|
|
10955
|
+
id: "claude-max",
|
|
10956
|
+
name: "Claude Max",
|
|
10957
|
+
description: "Direct Claude Max subscription (requires Claude Code login)"
|
|
10958
|
+
}
|
|
10959
|
+
];
|
|
10960
|
+
ProviderSelector = ({
|
|
10961
|
+
currentProvider,
|
|
10962
|
+
onSelect,
|
|
10963
|
+
onCancel,
|
|
10964
|
+
claudeMaxAvailable
|
|
10965
|
+
}) => {
|
|
10966
|
+
const availableProviders = PROVIDERS.filter(
|
|
10967
|
+
(p) => p.id !== "claude-max" || claudeMaxAvailable
|
|
10968
|
+
);
|
|
10969
|
+
const currentIndex = availableProviders.findIndex(
|
|
10970
|
+
(p) => p.id === currentProvider
|
|
10971
|
+
);
|
|
10972
|
+
const [selectedIndex, setSelectedIndex] = useState12(
|
|
10973
|
+
currentIndex >= 0 ? currentIndex : 0
|
|
10974
|
+
);
|
|
10975
|
+
useInput7((input, key) => {
|
|
10976
|
+
if (key.upArrow) {
|
|
10977
|
+
setSelectedIndex(
|
|
10978
|
+
(prev) => prev > 0 ? prev - 1 : availableProviders.length - 1
|
|
10979
|
+
);
|
|
10980
|
+
} else if (key.downArrow) {
|
|
10981
|
+
setSelectedIndex(
|
|
10982
|
+
(prev) => prev < availableProviders.length - 1 ? prev + 1 : 0
|
|
10983
|
+
);
|
|
10984
|
+
} else if (key.return) {
|
|
10985
|
+
onSelect(availableProviders[selectedIndex].id);
|
|
10986
|
+
} else if (key.escape || input === "q") {
|
|
10987
|
+
onCancel();
|
|
10988
|
+
}
|
|
10989
|
+
});
|
|
10990
|
+
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) => {
|
|
10991
|
+
const isSelected = index === selectedIndex;
|
|
10992
|
+
const isCurrent = provider.id === currentProvider;
|
|
10993
|
+
const indicator = isSelected ? "\u25B6 " : " ";
|
|
10994
|
+
return /* @__PURE__ */ React26.createElement(
|
|
10995
|
+
Text21,
|
|
10996
|
+
{
|
|
10997
|
+
backgroundColor: isSelected ? theme.text.accent : void 0,
|
|
10998
|
+
bold: isSelected,
|
|
10999
|
+
color: isSelected ? "black" : theme.text.primary,
|
|
11000
|
+
key: provider.id
|
|
11001
|
+
},
|
|
11002
|
+
indicator,
|
|
11003
|
+
provider.name,
|
|
11004
|
+
isCurrent && /* @__PURE__ */ React26.createElement(Text21, { color: isSelected ? "black" : theme.text.success }, " (current)"),
|
|
11005
|
+
/* @__PURE__ */ React26.createElement(Text21, { color: isSelected ? "black" : theme.text.dim }, " - ", provider.description)
|
|
11006
|
+
);
|
|
11007
|
+
})), /* @__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")));
|
|
11008
|
+
};
|
|
11009
|
+
}
|
|
11010
|
+
});
|
|
11011
|
+
|
|
10828
11012
|
// src/ui/components/SessionSelector.tsx
|
|
10829
|
-
import { Box as
|
|
10830
|
-
import
|
|
11013
|
+
import { Box as Box24, Text as Text22, useInput as useInput8 } from "ink";
|
|
11014
|
+
import React27, { useEffect as useEffect11, useState as useState13 } from "react";
|
|
10831
11015
|
function getSessionPrefix(authMethod) {
|
|
10832
11016
|
return authMethod === "api-key" ? "[Team]" : "[Me]";
|
|
10833
11017
|
}
|
|
@@ -10842,12 +11026,12 @@ var init_SessionSelector = __esm({
|
|
|
10842
11026
|
onSelect,
|
|
10843
11027
|
onCancel
|
|
10844
11028
|
}) => {
|
|
10845
|
-
const [allSessions, setAllSessions] =
|
|
10846
|
-
const [selectedIndex, setSelectedIndex] =
|
|
10847
|
-
const [isLoading, setIsLoading] =
|
|
10848
|
-
const [hasMore, setHasMore] =
|
|
10849
|
-
const [totalSessions, setTotalSessions] =
|
|
10850
|
-
const [error, setError] =
|
|
11029
|
+
const [allSessions, setAllSessions] = useState13([]);
|
|
11030
|
+
const [selectedIndex, setSelectedIndex] = useState13(0);
|
|
11031
|
+
const [isLoading, setIsLoading] = useState13(false);
|
|
11032
|
+
const [hasMore, setHasMore] = useState13(true);
|
|
11033
|
+
const [totalSessions, setTotalSessions] = useState13(0);
|
|
11034
|
+
const [error, setError] = useState13(null);
|
|
10851
11035
|
useEffect11(() => {
|
|
10852
11036
|
loadMoreSessions();
|
|
10853
11037
|
}, []);
|
|
@@ -10874,7 +11058,7 @@ var init_SessionSelector = __esm({
|
|
|
10874
11058
|
setIsLoading(false);
|
|
10875
11059
|
}
|
|
10876
11060
|
};
|
|
10877
|
-
|
|
11061
|
+
useInput8((input, key) => {
|
|
10878
11062
|
if (allSessions.length === 0) {
|
|
10879
11063
|
if (key.escape || input === "q") {
|
|
10880
11064
|
onCancel();
|
|
@@ -10898,13 +11082,13 @@ var init_SessionSelector = __esm({
|
|
|
10898
11082
|
}
|
|
10899
11083
|
});
|
|
10900
11084
|
if (error) {
|
|
10901
|
-
return /* @__PURE__ */
|
|
11085
|
+
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
11086
|
}
|
|
10903
11087
|
if (allSessions.length === 0 && isLoading) {
|
|
10904
|
-
return /* @__PURE__ */
|
|
11088
|
+
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
11089
|
}
|
|
10906
11090
|
if (allSessions.length === 0 && !isLoading) {
|
|
10907
|
-
return /* @__PURE__ */
|
|
11091
|
+
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
11092
|
}
|
|
10909
11093
|
const VISIBLE_ITEMS3 = 10;
|
|
10910
11094
|
let startIndex;
|
|
@@ -10924,7 +11108,7 @@ var init_SessionSelector = __esm({
|
|
|
10924
11108
|
const visibleSessions = allSessions.slice(startIndex, endIndex);
|
|
10925
11109
|
const MAX_TITLE_WIDTH = 50;
|
|
10926
11110
|
const PREFIX_WIDTH = 6;
|
|
10927
|
-
return /* @__PURE__ */
|
|
11111
|
+
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
11112
|
const actualIndex = startIndex + index;
|
|
10929
11113
|
const isSelected = actualIndex === selectedIndex;
|
|
10930
11114
|
const title = item.session.title || "Untitled session";
|
|
@@ -10948,8 +11132,8 @@ var init_SessionSelector = __esm({
|
|
|
10948
11132
|
const prefixColor = item.prefix === "[Me]" ? "cyan" : "yellow";
|
|
10949
11133
|
const indicator = isSelected ? "\u25B6 " : " ";
|
|
10950
11134
|
const bgColor = isSelected ? theme.text.accent : void 0;
|
|
10951
|
-
return /* @__PURE__ */
|
|
10952
|
-
})), /* @__PURE__ */
|
|
11135
|
+
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, ")"));
|
|
11136
|
+
})), /* @__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
11137
|
};
|
|
10954
11138
|
}
|
|
10955
11139
|
});
|
|
@@ -10999,10 +11183,10 @@ var init_useOverlayEscapeGuard = __esm({
|
|
|
10999
11183
|
|
|
11000
11184
|
// src/ui/App.tsx
|
|
11001
11185
|
import { execSync as execSync6 } from "child_process";
|
|
11002
|
-
import { homedir as
|
|
11003
|
-
import { Box as
|
|
11186
|
+
import { homedir as homedir6 } from "os";
|
|
11187
|
+
import { Box as Box25, Text as Text23, useApp as useApp2, useStdout as useStdout2 } from "ink";
|
|
11004
11188
|
import Spinner3 from "ink-spinner";
|
|
11005
|
-
import
|
|
11189
|
+
import React28, { useEffect as useEffect13, useRef as useRef4, useState as useState14 } from "react";
|
|
11006
11190
|
var getGitBranch2, getCurrentFolder2, AppContent, App;
|
|
11007
11191
|
var init_App = __esm({
|
|
11008
11192
|
"src/ui/App.tsx"() {
|
|
@@ -11011,7 +11195,9 @@ var init_App = __esm({
|
|
|
11011
11195
|
init_login();
|
|
11012
11196
|
init_setup();
|
|
11013
11197
|
init_prompts();
|
|
11198
|
+
init_claude_max();
|
|
11014
11199
|
init_command_discovery();
|
|
11200
|
+
init_settings_loader();
|
|
11015
11201
|
init_stdio();
|
|
11016
11202
|
init_token_storage();
|
|
11017
11203
|
init_version();
|
|
@@ -11023,6 +11209,7 @@ var init_App = __esm({
|
|
|
11023
11209
|
init_InputPrompt();
|
|
11024
11210
|
init_MessageList();
|
|
11025
11211
|
init_ModelSelector();
|
|
11212
|
+
init_ProviderSelector();
|
|
11026
11213
|
init_SessionSelector();
|
|
11027
11214
|
init_SessionContext();
|
|
11028
11215
|
init_useKeypress();
|
|
@@ -11039,7 +11226,7 @@ var init_App = __esm({
|
|
|
11039
11226
|
};
|
|
11040
11227
|
getCurrentFolder2 = (configCwd) => {
|
|
11041
11228
|
const cwd = configCwd || process.cwd();
|
|
11042
|
-
const home =
|
|
11229
|
+
const home = homedir6();
|
|
11043
11230
|
if (cwd.startsWith(home)) {
|
|
11044
11231
|
return `~${cwd.slice(home.length)}`;
|
|
11045
11232
|
}
|
|
@@ -11048,28 +11235,29 @@ var init_App = __esm({
|
|
|
11048
11235
|
AppContent = ({ config: config2, sessionId, webUrl, queuedTasks = [], onExit, onSubmitTask, apiClient, onResumeSession, onClearSession }) => {
|
|
11049
11236
|
const { exit } = useApp2();
|
|
11050
11237
|
const { stdout } = useStdout2();
|
|
11051
|
-
const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel, refreshStatic } = useSession();
|
|
11238
|
+
const { addMessage, clearMessages, isAgentRunning, messages, setSessionId, setWebUrl, setShouldInterruptAgent, setIsAgentRunning, toggleAllToolOutputs, allToolsExpanded, selectedModel, setSelectedModel, refreshStatic, toggleToolGroups, llmProvider, setLlmProvider } = useSession();
|
|
11052
11239
|
useModeToggle();
|
|
11053
|
-
const [terminalWidth, setTerminalWidth] =
|
|
11054
|
-
const [showHelp, setShowHelp] =
|
|
11055
|
-
const [showInput, setShowInput] =
|
|
11056
|
-
const [gitBranch] =
|
|
11057
|
-
const [currentFolder] =
|
|
11058
|
-
const [hasInputContent, setHasInputContent] =
|
|
11059
|
-
const [exitWarning, setExitWarning] =
|
|
11240
|
+
const [terminalWidth, setTerminalWidth] = useState14(process.stdout.columns || 80);
|
|
11241
|
+
const [showHelp, setShowHelp] = useState14(false);
|
|
11242
|
+
const [showInput, setShowInput] = useState14(true);
|
|
11243
|
+
const [gitBranch] = useState14(() => getGitBranch2());
|
|
11244
|
+
const [currentFolder] = useState14(() => getCurrentFolder2(config2.cwd));
|
|
11245
|
+
const [hasInputContent, setHasInputContent] = useState14(false);
|
|
11246
|
+
const [exitWarning, setExitWarning] = useState14(null);
|
|
11060
11247
|
const inputPromptRef = useRef4(null);
|
|
11061
|
-
const [showSessionSelector, setShowSessionSelector] =
|
|
11062
|
-
const [showModelSelector, setShowModelSelector] =
|
|
11063
|
-
const [
|
|
11064
|
-
const [
|
|
11065
|
-
const [
|
|
11066
|
-
const [
|
|
11067
|
-
const [
|
|
11248
|
+
const [showSessionSelector, setShowSessionSelector] = useState14(false);
|
|
11249
|
+
const [showModelSelector, setShowModelSelector] = useState14(false);
|
|
11250
|
+
const [showProviderSelector, setShowProviderSelector] = useState14(false);
|
|
11251
|
+
const [showFeedbackDialog, setShowFeedbackDialog] = useState14(false);
|
|
11252
|
+
const [isLoadingSession, setIsLoadingSession] = useState14(false);
|
|
11253
|
+
const [showFixFlow, setShowFixFlow] = useState14(false);
|
|
11254
|
+
const [fixRunId, setFixRunId] = useState14(void 0);
|
|
11255
|
+
const [authState, setAuthState] = useState14(
|
|
11068
11256
|
() => config2.supatestApiKey ? "authenticated" /* Authenticated */ : "unauthenticated" /* Unauthenticated */
|
|
11069
11257
|
);
|
|
11070
|
-
const [showAuthDialog, setShowAuthDialog] =
|
|
11258
|
+
const [showAuthDialog, setShowAuthDialog] = useState14(false);
|
|
11071
11259
|
const { isOverlayOpen, isCancelSuppressed, markOverlayClosed } = useOverlayEscapeGuard({
|
|
11072
|
-
overlays: [showHelp, showSessionSelector, showAuthDialog, showModelSelector, showFeedbackDialog, showFixFlow]
|
|
11260
|
+
overlays: [showHelp, showSessionSelector, showAuthDialog, showModelSelector, showProviderSelector, showFeedbackDialog, showFixFlow]
|
|
11073
11261
|
});
|
|
11074
11262
|
useEffect13(() => {
|
|
11075
11263
|
if (!config2.supatestApiKey) {
|
|
@@ -11184,6 +11372,10 @@ var init_App = __esm({
|
|
|
11184
11372
|
setShowModelSelector(true);
|
|
11185
11373
|
return;
|
|
11186
11374
|
}
|
|
11375
|
+
if (command === "/provider") {
|
|
11376
|
+
setShowProviderSelector(true);
|
|
11377
|
+
return;
|
|
11378
|
+
}
|
|
11187
11379
|
if (command === "/fix" || command.startsWith("/fix ")) {
|
|
11188
11380
|
if (authState !== "authenticated" /* Authenticated */) {
|
|
11189
11381
|
addMessage({
|
|
@@ -11319,6 +11511,20 @@ var init_App = __esm({
|
|
|
11319
11511
|
markOverlayClosed();
|
|
11320
11512
|
setShowModelSelector(false);
|
|
11321
11513
|
};
|
|
11514
|
+
const handleProviderSelect = (provider) => {
|
|
11515
|
+
setShowProviderSelector(false);
|
|
11516
|
+
markOverlayClosed();
|
|
11517
|
+
setLlmProvider(provider);
|
|
11518
|
+
saveSupatestSettings(config2.cwd || process.cwd(), { llmProvider: provider });
|
|
11519
|
+
addMessage({
|
|
11520
|
+
type: "assistant",
|
|
11521
|
+
content: `LLM Provider changed to: ${provider === "claude-max" ? "Claude Max" : "Supatest Managed"}. This setting has been saved and will persist across sessions.`
|
|
11522
|
+
});
|
|
11523
|
+
};
|
|
11524
|
+
const handleProviderSelectorCancel = () => {
|
|
11525
|
+
markOverlayClosed();
|
|
11526
|
+
setShowProviderSelector(false);
|
|
11527
|
+
};
|
|
11322
11528
|
const handleFeedbackSubmit = async (category, description) => {
|
|
11323
11529
|
setShowFeedbackDialog(false);
|
|
11324
11530
|
markOverlayClosed();
|
|
@@ -11463,7 +11669,7 @@ var init_App = __esm({
|
|
|
11463
11669
|
clearTerminalViewportAndScrollback();
|
|
11464
11670
|
}
|
|
11465
11671
|
if (key.ctrl && key.name === "o") {
|
|
11466
|
-
|
|
11672
|
+
toggleToolGroups();
|
|
11467
11673
|
}
|
|
11468
11674
|
},
|
|
11469
11675
|
{ isActive: !isOverlayOpen }
|
|
@@ -11476,21 +11682,21 @@ var init_App = __esm({
|
|
|
11476
11682
|
});
|
|
11477
11683
|
}
|
|
11478
11684
|
}, []);
|
|
11479
|
-
return /* @__PURE__ */
|
|
11480
|
-
|
|
11685
|
+
return /* @__PURE__ */ React28.createElement(
|
|
11686
|
+
Box25,
|
|
11481
11687
|
{
|
|
11482
11688
|
flexDirection: "column",
|
|
11483
11689
|
paddingX: 1
|
|
11484
11690
|
},
|
|
11485
|
-
/* @__PURE__ */
|
|
11486
|
-
showHelp && /* @__PURE__ */
|
|
11691
|
+
/* @__PURE__ */ React28.createElement(MessageList, { currentFolder, gitBranch, queuedTasks, terminalWidth }),
|
|
11692
|
+
showHelp && /* @__PURE__ */ React28.createElement(
|
|
11487
11693
|
HelpMenu,
|
|
11488
11694
|
{
|
|
11489
11695
|
isAuthenticated: authState === "authenticated" /* Authenticated */,
|
|
11490
11696
|
onClose: handleHelpClose
|
|
11491
11697
|
}
|
|
11492
11698
|
),
|
|
11493
|
-
showSessionSelector && apiClient && /* @__PURE__ */
|
|
11699
|
+
showSessionSelector && apiClient && /* @__PURE__ */ React28.createElement(
|
|
11494
11700
|
SessionSelector,
|
|
11495
11701
|
{
|
|
11496
11702
|
apiClient,
|
|
@@ -11498,29 +11704,39 @@ var init_App = __esm({
|
|
|
11498
11704
|
onSelect: handleSessionSelect
|
|
11499
11705
|
}
|
|
11500
11706
|
),
|
|
11501
|
-
isLoadingSession && /* @__PURE__ */
|
|
11502
|
-
showModelSelector && /* @__PURE__ */
|
|
11707
|
+
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")),
|
|
11708
|
+
showModelSelector && /* @__PURE__ */ React28.createElement(
|
|
11503
11709
|
ModelSelector,
|
|
11504
11710
|
{
|
|
11505
11711
|
currentModel: selectedModel,
|
|
11712
|
+
isClaudeMax: !!config2.oauthToken,
|
|
11506
11713
|
onCancel: handleModelSelectorCancel,
|
|
11507
11714
|
onSelect: handleModelSelect
|
|
11508
11715
|
}
|
|
11509
11716
|
),
|
|
11510
|
-
|
|
11717
|
+
showProviderSelector && /* @__PURE__ */ React28.createElement(
|
|
11718
|
+
ProviderSelector,
|
|
11719
|
+
{
|
|
11720
|
+
claudeMaxAvailable: isClaudeMaxAvailable(),
|
|
11721
|
+
currentProvider: llmProvider,
|
|
11722
|
+
onCancel: handleProviderSelectorCancel,
|
|
11723
|
+
onSelect: handleProviderSelect
|
|
11724
|
+
}
|
|
11725
|
+
),
|
|
11726
|
+
showAuthDialog && /* @__PURE__ */ React28.createElement(
|
|
11511
11727
|
AuthDialog,
|
|
11512
11728
|
{
|
|
11513
11729
|
onLogin: handleLogin
|
|
11514
11730
|
}
|
|
11515
11731
|
),
|
|
11516
|
-
showFeedbackDialog && /* @__PURE__ */
|
|
11732
|
+
showFeedbackDialog && /* @__PURE__ */ React28.createElement(
|
|
11517
11733
|
FeedbackDialog,
|
|
11518
11734
|
{
|
|
11519
11735
|
onCancel: handleFeedbackCancel,
|
|
11520
11736
|
onSubmit: handleFeedbackSubmit
|
|
11521
11737
|
}
|
|
11522
11738
|
),
|
|
11523
|
-
showFixFlow && apiClient && /* @__PURE__ */
|
|
11739
|
+
showFixFlow && apiClient && /* @__PURE__ */ React28.createElement(
|
|
11524
11740
|
FixFlow,
|
|
11525
11741
|
{
|
|
11526
11742
|
apiClient,
|
|
@@ -11530,12 +11746,13 @@ var init_App = __esm({
|
|
|
11530
11746
|
onStartFix: handleFixStart
|
|
11531
11747
|
}
|
|
11532
11748
|
),
|
|
11533
|
-
/* @__PURE__ */
|
|
11749
|
+
/* @__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
11750
|
InputPrompt,
|
|
11535
11751
|
{
|
|
11536
11752
|
currentFolder,
|
|
11537
11753
|
cwd: config2.cwd,
|
|
11538
11754
|
gitBranch,
|
|
11755
|
+
isClaudeMax: !!config2.oauthToken,
|
|
11539
11756
|
onHelpToggle: () => setShowHelp((prev) => !prev),
|
|
11540
11757
|
onInputChange: (val) => setHasInputContent(val.trim().length > 0),
|
|
11541
11758
|
onSubmit: handleSubmitTask,
|
|
@@ -11546,7 +11763,7 @@ var init_App = __esm({
|
|
|
11546
11763
|
);
|
|
11547
11764
|
};
|
|
11548
11765
|
App = (props) => {
|
|
11549
|
-
return /* @__PURE__ */
|
|
11766
|
+
return /* @__PURE__ */ React28.createElement(AppContent, { ...props });
|
|
11550
11767
|
};
|
|
11551
11768
|
}
|
|
11552
11769
|
});
|
|
@@ -11582,7 +11799,7 @@ __export(interactive_exports, {
|
|
|
11582
11799
|
runInteractive: () => runInteractive
|
|
11583
11800
|
});
|
|
11584
11801
|
import { render as render2 } from "ink";
|
|
11585
|
-
import
|
|
11802
|
+
import React29, { useEffect as useEffect15, useRef as useRef5 } from "react";
|
|
11586
11803
|
function getToolDescription2(toolName, input) {
|
|
11587
11804
|
switch (toolName) {
|
|
11588
11805
|
case "Read":
|
|
@@ -11715,7 +11932,7 @@ async function runInteractive(config2) {
|
|
|
11715
11932
|
webUrl = session.webUrl;
|
|
11716
11933
|
}
|
|
11717
11934
|
const { unmount, waitUntilExit } = render2(
|
|
11718
|
-
/* @__PURE__ */
|
|
11935
|
+
/* @__PURE__ */ React29.createElement(
|
|
11719
11936
|
InteractiveApp,
|
|
11720
11937
|
{
|
|
11721
11938
|
apiClient,
|
|
@@ -11770,7 +11987,9 @@ var init_interactive = __esm({
|
|
|
11770
11987
|
init_SessionContext();
|
|
11771
11988
|
init_useBracketedPaste();
|
|
11772
11989
|
init_mouse();
|
|
11990
|
+
init_claude_max();
|
|
11773
11991
|
init_logger();
|
|
11992
|
+
init_settings_loader();
|
|
11774
11993
|
init_stdio();
|
|
11775
11994
|
init_version();
|
|
11776
11995
|
AgentRunner = ({ config: config2, sessionId, apiClient, messageBridge, onComplete, onTurnComplete }) => {
|
|
@@ -11787,7 +12006,8 @@ var init_interactive = __esm({
|
|
|
11787
12006
|
agentMode,
|
|
11788
12007
|
setAgentMode,
|
|
11789
12008
|
planFilePath,
|
|
11790
|
-
selectedModel
|
|
12009
|
+
selectedModel,
|
|
12010
|
+
llmProvider
|
|
11791
12011
|
} = useSession();
|
|
11792
12012
|
const agentRef = useRef5(null);
|
|
11793
12013
|
useEffect15(() => {
|
|
@@ -11803,7 +12023,7 @@ var init_interactive = __esm({
|
|
|
11803
12023
|
try {
|
|
11804
12024
|
const supatestApiKey = apiClient.getApiKey?.() || config2.supatestApiKey || "";
|
|
11805
12025
|
const proxyUrl = config2.supatestApiUrl || "https://code-api.supatest.ai";
|
|
11806
|
-
const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}
|
|
12026
|
+
const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}`;
|
|
11807
12027
|
process.env.ANTHROPIC_BASE_URL = baseUrl;
|
|
11808
12028
|
process.env.ANTHROPIC_API_KEY = supatestApiKey;
|
|
11809
12029
|
const presenter = new ReactPresenter(
|
|
@@ -11844,12 +12064,22 @@ var init_interactive = __esm({
|
|
|
11844
12064
|
sessionId,
|
|
11845
12065
|
config2.verbose
|
|
11846
12066
|
);
|
|
12067
|
+
let oauthToken;
|
|
12068
|
+
if (llmProvider === "claude-max") {
|
|
12069
|
+
if (isClaudeMaxAvailable()) {
|
|
12070
|
+
oauthToken = "use-claude-max";
|
|
12071
|
+
logger.info("Using Claude Max subscription for LLM calls");
|
|
12072
|
+
} else {
|
|
12073
|
+
logger.warn("Claude Max selected but not available. Falling back to Supatest Managed.");
|
|
12074
|
+
}
|
|
12075
|
+
}
|
|
11847
12076
|
const runConfig = {
|
|
11848
12077
|
...config2,
|
|
11849
12078
|
supatestApiKey,
|
|
11850
12079
|
mode: agentMode,
|
|
11851
12080
|
planFilePath,
|
|
11852
12081
|
selectedModel,
|
|
12082
|
+
oauthToken,
|
|
11853
12083
|
systemPromptAppend: agentMode === "plan" ? config.planSystemPrompt : config2.systemPromptAppend
|
|
11854
12084
|
};
|
|
11855
12085
|
const agent2 = new CoreAgent(presenter, messageBridge);
|
|
@@ -11894,17 +12124,17 @@ var init_interactive = __esm({
|
|
|
11894
12124
|
setIsAgentRunning,
|
|
11895
12125
|
setUsageStats
|
|
11896
12126
|
} = useSession();
|
|
11897
|
-
const [sessionId, setSessionId] =
|
|
11898
|
-
const [currentTask, setCurrentTask] =
|
|
11899
|
-
const [taskId, setTaskId] =
|
|
11900
|
-
const [shouldRunAgent, setShouldRunAgent] =
|
|
11901
|
-
const [taskQueue, setTaskQueue] =
|
|
11902
|
-
const [providerSessionId, setProviderSessionId] =
|
|
11903
|
-
const messageBridgeRef =
|
|
11904
|
-
const lastSubmitRef =
|
|
11905
|
-
const [pendingInjected, setPendingInjected] =
|
|
11906
|
-
const pendingInjectedRef =
|
|
11907
|
-
|
|
12127
|
+
const [sessionId, setSessionId] = React29.useState(initialSessionId);
|
|
12128
|
+
const [currentTask, setCurrentTask] = React29.useState(config2.task);
|
|
12129
|
+
const [taskId, setTaskId] = React29.useState(0);
|
|
12130
|
+
const [shouldRunAgent, setShouldRunAgent] = React29.useState(!!config2.task);
|
|
12131
|
+
const [taskQueue, setTaskQueue] = React29.useState([]);
|
|
12132
|
+
const [providerSessionId, setProviderSessionId] = React29.useState();
|
|
12133
|
+
const messageBridgeRef = React29.useRef(null);
|
|
12134
|
+
const lastSubmitRef = React29.useRef(null);
|
|
12135
|
+
const [pendingInjected, setPendingInjected] = React29.useState([]);
|
|
12136
|
+
const pendingInjectedRef = React29.useRef([]);
|
|
12137
|
+
React29.useEffect(() => {
|
|
11908
12138
|
pendingInjectedRef.current = pendingInjected;
|
|
11909
12139
|
}, [pendingInjected]);
|
|
11910
12140
|
const handleSubmitTask = async (task) => {
|
|
@@ -11967,7 +12197,7 @@ var init_interactive = __esm({
|
|
|
11967
12197
|
if (shouldRunAgent && !messageBridgeRef.current) {
|
|
11968
12198
|
messageBridgeRef.current = new MessageBridge(providerSessionId || "");
|
|
11969
12199
|
}
|
|
11970
|
-
|
|
12200
|
+
React29.useEffect(() => {
|
|
11971
12201
|
if (!shouldRunAgent && taskQueue.length > 0) {
|
|
11972
12202
|
const [nextTask, ...remaining] = taskQueue;
|
|
11973
12203
|
setTaskQueue(remaining);
|
|
@@ -11981,14 +12211,14 @@ var init_interactive = __esm({
|
|
|
11981
12211
|
setShouldRunAgent(true);
|
|
11982
12212
|
}
|
|
11983
12213
|
}, [shouldRunAgent, taskQueue, addMessage, providerSessionId]);
|
|
11984
|
-
const handleClearSession =
|
|
12214
|
+
const handleClearSession = React29.useCallback(() => {
|
|
11985
12215
|
setSessionId(void 0);
|
|
11986
12216
|
setContextSessionId(void 0);
|
|
11987
12217
|
setProviderSessionId(void 0);
|
|
11988
12218
|
setTaskQueue([]);
|
|
11989
12219
|
setPendingInjected([]);
|
|
11990
12220
|
}, [setContextSessionId]);
|
|
11991
|
-
return /* @__PURE__ */
|
|
12221
|
+
return /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement(
|
|
11992
12222
|
App,
|
|
11993
12223
|
{
|
|
11994
12224
|
apiClient,
|
|
@@ -12051,7 +12281,7 @@ var init_interactive = __esm({
|
|
|
12051
12281
|
sessionId,
|
|
12052
12282
|
webUrl
|
|
12053
12283
|
}
|
|
12054
|
-
), shouldRunAgent && currentTask && sessionId && messageBridgeRef.current && /* @__PURE__ */
|
|
12284
|
+
), shouldRunAgent && currentTask && sessionId && messageBridgeRef.current && /* @__PURE__ */ React29.createElement(
|
|
12055
12285
|
AgentRunner,
|
|
12056
12286
|
{
|
|
12057
12287
|
apiClient,
|
|
@@ -12074,7 +12304,9 @@ var init_interactive = __esm({
|
|
|
12074
12304
|
};
|
|
12075
12305
|
InteractiveApp = (props) => {
|
|
12076
12306
|
useBracketedPaste();
|
|
12077
|
-
|
|
12307
|
+
const settings = loadSupatestSettings(props.config.cwd || process.cwd());
|
|
12308
|
+
const initialProvider = settings.llmProvider || "supatest-managed";
|
|
12309
|
+
return /* @__PURE__ */ React29.createElement(KeypressProvider, null, /* @__PURE__ */ React29.createElement(SessionProvider, { initialLlmProvider: initialProvider, initialModel: props.config.selectedModel }, /* @__PURE__ */ React29.createElement(InteractiveAppContent, { ...props })));
|
|
12078
12310
|
};
|
|
12079
12311
|
}
|
|
12080
12312
|
});
|
|
@@ -12090,7 +12322,7 @@ import { Command } from "commander";
|
|
|
12090
12322
|
init_api_client();
|
|
12091
12323
|
import chalk3 from "chalk";
|
|
12092
12324
|
import { render } from "ink";
|
|
12093
|
-
import
|
|
12325
|
+
import React15 from "react";
|
|
12094
12326
|
|
|
12095
12327
|
// src/ui/HeadlessApp.tsx
|
|
12096
12328
|
await init_agent();
|
|
@@ -12099,8 +12331,8 @@ init_MessageList();
|
|
|
12099
12331
|
init_SessionContext();
|
|
12100
12332
|
import { execSync as execSync2 } from "child_process";
|
|
12101
12333
|
import { homedir as homedir3 } from "os";
|
|
12102
|
-
import { Box as
|
|
12103
|
-
import
|
|
12334
|
+
import { Box as Box13, useApp } from "ink";
|
|
12335
|
+
import React14, { useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
12104
12336
|
var getGitBranch = () => {
|
|
12105
12337
|
try {
|
|
12106
12338
|
return execSync2("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
|
|
@@ -12133,7 +12365,7 @@ var HeadlessAgentRunner = ({ config: config2, sessionId, apiClient, onComplete }
|
|
|
12133
12365
|
setIsAgentRunning(true);
|
|
12134
12366
|
try {
|
|
12135
12367
|
const proxyUrl = config2.supatestApiUrl || "https://code-api.supatest.ai";
|
|
12136
|
-
const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}
|
|
12368
|
+
const baseUrl = `${proxyUrl}/v1/sessions/${sessionId}`;
|
|
12137
12369
|
process.env.ANTHROPIC_BASE_URL = baseUrl;
|
|
12138
12370
|
process.env.ANTHROPIC_API_KEY = config2.supatestApiKey;
|
|
12139
12371
|
const presenter = new ReactPresenter(
|
|
@@ -12244,7 +12476,7 @@ var HeadlessAppContent = ({
|
|
|
12244
12476
|
onComplete(success, providerSessionId);
|
|
12245
12477
|
exit();
|
|
12246
12478
|
};
|
|
12247
|
-
return /* @__PURE__ */
|
|
12479
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React14.createElement(
|
|
12248
12480
|
MessageList,
|
|
12249
12481
|
{
|
|
12250
12482
|
currentFolder,
|
|
@@ -12252,7 +12484,7 @@ var HeadlessAppContent = ({
|
|
|
12252
12484
|
headless: true,
|
|
12253
12485
|
terminalWidth
|
|
12254
12486
|
}
|
|
12255
|
-
), /* @__PURE__ */
|
|
12487
|
+
), /* @__PURE__ */ React14.createElement(
|
|
12256
12488
|
HeadlessAgentRunner,
|
|
12257
12489
|
{
|
|
12258
12490
|
apiClient,
|
|
@@ -12263,7 +12495,7 @@ var HeadlessAppContent = ({
|
|
|
12263
12495
|
));
|
|
12264
12496
|
};
|
|
12265
12497
|
var HeadlessApp = (props) => {
|
|
12266
|
-
return /* @__PURE__ */
|
|
12498
|
+
return /* @__PURE__ */ React14.createElement(SessionProvider, { initialModel: props.config.selectedModel }, /* @__PURE__ */ React14.createElement(HeadlessAppContent, { ...props }));
|
|
12267
12499
|
};
|
|
12268
12500
|
|
|
12269
12501
|
// src/modes/headless.ts
|
|
@@ -12332,7 +12564,7 @@ async function runAgent(config2) {
|
|
|
12332
12564
|
}
|
|
12333
12565
|
};
|
|
12334
12566
|
const { unmount, waitUntilExit } = render(
|
|
12335
|
-
|
|
12567
|
+
React15.createElement(HeadlessApp, {
|
|
12336
12568
|
config: config2,
|
|
12337
12569
|
sessionId,
|
|
12338
12570
|
webUrl,
|
|
@@ -12407,43 +12639,12 @@ Updating Supatest CLI ${CLI_VERSION} \u2192 ${latest}...`);
|
|
|
12407
12639
|
|
|
12408
12640
|
// src/index.ts
|
|
12409
12641
|
init_banner();
|
|
12410
|
-
|
|
12411
|
-
// src/utils/claude-max.ts
|
|
12412
|
-
init_logger();
|
|
12413
|
-
import { execSync as execSync4 } from "child_process";
|
|
12414
|
-
function isClaudeMaxAvailable() {
|
|
12415
|
-
logger.debug("[claude-max] Checking if Claude Code credentials exist in keychain");
|
|
12416
|
-
try {
|
|
12417
|
-
const credentialsJson = execSync4(
|
|
12418
|
-
'security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null',
|
|
12419
|
-
{ encoding: "utf-8" }
|
|
12420
|
-
).trim();
|
|
12421
|
-
if (!credentialsJson) {
|
|
12422
|
-
logger.debug("[claude-max] No credentials found in keychain");
|
|
12423
|
-
return false;
|
|
12424
|
-
}
|
|
12425
|
-
const credentials = JSON.parse(credentialsJson);
|
|
12426
|
-
const hasOauth = !!credentials.claudeAiOauth?.accessToken;
|
|
12427
|
-
logger.debug("[claude-max] Credentials check", {
|
|
12428
|
-
hasOauth,
|
|
12429
|
-
hasRefreshToken: !!credentials.claudeAiOauth?.refreshToken
|
|
12430
|
-
});
|
|
12431
|
-
return hasOauth;
|
|
12432
|
-
} catch (error) {
|
|
12433
|
-
logger.debug("[claude-max] Error checking keychain", {
|
|
12434
|
-
error: error instanceof Error ? error.message : String(error)
|
|
12435
|
-
});
|
|
12436
|
-
return false;
|
|
12437
|
-
}
|
|
12438
|
-
}
|
|
12439
|
-
|
|
12440
|
-
// src/index.ts
|
|
12441
12642
|
init_error_logger();
|
|
12442
12643
|
init_logger();
|
|
12443
12644
|
|
|
12444
12645
|
// src/utils/node-version.ts
|
|
12445
12646
|
init_logger();
|
|
12446
|
-
import { execSync as
|
|
12647
|
+
import { execSync as execSync4 } from "child_process";
|
|
12447
12648
|
var MINIMUM_NODE_VERSION2 = 18;
|
|
12448
12649
|
function parseVersion2(versionString) {
|
|
12449
12650
|
const cleaned = versionString.trim().replace(/^v/, "");
|
|
@@ -12460,7 +12661,7 @@ function parseVersion2(versionString) {
|
|
|
12460
12661
|
}
|
|
12461
12662
|
function getNodeVersion2() {
|
|
12462
12663
|
try {
|
|
12463
|
-
const versionOutput =
|
|
12664
|
+
const versionOutput = execSync4("node --version", {
|
|
12464
12665
|
encoding: "utf-8",
|
|
12465
12666
|
stdio: ["ignore", "pipe", "ignore"]
|
|
12466
12667
|
});
|
|
@@ -12577,7 +12778,7 @@ program.name("supatest").description(
|
|
|
12577
12778
|
"-m, --claude-max-iterations <number>",
|
|
12578
12779
|
"Maximum number of iterations",
|
|
12579
12780
|
"100"
|
|
12580
|
-
).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>", "
|
|
12781
|
+
).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) => {
|
|
12581
12782
|
try {
|
|
12582
12783
|
checkNodeVersion2();
|
|
12583
12784
|
await checkAndAutoUpdate();
|
|
@@ -12614,17 +12815,6 @@ program.name("supatest").description(
|
|
|
12614
12815
|
let supatestApiKey;
|
|
12615
12816
|
let oauthToken;
|
|
12616
12817
|
const supatestApiUrl = options.supatestApiUrl || config.supatestApiUrl;
|
|
12617
|
-
if (options.claudeMax) {
|
|
12618
|
-
if (!isClaudeMaxAvailable()) {
|
|
12619
|
-
logger.error("Claude Max not available. Please ensure:");
|
|
12620
|
-
logger.error(" 1. Claude Code is installed");
|
|
12621
|
-
logger.error(" 2. You are logged in with a Claude Max subscription");
|
|
12622
|
-
logger.error(" 3. Run 'claude' and authenticate if needed");
|
|
12623
|
-
process.exit(1);
|
|
12624
|
-
}
|
|
12625
|
-
oauthToken = "use-claude-max";
|
|
12626
|
-
logger.info("Using Claude Max subscription for LLM calls");
|
|
12627
|
-
}
|
|
12628
12818
|
if (isHeadlessMode) {
|
|
12629
12819
|
supatestApiKey = normalizeSupatestKey(
|
|
12630
12820
|
options.supatestApiKey || config.supatestApiKey,
|
|
@@ -12650,15 +12840,16 @@ program.name("supatest").description(
|
|
|
12650
12840
|
}
|
|
12651
12841
|
}
|
|
12652
12842
|
let selectedModel;
|
|
12653
|
-
const modelOption = options.model ||
|
|
12654
|
-
if (modelOption) {
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12843
|
+
const modelOption = options.model || "medium";
|
|
12844
|
+
if (modelOption && isValidModelId(modelOption)) {
|
|
12845
|
+
selectedModel = modelOption;
|
|
12846
|
+
} else {
|
|
12847
|
+
if (modelOption && modelOption !== "medium") {
|
|
12658
12848
|
const validModels = AVAILABLE_MODELS.map((m) => m.id).join(", ");
|
|
12659
|
-
logger.warn(`Invalid model "${modelOption}". Valid models: ${validModels}`);
|
|
12849
|
+
logger.warn(`Invalid model "${modelOption}". Valid models: ${validModels} or tier names: small, medium, premium`);
|
|
12660
12850
|
logger.warn("Using default model instead.");
|
|
12661
12851
|
}
|
|
12852
|
+
selectedModel = "medium";
|
|
12662
12853
|
}
|
|
12663
12854
|
if (isHeadlessMode) {
|
|
12664
12855
|
if (!prompt) {
|
|
@@ -12670,7 +12861,7 @@ program.name("supatest").description(
|
|
|
12670
12861
|
logs,
|
|
12671
12862
|
supatestApiKey,
|
|
12672
12863
|
supatestApiUrl,
|
|
12673
|
-
maxIterations: Number.parseInt(options.maxIterations || "
|
|
12864
|
+
maxIterations: Number.parseInt(options.maxIterations || "100", 10),
|
|
12674
12865
|
verbose: options.verbose || false,
|
|
12675
12866
|
cwd: options.cwd,
|
|
12676
12867
|
systemPromptAppend: config.headlessSystemPrompt,
|
|
@@ -12686,7 +12877,7 @@ program.name("supatest").description(
|
|
|
12686
12877
|
logs,
|
|
12687
12878
|
supatestApiKey,
|
|
12688
12879
|
supatestApiUrl,
|
|
12689
|
-
maxIterations: Number.parseInt(options.maxIterations || "
|
|
12880
|
+
maxIterations: Number.parseInt(options.maxIterations || "100", 10),
|
|
12690
12881
|
verbose: options.verbose || false,
|
|
12691
12882
|
cwd: options.cwd,
|
|
12692
12883
|
systemPromptAppend: config.interactiveSystemPrompt,
|