@supatest/cli 0.0.21 → 0.0.22
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 +73 -72
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -3904,7 +3904,7 @@ var CLI_VERSION;
|
|
|
3904
3904
|
var init_version = __esm({
|
|
3905
3905
|
"src/version.ts"() {
|
|
3906
3906
|
"use strict";
|
|
3907
|
-
CLI_VERSION = "0.0.
|
|
3907
|
+
CLI_VERSION = "0.0.22";
|
|
3908
3908
|
}
|
|
3909
3909
|
});
|
|
3910
3910
|
|
|
@@ -4195,12 +4195,24 @@ ${"=".repeat(80)}
|
|
|
4195
4195
|
});
|
|
4196
4196
|
|
|
4197
4197
|
// src/services/api-client.ts
|
|
4198
|
-
|
|
4198
|
+
import { Agent, setGlobalDispatcher } from "undici";
|
|
4199
|
+
var agent, ApiError, ApiClient;
|
|
4199
4200
|
var init_api_client = __esm({
|
|
4200
4201
|
"src/services/api-client.ts"() {
|
|
4201
4202
|
"use strict";
|
|
4202
4203
|
init_error_logger();
|
|
4203
4204
|
init_logger();
|
|
4205
|
+
agent = new Agent({
|
|
4206
|
+
keepAliveTimeout: 3e4,
|
|
4207
|
+
// Keep connections alive for 30s
|
|
4208
|
+
keepAliveMaxTimeout: 6e4,
|
|
4209
|
+
// Max time to keep connection alive
|
|
4210
|
+
connections: 10,
|
|
4211
|
+
// Max connections per origin
|
|
4212
|
+
pipelining: 1
|
|
4213
|
+
// Enable HTTP pipelining
|
|
4214
|
+
});
|
|
4215
|
+
setGlobalDispatcher(agent);
|
|
4204
4216
|
ApiError = class extends Error {
|
|
4205
4217
|
status;
|
|
4206
4218
|
isAuthError;
|
|
@@ -4729,7 +4741,7 @@ var init_agent = __esm({
|
|
|
4729
4741
|
}
|
|
4730
4742
|
async run(config2) {
|
|
4731
4743
|
this.abortController = new AbortController();
|
|
4732
|
-
|
|
4744
|
+
this.presenter.onStart(config2);
|
|
4733
4745
|
const claudeCodePath = await this.resolveClaudeCodePath();
|
|
4734
4746
|
let prompt = config2.task;
|
|
4735
4747
|
if (config2.logs) {
|
|
@@ -4746,9 +4758,9 @@ ${config2.logs}
|
|
|
4746
4758
|
const customAgents = discoverAgents(cwd);
|
|
4747
4759
|
let customAgentsPrompt;
|
|
4748
4760
|
if (customAgents.length > 0) {
|
|
4749
|
-
const agentList = customAgents.map((
|
|
4750
|
-
const modelInfo =
|
|
4751
|
-
return `- **${
|
|
4761
|
+
const agentList = customAgents.map((agent2) => {
|
|
4762
|
+
const modelInfo = agent2.model ? ` (model: ${agent2.model})` : "";
|
|
4763
|
+
return `- **${agent2.name}**${modelInfo}: ${agent2.description || "No description"}`;
|
|
4752
4764
|
}).join("\n");
|
|
4753
4765
|
customAgentsPrompt = `
|
|
4754
4766
|
|
|
@@ -4798,21 +4810,14 @@ ${projectInstructions}`,
|
|
|
4798
4810
|
pathToClaudeCodeExecutable: claudeCodePath,
|
|
4799
4811
|
includePartialMessages: true,
|
|
4800
4812
|
executable: "node",
|
|
4801
|
-
// MCP servers
|
|
4802
|
-
//
|
|
4813
|
+
// MCP servers from .supatest/mcp.json
|
|
4814
|
+
// Users can add servers like Playwright if needed
|
|
4803
4815
|
mcpServers: (() => {
|
|
4804
|
-
const
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
args: ["-y", "@playwright/mcp@latest"]
|
|
4810
|
-
},
|
|
4811
|
-
// User-defined servers override defaults (spread after)
|
|
4812
|
-
...userServers
|
|
4813
|
-
};
|
|
4814
|
-
this.presenter.onLog(`MCP servers loaded: ${Object.keys(allServers).join(", ")}`);
|
|
4815
|
-
return allServers;
|
|
4816
|
+
const servers = loadMcpServers(cwd);
|
|
4817
|
+
if (Object.keys(servers).length > 0) {
|
|
4818
|
+
this.presenter.onLog(`MCP servers: ${Object.keys(servers).join(", ")}`);
|
|
4819
|
+
}
|
|
4820
|
+
return servers;
|
|
4816
4821
|
})(),
|
|
4817
4822
|
// Resume from previous session if providerSessionId is provided
|
|
4818
4823
|
// This allows the agent to continue conversations with full context
|
|
@@ -4882,16 +4887,16 @@ ${projectInstructions}`,
|
|
|
4882
4887
|
for (const block of content) {
|
|
4883
4888
|
if (block.type === "text") {
|
|
4884
4889
|
resultText += block.text + "\n";
|
|
4885
|
-
|
|
4890
|
+
this.presenter.onAssistantText(block.text);
|
|
4886
4891
|
} else if (block.type === "thinking") {
|
|
4887
|
-
|
|
4892
|
+
this.presenter.onThinking(block.thinking);
|
|
4888
4893
|
} else if (block.type === "tool_use") {
|
|
4889
4894
|
const toolName = block.name;
|
|
4890
4895
|
const input = block.input;
|
|
4891
4896
|
if ((toolName === "Write" || toolName === "Edit") && input?.file_path) {
|
|
4892
4897
|
filesModified.add(input.file_path);
|
|
4893
4898
|
}
|
|
4894
|
-
|
|
4899
|
+
this.presenter.onToolUse(toolName, input, block.id);
|
|
4895
4900
|
}
|
|
4896
4901
|
}
|
|
4897
4902
|
}
|
|
@@ -4909,7 +4914,7 @@ ${projectInstructions}`,
|
|
|
4909
4914
|
cacheReadTokens: cumulativeCacheReadTokens,
|
|
4910
4915
|
cacheCreationTokens: cumulativeCacheCreationTokens
|
|
4911
4916
|
};
|
|
4912
|
-
|
|
4917
|
+
this.presenter.onUsageUpdate?.({
|
|
4913
4918
|
model: currentModel,
|
|
4914
4919
|
inputTokens: cumulativeInputTokens,
|
|
4915
4920
|
outputTokens: cumulativeOutputTokens,
|
|
@@ -4917,7 +4922,7 @@ ${projectInstructions}`,
|
|
|
4917
4922
|
cacheCreationTokens: cumulativeCacheCreationTokens
|
|
4918
4923
|
});
|
|
4919
4924
|
}
|
|
4920
|
-
|
|
4925
|
+
this.presenter.onTurnComplete(content);
|
|
4921
4926
|
} else if (msg.type === "result") {
|
|
4922
4927
|
iterations = msg.num_turns;
|
|
4923
4928
|
const modelName = Object.keys(msg.modelUsage || {})[0] || "unknown";
|
|
@@ -4954,7 +4959,7 @@ ${projectInstructions}`,
|
|
|
4954
4959
|
if ("errors" in msg && Array.isArray(msg.errors)) {
|
|
4955
4960
|
errors.push(...msg.errors);
|
|
4956
4961
|
for (const error of msg.errors) {
|
|
4957
|
-
|
|
4962
|
+
this.presenter.onError(error);
|
|
4958
4963
|
}
|
|
4959
4964
|
}
|
|
4960
4965
|
}
|
|
@@ -4965,7 +4970,7 @@ ${projectInstructions}`,
|
|
|
4965
4970
|
if (block.type === "tool_result" && block.tool_use_id) {
|
|
4966
4971
|
if (this.presenter.onToolResult) {
|
|
4967
4972
|
const resultContent = Array.isArray(block.content) ? block.content.map((c2) => c2.text || "").join("\n") : typeof block.content === "string" ? block.content : "";
|
|
4968
|
-
|
|
4973
|
+
this.presenter.onToolResult(block.tool_use_id, resultContent);
|
|
4969
4974
|
}
|
|
4970
4975
|
}
|
|
4971
4976
|
}
|
|
@@ -4982,7 +4987,7 @@ ${projectInstructions}`,
|
|
|
4982
4987
|
wasInterrupted = true;
|
|
4983
4988
|
} else if (config2.providerSessionId && isSessionExpiredError(errorMessage)) {
|
|
4984
4989
|
const expiredMessage = "Can't continue conversation older than 30 days. Please start a new session.";
|
|
4985
|
-
|
|
4990
|
+
this.presenter.onError(expiredMessage);
|
|
4986
4991
|
hasError = true;
|
|
4987
4992
|
errors.push(expiredMessage);
|
|
4988
4993
|
} else {
|
|
@@ -4993,7 +4998,7 @@ ${projectInstructions}`,
|
|
|
4993
4998
|
// Truncate for log size
|
|
4994
4999
|
iteration: iterations
|
|
4995
5000
|
});
|
|
4996
|
-
|
|
5001
|
+
this.presenter.onError(errorMessage);
|
|
4997
5002
|
hasError = true;
|
|
4998
5003
|
errors.push(errorMessage);
|
|
4999
5004
|
}
|
|
@@ -5010,7 +5015,7 @@ ${projectInstructions}`,
|
|
|
5010
5015
|
providerSessionId,
|
|
5011
5016
|
usage: queryUsage
|
|
5012
5017
|
};
|
|
5013
|
-
|
|
5018
|
+
this.presenter.onComplete(result);
|
|
5014
5019
|
return result;
|
|
5015
5020
|
}
|
|
5016
5021
|
async resolveClaudeCodePath() {
|
|
@@ -5039,7 +5044,7 @@ ${projectInstructions}`,
|
|
|
5039
5044
|
} catch {
|
|
5040
5045
|
const error = `Claude Code executable not found at: ${claudeCodePath}
|
|
5041
5046
|
Set SUPATEST_CLAUDE_CODE_PATH environment variable to override.`;
|
|
5042
|
-
|
|
5047
|
+
this.presenter.onError(error);
|
|
5043
5048
|
throw new Error(error);
|
|
5044
5049
|
}
|
|
5045
5050
|
return claudeCodePath;
|
|
@@ -5079,6 +5084,10 @@ function getToolDescription(toolName, input) {
|
|
|
5079
5084
|
return toolName;
|
|
5080
5085
|
}
|
|
5081
5086
|
}
|
|
5087
|
+
function streamEventAsync(apiClient, sessionId, event) {
|
|
5088
|
+
apiClient.streamEvent(sessionId, event).catch(() => {
|
|
5089
|
+
});
|
|
5090
|
+
}
|
|
5082
5091
|
var CONTEXT_WINDOWS, ReactPresenter;
|
|
5083
5092
|
var init_react = __esm({
|
|
5084
5093
|
"src/presenters/react.ts"() {
|
|
@@ -5109,19 +5118,18 @@ var init_react = __esm({
|
|
|
5109
5118
|
this.sessionId = sessionId;
|
|
5110
5119
|
this.verbose = verbose;
|
|
5111
5120
|
}
|
|
5112
|
-
|
|
5113
|
-
|
|
5121
|
+
onStart(config2) {
|
|
5122
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5114
5123
|
type: "query_start",
|
|
5115
5124
|
prompt: config2.task
|
|
5116
|
-
};
|
|
5117
|
-
await this.apiClient.streamEvent(this.sessionId, event);
|
|
5125
|
+
});
|
|
5118
5126
|
}
|
|
5119
5127
|
onLog(message) {
|
|
5120
5128
|
if (this.verbose) {
|
|
5121
5129
|
console.error(message);
|
|
5122
5130
|
}
|
|
5123
5131
|
}
|
|
5124
|
-
|
|
5132
|
+
onAssistantText(text) {
|
|
5125
5133
|
if (!this.hasAssistantMessage) {
|
|
5126
5134
|
this.callbacks.addMessage({
|
|
5127
5135
|
type: "assistant",
|
|
@@ -5136,13 +5144,12 @@ var init_react = __esm({
|
|
|
5136
5144
|
content: this.currentAssistantText
|
|
5137
5145
|
});
|
|
5138
5146
|
}
|
|
5139
|
-
|
|
5147
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5140
5148
|
type: "assistant_text",
|
|
5141
5149
|
delta: text
|
|
5142
|
-
};
|
|
5143
|
-
await this.apiClient.streamEvent(this.sessionId, textEvent);
|
|
5150
|
+
});
|
|
5144
5151
|
}
|
|
5145
|
-
|
|
5152
|
+
onThinking(text) {
|
|
5146
5153
|
if (!this.hasThinkingMessage) {
|
|
5147
5154
|
this.callbacks.addMessage({
|
|
5148
5155
|
type: "thinking",
|
|
@@ -5157,13 +5164,12 @@ var init_react = __esm({
|
|
|
5157
5164
|
content: this.currentThinkingText
|
|
5158
5165
|
});
|
|
5159
5166
|
}
|
|
5160
|
-
|
|
5167
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5161
5168
|
type: "assistant_thinking",
|
|
5162
5169
|
delta: text
|
|
5163
|
-
};
|
|
5164
|
-
await this.apiClient.streamEvent(this.sessionId, thinkingEvent);
|
|
5170
|
+
});
|
|
5165
5171
|
}
|
|
5166
|
-
|
|
5172
|
+
onToolUse(tool, input, toolId) {
|
|
5167
5173
|
const message = {
|
|
5168
5174
|
type: "tool",
|
|
5169
5175
|
content: getToolDescription(tool, input),
|
|
@@ -5207,48 +5213,45 @@ var init_react = __esm({
|
|
|
5207
5213
|
} else if (tool === "EnterPlanMode") {
|
|
5208
5214
|
this.callbacks.onEnterPlanMode?.();
|
|
5209
5215
|
}
|
|
5210
|
-
|
|
5216
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5211
5217
|
type: "tool_use",
|
|
5212
5218
|
id: toolId,
|
|
5213
5219
|
name: tool,
|
|
5214
5220
|
input: input || {}
|
|
5215
|
-
};
|
|
5216
|
-
await this.apiClient.streamEvent(this.sessionId, toolUseEvent);
|
|
5221
|
+
});
|
|
5217
5222
|
}
|
|
5218
|
-
|
|
5223
|
+
onToolResult(toolId, result) {
|
|
5219
5224
|
this.callbacks.updateMessageByToolId(toolId, {
|
|
5220
5225
|
toolResult: result
|
|
5221
5226
|
});
|
|
5222
|
-
|
|
5227
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5223
5228
|
type: "tool_result",
|
|
5224
5229
|
tool_use_id: toolId,
|
|
5225
5230
|
content: result
|
|
5226
|
-
};
|
|
5227
|
-
await this.apiClient.streamEvent(this.sessionId, toolResultEvent);
|
|
5231
|
+
});
|
|
5228
5232
|
}
|
|
5229
|
-
|
|
5230
|
-
|
|
5233
|
+
onTurnComplete(content) {
|
|
5234
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5231
5235
|
type: "message_complete",
|
|
5232
5236
|
message: {
|
|
5233
5237
|
role: "assistant",
|
|
5234
5238
|
content
|
|
5235
5239
|
}
|
|
5236
|
-
};
|
|
5237
|
-
await this.apiClient.streamEvent(this.sessionId, messageCompleteEvent);
|
|
5240
|
+
});
|
|
5238
5241
|
this.callbacks.onTurnComplete?.();
|
|
5239
5242
|
}
|
|
5240
|
-
|
|
5243
|
+
onError(error) {
|
|
5241
5244
|
this.callbacks.addMessage({
|
|
5242
5245
|
type: "error",
|
|
5243
5246
|
content: error,
|
|
5244
5247
|
errorType: "error"
|
|
5245
5248
|
});
|
|
5246
|
-
|
|
5249
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5247
5250
|
type: "session_error",
|
|
5248
5251
|
error
|
|
5249
5252
|
});
|
|
5250
5253
|
}
|
|
5251
|
-
|
|
5254
|
+
onUsageUpdate(usage) {
|
|
5252
5255
|
const contextWindow = CONTEXT_WINDOWS[usage.model] || 2e5;
|
|
5253
5256
|
const contextTokens = usage.inputTokens + usage.cacheReadTokens + usage.cacheCreationTokens;
|
|
5254
5257
|
const contextPct = contextTokens / contextWindow * 100;
|
|
@@ -5269,10 +5272,10 @@ var init_react = __esm({
|
|
|
5269
5272
|
};
|
|
5270
5273
|
});
|
|
5271
5274
|
}
|
|
5272
|
-
|
|
5275
|
+
onComplete(result) {
|
|
5273
5276
|
if (result.usage) {
|
|
5274
5277
|
const queryStatus = result.success ? "success" : result.error?.toLowerCase().includes("interrupt") ? "interrupted" : "error";
|
|
5275
|
-
|
|
5278
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5276
5279
|
type: "query_complete",
|
|
5277
5280
|
usage: result.usage,
|
|
5278
5281
|
result: {
|
|
@@ -5283,11 +5286,11 @@ var init_react = __esm({
|
|
|
5283
5286
|
});
|
|
5284
5287
|
}
|
|
5285
5288
|
if (result.success) {
|
|
5286
|
-
|
|
5289
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5287
5290
|
type: "session_complete"
|
|
5288
5291
|
});
|
|
5289
5292
|
} else {
|
|
5290
|
-
|
|
5293
|
+
streamEventAsync(this.apiClient, this.sessionId, {
|
|
5291
5294
|
type: "session_error",
|
|
5292
5295
|
error: result.error || "Unknown error"
|
|
5293
5296
|
});
|
|
@@ -9436,9 +9439,9 @@ var init_interactive = __esm({
|
|
|
9436
9439
|
selectedModel,
|
|
9437
9440
|
systemPromptAppend: agentMode === "plan" ? config.planSystemPrompt : config2.systemPromptAppend
|
|
9438
9441
|
};
|
|
9439
|
-
const
|
|
9440
|
-
agentRef.current =
|
|
9441
|
-
const result = await
|
|
9442
|
+
const agent2 = new CoreAgent(presenter, messageBridge);
|
|
9443
|
+
agentRef.current = agent2;
|
|
9444
|
+
const result = await agent2.run(runConfig);
|
|
9442
9445
|
if (isMounted) {
|
|
9443
9446
|
onComplete(result.success, result.providerSessionId);
|
|
9444
9447
|
}
|
|
@@ -9752,9 +9755,9 @@ var HeadlessAgentRunner = ({ config: config2, sessionId, apiClient, onComplete }
|
|
|
9752
9755
|
sessionId,
|
|
9753
9756
|
config2.verbose
|
|
9754
9757
|
);
|
|
9755
|
-
const
|
|
9756
|
-
agentRef.current =
|
|
9757
|
-
const result = await
|
|
9758
|
+
const agent2 = new CoreAgent(presenter);
|
|
9759
|
+
agentRef.current = agent2;
|
|
9760
|
+
const result = await agent2.run(config2);
|
|
9758
9761
|
if (isMounted) {
|
|
9759
9762
|
onComplete(result.success, result.providerSessionId);
|
|
9760
9763
|
}
|
|
@@ -9825,10 +9828,8 @@ var HeadlessAppContent = ({
|
|
|
9825
9828
|
const handleComplete = (success, providerSessionId) => {
|
|
9826
9829
|
if (hasCompletedRef.current) return;
|
|
9827
9830
|
hasCompletedRef.current = true;
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
exit();
|
|
9831
|
-
}, 100);
|
|
9831
|
+
onComplete(success, providerSessionId);
|
|
9832
|
+
exit();
|
|
9832
9833
|
};
|
|
9833
9834
|
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React13.createElement(
|
|
9834
9835
|
MessageList,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supatest/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "Supatest CLI - AI-powered task automation for CI/CD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"react": "^19.0.0",
|
|
64
64
|
"string-width": "^8.1.0",
|
|
65
65
|
"strip-ansi": "^7.1.2",
|
|
66
|
+
"undici": "^7.16.0",
|
|
66
67
|
"wrap-ansi": "^9.0.2"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|