@hasna/testers 0.0.34 → 0.0.36
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/cli/index.js +1224 -1063
- package/dist/db/workflows.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +989 -214
- package/dist/lib/ai-client.d.ts +10 -2
- package/dist/lib/ai-client.d.ts.map +1 -1
- package/dist/lib/assertions.d.ts +4 -1
- package/dist/lib/assertions.d.ts.map +1 -1
- package/dist/lib/browser-compat.d.ts +14 -0
- package/dist/lib/browser-compat.d.ts.map +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/crawl-and-generate.d.ts +1 -1
- package/dist/lib/crawl-and-generate.d.ts.map +1 -1
- package/dist/lib/generator.d.ts.map +1 -1
- package/dist/lib/healer.d.ts.map +1 -1
- package/dist/lib/hybrid-runner.d.ts.map +1 -1
- package/dist/lib/judge.d.ts +3 -3
- package/dist/lib/judge.d.ts.map +1 -1
- package/dist/lib/repo-discovery.d.ts.map +1 -1
- package/dist/lib/repo-executor.d.ts.map +1 -1
- package/dist/lib/runner.d.ts +30 -1
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/session-converter.d.ts.map +1 -1
- package/dist/lib/workflow-runner.d.ts +73 -5
- package/dist/lib/workflow-runner.d.ts.map +1 -1
- package/dist/mcp/http.d.ts +1 -1
- package/dist/mcp/index.js +1016 -851
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/server/index.js +942 -609
- package/dist/types/index.d.ts +23 -3
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +7 -6
package/dist/cli/index.js
CHANGED
|
@@ -2100,6 +2100,56 @@ var require_commander = __commonJS((exports) => {
|
|
|
2100
2100
|
});
|
|
2101
2101
|
|
|
2102
2102
|
// src/types/index.ts
|
|
2103
|
+
function isRecord(value) {
|
|
2104
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2105
|
+
}
|
|
2106
|
+
function stringValue(value) {
|
|
2107
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
2108
|
+
}
|
|
2109
|
+
function numberValue(value) {
|
|
2110
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
2111
|
+
}
|
|
2112
|
+
function stringMap(value) {
|
|
2113
|
+
if (!isRecord(value))
|
|
2114
|
+
return;
|
|
2115
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
2116
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
2117
|
+
}
|
|
2118
|
+
function cleanupValue(value) {
|
|
2119
|
+
if (value === "delete" || value === "stop" || value === "keep")
|
|
2120
|
+
return value;
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
function workflowExecutionFromValue(value) {
|
|
2124
|
+
const input = isRecord(value) ? value : {};
|
|
2125
|
+
const rawTarget = stringValue(input["target"]) ?? "local";
|
|
2126
|
+
if (rawTarget === "local") {
|
|
2127
|
+
const timeoutMs2 = numberValue(input["timeoutMs"]);
|
|
2128
|
+
return timeoutMs2 === undefined ? { target: "local" } : { target: "local", timeoutMs: timeoutMs2 };
|
|
2129
|
+
}
|
|
2130
|
+
if (rawTarget !== "sandbox" && rawTarget !== "connector:e2b") {
|
|
2131
|
+
throw new Error(`Unsupported workflow execution target: ${rawTarget}`);
|
|
2132
|
+
}
|
|
2133
|
+
const provider = rawTarget === "connector:e2b" ? "e2b" : stringValue(input["provider"]) ?? stringValue(input["connector"]);
|
|
2134
|
+
const sandboxImage = stringValue(input["sandboxImage"]) ?? stringValue(input["sandboxTemplate"]);
|
|
2135
|
+
const sandboxRemoteDir = stringValue(input["sandboxRemoteDir"]);
|
|
2136
|
+
const sandboxCleanup = cleanupValue(input["sandboxCleanup"]);
|
|
2137
|
+
const setupCommand = stringValue(input["setupCommand"]);
|
|
2138
|
+
const packageSpec = stringValue(input["packageSpec"]);
|
|
2139
|
+
const timeoutMs = numberValue(input["timeoutMs"]);
|
|
2140
|
+
const env = stringMap(input["env"]);
|
|
2141
|
+
return {
|
|
2142
|
+
target: "sandbox",
|
|
2143
|
+
...provider ? { provider } : {},
|
|
2144
|
+
...sandboxImage ? { sandboxImage } : {},
|
|
2145
|
+
...sandboxRemoteDir ? { sandboxRemoteDir } : {},
|
|
2146
|
+
...sandboxCleanup ? { sandboxCleanup } : {},
|
|
2147
|
+
...setupCommand ? { setupCommand } : {},
|
|
2148
|
+
...packageSpec ? { packageSpec } : {},
|
|
2149
|
+
...timeoutMs !== undefined ? { timeoutMs } : {},
|
|
2150
|
+
...env ? { env } : {}
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2103
2153
|
function workflowFromRow(row) {
|
|
2104
2154
|
return {
|
|
2105
2155
|
id: row.id,
|
|
@@ -2109,7 +2159,7 @@ function workflowFromRow(row) {
|
|
|
2109
2159
|
scenarioFilter: JSON.parse(row.scenario_filter || "{}"),
|
|
2110
2160
|
personaIds: JSON.parse(row.persona_ids || "[]"),
|
|
2111
2161
|
goal: row.goal ? JSON.parse(row.goal) : null,
|
|
2112
|
-
execution: JSON.parse(row.execution || '{"target":"local"}'),
|
|
2162
|
+
execution: workflowExecutionFromValue(JSON.parse(row.execution || '{"target":"local"}')),
|
|
2113
2163
|
settings: JSON.parse(row.settings || "{}"),
|
|
2114
2164
|
enabled: row.enabled === 1,
|
|
2115
2165
|
createdAt: row.created_at,
|
|
@@ -13933,6 +13983,10 @@ function loadConfig() {
|
|
|
13933
13983
|
if (envApiKey) {
|
|
13934
13984
|
config.anthropicApiKey = envApiKey;
|
|
13935
13985
|
}
|
|
13986
|
+
const envSelfHeal = process.env["TESTERS_SELF_HEAL"];
|
|
13987
|
+
if (envSelfHeal !== undefined) {
|
|
13988
|
+
config.selfHeal = ["1", "true", "yes", "on"].includes(envSelfHeal.toLowerCase());
|
|
13989
|
+
}
|
|
13936
13990
|
return config;
|
|
13937
13991
|
}
|
|
13938
13992
|
var CONFIG_DIR3, CONFIG_PATH2;
|
|
@@ -13969,12 +14023,11 @@ Original selector that failed: "${request.failedSelector}"
|
|
|
13969
14023
|
Please identify the correct selector from the screenshot.`;
|
|
13970
14024
|
let rawResponse = "";
|
|
13971
14025
|
try {
|
|
13972
|
-
if (provider
|
|
13973
|
-
const
|
|
13974
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
14026
|
+
if (provider !== "anthropic") {
|
|
14027
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
13975
14028
|
const resp = await callOpenAICompatible({
|
|
13976
|
-
baseUrl,
|
|
13977
|
-
apiKey,
|
|
14029
|
+
baseUrl: compat.baseUrl,
|
|
14030
|
+
apiKey: compat.apiKey,
|
|
13978
14031
|
model,
|
|
13979
14032
|
system: HEAL_SYSTEM,
|
|
13980
14033
|
messages: [{ role: "user", content: userMessage }],
|
|
@@ -14068,12 +14121,15 @@ var init_healer = __esm(() => {
|
|
|
14068
14121
|
var exports_ai_client = {};
|
|
14069
14122
|
__export(exports_ai_client, {
|
|
14070
14123
|
runAgentLoop: () => runAgentLoop,
|
|
14124
|
+
resolveProviderApiKeyForModel: () => resolveProviderApiKeyForModel,
|
|
14071
14125
|
resolveModel: () => resolveModel,
|
|
14072
14126
|
executeTool: () => executeTool,
|
|
14073
14127
|
detectProvider: () => detectProvider,
|
|
14128
|
+
createOpenAICompatibleConfig: () => createOpenAICompatibleConfig,
|
|
14074
14129
|
createClientForModel: () => createClientForModel,
|
|
14075
14130
|
createClient: () => createClient,
|
|
14076
14131
|
callOpenAICompatible: () => callOpenAICompatible,
|
|
14132
|
+
buildScenarioUserMessage: () => buildScenarioUserMessage,
|
|
14077
14133
|
BROWSER_TOOLS: () => BROWSER_TOOLS
|
|
14078
14134
|
});
|
|
14079
14135
|
import Anthropic2 from "@anthropic-ai/sdk";
|
|
@@ -14486,7 +14542,6 @@ async function executeTool(page, screenshotter, toolName, toolInput, context) {
|
|
|
14486
14542
|
const assertionType = toolInput.assertion_type;
|
|
14487
14543
|
const selector = toolInput.selector;
|
|
14488
14544
|
const expected = toolInput.expected;
|
|
14489
|
-
const sessionId = context.sessionId ?? "default";
|
|
14490
14545
|
switch (assertionType) {
|
|
14491
14546
|
case "element_exists": {
|
|
14492
14547
|
if (!selector)
|
|
@@ -14551,7 +14606,6 @@ async function executeTool(page, screenshotter, toolName, toolInput, context) {
|
|
|
14551
14606
|
case "browser_intercept": {
|
|
14552
14607
|
const action = toolInput.action;
|
|
14553
14608
|
const pattern = toolInput.pattern;
|
|
14554
|
-
const interceptAction = toolInput.intercept_action;
|
|
14555
14609
|
const statusCode = toolInput.status_code;
|
|
14556
14610
|
const body = toolInput.body;
|
|
14557
14611
|
const sessionId = context.sessionId ?? "default";
|
|
@@ -14628,7 +14682,28 @@ ${JSON.stringify(har, null, 2)}` };
|
|
|
14628
14682
|
}
|
|
14629
14683
|
case "browser_a11y": {
|
|
14630
14684
|
const level = toolInput.level ?? "AA";
|
|
14631
|
-
const snapshot = await page.
|
|
14685
|
+
const snapshot = await page.evaluate(() => {
|
|
14686
|
+
function readRole(el) {
|
|
14687
|
+
return el.getAttribute("role") ?? el.tagName.toLowerCase();
|
|
14688
|
+
}
|
|
14689
|
+
function readName(el) {
|
|
14690
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
14691
|
+
if (labelledBy) {
|
|
14692
|
+
const labelledText = labelledBy.split(/\s+/).map((id) => document.getElementById(id)?.textContent?.trim()).filter(Boolean).join(" ");
|
|
14693
|
+
if (labelledText)
|
|
14694
|
+
return labelledText;
|
|
14695
|
+
}
|
|
14696
|
+
return el.getAttribute("aria-label") ?? el.getAttribute("alt") ?? el.textContent?.trim() ?? "";
|
|
14697
|
+
}
|
|
14698
|
+
function walk(el) {
|
|
14699
|
+
return {
|
|
14700
|
+
role: readRole(el),
|
|
14701
|
+
name: readName(el),
|
|
14702
|
+
children: Array.from(el.children).map((child) => walk(child))
|
|
14703
|
+
};
|
|
14704
|
+
}
|
|
14705
|
+
return document.body ? walk(document.body) : null;
|
|
14706
|
+
});
|
|
14632
14707
|
if (!snapshot)
|
|
14633
14708
|
return { result: "Error: could not capture accessibility tree" };
|
|
14634
14709
|
const issues = [];
|
|
@@ -14670,6 +14745,38 @@ ${filtered.join(`
|
|
|
14670
14745
|
return { result: `Error executing ${toolName}: ${message}` };
|
|
14671
14746
|
}
|
|
14672
14747
|
}
|
|
14748
|
+
function resolveStartUrl(baseUrl, targetPath) {
|
|
14749
|
+
try {
|
|
14750
|
+
return new URL(targetPath, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString();
|
|
14751
|
+
} catch {
|
|
14752
|
+
return `${baseUrl.replace(/\/+$/, "")}/${targetPath.replace(/^\/+/, "")}`;
|
|
14753
|
+
}
|
|
14754
|
+
}
|
|
14755
|
+
function buildScenarioUserMessage(scenario, baseUrl) {
|
|
14756
|
+
const userParts = [
|
|
14757
|
+
`**Scenario:** ${scenario.name}`,
|
|
14758
|
+
`**Description:** ${scenario.description}`
|
|
14759
|
+
];
|
|
14760
|
+
if (baseUrl) {
|
|
14761
|
+
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
14762
|
+
userParts.push(`**Base URL:** ${normalizedBaseUrl}`);
|
|
14763
|
+
if (scenario.targetPath) {
|
|
14764
|
+
userParts.push(`**Start URL:** ${resolveStartUrl(normalizedBaseUrl, scenario.targetPath)}`);
|
|
14765
|
+
}
|
|
14766
|
+
userParts.push("**Navigation Boundary:** Treat the Base URL as the application under test. Resolve relative paths and in-app navigation against this origin. Do not navigate to another host unless a step explicitly includes an absolute external URL.");
|
|
14767
|
+
}
|
|
14768
|
+
if (scenario.targetPath) {
|
|
14769
|
+
userParts.push(`**Target Path:** ${scenario.targetPath}`);
|
|
14770
|
+
}
|
|
14771
|
+
if (scenario.steps.length > 0) {
|
|
14772
|
+
userParts.push("**Steps:**");
|
|
14773
|
+
for (let i = 0;i < scenario.steps.length; i++) {
|
|
14774
|
+
userParts.push(`${i + 1}. ${scenario.steps[i]}`);
|
|
14775
|
+
}
|
|
14776
|
+
}
|
|
14777
|
+
return userParts.join(`
|
|
14778
|
+
`);
|
|
14779
|
+
}
|
|
14673
14780
|
async function runAgentLoop(options) {
|
|
14674
14781
|
const {
|
|
14675
14782
|
client,
|
|
@@ -14679,6 +14786,7 @@ async function runAgentLoop(options) {
|
|
|
14679
14786
|
model,
|
|
14680
14787
|
runId,
|
|
14681
14788
|
sessionId,
|
|
14789
|
+
baseUrl,
|
|
14682
14790
|
maxTurns = 30,
|
|
14683
14791
|
onStep,
|
|
14684
14792
|
persona,
|
|
@@ -14726,21 +14834,7 @@ Instructions: ${persona.instructions}` : "",
|
|
|
14726
14834
|
"- Verify both positive and negative states"
|
|
14727
14835
|
].join(`
|
|
14728
14836
|
`) + personaSection;
|
|
14729
|
-
const
|
|
14730
|
-
`**Scenario:** ${scenario.name}`,
|
|
14731
|
-
`**Description:** ${scenario.description}`
|
|
14732
|
-
];
|
|
14733
|
-
if (scenario.targetPath) {
|
|
14734
|
-
userParts.push(`**Target Path:** ${scenario.targetPath}`);
|
|
14735
|
-
}
|
|
14736
|
-
if (scenario.steps.length > 0) {
|
|
14737
|
-
userParts.push("**Steps:**");
|
|
14738
|
-
for (let i = 0;i < scenario.steps.length; i++) {
|
|
14739
|
-
userParts.push(`${i + 1}. ${scenario.steps[i]}`);
|
|
14740
|
-
}
|
|
14741
|
-
}
|
|
14742
|
-
const userMessage = userParts.join(`
|
|
14743
|
-
`);
|
|
14837
|
+
const userMessage = buildScenarioUserMessage(scenario, baseUrl);
|
|
14744
14838
|
const screenshots = [];
|
|
14745
14839
|
let tokensUsed = 0;
|
|
14746
14840
|
let stepNumber = 0;
|
|
@@ -14803,7 +14897,7 @@ Instructions: ${persona.instructions}` : "",
|
|
|
14803
14897
|
if (onStep) {
|
|
14804
14898
|
onStep({ type: "tool_call", toolName: toolBlock.name, toolInput, stepNumber });
|
|
14805
14899
|
}
|
|
14806
|
-
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber, sessionId, a11y });
|
|
14900
|
+
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber, sessionId: sessionId ?? runId, a11y });
|
|
14807
14901
|
if (onStep) {
|
|
14808
14902
|
onStep({ type: "tool_result", toolName: toolBlock.name, toolResult: execResult.result, stepNumber });
|
|
14809
14903
|
}
|
|
@@ -14854,10 +14948,17 @@ function detectProvider(model) {
|
|
|
14854
14948
|
return "openai";
|
|
14855
14949
|
if (model.startsWith("gemini-"))
|
|
14856
14950
|
return "google";
|
|
14951
|
+
if (model.startsWith("glm-") || model.startsWith("zai/") || model.startsWith("zai-"))
|
|
14952
|
+
return "zai";
|
|
14857
14953
|
if (model.startsWith("llama-") || model.startsWith("qwen-") || model.includes("cerebras"))
|
|
14858
14954
|
return "cerebras";
|
|
14859
14955
|
return "anthropic";
|
|
14860
14956
|
}
|
|
14957
|
+
function resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
14958
|
+
if (explicitApiKey)
|
|
14959
|
+
return explicitApiKey;
|
|
14960
|
+
return detectProvider(model) === "anthropic" ? configuredAnthropicApiKey : undefined;
|
|
14961
|
+
}
|
|
14861
14962
|
function createClient(apiKey) {
|
|
14862
14963
|
const key = apiKey ?? process.env["ANTHROPIC_API_KEY"];
|
|
14863
14964
|
if (!key) {
|
|
@@ -14935,26 +15036,34 @@ async function callOpenAICompatible(options) {
|
|
|
14935
15036
|
const usage = { input_tokens: data.usage?.prompt_tokens ?? 0, output_tokens: data.usage?.completion_tokens ?? 0 };
|
|
14936
15037
|
return { content, stop_reason: stopReason, usage };
|
|
14937
15038
|
}
|
|
14938
|
-
function
|
|
14939
|
-
const provider = detectProvider(model);
|
|
15039
|
+
function createOpenAICompatibleConfig(provider, apiKey) {
|
|
14940
15040
|
if (provider === "openai") {
|
|
14941
|
-
const
|
|
14942
|
-
if (!
|
|
15041
|
+
const key2 = apiKey ?? process.env["OPENAI_API_KEY"];
|
|
15042
|
+
if (!key2)
|
|
14943
15043
|
throw new AIClientError("No OpenAI API key. Set OPENAI_API_KEY or pass it explicitly.");
|
|
14944
|
-
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey:
|
|
15044
|
+
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: key2 };
|
|
14945
15045
|
}
|
|
14946
15046
|
if (provider === "google") {
|
|
14947
|
-
const
|
|
14948
|
-
if (!
|
|
15047
|
+
const key2 = apiKey ?? process.env["GOOGLE_API_KEY"];
|
|
15048
|
+
if (!key2)
|
|
14949
15049
|
throw new AIClientError("No Google API key. Set GOOGLE_API_KEY or pass it explicitly.");
|
|
14950
|
-
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey:
|
|
15050
|
+
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: key2 };
|
|
14951
15051
|
}
|
|
14952
15052
|
if (provider === "cerebras") {
|
|
14953
|
-
const
|
|
14954
|
-
if (!
|
|
15053
|
+
const key2 = apiKey ?? process.env["CEREBRAS_API_KEY"];
|
|
15054
|
+
if (!key2)
|
|
14955
15055
|
throw new AIClientError("No Cerebras API key. Set CEREBRAS_API_KEY or pass it explicitly.");
|
|
14956
|
-
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey:
|
|
15056
|
+
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey: key2 };
|
|
14957
15057
|
}
|
|
15058
|
+
const key = apiKey ?? process.env["ZAI_API_KEY"];
|
|
15059
|
+
if (!key)
|
|
15060
|
+
throw new AIClientError("No Z.AI API key. Set ZAI_API_KEY or pass it explicitly.");
|
|
15061
|
+
return { provider: "zai", baseUrl: "https://api.z.ai/api/paas/v4", apiKey: key };
|
|
15062
|
+
}
|
|
15063
|
+
function createClientForModel(model, apiKey) {
|
|
15064
|
+
const provider = detectProvider(model);
|
|
15065
|
+
if (provider !== "anthropic")
|
|
15066
|
+
return createOpenAICompatibleConfig(provider, apiKey);
|
|
14958
15067
|
return createClient(apiKey);
|
|
14959
15068
|
}
|
|
14960
15069
|
var activeHARs, activeCoverage, BROWSER_TOOLS;
|
|
@@ -15531,22 +15640,22 @@ function resolveJudgeModel(config) {
|
|
|
15531
15640
|
apiKey = process.env["GOOGLE_API_KEY"];
|
|
15532
15641
|
else if (provider === "cerebras")
|
|
15533
15642
|
apiKey = process.env["CEREBRAS_API_KEY"];
|
|
15643
|
+
else if (provider === "zai")
|
|
15644
|
+
apiKey = process.env["ZAI_API_KEY"];
|
|
15534
15645
|
}
|
|
15535
15646
|
if (!apiKey) {
|
|
15536
|
-
|
|
15537
|
-
if (!apiKey)
|
|
15538
|
-
throw new AIClientError("No API key found for judge. Set ANTHROPIC_API_KEY, CEREBRAS_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY.");
|
|
15647
|
+
throw new AIClientError(`No API key found for ${provider} judge provider.`);
|
|
15539
15648
|
}
|
|
15540
15649
|
return { model, provider, apiKey };
|
|
15541
15650
|
}
|
|
15542
15651
|
async function callJudge(prompt, config) {
|
|
15543
15652
|
const { model, provider, apiKey } = resolveJudgeModel(config);
|
|
15544
15653
|
const threshold = 0.7;
|
|
15545
|
-
if (provider
|
|
15546
|
-
const
|
|
15654
|
+
if (provider !== "anthropic") {
|
|
15655
|
+
const compat = createOpenAICompatibleConfig(provider, apiKey);
|
|
15547
15656
|
const resp2 = await callOpenAICompatible({
|
|
15548
|
-
baseUrl,
|
|
15549
|
-
apiKey,
|
|
15657
|
+
baseUrl: compat.baseUrl,
|
|
15658
|
+
apiKey: compat.apiKey,
|
|
15550
15659
|
model,
|
|
15551
15660
|
system: LLM_SYSTEM,
|
|
15552
15661
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -17494,6 +17603,381 @@ var init_failure_pipeline = __esm(() => {
|
|
|
17494
17603
|
init_todos_connector();
|
|
17495
17604
|
});
|
|
17496
17605
|
|
|
17606
|
+
// src/lib/a11y-audit.ts
|
|
17607
|
+
async function runA11yAudit(page, options = {}) {
|
|
17608
|
+
const { level = "AA", rules, exclude = [] } = options;
|
|
17609
|
+
await page.addScriptTag({ url: "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.9.1/axe.min.js" });
|
|
17610
|
+
const config = {
|
|
17611
|
+
runOnly: {
|
|
17612
|
+
type: level === "AAA" ? "standard" : "tag",
|
|
17613
|
+
values: level === "AAA" ? undefined : [level, "best-practice"]
|
|
17614
|
+
}
|
|
17615
|
+
};
|
|
17616
|
+
if (rules && rules.length > 0) {
|
|
17617
|
+
config.rules = Object.fromEntries(rules.map((r) => [r, { enabled: true }]));
|
|
17618
|
+
}
|
|
17619
|
+
if (exclude.length > 0) {
|
|
17620
|
+
config.exclude = exclude;
|
|
17621
|
+
}
|
|
17622
|
+
const result = await page.evaluate(async (auditConfig) => {
|
|
17623
|
+
const axeResult = await window.axe.run(auditConfig);
|
|
17624
|
+
return axeResult;
|
|
17625
|
+
}, config);
|
|
17626
|
+
const violations = (result.violations ?? []).map((v) => ({
|
|
17627
|
+
id: v.id,
|
|
17628
|
+
impact: v.impact,
|
|
17629
|
+
description: v.description,
|
|
17630
|
+
help: v.help,
|
|
17631
|
+
helpUrl: v.helpUrl,
|
|
17632
|
+
nodes: (v.nodes ?? []).map((n) => ({
|
|
17633
|
+
html: n.html,
|
|
17634
|
+
target: n.target,
|
|
17635
|
+
failureSummary: n.failureSummary
|
|
17636
|
+
}))
|
|
17637
|
+
}));
|
|
17638
|
+
const passes = (result.passes ?? []).map((p) => ({
|
|
17639
|
+
id: p.id,
|
|
17640
|
+
description: p.description
|
|
17641
|
+
}));
|
|
17642
|
+
const incomplete = (result.incomplete ?? []).map((i) => ({
|
|
17643
|
+
id: i.id,
|
|
17644
|
+
description: i.description,
|
|
17645
|
+
impact: i.impact
|
|
17646
|
+
}));
|
|
17647
|
+
const criticalCount = violations.filter((v) => v.impact === "critical").length;
|
|
17648
|
+
const seriousCount = violations.filter((v) => v.impact === "serious").length;
|
|
17649
|
+
const moderateCount = violations.filter((v) => v.impact === "moderate").length;
|
|
17650
|
+
const minorCount = violations.filter((v) => v.impact === "minor").length;
|
|
17651
|
+
return {
|
|
17652
|
+
violations,
|
|
17653
|
+
passes,
|
|
17654
|
+
incomplete,
|
|
17655
|
+
url: page.url(),
|
|
17656
|
+
timestamp: new Date().toISOString(),
|
|
17657
|
+
totalViolations: violations.length,
|
|
17658
|
+
criticalCount,
|
|
17659
|
+
seriousCount,
|
|
17660
|
+
moderateCount,
|
|
17661
|
+
minorCount
|
|
17662
|
+
};
|
|
17663
|
+
}
|
|
17664
|
+
|
|
17665
|
+
// src/lib/assertions.ts
|
|
17666
|
+
async function evaluateAssertions(page, assertions, context = {}) {
|
|
17667
|
+
const results = [];
|
|
17668
|
+
for (const assertion of assertions) {
|
|
17669
|
+
try {
|
|
17670
|
+
const result = await evaluateOne(page, assertion, context);
|
|
17671
|
+
results.push(result);
|
|
17672
|
+
} catch (err) {
|
|
17673
|
+
results.push({
|
|
17674
|
+
assertion,
|
|
17675
|
+
passed: false,
|
|
17676
|
+
actual: "",
|
|
17677
|
+
error: err instanceof Error ? err.message : String(err)
|
|
17678
|
+
});
|
|
17679
|
+
}
|
|
17680
|
+
}
|
|
17681
|
+
return results;
|
|
17682
|
+
}
|
|
17683
|
+
async function evaluateOne(page, assertion, context) {
|
|
17684
|
+
switch (assertion.type) {
|
|
17685
|
+
case "visible": {
|
|
17686
|
+
const visible = await page.locator(assertion.selector).isVisible();
|
|
17687
|
+
return {
|
|
17688
|
+
assertion,
|
|
17689
|
+
passed: visible,
|
|
17690
|
+
actual: String(visible)
|
|
17691
|
+
};
|
|
17692
|
+
}
|
|
17693
|
+
case "not_visible": {
|
|
17694
|
+
const visible = await page.locator(assertion.selector).isVisible();
|
|
17695
|
+
return {
|
|
17696
|
+
assertion,
|
|
17697
|
+
passed: !visible,
|
|
17698
|
+
actual: String(visible)
|
|
17699
|
+
};
|
|
17700
|
+
}
|
|
17701
|
+
case "text_contains": {
|
|
17702
|
+
const text = await page.locator(assertion.selector).textContent() ?? "";
|
|
17703
|
+
const expected = String(assertion.expected ?? "");
|
|
17704
|
+
return {
|
|
17705
|
+
assertion,
|
|
17706
|
+
passed: text.includes(expected),
|
|
17707
|
+
actual: text
|
|
17708
|
+
};
|
|
17709
|
+
}
|
|
17710
|
+
case "text_equals": {
|
|
17711
|
+
const text = await page.locator(assertion.selector).textContent() ?? "";
|
|
17712
|
+
const expected = String(assertion.expected ?? "");
|
|
17713
|
+
return {
|
|
17714
|
+
assertion,
|
|
17715
|
+
passed: text.trim() === expected.trim(),
|
|
17716
|
+
actual: text
|
|
17717
|
+
};
|
|
17718
|
+
}
|
|
17719
|
+
case "element_count": {
|
|
17720
|
+
const count = await page.locator(assertion.selector).count();
|
|
17721
|
+
const expected = Number(assertion.expected ?? 0);
|
|
17722
|
+
return {
|
|
17723
|
+
assertion,
|
|
17724
|
+
passed: count === expected,
|
|
17725
|
+
actual: String(count)
|
|
17726
|
+
};
|
|
17727
|
+
}
|
|
17728
|
+
case "no_console_errors": {
|
|
17729
|
+
if (context.consoleErrors !== undefined) {
|
|
17730
|
+
const errors = context.consoleErrors.filter(Boolean);
|
|
17731
|
+
return {
|
|
17732
|
+
assertion,
|
|
17733
|
+
passed: errors.length === 0,
|
|
17734
|
+
actual: errors.length === 0 ? "No console errors captured" : errors.slice(0, 3).join(" | ")
|
|
17735
|
+
};
|
|
17736
|
+
}
|
|
17737
|
+
const errorElements = await page.locator('[role="alert"], .error, .error-message, [data-testid="error"]').count();
|
|
17738
|
+
return {
|
|
17739
|
+
assertion,
|
|
17740
|
+
passed: errorElements === 0,
|
|
17741
|
+
actual: `${errorElements} error element(s) found`
|
|
17742
|
+
};
|
|
17743
|
+
}
|
|
17744
|
+
case "no_a11y_violations": {
|
|
17745
|
+
try {
|
|
17746
|
+
const auditResult = await runA11yAudit(page);
|
|
17747
|
+
const hasIssues = auditResult.violations.length > 0;
|
|
17748
|
+
return {
|
|
17749
|
+
assertion,
|
|
17750
|
+
passed: !hasIssues,
|
|
17751
|
+
actual: hasIssues ? `${auditResult.totalViolations} violation(s): ${auditResult.violations.map((v) => v.id).join(", ")}` : "No accessibility violations found"
|
|
17752
|
+
};
|
|
17753
|
+
} catch (err) {
|
|
17754
|
+
return {
|
|
17755
|
+
assertion,
|
|
17756
|
+
passed: false,
|
|
17757
|
+
actual: "",
|
|
17758
|
+
error: err instanceof Error ? err.message : String(err)
|
|
17759
|
+
};
|
|
17760
|
+
}
|
|
17761
|
+
}
|
|
17762
|
+
case "url_contains": {
|
|
17763
|
+
const url = page.url();
|
|
17764
|
+
const expected = String(assertion.expected ?? "");
|
|
17765
|
+
return {
|
|
17766
|
+
assertion,
|
|
17767
|
+
passed: url.includes(expected),
|
|
17768
|
+
actual: url
|
|
17769
|
+
};
|
|
17770
|
+
}
|
|
17771
|
+
case "title_contains": {
|
|
17772
|
+
const title = await page.title();
|
|
17773
|
+
const expected = String(assertion.expected ?? "");
|
|
17774
|
+
return {
|
|
17775
|
+
assertion,
|
|
17776
|
+
passed: title.includes(expected),
|
|
17777
|
+
actual: title
|
|
17778
|
+
};
|
|
17779
|
+
}
|
|
17780
|
+
case "cookie_exists": {
|
|
17781
|
+
const cookieName = assertion.expected;
|
|
17782
|
+
const cookies = await page.context().cookies();
|
|
17783
|
+
const found = cookies.some((c) => c.name === cookieName);
|
|
17784
|
+
return {
|
|
17785
|
+
assertion,
|
|
17786
|
+
passed: found,
|
|
17787
|
+
actual: found ? `Cookie "${cookieName}" exists` : `Cookie "${cookieName}" not found`
|
|
17788
|
+
};
|
|
17789
|
+
}
|
|
17790
|
+
case "cookie_not_exists": {
|
|
17791
|
+
const cookieName = assertion.expected;
|
|
17792
|
+
const cookies = await page.context().cookies();
|
|
17793
|
+
const found = cookies.some((c) => c.name === cookieName);
|
|
17794
|
+
return {
|
|
17795
|
+
assertion,
|
|
17796
|
+
passed: !found,
|
|
17797
|
+
actual: found ? `Cookie "${cookieName}" found (unexpected)` : `Cookie "${cookieName}" does not exist`
|
|
17798
|
+
};
|
|
17799
|
+
}
|
|
17800
|
+
case "cookie_value": {
|
|
17801
|
+
const [cookieName, expectedValue] = assertion.expected.split("=", 2);
|
|
17802
|
+
const cookies = await page.context().cookies();
|
|
17803
|
+
const cookie = cookies.find((c) => c.name === cookieName);
|
|
17804
|
+
const actualValue = cookie?.value ?? "";
|
|
17805
|
+
return {
|
|
17806
|
+
assertion,
|
|
17807
|
+
passed: actualValue === expectedValue,
|
|
17808
|
+
actual: cookie ? `${cookieName}=${actualValue}` : `Cookie "${cookieName}" not found`
|
|
17809
|
+
};
|
|
17810
|
+
}
|
|
17811
|
+
case "local_storage_exists": {
|
|
17812
|
+
const key = assertion.expected;
|
|
17813
|
+
const value = await page.evaluate((k) => localStorage.getItem(k), key);
|
|
17814
|
+
return {
|
|
17815
|
+
assertion,
|
|
17816
|
+
passed: value !== null,
|
|
17817
|
+
actual: value !== null ? `Key "${key}" exists with value "${value}"` : `Key "${key}" not found in localStorage`
|
|
17818
|
+
};
|
|
17819
|
+
}
|
|
17820
|
+
case "local_storage_not_exists": {
|
|
17821
|
+
const key = assertion.expected;
|
|
17822
|
+
const value = await page.evaluate((k) => localStorage.getItem(k), key);
|
|
17823
|
+
return {
|
|
17824
|
+
assertion,
|
|
17825
|
+
passed: value === null,
|
|
17826
|
+
actual: value !== null ? `Key "${key}" exists (unexpected)` : `Key "${key}" does not exist in localStorage`
|
|
17827
|
+
};
|
|
17828
|
+
}
|
|
17829
|
+
case "local_storage_value": {
|
|
17830
|
+
const [lsKey, expectedValue] = assertion.expected.split("=", 2);
|
|
17831
|
+
const value = await page.evaluate((k) => localStorage.getItem(k), lsKey ?? "");
|
|
17832
|
+
return {
|
|
17833
|
+
assertion,
|
|
17834
|
+
passed: value === expectedValue,
|
|
17835
|
+
actual: value !== null ? `${lsKey}=${value}` : `Key "${lsKey}" not found in localStorage`
|
|
17836
|
+
};
|
|
17837
|
+
}
|
|
17838
|
+
case "session_storage_value": {
|
|
17839
|
+
const [ssKey, expectedValue] = assertion.expected.split("=", 2);
|
|
17840
|
+
const value = await page.evaluate((k) => sessionStorage.getItem(k), ssKey ?? "");
|
|
17841
|
+
return {
|
|
17842
|
+
assertion,
|
|
17843
|
+
passed: value === expectedValue,
|
|
17844
|
+
actual: value !== null ? `${ssKey}=${value}` : `Key "${ssKey}" not found in sessionStorage`
|
|
17845
|
+
};
|
|
17846
|
+
}
|
|
17847
|
+
case "session_storage_not_exists": {
|
|
17848
|
+
const key = assertion.expected;
|
|
17849
|
+
const value = await page.evaluate((k) => sessionStorage.getItem(k), key);
|
|
17850
|
+
return {
|
|
17851
|
+
assertion,
|
|
17852
|
+
passed: value === null,
|
|
17853
|
+
actual: value !== null ? `Key "${key}" exists (unexpected)` : `Key "${key}" does not exist in sessionStorage`
|
|
17854
|
+
};
|
|
17855
|
+
}
|
|
17856
|
+
default: {
|
|
17857
|
+
return {
|
|
17858
|
+
assertion,
|
|
17859
|
+
passed: false,
|
|
17860
|
+
actual: "",
|
|
17861
|
+
error: `Unknown assertion type: ${assertion.type}`
|
|
17862
|
+
};
|
|
17863
|
+
}
|
|
17864
|
+
}
|
|
17865
|
+
}
|
|
17866
|
+
function parseAssertionString(str) {
|
|
17867
|
+
const trimmed = str.trim();
|
|
17868
|
+
if (trimmed === "no-console-errors") {
|
|
17869
|
+
return { type: "no_console_errors", description: "No console errors" };
|
|
17870
|
+
}
|
|
17871
|
+
if (trimmed.startsWith("url:contains:")) {
|
|
17872
|
+
const expected = trimmed.slice("url:contains:".length);
|
|
17873
|
+
return { type: "url_contains", expected, description: `URL contains "${expected}"` };
|
|
17874
|
+
}
|
|
17875
|
+
if (trimmed.startsWith("title:contains:")) {
|
|
17876
|
+
const expected = trimmed.slice("title:contains:".length);
|
|
17877
|
+
return { type: "title_contains", expected, description: `Title contains "${expected}"` };
|
|
17878
|
+
}
|
|
17879
|
+
if (trimmed.startsWith("count:")) {
|
|
17880
|
+
const rest = trimmed.slice("count:".length);
|
|
17881
|
+
const eqIdx = rest.indexOf(" eq:");
|
|
17882
|
+
if (eqIdx === -1) {
|
|
17883
|
+
throw new Error(`Invalid count assertion format: ${str}. Expected "count:<selector> eq:<number>"`);
|
|
17884
|
+
}
|
|
17885
|
+
const selector = rest.slice(0, eqIdx);
|
|
17886
|
+
const expected = parseInt(rest.slice(eqIdx + " eq:".length), 10);
|
|
17887
|
+
return { type: "element_count", selector, expected, description: `${selector} count equals ${expected}` };
|
|
17888
|
+
}
|
|
17889
|
+
if (trimmed.startsWith("text:")) {
|
|
17890
|
+
const rest = trimmed.slice("text:".length);
|
|
17891
|
+
const containsIdx = rest.indexOf(" contains:");
|
|
17892
|
+
const equalsIdx = rest.indexOf(" equals:");
|
|
17893
|
+
if (containsIdx !== -1) {
|
|
17894
|
+
const selector = rest.slice(0, containsIdx);
|
|
17895
|
+
const expected = rest.slice(containsIdx + " contains:".length);
|
|
17896
|
+
return { type: "text_contains", selector, expected, description: `${selector} text contains "${expected}"` };
|
|
17897
|
+
}
|
|
17898
|
+
if (equalsIdx !== -1) {
|
|
17899
|
+
const selector = rest.slice(0, equalsIdx);
|
|
17900
|
+
const expected = rest.slice(equalsIdx + " equals:".length);
|
|
17901
|
+
return { type: "text_equals", selector, expected, description: `${selector} text equals "${expected}"` };
|
|
17902
|
+
}
|
|
17903
|
+
throw new Error(`Invalid text assertion format: ${str}. Expected "text:<selector> contains:<text>" or "text:<selector> equals:<text>"`);
|
|
17904
|
+
}
|
|
17905
|
+
if (trimmed.startsWith("selector:")) {
|
|
17906
|
+
const rest = trimmed.slice("selector:".length);
|
|
17907
|
+
const lastSpace = rest.lastIndexOf(" ");
|
|
17908
|
+
if (lastSpace === -1) {
|
|
17909
|
+
throw new Error(`Invalid selector assertion format: ${str}. Expected "selector:<selector> visible" or "selector:<selector> not-visible"`);
|
|
17910
|
+
}
|
|
17911
|
+
const selector = rest.slice(0, lastSpace);
|
|
17912
|
+
const action = rest.slice(lastSpace + 1);
|
|
17913
|
+
if (action === "visible") {
|
|
17914
|
+
return { type: "visible", selector, description: `${selector} is visible` };
|
|
17915
|
+
}
|
|
17916
|
+
if (action === "not-visible") {
|
|
17917
|
+
return { type: "not_visible", selector, description: `${selector} is not visible` };
|
|
17918
|
+
}
|
|
17919
|
+
throw new Error(`Unknown selector action: "${action}". Expected "visible" or "not-visible"`);
|
|
17920
|
+
}
|
|
17921
|
+
if (trimmed.startsWith("cookie:exists:")) {
|
|
17922
|
+
const name = trimmed.slice("cookie:exists:".length);
|
|
17923
|
+
return { type: "cookie_exists", expected: name, description: `Cookie "${name}" exists` };
|
|
17924
|
+
}
|
|
17925
|
+
if (trimmed.startsWith("cookie:not-exists:")) {
|
|
17926
|
+
const name = trimmed.slice("cookie:not-exists:".length);
|
|
17927
|
+
return { type: "cookie_not_exists", expected: name, description: `Cookie "${name}" does not exist` };
|
|
17928
|
+
}
|
|
17929
|
+
if (trimmed.startsWith("cookie:value:")) {
|
|
17930
|
+
const valueStr = trimmed.slice("cookie:value:".length);
|
|
17931
|
+
return { type: "cookie_value", expected: valueStr, description: `Cookie value is "${valueStr}"` };
|
|
17932
|
+
}
|
|
17933
|
+
if (trimmed.startsWith("local:exists:")) {
|
|
17934
|
+
const key = trimmed.slice("local:exists:".length);
|
|
17935
|
+
return { type: "local_storage_exists", expected: key, description: `LocalStorage key "${key}" exists` };
|
|
17936
|
+
}
|
|
17937
|
+
if (trimmed.startsWith("local:not-exists:")) {
|
|
17938
|
+
const key = trimmed.slice("local:not-exists:".length);
|
|
17939
|
+
return { type: "local_storage_not_exists", expected: key, description: `LocalStorage key "${key}" does not exist` };
|
|
17940
|
+
}
|
|
17941
|
+
if (trimmed.startsWith("local:value:")) {
|
|
17942
|
+
const valueStr = trimmed.slice("local:value:".length);
|
|
17943
|
+
return { type: "local_storage_value", expected: valueStr, description: `LocalStorage value is "${valueStr}"` };
|
|
17944
|
+
}
|
|
17945
|
+
if (trimmed.startsWith("session:value:")) {
|
|
17946
|
+
const valueStr = trimmed.slice("session:value:".length);
|
|
17947
|
+
return { type: "session_storage_value", expected: valueStr, description: `SessionStorage value is "${valueStr}"` };
|
|
17948
|
+
}
|
|
17949
|
+
if (trimmed.startsWith("session:not-exists:")) {
|
|
17950
|
+
const key = trimmed.slice("session:not-exists:".length);
|
|
17951
|
+
return { type: "session_storage_not_exists", expected: key, description: `SessionStorage key "${key}" does not exist` };
|
|
17952
|
+
}
|
|
17953
|
+
throw new Error(`Cannot parse assertion: "${str}". See --help for assertion formats.`);
|
|
17954
|
+
}
|
|
17955
|
+
function allAssertionsPassed(results) {
|
|
17956
|
+
return results.every((r) => r.passed);
|
|
17957
|
+
}
|
|
17958
|
+
function formatAssertionResults(results) {
|
|
17959
|
+
if (results.length === 0)
|
|
17960
|
+
return "No assertions.";
|
|
17961
|
+
const lines = [];
|
|
17962
|
+
for (const r of results) {
|
|
17963
|
+
const icon = r.passed ? "PASS" : "FAIL";
|
|
17964
|
+
const desc = r.assertion.description || `${r.assertion.type}${r.assertion.selector ? ` ${r.assertion.selector}` : ""}`;
|
|
17965
|
+
let line = ` [${icon}] ${desc}`;
|
|
17966
|
+
if (!r.passed) {
|
|
17967
|
+
line += ` (actual: ${r.actual})`;
|
|
17968
|
+
if (r.error)
|
|
17969
|
+
line += ` \u2014 ${r.error}`;
|
|
17970
|
+
}
|
|
17971
|
+
lines.push(line);
|
|
17972
|
+
}
|
|
17973
|
+
const passed = results.filter((r) => r.passed).length;
|
|
17974
|
+
lines.push(`
|
|
17975
|
+
${passed}/${results.length} assertions passed.`);
|
|
17976
|
+
return lines.join(`
|
|
17977
|
+
`);
|
|
17978
|
+
}
|
|
17979
|
+
var init_assertions = () => {};
|
|
17980
|
+
|
|
17497
17981
|
// src/db/flows.ts
|
|
17498
17982
|
var exports_flows = {};
|
|
17499
17983
|
__export(exports_flows, {
|
|
@@ -17652,7 +18136,10 @@ __export(exports_runner, {
|
|
|
17652
18136
|
runSingleScenario: () => runSingleScenario,
|
|
17653
18137
|
runByFilter: () => runByFilter,
|
|
17654
18138
|
runBatch: () => runBatch,
|
|
17655
|
-
|
|
18139
|
+
resolveScenariosForRun: () => resolveScenariosForRun,
|
|
18140
|
+
resolveAgentApiKeyForModel: () => resolveAgentApiKeyForModel,
|
|
18141
|
+
onRunEvent: () => onRunEvent,
|
|
18142
|
+
applyStructuredAssertionsToResult: () => applyStructuredAssertionsToResult
|
|
17656
18143
|
});
|
|
17657
18144
|
import { mkdirSync as mkdirSync8 } from "fs";
|
|
17658
18145
|
import { join as join13 } from "path";
|
|
@@ -17664,6 +18151,57 @@ function emit(event) {
|
|
|
17664
18151
|
if (eventHandler)
|
|
17665
18152
|
eventHandler(event);
|
|
17666
18153
|
}
|
|
18154
|
+
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
18155
|
+
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
18156
|
+
}
|
|
18157
|
+
function assertionDescription(result) {
|
|
18158
|
+
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
18159
|
+
}
|
|
18160
|
+
function summarizeAssertionResult(result) {
|
|
18161
|
+
const description = assertionDescription(result);
|
|
18162
|
+
if (result.passed)
|
|
18163
|
+
return description;
|
|
18164
|
+
const suffix = result.error ? `; ${result.error}` : "";
|
|
18165
|
+
return `${description} (actual: ${result.actual}${suffix})`;
|
|
18166
|
+
}
|
|
18167
|
+
async function applyStructuredAssertionsToResult(input) {
|
|
18168
|
+
const assertions = input.scenario.assertions ?? [];
|
|
18169
|
+
if (assertions.length === 0) {
|
|
18170
|
+
return {
|
|
18171
|
+
status: input.status,
|
|
18172
|
+
reasoning: input.reasoning,
|
|
18173
|
+
assertionsPassed: [],
|
|
18174
|
+
assertionsFailed: [],
|
|
18175
|
+
assertionResults: []
|
|
18176
|
+
};
|
|
18177
|
+
}
|
|
18178
|
+
const results = await evaluateAssertions(input.page, assertions, {
|
|
18179
|
+
consoleErrors: input.consoleErrors
|
|
18180
|
+
});
|
|
18181
|
+
const assertionsPassed = results.filter((r) => r.passed).map(summarizeAssertionResult);
|
|
18182
|
+
const assertionsFailed = results.filter((r) => !r.passed).map(summarizeAssertionResult);
|
|
18183
|
+
const assertionResults = results.map((result) => ({
|
|
18184
|
+
type: result.assertion.type,
|
|
18185
|
+
description: assertionDescription(result),
|
|
18186
|
+
passed: result.passed,
|
|
18187
|
+
actual: result.actual,
|
|
18188
|
+
...result.error ? { error: result.error } : {}
|
|
18189
|
+
}));
|
|
18190
|
+
const assertionsOk = allAssertionsPassed(results);
|
|
18191
|
+
const status = assertionsOk || input.status !== "passed" ? input.status : "failed";
|
|
18192
|
+
const assertionHeading = assertionsOk ? "Structured assertions passed:" : "Structured assertions failed:";
|
|
18193
|
+
const reasoningParts = [input.reasoning, `${assertionHeading}
|
|
18194
|
+
${formatAssertionResults(results)}`].map((part) => part.trim()).filter(Boolean);
|
|
18195
|
+
return {
|
|
18196
|
+
status,
|
|
18197
|
+
reasoning: reasoningParts.join(`
|
|
18198
|
+
|
|
18199
|
+
`),
|
|
18200
|
+
assertionsPassed,
|
|
18201
|
+
assertionsFailed,
|
|
18202
|
+
assertionResults
|
|
18203
|
+
};
|
|
18204
|
+
}
|
|
17667
18205
|
function withTimeout(promise, ms, label) {
|
|
17668
18206
|
return new Promise((resolve, reject) => {
|
|
17669
18207
|
const warningAt = Math.floor(ms * 0.8);
|
|
@@ -17724,7 +18262,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
17724
18262
|
});
|
|
17725
18263
|
}
|
|
17726
18264
|
}
|
|
17727
|
-
const client = createClientForModel(model, effectiveOptions.apiKey
|
|
18265
|
+
const client = createClientForModel(model, resolveAgentApiKeyForModel(model, effectiveOptions.apiKey, config.anthropicApiKey));
|
|
17728
18266
|
const screenshotter = new Screenshotter({
|
|
17729
18267
|
baseDir: effectiveOptions.screenshotDir ?? config.screenshots.dir
|
|
17730
18268
|
});
|
|
@@ -17834,6 +18372,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
17834
18372
|
model,
|
|
17835
18373
|
runId,
|
|
17836
18374
|
sessionId: result.id,
|
|
18375
|
+
baseUrl: options.url,
|
|
17837
18376
|
maxTurns: effectiveOptions.minimal ? 10 : 30,
|
|
17838
18377
|
a11y: effectiveOptions.a11y,
|
|
17839
18378
|
persona: persona ? {
|
|
@@ -17916,27 +18455,46 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
17916
18455
|
closeSession(result.id);
|
|
17917
18456
|
const lightpandaNote = options.engine === "lightpanda" ? " (Running with Lightpanda \u2014 no screenshots)" : options.engine === "bun" ? " (Running with Bun.WebView \u2014 native, ~11x faster)" : "";
|
|
17918
18457
|
const networkMeta = networkErrors.length > 0 ? { networkErrors: networkErrors.slice(0, 20) } : {};
|
|
17919
|
-
|
|
18458
|
+
const baseReasoning = agentResult.reasoning ? agentResult.reasoning + lightpandaNote : lightpandaNote || "";
|
|
18459
|
+
const assertionOutcome = await applyStructuredAssertionsToResult({
|
|
18460
|
+
page,
|
|
18461
|
+
scenario,
|
|
18462
|
+
consoleErrors,
|
|
17920
18463
|
status: agentResult.status,
|
|
17921
|
-
reasoning:
|
|
18464
|
+
reasoning: baseReasoning
|
|
18465
|
+
});
|
|
18466
|
+
const structuredAssertionMeta = assertionOutcome.assertionResults.length > 0 ? {
|
|
18467
|
+
structuredAssertions: {
|
|
18468
|
+
passed: assertionOutcome.assertionsPassed,
|
|
18469
|
+
failed: assertionOutcome.assertionsFailed,
|
|
18470
|
+
results: assertionOutcome.assertionResults
|
|
18471
|
+
}
|
|
18472
|
+
} : {};
|
|
18473
|
+
let updatedResult = updateResult(result.id, {
|
|
18474
|
+
status: assertionOutcome.status,
|
|
18475
|
+
reasoning: assertionOutcome.reasoning || undefined,
|
|
17922
18476
|
stepsCompleted: agentResult.stepsCompleted,
|
|
17923
18477
|
durationMs: Date.now() - new Date(result.createdAt).getTime(),
|
|
17924
18478
|
tokensUsed: agentResult.tokensUsed,
|
|
17925
18479
|
costCents: estimateCost(model, agentResult.tokensUsed),
|
|
17926
|
-
metadata: {
|
|
18480
|
+
metadata: {
|
|
18481
|
+
consoleLogs,
|
|
18482
|
+
...networkErrors.length > 0 ? networkMeta : {},
|
|
18483
|
+
...structuredAssertionMeta
|
|
18484
|
+
}
|
|
17927
18485
|
});
|
|
17928
|
-
if (
|
|
17929
|
-
const failureAnalysis = analyzeFailure(null,
|
|
18486
|
+
if (assertionOutcome.status === "failed" || assertionOutcome.status === "error") {
|
|
18487
|
+
const failureAnalysis = analyzeFailure(null, assertionOutcome.reasoning ?? null);
|
|
17930
18488
|
if (failureAnalysis) {
|
|
17931
18489
|
updatedResult = updateResult(result.id, { failureAnalysis });
|
|
17932
18490
|
}
|
|
17933
18491
|
}
|
|
17934
|
-
if (
|
|
18492
|
+
if (assertionOutcome.status === "passed") {
|
|
17935
18493
|
try {
|
|
17936
18494
|
updateScenarioPassedCache(scenario.id, options.url);
|
|
17937
18495
|
} catch {}
|
|
17938
18496
|
}
|
|
17939
|
-
const eventType =
|
|
18497
|
+
const eventType = assertionOutcome.status === "passed" ? "scenario:pass" : "scenario:fail";
|
|
17940
18498
|
emit({ type: eventType, scenarioId: scenario.id, scenarioName: scenario.name, resultId: result.id, runId });
|
|
17941
18499
|
return updatedResult;
|
|
17942
18500
|
} catch (error) {
|
|
@@ -17961,7 +18519,8 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
17961
18519
|
} finally {
|
|
17962
18520
|
if (harPath) {
|
|
17963
18521
|
try {
|
|
17964
|
-
|
|
18522
|
+
const existing = getResult(result.id);
|
|
18523
|
+
updateResult(result.id, { metadata: { ...existing?.metadata ?? {}, harPath } });
|
|
17965
18524
|
} catch {}
|
|
17966
18525
|
}
|
|
17967
18526
|
if (browser) {
|
|
@@ -18133,22 +18692,31 @@ async function runBatch(scenarios, options) {
|
|
|
18133
18692
|
}
|
|
18134
18693
|
return { run: finalRun, results };
|
|
18135
18694
|
}
|
|
18136
|
-
|
|
18137
|
-
|
|
18695
|
+
function findScenarioInList(scenarios, id) {
|
|
18696
|
+
return scenarios.find((scenario) => scenario.id === id || scenario.shortId === id || scenario.id.startsWith(id)) ?? null;
|
|
18697
|
+
}
|
|
18698
|
+
function resolveScenariosForRun(options) {
|
|
18138
18699
|
if (options.scenarioIds && options.scenarioIds.length > 0) {
|
|
18139
|
-
const
|
|
18140
|
-
|
|
18141
|
-
|
|
18142
|
-
|
|
18143
|
-
|
|
18700
|
+
const scoped = listScenarios({ projectId: options.projectId });
|
|
18701
|
+
const resolved = [];
|
|
18702
|
+
const seen = new Set;
|
|
18703
|
+
for (const id of options.scenarioIds) {
|
|
18704
|
+
const scenario = findScenarioInList(scoped, id) ?? getScenario(id);
|
|
18705
|
+
if (scenario && !seen.has(scenario.id)) {
|
|
18706
|
+
resolved.push(scenario);
|
|
18707
|
+
seen.add(scenario.id);
|
|
18708
|
+
}
|
|
18144
18709
|
}
|
|
18145
|
-
|
|
18146
|
-
scenarios = listScenarios({
|
|
18147
|
-
projectId: options.projectId,
|
|
18148
|
-
tags: options.tags,
|
|
18149
|
-
priority: options.priority
|
|
18150
|
-
});
|
|
18710
|
+
return resolved;
|
|
18151
18711
|
}
|
|
18712
|
+
return listScenarios({
|
|
18713
|
+
projectId: options.projectId,
|
|
18714
|
+
tags: options.tags,
|
|
18715
|
+
priority: options.priority
|
|
18716
|
+
});
|
|
18717
|
+
}
|
|
18718
|
+
async function runByFilter(options) {
|
|
18719
|
+
const scenarios = resolveScenariosForRun(options);
|
|
18152
18720
|
if (scenarios.length === 0) {
|
|
18153
18721
|
const config = loadConfig();
|
|
18154
18722
|
const model = resolveModel(options.model ?? config.defaultModel);
|
|
@@ -18161,17 +18729,7 @@ async function runByFilter(options) {
|
|
|
18161
18729
|
function startRunAsync(options) {
|
|
18162
18730
|
const config = loadConfig();
|
|
18163
18731
|
const model = resolveModel(options.model ?? config.defaultModel);
|
|
18164
|
-
|
|
18165
|
-
if (options.scenarioIds && options.scenarioIds.length > 0) {
|
|
18166
|
-
const all = listScenarios({ projectId: options.projectId });
|
|
18167
|
-
scenarios = all.filter((s) => options.scenarioIds.includes(s.id) || options.scenarioIds.includes(s.shortId));
|
|
18168
|
-
} else {
|
|
18169
|
-
scenarios = listScenarios({
|
|
18170
|
-
projectId: options.projectId,
|
|
18171
|
-
tags: options.tags,
|
|
18172
|
-
priority: options.priority
|
|
18173
|
-
});
|
|
18174
|
-
}
|
|
18732
|
+
const scenarios = resolveScenariosForRun(options);
|
|
18175
18733
|
if (!options.skipBudgetCheck) {
|
|
18176
18734
|
const cap = options.maxCostCents ?? config.defaultMaxCostCents;
|
|
18177
18735
|
if (cap !== undefined && cap > 0 && scenarios.length > 0) {
|
|
@@ -18275,6 +18833,7 @@ var init_runner = __esm(() => {
|
|
|
18275
18833
|
init_session_tracker();
|
|
18276
18834
|
init_webhooks();
|
|
18277
18835
|
init_failure_pipeline();
|
|
18836
|
+
init_assertions();
|
|
18278
18837
|
});
|
|
18279
18838
|
|
|
18280
18839
|
// src/lib/reporter.ts
|
|
@@ -19778,7 +20337,6 @@ var require_range = __commonJS((exports, module) => {
|
|
|
19778
20337
|
return this.range;
|
|
19779
20338
|
}
|
|
19780
20339
|
parseRange(range) {
|
|
19781
|
-
range = range.replace(BUILDSTRIPRE, "");
|
|
19782
20340
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
19783
20341
|
const memoKey = memoOpts + ":" + range;
|
|
19784
20342
|
const cached = cache.get(memoKey);
|
|
@@ -19860,14 +20418,12 @@ var require_range = __commonJS((exports, module) => {
|
|
|
19860
20418
|
var SemVer = require_semver();
|
|
19861
20419
|
var {
|
|
19862
20420
|
safeRe: re,
|
|
19863
|
-
src,
|
|
19864
20421
|
t,
|
|
19865
20422
|
comparatorTrimReplace,
|
|
19866
20423
|
tildeTrimReplace,
|
|
19867
20424
|
caretTrimReplace
|
|
19868
20425
|
} = require_re();
|
|
19869
20426
|
var { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require_constants();
|
|
19870
|
-
var BUILDSTRIPRE = new RegExp(src[t.BUILD], "g");
|
|
19871
20427
|
var isNullSet = (c) => c.value === "<0.0.0-0";
|
|
19872
20428
|
var isAny = (c) => c.value === "";
|
|
19873
20429
|
var isSatisfiable = (comparators, options) => {
|
|
@@ -25417,18 +25973,7 @@ function normalizeFilter(input) {
|
|
|
25417
25973
|
};
|
|
25418
25974
|
}
|
|
25419
25975
|
function normalizeExecution(input) {
|
|
25420
|
-
|
|
25421
|
-
if (target === "connector:e2b") {
|
|
25422
|
-
return {
|
|
25423
|
-
target,
|
|
25424
|
-
connector: input?.connector ?? "e2b",
|
|
25425
|
-
operation: input?.operation ?? "run",
|
|
25426
|
-
sandboxTemplate: input?.sandboxTemplate,
|
|
25427
|
-
timeoutMs: input?.timeoutMs,
|
|
25428
|
-
env: input?.env
|
|
25429
|
-
};
|
|
25430
|
-
}
|
|
25431
|
-
return { ...DEFAULT_EXECUTION, timeoutMs: input?.timeoutMs };
|
|
25976
|
+
return input ? workflowExecutionFromValue(input) : DEFAULT_EXECUTION;
|
|
25432
25977
|
}
|
|
25433
25978
|
function createTestingWorkflow(input) {
|
|
25434
25979
|
const db2 = getDatabase();
|
|
@@ -25792,12 +26337,28 @@ Rules:
|
|
|
25792
26337
|
];
|
|
25793
26338
|
const messages = [{ role: "user", content: contentParts }];
|
|
25794
26339
|
try {
|
|
25795
|
-
|
|
25796
|
-
|
|
25797
|
-
|
|
25798
|
-
|
|
25799
|
-
|
|
25800
|
-
|
|
26340
|
+
let text;
|
|
26341
|
+
const provider = detectProvider(model);
|
|
26342
|
+
if (provider !== "anthropic") {
|
|
26343
|
+
const compat = client;
|
|
26344
|
+
const response = await callOpenAICompatible({
|
|
26345
|
+
baseUrl: compat.baseUrl,
|
|
26346
|
+
apiKey: compat.apiKey,
|
|
26347
|
+
model,
|
|
26348
|
+
system: "You are a QA engineer.",
|
|
26349
|
+
messages: [{ role: "user", content: prompt }],
|
|
26350
|
+
tools: [],
|
|
26351
|
+
maxTokens: 2048
|
|
26352
|
+
});
|
|
26353
|
+
text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
26354
|
+
} else {
|
|
26355
|
+
const response = await anthropicClient.messages.create({
|
|
26356
|
+
model,
|
|
26357
|
+
max_tokens: 2048,
|
|
26358
|
+
messages
|
|
26359
|
+
});
|
|
26360
|
+
text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
26361
|
+
}
|
|
25801
26362
|
const match = text.match(/\[[\s\S]*\]/);
|
|
25802
26363
|
if (!match)
|
|
25803
26364
|
return [];
|
|
@@ -25825,7 +26386,7 @@ async function crawlAndGenerate(options) {
|
|
|
25825
26386
|
} = options;
|
|
25826
26387
|
const config = loadConfig();
|
|
25827
26388
|
const model = resolveModel(options.model ?? config.defaultModel ?? "thorough");
|
|
25828
|
-
const client =
|
|
26389
|
+
const client = createClientForModel(model, resolveProviderApiKeyForModel(model, options.apiKey, config.anthropicApiKey));
|
|
25829
26390
|
const rootOrigin = new URL(url).origin;
|
|
25830
26391
|
const visited = new Set;
|
|
25831
26392
|
const queue = [url];
|
|
@@ -25905,7 +26466,6 @@ var init_crawl_and_generate = __esm(() => {
|
|
|
25905
26466
|
init_scenarios();
|
|
25906
26467
|
init_ai_client();
|
|
25907
26468
|
init_config2();
|
|
25908
|
-
init_ai_client();
|
|
25909
26469
|
DEFAULT_SKIP_PATTERNS = [
|
|
25910
26470
|
"/logout",
|
|
25911
26471
|
"/sign-out",
|
|
@@ -26023,54 +26583,52 @@ import { promises as fsPromises } from "fs";
|
|
|
26023
26583
|
import { createHash as createHash2, createPrivateKey, createPublicKey, sign } from "crypto";
|
|
26024
26584
|
import { promises as fs2 } from "fs";
|
|
26025
26585
|
import { homedir as homedir22 } from "os";
|
|
26026
|
-
import { dirname as dirname32, join as
|
|
26586
|
+
import { dirname as dirname32, join as join52 } from "path";
|
|
26027
26587
|
import { exec } from "child_process";
|
|
26028
26588
|
import { promisify } from "util";
|
|
26029
|
-
import { readFileSync as
|
|
26589
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
26030
26590
|
import { webcrypto as crypto2 } from "crypto";
|
|
26031
|
-
import { existsSync as
|
|
26032
|
-
import { join as
|
|
26591
|
+
import { existsSync as existsSync42, writeFileSync as writeFileSync32, readFileSync as readFileSync22, mkdirSync as mkdirSync32 } from "fs";
|
|
26592
|
+
import { join as join42 } from "path";
|
|
26033
26593
|
import { Database as Database4 } from "bun:sqlite";
|
|
26034
26594
|
import { existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
|
|
26035
|
-
import { dirname as dirname4, join as
|
|
26036
|
-
import { existsSync as existsSync22, writeFileSync as
|
|
26595
|
+
import { dirname as dirname4, join as join19, resolve as resolve2 } from "path";
|
|
26596
|
+
import { existsSync as existsSync22, writeFileSync as writeFileSync7 } from "fs";
|
|
26037
26597
|
import { join as join22 } from "path";
|
|
26038
|
-
import { execFileSync } from "child_process";
|
|
26039
|
-
import {
|
|
26040
|
-
import { join as join32 } from "path";
|
|
26041
|
-
import { hostname } from "os";
|
|
26042
|
-
import { existsSync as existsSync42, readFileSync as readFileSync22, writeFileSync as writeFileSync32, mkdirSync as mkdirSync22 } from "fs";
|
|
26598
|
+
import { execSync as execSync3, execFileSync } from "child_process";
|
|
26599
|
+
import { existsSync as existsSync32, readFileSync as readFileSync7, writeFileSync as writeFileSync22, mkdirSync as mkdirSync22 } from "fs";
|
|
26043
26600
|
import { homedir as homedir11 } from "os";
|
|
26044
|
-
import { join as
|
|
26601
|
+
import { join as join32, dirname as dirname22 } from "path";
|
|
26602
|
+
import { hostname } from "os";
|
|
26045
26603
|
import { Buffer as Buffer2 } from "buffer";
|
|
26046
26604
|
import * as zlib from "zlib";
|
|
26047
26605
|
import { Readable } from "stream";
|
|
26048
26606
|
import { Writable } from "stream";
|
|
26049
26607
|
import { createHash as createHash22 } from "crypto";
|
|
26050
|
-
import { mkdirSync as mkdirSync4, statSync as statSync2, writeFileSync as
|
|
26051
|
-
import { dirname as dirname42, join as
|
|
26608
|
+
import { mkdirSync as mkdirSync4, statSync as statSync2, writeFileSync as writeFileSync42 } from "fs";
|
|
26609
|
+
import { dirname as dirname42, join as join62, relative as relative3 } from "path";
|
|
26052
26610
|
import { readdir, readFile as readFile2 } from "fs/promises";
|
|
26053
|
-
import { existsSync as
|
|
26054
|
-
import { basename as basename2, join as
|
|
26611
|
+
import { existsSync as existsSync62, readdirSync as readdirSync5, readFileSync as readFileSync42, statSync as statSync22 } from "fs";
|
|
26612
|
+
import { basename as basename2, join as join72, resolve as resolve22 } from "path";
|
|
26055
26613
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
26056
|
-
import { existsSync as
|
|
26057
|
-
import { dirname as dirname5, join as
|
|
26614
|
+
import { existsSync as existsSync72, readFileSync as readFileSync52, writeFileSync as writeFileSync52, mkdirSync as mkdirSync52 } from "fs";
|
|
26615
|
+
import { dirname as dirname5, join as join82 } from "path";
|
|
26058
26616
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
26059
|
-
import { existsSync as existsSync112 } from "fs";
|
|
26060
|
-
import { join as join122 } from "path";
|
|
26061
|
-
import { execFileSync as execFileSync3 } from "child_process";
|
|
26062
|
-
import { existsSync as existsSync92 } from "fs";
|
|
26063
|
-
import { homedir as homedir32, hostname as hostname2, platform as platform2, type } from "os";
|
|
26064
|
-
import { join as join102 } from "path";
|
|
26065
26617
|
import { existsSync as existsSync102 } from "fs";
|
|
26066
|
-
import { execSync as execSync3 } from "child_process";
|
|
26067
26618
|
import { join as join112 } from "path";
|
|
26619
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
26620
|
+
import { existsSync as existsSync82 } from "fs";
|
|
26621
|
+
import { homedir as homedir32, hostname as hostname2, platform as platform2, type } from "os";
|
|
26622
|
+
import { join as join92 } from "path";
|
|
26623
|
+
import { existsSync as existsSync92 } from "fs";
|
|
26068
26624
|
import { execSync as execSync22 } from "child_process";
|
|
26069
|
-
import {
|
|
26625
|
+
import { join as join102 } from "path";
|
|
26626
|
+
import { execSync as execSync32 } from "child_process";
|
|
26627
|
+
import { readFileSync as readFileSync62 } from "fs";
|
|
26070
26628
|
import { mkdirSync as mkdirSync62 } from "fs";
|
|
26071
|
-
import { dirname as dirname6, join as
|
|
26629
|
+
import { dirname as dirname6, join as join122 } from "path";
|
|
26072
26630
|
import { fileURLToPath } from "url";
|
|
26073
|
-
import { existsSync as
|
|
26631
|
+
import { existsSync as existsSync112 } from "fs";
|
|
26074
26632
|
function __accessProp3(key) {
|
|
26075
26633
|
return this[key];
|
|
26076
26634
|
}
|
|
@@ -26209,12 +26767,12 @@ function getDbPath2() {
|
|
|
26209
26767
|
return process.env["PROJECTS_DB_PATH"];
|
|
26210
26768
|
}
|
|
26211
26769
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
26212
|
-
return
|
|
26770
|
+
return join19(home, ".hasna", "projects", "projects.db");
|
|
26213
26771
|
}
|
|
26214
26772
|
function ensureDir2(filePath) {
|
|
26215
26773
|
if (filePath === ":memory:")
|
|
26216
26774
|
return;
|
|
26217
|
-
const dir = dirname4(
|
|
26775
|
+
const dir = dirname4(resolve2(filePath));
|
|
26218
26776
|
if (!existsSync16(dir)) {
|
|
26219
26777
|
mkdirSync13(dir, { recursive: true });
|
|
26220
26778
|
}
|
|
@@ -26247,25 +26805,14 @@ function uuid2() {
|
|
|
26247
26805
|
function isGitRepo(path) {
|
|
26248
26806
|
return existsSync22(join22(path, ".git"));
|
|
26249
26807
|
}
|
|
26250
|
-
function getCurrentBranch(path) {
|
|
26251
|
-
return execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
26252
|
-
cwd: path,
|
|
26253
|
-
stdio: "pipe",
|
|
26254
|
-
encoding: "utf-8",
|
|
26255
|
-
env: process.env
|
|
26256
|
-
}).trim();
|
|
26257
|
-
}
|
|
26258
|
-
function bootstrapPathsToStage(path) {
|
|
26259
|
-
return BOOTSTRAP_PATHS.filter((entry) => existsSync22(join22(path, entry)));
|
|
26260
|
-
}
|
|
26261
26808
|
function gitInit(project) {
|
|
26262
26809
|
const { path, name, id, slug } = project;
|
|
26263
26810
|
if (isGitRepo(path))
|
|
26264
26811
|
return;
|
|
26265
|
-
|
|
26812
|
+
execSync3("git init", { cwd: path, stdio: "pipe" });
|
|
26266
26813
|
const gitignorePath = join22(path, ".gitignore");
|
|
26267
26814
|
if (!existsSync22(gitignorePath)) {
|
|
26268
|
-
|
|
26815
|
+
writeFileSync7(gitignorePath, GITIGNORE_TEMPLATE, "utf-8");
|
|
26269
26816
|
}
|
|
26270
26817
|
const projectJson = {
|
|
26271
26818
|
id,
|
|
@@ -26274,18 +26821,26 @@ function gitInit(project) {
|
|
|
26274
26821
|
created_at: project.created_at,
|
|
26275
26822
|
integrations: project.integrations ?? {}
|
|
26276
26823
|
};
|
|
26277
|
-
|
|
26824
|
+
writeFileSync7(join22(path, ".project.json"), JSON.stringify(projectJson, null, 2) + `
|
|
26278
26825
|
`, "utf-8");
|
|
26279
|
-
|
|
26280
|
-
|
|
26281
|
-
return;
|
|
26282
|
-
execFileSync("git", ["add", ...staged], { cwd: path, stdio: "pipe", env: process.env });
|
|
26283
|
-
execFileSync("git", ["commit", "-m", `chore: init project ${name}`], {
|
|
26826
|
+
execSync3("git add .gitignore .project.json", { cwd: path, stdio: "pipe" });
|
|
26827
|
+
execSync3(`git commit -m "chore: init project ${name}"`, {
|
|
26284
26828
|
cwd: path,
|
|
26285
26829
|
stdio: "pipe",
|
|
26286
26830
|
env: { ...process.env, GIT_AUTHOR_NAME: "open-projects", GIT_COMMITTER_NAME: "open-projects" }
|
|
26287
26831
|
});
|
|
26288
26832
|
}
|
|
26833
|
+
function getConfig() {
|
|
26834
|
+
if (existsSync32(CONFIG_PATH3)) {
|
|
26835
|
+
try {
|
|
26836
|
+
const user = JSON.parse(readFileSync7(CONFIG_PATH3, "utf-8"));
|
|
26837
|
+
return { ...DEFAULTS, ...user };
|
|
26838
|
+
} catch {
|
|
26839
|
+
return { ...DEFAULTS };
|
|
26840
|
+
}
|
|
26841
|
+
}
|
|
26842
|
+
return { ...DEFAULTS };
|
|
26843
|
+
}
|
|
26289
26844
|
function rowToWorkdir(row) {
|
|
26290
26845
|
return {
|
|
26291
26846
|
...row,
|
|
@@ -26329,176 +26884,6 @@ function removeWorkdir(projectId, path, db2) {
|
|
|
26329
26884
|
const d = db2 || getDatabase2();
|
|
26330
26885
|
d.run("DELETE FROM project_workdirs WHERE project_id = ? AND path = ?", [projectId, path]);
|
|
26331
26886
|
}
|
|
26332
|
-
function markWorkdirGenerated(projectId, path, db2) {
|
|
26333
|
-
const d = db2 || getDatabase2();
|
|
26334
|
-
d.run("UPDATE project_workdirs SET claude_md_generated = 1, agents_md_generated = 1 WHERE project_id = ? AND path = ?", [projectId, path]);
|
|
26335
|
-
}
|
|
26336
|
-
function buildWorkdirList(workdirs, currentPath) {
|
|
26337
|
-
return workdirs.map((w) => {
|
|
26338
|
-
const isCurrent = w.path === currentPath;
|
|
26339
|
-
const primary = w.is_primary ? " (primary)" : "";
|
|
26340
|
-
const current = isCurrent ? " \u2190 you are here" : "";
|
|
26341
|
-
return `- \`${w.path}\` [${w.label}]${primary}${current} *(machine: ${w.machine_id})*`;
|
|
26342
|
-
}).join(`
|
|
26343
|
-
`);
|
|
26344
|
-
}
|
|
26345
|
-
function claudeMdContent(project, workdir, allWorkdirs) {
|
|
26346
|
-
const otherDirs = allWorkdirs.filter((w) => w.path !== workdir.path);
|
|
26347
|
-
const otherSection = otherDirs.length ? `
|
|
26348
|
-
## Other Working Directories
|
|
26349
|
-
${buildWorkdirList(otherDirs, workdir.path)}
|
|
26350
|
-
` : "";
|
|
26351
|
-
const integrations = Object.keys(project.integrations).length ? `
|
|
26352
|
-
## Integrations
|
|
26353
|
-
${Object.entries(project.integrations).filter(([, v]) => v).map(([k, v]) => `- **${k}:** \`${v}\``).join(`
|
|
26354
|
-
`)}
|
|
26355
|
-
` : "";
|
|
26356
|
-
const tags = project.tags.length ? `
|
|
26357
|
-
**Tags:** ${project.tags.join(", ")}` : "";
|
|
26358
|
-
return `# Project: ${project.name}
|
|
26359
|
-
|
|
26360
|
-
> ${project.description ?? `Working directory for project **${project.name}**`}
|
|
26361
|
-
${tags}
|
|
26362
|
-
|
|
26363
|
-
## Working Directory
|
|
26364
|
-
|
|
26365
|
-
You are working in the **${workdir.label}** directory for this project:
|
|
26366
|
-
|
|
26367
|
-
\`\`\`
|
|
26368
|
-
${workdir.path}
|
|
26369
|
-
\`\`\`
|
|
26370
|
-
|
|
26371
|
-
**Write all code to this directory.** Do not write to other project directories unless explicitly instructed.
|
|
26372
|
-
|
|
26373
|
-
## Project Metadata
|
|
26374
|
-
|
|
26375
|
-
| Field | Value |
|
|
26376
|
-
|-------|-------|
|
|
26377
|
-
| ID | \`${project.id}\` |
|
|
26378
|
-
| Slug | \`${project.slug}\` |
|
|
26379
|
-
| Label | \`${workdir.label}\` |
|
|
26380
|
-
| Machine | \`${workdir.machine_id}\` |
|
|
26381
|
-
| Status | ${project.status} |
|
|
26382
|
-
${project.git_remote ? `| Git Remote | ${project.git_remote} |` : ""}
|
|
26383
|
-
${project.s3_bucket ? `| S3 Bucket | \`${project.s3_bucket}\` |` : ""}
|
|
26384
|
-
${integrations}${otherSection}
|
|
26385
|
-
## All Working Directories
|
|
26386
|
-
|
|
26387
|
-
${buildWorkdirList(allWorkdirs, workdir.path)}
|
|
26388
|
-
|
|
26389
|
-
## Instructions for AI Agents
|
|
26390
|
-
|
|
26391
|
-
1. **Write code in \`${workdir.path}\`** \u2014 this is your working directory for this session.
|
|
26392
|
-
2. Use \`projects sync ${project.slug}\` to push changes to S3.
|
|
26393
|
-
3. Use \`projects git ${project.slug} <args>\` to run git commands.
|
|
26394
|
-
4. If you need to switch to a different workdir, call \`projects_open\` with the project ID.
|
|
26395
|
-
|
|
26396
|
-
---
|
|
26397
|
-
*Generated by open-projects. Regenerate: \`projects workdir generate ${project.slug}\`*
|
|
26398
|
-
`.trimStart();
|
|
26399
|
-
}
|
|
26400
|
-
function agentsMdContent(project, workdir, allWorkdirs) {
|
|
26401
|
-
const otherDirs = allWorkdirs.filter((w) => w.path !== workdir.path);
|
|
26402
|
-
return `---
|
|
26403
|
-
project_id: ${project.id}
|
|
26404
|
-
project_slug: ${project.slug}
|
|
26405
|
-
project_name: ${project.name}
|
|
26406
|
-
working_directory: ${workdir.path}
|
|
26407
|
-
label: ${workdir.label}
|
|
26408
|
-
machine_id: ${workdir.machine_id}
|
|
26409
|
-
is_primary: ${workdir.is_primary}
|
|
26410
|
-
---
|
|
26411
|
-
|
|
26412
|
-
# ${project.name} \u2014 Agent Instructions
|
|
26413
|
-
|
|
26414
|
-
## Scope
|
|
26415
|
-
|
|
26416
|
-
This agent session is scoped to the **${workdir.label}** working directory:
|
|
26417
|
-
|
|
26418
|
-
\`\`\`
|
|
26419
|
-
${workdir.path}
|
|
26420
|
-
\`\`\`
|
|
26421
|
-
|
|
26422
|
-
**Only write files inside this directory** unless the user explicitly asks you to work elsewhere.
|
|
26423
|
-
${otherDirs.length ? `
|
|
26424
|
-
## Other workdirs for this project
|
|
26425
|
-
|
|
26426
|
-
${otherDirs.map((w) => `- \`${w.path}\` [${w.label}] on ${w.machine_id}`).join(`
|
|
26427
|
-
`)}
|
|
26428
|
-
` : ""}
|
|
26429
|
-
## Quick Reference
|
|
26430
|
-
|
|
26431
|
-
\`\`\`bash
|
|
26432
|
-
# Open this project
|
|
26433
|
-
cd ${workdir.path}
|
|
26434
|
-
|
|
26435
|
-
# Sync to S3
|
|
26436
|
-
projects sync ${project.slug}
|
|
26437
|
-
|
|
26438
|
-
# Git operations
|
|
26439
|
-
projects git ${project.slug} status
|
|
26440
|
-
projects git ${project.slug} log --oneline -10
|
|
26441
|
-
\`\`\`
|
|
26442
|
-
${Object.keys(project.integrations).length ? `
|
|
26443
|
-
## Service IDs
|
|
26444
|
-
|
|
26445
|
-
${Object.entries(project.integrations).filter(([, v]) => v).map(([k, v]) => `- **${k}:** \`${v}\``).join(`
|
|
26446
|
-
`)}
|
|
26447
|
-
` : ""}
|
|
26448
|
-
---
|
|
26449
|
-
*Generated by open-projects ${new Date().toISOString().slice(0, 10)}*
|
|
26450
|
-
`.trimStart();
|
|
26451
|
-
}
|
|
26452
|
-
function generateForWorkdir(project, workdir, allWorkdirs, options = {}) {
|
|
26453
|
-
const claudeMd = claudeMdContent(project, workdir, allWorkdirs);
|
|
26454
|
-
const agentsMd = agentsMdContent(project, workdir, allWorkdirs);
|
|
26455
|
-
const claudePath = join32(workdir.path, "CLAUDE.md");
|
|
26456
|
-
const agentsPath = join32(workdir.path, "AGENTS.md");
|
|
26457
|
-
let written = false;
|
|
26458
|
-
if (!options.dryRun && existsSync32(workdir.path)) {
|
|
26459
|
-
if (existsSync32(claudePath) && !options.force) {
|
|
26460
|
-
const existing = readFileSync8(claudePath, "utf-8");
|
|
26461
|
-
if (existing.includes("Generated by open-projects")) {
|
|
26462
|
-
writeFileSync22(claudePath, claudeMd, "utf-8");
|
|
26463
|
-
} else {
|
|
26464
|
-
const separator = `
|
|
26465
|
-
|
|
26466
|
-
---
|
|
26467
|
-
|
|
26468
|
-
<!-- open-projects -->
|
|
26469
|
-
`;
|
|
26470
|
-
const marker = "<!-- open-projects -->";
|
|
26471
|
-
if (existing.includes(marker)) {
|
|
26472
|
-
const before = existing.slice(0, existing.indexOf(marker) - separator.length + 1);
|
|
26473
|
-
writeFileSync22(claudePath, before + separator + claudeMd, "utf-8");
|
|
26474
|
-
} else {
|
|
26475
|
-
writeFileSync22(claudePath, existing.trimEnd() + separator + claudeMd, "utf-8");
|
|
26476
|
-
}
|
|
26477
|
-
}
|
|
26478
|
-
} else {
|
|
26479
|
-
writeFileSync22(claudePath, claudeMd, "utf-8");
|
|
26480
|
-
}
|
|
26481
|
-
writeFileSync22(agentsPath, agentsMd, "utf-8");
|
|
26482
|
-
markWorkdirGenerated(project.id, workdir.path, options.db);
|
|
26483
|
-
written = true;
|
|
26484
|
-
}
|
|
26485
|
-
return { path: workdir.path, claude_md: claudeMd, agents_md: agentsMd, written };
|
|
26486
|
-
}
|
|
26487
|
-
function generateAllWorkdirs(project, options = {}) {
|
|
26488
|
-
const workdirs = listWorkdirs(project.id, options.db);
|
|
26489
|
-
return workdirs.map((w) => generateForWorkdir(project, w, workdirs, options));
|
|
26490
|
-
}
|
|
26491
|
-
function getConfig() {
|
|
26492
|
-
if (existsSync42(CONFIG_PATH3)) {
|
|
26493
|
-
try {
|
|
26494
|
-
const user = JSON.parse(readFileSync22(CONFIG_PATH3, "utf-8"));
|
|
26495
|
-
return { ...DEFAULTS, ...user };
|
|
26496
|
-
} catch {
|
|
26497
|
-
return { ...DEFAULTS };
|
|
26498
|
-
}
|
|
26499
|
-
}
|
|
26500
|
-
return { ...DEFAULTS };
|
|
26501
|
-
}
|
|
26502
26887
|
function generateProjectId() {
|
|
26503
26888
|
return `prj_${nanoid()}`;
|
|
26504
26889
|
}
|
|
@@ -26506,10 +26891,12 @@ function slugify2(name) {
|
|
|
26506
26891
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
26507
26892
|
}
|
|
26508
26893
|
function scaffoldProject(path) {
|
|
26894
|
+
if (existsSync42(path))
|
|
26895
|
+
return;
|
|
26509
26896
|
mkdirSync32(path, { recursive: true });
|
|
26510
26897
|
const config = getConfig();
|
|
26511
26898
|
for (const dir of config.scaffold_dirs || ["data", "scripts", "assets", "docs"]) {
|
|
26512
|
-
mkdirSync32(
|
|
26899
|
+
mkdirSync32(join42(path, dir), { recursive: true });
|
|
26513
26900
|
}
|
|
26514
26901
|
}
|
|
26515
26902
|
function ensureUniqueSlug(base, db2, excludeId) {
|
|
@@ -26560,9 +26947,6 @@ function createProject2(input, db2) {
|
|
|
26560
26947
|
try {
|
|
26561
26948
|
addWorkdir({ project_id: id, path: input.path, label: "main", is_primary: true }, d);
|
|
26562
26949
|
} catch {}
|
|
26563
|
-
try {
|
|
26564
|
-
generateAllWorkdirs(project, { db: d });
|
|
26565
|
-
} catch {}
|
|
26566
26950
|
const shouldGitInit = input.git_init !== false;
|
|
26567
26951
|
if (shouldGitInit) {
|
|
26568
26952
|
try {
|
|
@@ -26668,10 +27052,10 @@ function setIntegrations(id, integrations, db2) {
|
|
|
26668
27052
|
id
|
|
26669
27053
|
]);
|
|
26670
27054
|
try {
|
|
26671
|
-
const jsonPath =
|
|
26672
|
-
if (
|
|
26673
|
-
const existing = JSON.parse(
|
|
26674
|
-
|
|
27055
|
+
const jsonPath = join42(project.path, ".project.json");
|
|
27056
|
+
if (existsSync42(jsonPath)) {
|
|
27057
|
+
const existing = JSON.parse(readFileSync22(jsonPath, "utf-8"));
|
|
27058
|
+
writeFileSync32(jsonPath, JSON.stringify({ ...existing, integrations: merged }, null, 2) + `
|
|
26675
27059
|
`, "utf-8");
|
|
26676
27060
|
}
|
|
26677
27061
|
} catch {}
|
|
@@ -27745,7 +28129,7 @@ async function collectLocalFiles(rootPath) {
|
|
|
27745
28129
|
async function walk(dir) {
|
|
27746
28130
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
27747
28131
|
for (const entry of entries) {
|
|
27748
|
-
const fullPath =
|
|
28132
|
+
const fullPath = join62(dir, entry.name);
|
|
27749
28133
|
if (entry.isDirectory()) {
|
|
27750
28134
|
await walk(fullPath);
|
|
27751
28135
|
} else if (entry.isFile()) {
|
|
@@ -27817,7 +28201,7 @@ async function syncProject(project, options = {}) {
|
|
|
27817
28201
|
continue;
|
|
27818
28202
|
}
|
|
27819
28203
|
try {
|
|
27820
|
-
const data = await readFile2(
|
|
28204
|
+
const data = await readFile2(join62(project.path, relPath));
|
|
27821
28205
|
await client.send(new PutObjectCommand({
|
|
27822
28206
|
Bucket: bucket,
|
|
27823
28207
|
Key: s3Key,
|
|
@@ -27855,9 +28239,9 @@ async function syncProject(project, options = {}) {
|
|
|
27855
28239
|
chunks.push(chunk);
|
|
27856
28240
|
}
|
|
27857
28241
|
const data = Buffer.concat(chunks);
|
|
27858
|
-
const localPath =
|
|
28242
|
+
const localPath = join62(project.path, relPath);
|
|
27859
28243
|
mkdirSync4(dirname42(localPath), { recursive: true });
|
|
27860
|
-
|
|
28244
|
+
writeFileSync42(localPath, data);
|
|
27861
28245
|
log(`pull: ${relPath} (${data.length}B)`);
|
|
27862
28246
|
result.pulled++;
|
|
27863
28247
|
result.bytes += data.length;
|
|
@@ -27878,18 +28262,18 @@ async function syncProject(project, options = {}) {
|
|
|
27878
28262
|
return result;
|
|
27879
28263
|
}
|
|
27880
28264
|
function inferProjectName(projectPath) {
|
|
27881
|
-
const pkgPath =
|
|
27882
|
-
if (
|
|
28265
|
+
const pkgPath = join72(projectPath, "package.json");
|
|
28266
|
+
if (existsSync62(pkgPath)) {
|
|
27883
28267
|
try {
|
|
27884
|
-
const pkg = JSON.parse(
|
|
28268
|
+
const pkg = JSON.parse(readFileSync42(pkgPath, "utf-8"));
|
|
27885
28269
|
if (pkg.name)
|
|
27886
28270
|
return pkg.name.replace(/^@[^/]+\//, "");
|
|
27887
28271
|
} catch {}
|
|
27888
28272
|
}
|
|
27889
|
-
const projPath =
|
|
27890
|
-
if (
|
|
28273
|
+
const projPath = join72(projectPath, ".project.json");
|
|
28274
|
+
if (existsSync62(projPath)) {
|
|
27891
28275
|
try {
|
|
27892
|
-
const p2 = JSON.parse(
|
|
28276
|
+
const p2 = JSON.parse(readFileSync42(projPath, "utf-8"));
|
|
27893
28277
|
if (p2.name)
|
|
27894
28278
|
return p2.name;
|
|
27895
28279
|
} catch {}
|
|
@@ -27897,11 +28281,11 @@ function inferProjectName(projectPath) {
|
|
|
27897
28281
|
return basename2(projectPath);
|
|
27898
28282
|
}
|
|
27899
28283
|
function inferGitRemote(projectPath) {
|
|
27900
|
-
const gitConfigPath =
|
|
27901
|
-
if (!
|
|
28284
|
+
const gitConfigPath = join72(projectPath, ".git", "config");
|
|
28285
|
+
if (!existsSync62(gitConfigPath))
|
|
27902
28286
|
return;
|
|
27903
28287
|
try {
|
|
27904
|
-
const config =
|
|
28288
|
+
const config = readFileSync42(gitConfigPath, "utf-8");
|
|
27905
28289
|
const match = config.match(/\[remote "origin"\][\s\S]*?url\s*=\s*(.+)/);
|
|
27906
28290
|
return match?.[1]?.trim();
|
|
27907
28291
|
} catch {
|
|
@@ -27911,7 +28295,7 @@ function inferGitRemote(projectPath) {
|
|
|
27911
28295
|
async function importProject(projectPath, options = {}) {
|
|
27912
28296
|
const absPath = resolve22(projectPath);
|
|
27913
28297
|
const log = options.onProgress ?? (() => {});
|
|
27914
|
-
if (!
|
|
28298
|
+
if (!existsSync62(absPath)) {
|
|
27915
28299
|
return { error: `Path does not exist: ${absPath}` };
|
|
27916
28300
|
}
|
|
27917
28301
|
const stat = statSync22(absPath);
|
|
@@ -27946,7 +28330,7 @@ async function importBulk(dirPath, options = {}) {
|
|
|
27946
28330
|
const absDir = resolve22(dirPath);
|
|
27947
28331
|
const result = { imported: [], skipped: [], errors: [] };
|
|
27948
28332
|
const log = options.onProgress ?? (() => {});
|
|
27949
|
-
if (!
|
|
28333
|
+
if (!existsSync62(absDir)) {
|
|
27950
28334
|
result.errors.push({ path: absDir, error: "Directory does not exist" });
|
|
27951
28335
|
return result;
|
|
27952
28336
|
}
|
|
@@ -27954,7 +28338,7 @@ async function importBulk(dirPath, options = {}) {
|
|
|
27954
28338
|
const dirs = entries.filter((e2) => e2.isDirectory() && !e2.name.startsWith("."));
|
|
27955
28339
|
log(`Found ${dirs.length} subdirectories in ${absDir}`);
|
|
27956
28340
|
for (const entry of dirs) {
|
|
27957
|
-
const subPath =
|
|
28341
|
+
const subPath = join72(absDir, entry.name);
|
|
27958
28342
|
const res = await importProject(subPath, options);
|
|
27959
28343
|
if (res.project) {
|
|
27960
28344
|
result.imported.push(res.project);
|
|
@@ -27989,8 +28373,7 @@ function publishProject(name, path, options = {}) {
|
|
|
27989
28373
|
} else {
|
|
27990
28374
|
execFileSync2("git", ["remote", "add", "origin", remote], { cwd: path, stdio: "pipe", env: process.env });
|
|
27991
28375
|
}
|
|
27992
|
-
|
|
27993
|
-
execFileSync2("git", ["push", "-u", "origin", branch, "--quiet"], { cwd: path, stdio: "pipe", env: process.env });
|
|
28376
|
+
execFileSync2("git", ["push", "-u", "origin", "main", "--quiet"], { cwd: path, stdio: "pipe", env: process.env });
|
|
27994
28377
|
pushed = true;
|
|
27995
28378
|
} catch {}
|
|
27996
28379
|
}
|
|
@@ -28016,14 +28399,14 @@ function getGitHubUrl(path) {
|
|
|
28016
28399
|
}
|
|
28017
28400
|
}
|
|
28018
28401
|
function getScheduleConfig() {
|
|
28019
|
-
if (!
|
|
28402
|
+
if (!existsSync72(CONFIG_PATH22)) {
|
|
28020
28403
|
return { enabled: false, interval: "daily", direction: "both" };
|
|
28021
28404
|
}
|
|
28022
|
-
return JSON.parse(
|
|
28405
|
+
return JSON.parse(readFileSync52(CONFIG_PATH22, "utf-8"));
|
|
28023
28406
|
}
|
|
28024
28407
|
function saveScheduleConfig(config) {
|
|
28025
28408
|
mkdirSync52(dirname5(CONFIG_PATH22), { recursive: true });
|
|
28026
|
-
|
|
28409
|
+
writeFileSync52(CONFIG_PATH22, JSON.stringify(config, null, 2) + `
|
|
28027
28410
|
`, "utf-8");
|
|
28028
28411
|
}
|
|
28029
28412
|
async function syncAll(direction = "both", onProgress) {
|
|
@@ -28053,7 +28436,7 @@ async function syncAll(direction = "both", onProgress) {
|
|
|
28053
28436
|
function getMachineProfile() {
|
|
28054
28437
|
const host = (process.env["HOSTNAME"] || hostname2()).split(".")[0] || hostname2();
|
|
28055
28438
|
const currentPlatform = platform2();
|
|
28056
|
-
const workspaceRoot = currentPlatform === "darwin" ?
|
|
28439
|
+
const workspaceRoot = currentPlatform === "darwin" ? join92(homedir32(), "Workspace") : join92(homedir32(), "workspace");
|
|
28057
28440
|
return {
|
|
28058
28441
|
hostname: host,
|
|
28059
28442
|
platform: currentPlatform,
|
|
@@ -28080,7 +28463,7 @@ function commandAvailability(command, versionArgs = ["--version"]) {
|
|
|
28080
28463
|
return { command, available: true, path: commandPath, version };
|
|
28081
28464
|
}
|
|
28082
28465
|
function pathExists(path) {
|
|
28083
|
-
return
|
|
28466
|
+
return existsSync82(path);
|
|
28084
28467
|
}
|
|
28085
28468
|
function classifyMachine(host, currentPlatform) {
|
|
28086
28469
|
if (host === "apple01")
|
|
@@ -28094,10 +28477,10 @@ function classifyMachine(host, currentPlatform) {
|
|
|
28094
28477
|
return "unknown";
|
|
28095
28478
|
}
|
|
28096
28479
|
function gitStatus(path) {
|
|
28097
|
-
if (!
|
|
28480
|
+
if (!existsSync92(join102(path, ".git")))
|
|
28098
28481
|
return "not a repo";
|
|
28099
28482
|
try {
|
|
28100
|
-
const out =
|
|
28483
|
+
const out = execSync22("git status --porcelain", { cwd: path, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
28101
28484
|
if (!out)
|
|
28102
28485
|
return "clean";
|
|
28103
28486
|
const n2 = out.split(`
|
|
@@ -28108,17 +28491,17 @@ function gitStatus(path) {
|
|
|
28108
28491
|
}
|
|
28109
28492
|
}
|
|
28110
28493
|
function dirSize(path) {
|
|
28111
|
-
if (!
|
|
28494
|
+
if (!existsSync92(path))
|
|
28112
28495
|
return 0;
|
|
28113
28496
|
try {
|
|
28114
|
-
const out =
|
|
28497
|
+
const out = execSync22(`du -sb -- "${path}" 2>/dev/null || du -sk -- "${path}" 2>/dev/null`, { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
28115
28498
|
return parseInt(out.split("\t")[0] ?? "0", 10);
|
|
28116
28499
|
} catch {
|
|
28117
28500
|
return 0;
|
|
28118
28501
|
}
|
|
28119
28502
|
}
|
|
28120
28503
|
function getProjectStatus(project) {
|
|
28121
|
-
const pathExists2 =
|
|
28504
|
+
const pathExists2 = existsSync92(project.path);
|
|
28122
28505
|
const workdirs = listWorkdirs(project.id);
|
|
28123
28506
|
const lastSync = getDatabase2().query("SELECT completed_at FROM sync_log WHERE project_id = ? AND status = 'completed' ORDER BY completed_at DESC LIMIT 1").get(project.id)?.completed_at ?? null;
|
|
28124
28507
|
return {
|
|
@@ -28131,21 +28514,18 @@ function getProjectStatus(project) {
|
|
|
28131
28514
|
};
|
|
28132
28515
|
}
|
|
28133
28516
|
function run(cmd) {
|
|
28134
|
-
return
|
|
28517
|
+
return execSync32(cmd, { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
28135
28518
|
}
|
|
28136
28519
|
function getTmuxSessionName(project) {
|
|
28137
|
-
|
|
28520
|
+
const raw = project.slug || project.name;
|
|
28521
|
+
if (project.path?.includes("opensourcedev")) {
|
|
28522
|
+
const normalized = raw.replace(/^proj-/, "");
|
|
28523
|
+
return normalized.startsWith("open-") ? normalized : `open-${normalized}`;
|
|
28524
|
+
}
|
|
28525
|
+
return raw;
|
|
28138
28526
|
}
|
|
28139
28527
|
function listSessions2() {
|
|
28140
|
-
|
|
28141
|
-
try {
|
|
28142
|
-
output = run("tmux list-sessions -F '#{session_name}:#{session_group}:#{session_windows}:#{session_attached}'");
|
|
28143
|
-
} catch (err) {
|
|
28144
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
28145
|
-
if (message.includes("no server running"))
|
|
28146
|
-
return [];
|
|
28147
|
-
throw err;
|
|
28148
|
-
}
|
|
28528
|
+
const output = run("tmux list-sessions -F '#{session_name}:#{session_group}:#{session_windows}:#{session_attached}'");
|
|
28149
28529
|
return output.split(`
|
|
28150
28530
|
`).filter(Boolean).map((line) => {
|
|
28151
28531
|
const [name, group, windows, attached] = line.split(":");
|
|
@@ -28253,7 +28633,7 @@ function getProjectLocations(project) {
|
|
|
28253
28633
|
const currentMachine = getMachineId();
|
|
28254
28634
|
return listWorkdirs(project.id).map((workdir) => ({
|
|
28255
28635
|
...workdir,
|
|
28256
|
-
exists:
|
|
28636
|
+
exists: existsSync102(workdir.path),
|
|
28257
28637
|
currentMachine: workdir.machine_id === currentMachine,
|
|
28258
28638
|
recommended: workdir.is_primary || workdir.path === project.path
|
|
28259
28639
|
}));
|
|
@@ -28290,7 +28670,7 @@ function buildProjectContext(project) {
|
|
|
28290
28670
|
};
|
|
28291
28671
|
}
|
|
28292
28672
|
function getGitContext(path) {
|
|
28293
|
-
if (!
|
|
28673
|
+
if (!existsSync102(join112(path, ".git"))) {
|
|
28294
28674
|
return { isRepo: false, branch: null, dirtyCount: null, remote: null };
|
|
28295
28675
|
}
|
|
28296
28676
|
return {
|
|
@@ -28333,7 +28713,7 @@ function setupMachineReport(options = {}) {
|
|
|
28333
28713
|
const dryRun = options.dryRun !== false;
|
|
28334
28714
|
const checks = [];
|
|
28335
28715
|
const dbDir = dirname6(getDbPath2());
|
|
28336
|
-
const cloudConfig =
|
|
28716
|
+
const cloudConfig = join122(process.env["HOME"] || "~", ".hasna", "cloud", "config.json");
|
|
28337
28717
|
checks.push(pathCheck("PROJECTS_DATA_DIR", "projects data dir", dbDir, options));
|
|
28338
28718
|
checks.push(pathCheck("WORKSPACE_ROOT", "workspace root", machine.workspaceRoot, options));
|
|
28339
28719
|
checks.push(commandCheck("bun", ["--version"], "Bun runtime"));
|
|
@@ -28394,8 +28774,8 @@ function commandCheck(command, versionArgs, label, missingStatus = "error") {
|
|
|
28394
28774
|
}
|
|
28395
28775
|
function packageVersion() {
|
|
28396
28776
|
try {
|
|
28397
|
-
const pkgPath =
|
|
28398
|
-
return JSON.parse(
|
|
28777
|
+
const pkgPath = join122(dirname6(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
28778
|
+
return JSON.parse(readFileSync62(pkgPath, "utf-8")).version || "0.0.0";
|
|
28399
28779
|
} catch {
|
|
28400
28780
|
return "0.0.0";
|
|
28401
28781
|
}
|
|
@@ -28409,7 +28789,7 @@ function findStaleIssues(project) {
|
|
|
28409
28789
|
const issues = [];
|
|
28410
28790
|
const currentMachine = getMachineId();
|
|
28411
28791
|
for (const p2 of projects) {
|
|
28412
|
-
if (p2.status === "active" && !
|
|
28792
|
+
if (p2.status === "active" && !existsSync112(p2.path)) {
|
|
28413
28793
|
issues.push({
|
|
28414
28794
|
code: "PROJECT_PATH_MISSING",
|
|
28415
28795
|
severity: "error",
|
|
@@ -28420,7 +28800,7 @@ function findStaleIssues(project) {
|
|
|
28420
28800
|
});
|
|
28421
28801
|
}
|
|
28422
28802
|
for (const workdir of listWorkdirs(p2.id)) {
|
|
28423
|
-
if (workdir.machine_id === currentMachine && !
|
|
28803
|
+
if (workdir.machine_id === currentMachine && !existsSync112(workdir.path)) {
|
|
28424
28804
|
issues.push({
|
|
28425
28805
|
code: "WORKDIR_PATH_MISSING",
|
|
28426
28806
|
severity: "warn",
|
|
@@ -29362,7 +29742,7 @@ Reference: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.ht
|
|
|
29362
29742
|
}
|
|
29363
29743
|
const credentials = await fromWebToken({
|
|
29364
29744
|
...init,
|
|
29365
|
-
webIdentityToken: import_shared_ini_file_loader10.externalDataInterceptor?.getTokenRecord?.()[webIdentityTokenFile] ??
|
|
29745
|
+
webIdentityToken: import_shared_ini_file_loader10.externalDataInterceptor?.getTokenRecord?.()[webIdentityTokenFile] ?? readFileSync32(webIdentityTokenFile, { encoding: "ascii" }),
|
|
29366
29746
|
roleArn,
|
|
29367
29747
|
roleSessionName
|
|
29368
29748
|
})(awsIdentityProperties);
|
|
@@ -29449,7 +29829,7 @@ coverage/
|
|
|
29449
29829
|
# Cache
|
|
29450
29830
|
.cache/
|
|
29451
29831
|
.turbo/
|
|
29452
|
-
`,
|
|
29832
|
+
`, CONFIG_PATH3, DEFAULTS, nanoid, import_protocol_http, addExpectContinueMiddlewareOptions, getAddExpectContinuePlugin = (options) => ({
|
|
29453
29833
|
applyToStack: (clientStack) => {
|
|
29454
29834
|
clientStack.add(addExpectContinueMiddleware(options), addExpectContinueMiddlewareOptions);
|
|
29455
29835
|
}
|
|
@@ -42528,11 +42908,11 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
42528
42908
|
var numberSelector = (obj, key, type2) => {
|
|
42529
42909
|
if (!(key in obj))
|
|
42530
42910
|
return;
|
|
42531
|
-
const
|
|
42532
|
-
if (Number.isNaN(
|
|
42911
|
+
const numberValue2 = parseInt(obj[key], 10);
|
|
42912
|
+
if (Number.isNaN(numberValue2)) {
|
|
42533
42913
|
throw new TypeError(`Cannot load ${type2} '${key}'. Expected number, got '${obj[key]}'.`);
|
|
42534
42914
|
}
|
|
42535
|
-
return
|
|
42915
|
+
return numberValue2;
|
|
42536
42916
|
};
|
|
42537
42917
|
exports.SelectorType = undefined;
|
|
42538
42918
|
(function(SelectorType2) {
|
|
@@ -47260,7 +47640,7 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
47260
47640
|
};
|
|
47261
47641
|
});
|
|
47262
47642
|
require_dist_cjs41 = __commonJS3((exports) => {
|
|
47263
|
-
var __dirname2 = "/
|
|
47643
|
+
var __dirname2 = "/home/hasna/workspace/hasna/opensource/open-projects/node_modules/@aws-sdk/util-user-agent-node/dist-cjs";
|
|
47264
47644
|
var node_os = __require3("os");
|
|
47265
47645
|
var node_process = __require3("process");
|
|
47266
47646
|
var utilConfigProvider = require_dist_cjs28();
|
|
@@ -50930,10 +51310,10 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
50930
51310
|
await fs2.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
|
|
50931
51311
|
}
|
|
50932
51312
|
getTokenFilePath() {
|
|
50933
|
-
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ??
|
|
51313
|
+
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join52(homedir22(), ".aws", "login", "cache");
|
|
50934
51314
|
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
50935
51315
|
const loginSessionSha256 = createHash2("sha256").update(loginSessionBytes).digest("hex");
|
|
50936
|
-
return
|
|
51316
|
+
return join52(directory, `${loginSessionSha256}.json`);
|
|
50937
51317
|
}
|
|
50938
51318
|
derToRawSignature(derSignature) {
|
|
50939
51319
|
let offset = 2;
|
|
@@ -51234,18 +51614,7 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
51234
51614
|
INSERT OR IGNORE INTO _migrations (id) VALUES (4);
|
|
51235
51615
|
`
|
|
51236
51616
|
];
|
|
51237
|
-
|
|
51238
|
-
".gitignore",
|
|
51239
|
-
".project.json",
|
|
51240
|
-
"CLAUDE.md",
|
|
51241
|
-
"AGENTS.md",
|
|
51242
|
-
"README.md",
|
|
51243
|
-
"docs",
|
|
51244
|
-
"data",
|
|
51245
|
-
"scripts",
|
|
51246
|
-
"assets"
|
|
51247
|
-
];
|
|
51248
|
-
CONFIG_PATH3 = join42(homedir11(), ".hasna", "projects", "config.json");
|
|
51617
|
+
CONFIG_PATH3 = join32(homedir11(), ".hasna", "projects", "config.json");
|
|
51249
51618
|
DEFAULTS = {
|
|
51250
51619
|
default_path: process.cwd(),
|
|
51251
51620
|
default_github_org: "hasnaxyz",
|
|
@@ -57031,7 +57400,7 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
57031
57400
|
}).s("AmazonS3", "PutObject", {}).n("S3Client", "PutObjectCommand").sc(PutObject$).build() {
|
|
57032
57401
|
};
|
|
57033
57402
|
MAX_FILE_SIZE = 100 * 1024 * 1024;
|
|
57034
|
-
CONFIG_PATH22 =
|
|
57403
|
+
CONFIG_PATH22 = join82(process.env["HOME"] || "~", ".hasna", "projects", "scheduler.json");
|
|
57035
57404
|
SPARK_MACHINES = new Set(["spark01", "spark02"]);
|
|
57036
57405
|
});
|
|
57037
57406
|
|
|
@@ -57289,7 +57658,7 @@ __export(exports_openapi_import, {
|
|
|
57289
57658
|
importFromOpenAPI: () => importFromOpenAPI,
|
|
57290
57659
|
importApiChecksFromOpenAPI: () => importApiChecksFromOpenAPI
|
|
57291
57660
|
});
|
|
57292
|
-
import { readFileSync as
|
|
57661
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
57293
57662
|
function parseSpec(content) {
|
|
57294
57663
|
try {
|
|
57295
57664
|
return JSON.parse(content);
|
|
@@ -57318,7 +57687,7 @@ function parseOpenAPISpec(filePathOrUrl) {
|
|
|
57318
57687
|
if (filePathOrUrl.startsWith("http")) {
|
|
57319
57688
|
throw new Error("URL fetching not supported yet. Download the spec file first.");
|
|
57320
57689
|
}
|
|
57321
|
-
content =
|
|
57690
|
+
content = readFileSync8(filePathOrUrl, "utf-8");
|
|
57322
57691
|
const spec = parseSpec(content);
|
|
57323
57692
|
const isOpenAPI3 = !!spec.openapi;
|
|
57324
57693
|
const isSwagger2 = !!spec.swagger;
|
|
@@ -57381,7 +57750,7 @@ function parseOpenAPISpecAsChecks(filePathOrUrl) {
|
|
|
57381
57750
|
if (filePathOrUrl.startsWith("http")) {
|
|
57382
57751
|
throw new Error("URL fetching not supported yet. Download the spec file first.");
|
|
57383
57752
|
}
|
|
57384
|
-
content =
|
|
57753
|
+
content = readFileSync8(filePathOrUrl, "utf-8");
|
|
57385
57754
|
const spec = parseSpec(content);
|
|
57386
57755
|
if (!spec.openapi && !spec.swagger) {
|
|
57387
57756
|
throw new Error("Not a valid OpenAPI 3.x or Swagger 2.0 spec");
|
|
@@ -57485,12 +57854,11 @@ APP STRUCTURE:
|
|
|
57485
57854
|
${summary}`;
|
|
57486
57855
|
let rawText = "";
|
|
57487
57856
|
let tokensUsed = 0;
|
|
57488
|
-
if (provider
|
|
57489
|
-
const
|
|
57490
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
57857
|
+
if (provider !== "anthropic") {
|
|
57858
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
57491
57859
|
const resp = await callOpenAICompatible({
|
|
57492
|
-
baseUrl,
|
|
57493
|
-
apiKey,
|
|
57860
|
+
baseUrl: compat.baseUrl,
|
|
57861
|
+
apiKey: compat.apiKey,
|
|
57494
57862
|
model,
|
|
57495
57863
|
system: GENERATOR_SYSTEM,
|
|
57496
57864
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -57721,7 +58089,7 @@ async function recordSession(url, options) {
|
|
|
57721
58089
|
await Promise.race([
|
|
57722
58090
|
page.waitForEvent("close").catch(() => {}),
|
|
57723
58091
|
context.waitForEvent("close").catch(() => {}),
|
|
57724
|
-
new Promise((
|
|
58092
|
+
new Promise((resolve3) => setTimeout(resolve3, timeout))
|
|
57725
58093
|
]);
|
|
57726
58094
|
clearInterval(pollInterval);
|
|
57727
58095
|
try {
|
|
@@ -74582,34 +74950,27 @@ var init_v3 = __esm(() => {
|
|
|
74582
74950
|
|
|
74583
74951
|
// node_modules/@ai-sdk/provider-utils/node_modules/eventsource-parser/dist/index.js
|
|
74584
74952
|
function noop(_arg) {}
|
|
74585
|
-
function createParser(
|
|
74586
|
-
if (typeof
|
|
74587
|
-
throw new TypeError("`
|
|
74588
|
-
const { onEvent = noop, onError = noop, onRetry = noop, onComment
|
|
74589
|
-
let
|
|
74953
|
+
function createParser(callbacks) {
|
|
74954
|
+
if (typeof callbacks == "function")
|
|
74955
|
+
throw new TypeError("`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?");
|
|
74956
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks, pendingFragments = [];
|
|
74957
|
+
let isFirstChunk = true, id, data = "", dataLines = 0, eventType;
|
|
74590
74958
|
function feed(chunk) {
|
|
74591
|
-
if (terminated)
|
|
74592
|
-
throw new Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");
|
|
74593
74959
|
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
74594
74960
|
const trailing2 = processLines(chunk);
|
|
74595
|
-
trailing2 !== "" &&
|
|
74961
|
+
trailing2 !== "" && pendingFragments.push(trailing2);
|
|
74596
74962
|
return;
|
|
74597
74963
|
}
|
|
74598
74964
|
if (chunk.indexOf(`
|
|
74599
74965
|
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
74600
|
-
pendingFragments.push(chunk)
|
|
74966
|
+
pendingFragments.push(chunk);
|
|
74601
74967
|
return;
|
|
74602
74968
|
}
|
|
74603
74969
|
pendingFragments.push(chunk);
|
|
74604
74970
|
const input = pendingFragments.join("");
|
|
74605
|
-
pendingFragments.length = 0
|
|
74971
|
+
pendingFragments.length = 0;
|
|
74606
74972
|
const trailing = processLines(input);
|
|
74607
|
-
trailing !== "" &&
|
|
74608
|
-
}
|
|
74609
|
-
function checkBufferSize() {
|
|
74610
|
-
maxBufferSize !== undefined && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = undefined, data = "", dataLines = 0, eventType = undefined, onError(new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
74611
|
-
type: "max-buffer-size-exceeded"
|
|
74612
|
-
}))));
|
|
74973
|
+
trailing !== "" && pendingFragments.push(trailing);
|
|
74613
74974
|
}
|
|
74614
74975
|
function processLines(chunk) {
|
|
74615
74976
|
let searchIndex = 0;
|
|
@@ -74721,7 +75082,7 @@ ${value}`, dataLines++;
|
|
|
74721
75082
|
const incompleteLine = pendingFragments.join("");
|
|
74722
75083
|
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
74723
75084
|
}
|
|
74724
|
-
isFirstChunk = true, id = undefined, data = "", dataLines = 0, eventType = undefined, pendingFragments.length = 0
|
|
75085
|
+
isFirstChunk = true, id = undefined, data = "", dataLines = 0, eventType = undefined, pendingFragments.length = 0;
|
|
74725
75086
|
}
|
|
74726
75087
|
return { feed, reset };
|
|
74727
75088
|
}
|
|
@@ -74745,7 +75106,7 @@ var EventSourceParserStream;
|
|
|
74745
75106
|
var init_stream = __esm(() => {
|
|
74746
75107
|
init_dist4();
|
|
74747
75108
|
EventSourceParserStream = class EventSourceParserStream extends TransformStream {
|
|
74748
|
-
constructor({ onError, onRetry, onComment
|
|
75109
|
+
constructor({ onError, onRetry, onComment } = {}) {
|
|
74749
75110
|
let parser;
|
|
74750
75111
|
super({
|
|
74751
75112
|
start(controller) {
|
|
@@ -74754,11 +75115,10 @@ var init_stream = __esm(() => {
|
|
|
74754
75115
|
controller.enqueue(event);
|
|
74755
75116
|
},
|
|
74756
75117
|
onError(error40) {
|
|
74757
|
-
|
|
75118
|
+
onError === "terminate" ? controller.error(error40) : typeof onError == "function" && onError(error40);
|
|
74758
75119
|
},
|
|
74759
75120
|
onRetry,
|
|
74760
|
-
onComment
|
|
74761
|
-
maxBufferSize
|
|
75121
|
+
onComment
|
|
74762
75122
|
});
|
|
74763
75123
|
},
|
|
74764
75124
|
transform(chunk) {
|
|
@@ -76100,7 +76460,7 @@ function createProviderToolFactoryWithOutputSchema({
|
|
|
76100
76460
|
supportsDeferredResults
|
|
76101
76461
|
});
|
|
76102
76462
|
}
|
|
76103
|
-
async function
|
|
76463
|
+
async function resolve3(value) {
|
|
76104
76464
|
if (typeof value === "function") {
|
|
76105
76465
|
value = value();
|
|
76106
76466
|
}
|
|
@@ -76197,7 +76557,7 @@ var DelayedPromise = class {
|
|
|
76197
76557
|
});
|
|
76198
76558
|
}
|
|
76199
76559
|
return () => `${prefix}${separator}${generator()}`;
|
|
76200
|
-
}, generateId, FETCH_FAILED_ERROR_MESSAGES, BUN_ERROR_CODES, VERSION = "4.0.
|
|
76560
|
+
}, generateId, FETCH_FAILED_ERROR_MESSAGES, BUN_ERROR_CODES, VERSION = "4.0.26", getOriginalFetch = () => globalThis.fetch, getFromApi = async ({
|
|
76201
76561
|
url: url2,
|
|
76202
76562
|
headers = {},
|
|
76203
76563
|
successfulResponseHandler,
|
|
@@ -76863,19 +77223,19 @@ var require_token_io = __commonJS((exports, module) => {
|
|
|
76863
77223
|
getUserDataDir: () => getUserDataDir
|
|
76864
77224
|
});
|
|
76865
77225
|
module.exports = __toCommonJS2(token_io_exports);
|
|
76866
|
-
var
|
|
76867
|
-
var
|
|
77226
|
+
var import_path26 = __toESM4(__require("path"));
|
|
77227
|
+
var import_fs30 = __toESM4(__require("fs"));
|
|
76868
77228
|
var import_os13 = __toESM4(__require("os"));
|
|
76869
77229
|
var import_token_error = require_token_error();
|
|
76870
77230
|
function findRootDir() {
|
|
76871
77231
|
try {
|
|
76872
77232
|
let dir = process.cwd();
|
|
76873
|
-
while (dir !==
|
|
76874
|
-
const pkgPath =
|
|
76875
|
-
if (
|
|
77233
|
+
while (dir !== import_path26.default.dirname(dir)) {
|
|
77234
|
+
const pkgPath = import_path26.default.join(dir, ".vercel");
|
|
77235
|
+
if (import_fs30.default.existsSync(pkgPath)) {
|
|
76876
77236
|
return dir;
|
|
76877
77237
|
}
|
|
76878
|
-
dir =
|
|
77238
|
+
dir = import_path26.default.dirname(dir);
|
|
76879
77239
|
}
|
|
76880
77240
|
} catch (e2) {
|
|
76881
77241
|
throw new import_token_error.VercelOidcTokenError("Token refresh only supported in node server environments");
|
|
@@ -76888,9 +77248,9 @@ var require_token_io = __commonJS((exports, module) => {
|
|
|
76888
77248
|
}
|
|
76889
77249
|
switch (import_os13.default.platform()) {
|
|
76890
77250
|
case "darwin":
|
|
76891
|
-
return
|
|
77251
|
+
return import_path26.default.join(import_os13.default.homedir(), "Library/Application Support");
|
|
76892
77252
|
case "linux":
|
|
76893
|
-
return
|
|
77253
|
+
return import_path26.default.join(import_os13.default.homedir(), ".local/share");
|
|
76894
77254
|
case "win32":
|
|
76895
77255
|
if (process.env.LOCALAPPDATA) {
|
|
76896
77256
|
return process.env.LOCALAPPDATA;
|
|
@@ -77787,7 +78147,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77787
78147
|
try {
|
|
77788
78148
|
const { value } = await getFromApi({
|
|
77789
78149
|
url: `${this.config.baseURL}/config`,
|
|
77790
|
-
headers: await
|
|
78150
|
+
headers: await resolve3(this.config.headers()),
|
|
77791
78151
|
successfulResponseHandler: createJsonResponseHandler(gatewayAvailableModelsResponseSchema),
|
|
77792
78152
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
77793
78153
|
errorSchema: exports_external2.any(),
|
|
@@ -77805,7 +78165,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77805
78165
|
const baseUrl = new URL(this.config.baseURL);
|
|
77806
78166
|
const { value } = await getFromApi({
|
|
77807
78167
|
url: `${baseUrl.origin}/v1/credits`,
|
|
77808
|
-
headers: await
|
|
78168
|
+
headers: await resolve3(this.config.headers()),
|
|
77809
78169
|
successfulResponseHandler: createJsonResponseHandler(gatewayCreditsResponseSchema),
|
|
77810
78170
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
77811
78171
|
errorSchema: exports_external2.any(),
|
|
@@ -77851,7 +78211,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77851
78211
|
}
|
|
77852
78212
|
const { value } = await getFromApi({
|
|
77853
78213
|
url: `${baseUrl.origin}/v1/report?${searchParams.toString()}`,
|
|
77854
|
-
headers: await
|
|
78214
|
+
headers: await resolve3(this.config.headers()),
|
|
77855
78215
|
successfulResponseHandler: createJsonResponseHandler(gatewaySpendReportResponseSchema),
|
|
77856
78216
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
77857
78217
|
errorSchema: exports_external2.any(),
|
|
@@ -77873,7 +78233,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77873
78233
|
const baseUrl = new URL(this.config.baseURL);
|
|
77874
78234
|
const { value } = await getFromApi({
|
|
77875
78235
|
url: `${baseUrl.origin}/v1/generation?id=${encodeURIComponent(params.id)}`,
|
|
77876
|
-
headers: await
|
|
78236
|
+
headers: await resolve3(this.config.headers()),
|
|
77877
78237
|
successfulResponseHandler: createJsonResponseHandler(gatewayGenerationInfoResponseSchema),
|
|
77878
78238
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
77879
78239
|
errorSchema: exports_external2.any(),
|
|
@@ -77906,7 +78266,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77906
78266
|
async doGenerate(options) {
|
|
77907
78267
|
const { args, warnings } = await this.getArgs(options);
|
|
77908
78268
|
const { abortSignal } = options;
|
|
77909
|
-
const resolvedHeaders = await
|
|
78269
|
+
const resolvedHeaders = await resolve3(this.config.headers());
|
|
77910
78270
|
try {
|
|
77911
78271
|
const {
|
|
77912
78272
|
responseHeaders,
|
|
@@ -77914,7 +78274,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77914
78274
|
rawValue: rawResponse
|
|
77915
78275
|
} = await postJsonToApi({
|
|
77916
78276
|
url: this.getUrl(),
|
|
77917
|
-
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await
|
|
78277
|
+
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await resolve3(this.config.o11yHeaders)),
|
|
77918
78278
|
body: args,
|
|
77919
78279
|
successfulResponseHandler: createJsonResponseHandler(exports_external2.any()),
|
|
77920
78280
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
@@ -77937,11 +78297,11 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
77937
78297
|
async doStream(options) {
|
|
77938
78298
|
const { args, warnings } = await this.getArgs(options);
|
|
77939
78299
|
const { abortSignal } = options;
|
|
77940
|
-
const resolvedHeaders = await
|
|
78300
|
+
const resolvedHeaders = await resolve3(this.config.headers());
|
|
77941
78301
|
try {
|
|
77942
78302
|
const { value: response, responseHeaders } = await postJsonToApi({
|
|
77943
78303
|
url: this.getUrl(),
|
|
77944
|
-
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await
|
|
78304
|
+
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await resolve3(this.config.o11yHeaders)),
|
|
77945
78305
|
body: args,
|
|
77946
78306
|
successfulResponseHandler: createEventSourceResponseHandler(exports_external2.any()),
|
|
77947
78307
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
@@ -78026,7 +78386,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78026
78386
|
providerOptions
|
|
78027
78387
|
}) {
|
|
78028
78388
|
var _a92;
|
|
78029
|
-
const resolvedHeaders = await
|
|
78389
|
+
const resolvedHeaders = await resolve3(this.config.headers());
|
|
78030
78390
|
try {
|
|
78031
78391
|
const {
|
|
78032
78392
|
responseHeaders,
|
|
@@ -78034,7 +78394,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78034
78394
|
rawValue
|
|
78035
78395
|
} = await postJsonToApi({
|
|
78036
78396
|
url: this.getUrl(),
|
|
78037
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
78397
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders)),
|
|
78038
78398
|
body: {
|
|
78039
78399
|
values,
|
|
78040
78400
|
...providerOptions ? { providerOptions } : {}
|
|
@@ -78090,7 +78450,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78090
78450
|
abortSignal
|
|
78091
78451
|
}) {
|
|
78092
78452
|
var _a92, _b92, _c2, _d2;
|
|
78093
|
-
const resolvedHeaders = await
|
|
78453
|
+
const resolvedHeaders = await resolve3(this.config.headers());
|
|
78094
78454
|
try {
|
|
78095
78455
|
const {
|
|
78096
78456
|
responseHeaders,
|
|
@@ -78098,7 +78458,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78098
78458
|
rawValue
|
|
78099
78459
|
} = await postJsonToApi({
|
|
78100
78460
|
url: this.getUrl(),
|
|
78101
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
78461
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders)),
|
|
78102
78462
|
body: {
|
|
78103
78463
|
prompt,
|
|
78104
78464
|
n: n2,
|
|
@@ -78173,11 +78533,11 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78173
78533
|
abortSignal
|
|
78174
78534
|
}) {
|
|
78175
78535
|
var _a92;
|
|
78176
|
-
const resolvedHeaders = await
|
|
78536
|
+
const resolvedHeaders = await resolve3(this.config.headers());
|
|
78177
78537
|
try {
|
|
78178
78538
|
const { responseHeaders, value: responseBody } = await postJsonToApi({
|
|
78179
78539
|
url: this.getUrl(),
|
|
78180
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
78540
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders), { accept: "text/event-stream" }),
|
|
78181
78541
|
body: {
|
|
78182
78542
|
prompt,
|
|
78183
78543
|
n: n2,
|
|
@@ -78300,7 +78660,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78300
78660
|
abortSignal,
|
|
78301
78661
|
providerOptions
|
|
78302
78662
|
}) {
|
|
78303
|
-
const resolvedHeaders = await
|
|
78663
|
+
const resolvedHeaders = await resolve3(this.config.headers());
|
|
78304
78664
|
try {
|
|
78305
78665
|
const {
|
|
78306
78666
|
responseHeaders,
|
|
@@ -78308,7 +78668,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78308
78668
|
rawValue
|
|
78309
78669
|
} = await postJsonToApi({
|
|
78310
78670
|
url: this.getUrl(),
|
|
78311
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
78671
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve3(this.config.o11yHeaders)),
|
|
78312
78672
|
body: {
|
|
78313
78673
|
documents,
|
|
78314
78674
|
query,
|
|
@@ -78342,7 +78702,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
78342
78702
|
"ai-model-id": this.modelId
|
|
78343
78703
|
};
|
|
78344
78704
|
}
|
|
78345
|
-
}, gatewayRerankingResponseSchema, parallelSearchInputSchema, parallelSearchOutputSchema, parallelSearchToolFactory, parallelSearch = (config2 = {}) => parallelSearchToolFactory(config2), perplexitySearchInputSchema, perplexitySearchOutputSchema, perplexitySearchToolFactory, perplexitySearch = (config2 = {}) => perplexitySearchToolFactory(config2), gatewayTools, VERSION2 = "3.0.
|
|
78705
|
+
}, gatewayRerankingResponseSchema, parallelSearchInputSchema, parallelSearchOutputSchema, parallelSearchToolFactory, parallelSearch = (config2 = {}) => parallelSearchToolFactory(config2), perplexitySearchInputSchema, perplexitySearchOutputSchema, perplexitySearchToolFactory, perplexitySearch = (config2 = {}) => perplexitySearchToolFactory(config2), gatewayTools, VERSION2 = "3.0.110", AI_GATEWAY_PROTOCOL_VERSION = "0.0.1", gateway;
|
|
78346
78706
|
var init_dist6 = __esm(() => {
|
|
78347
78707
|
init_dist5();
|
|
78348
78708
|
init_dist3();
|
|
@@ -78381,15 +78741,13 @@ var init_dist6 = __esm(() => {
|
|
|
78381
78741
|
message,
|
|
78382
78742
|
statusCode = 500,
|
|
78383
78743
|
cause,
|
|
78384
|
-
generationId
|
|
78385
|
-
isRetryable = statusCode != null && (statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500)
|
|
78744
|
+
generationId
|
|
78386
78745
|
}) {
|
|
78387
78746
|
super(generationId ? `${message} [${generationId}]` : message);
|
|
78388
78747
|
this[_a17] = true;
|
|
78389
78748
|
this.statusCode = statusCode;
|
|
78390
78749
|
this.cause = cause;
|
|
78391
78750
|
this.generationId = generationId;
|
|
78392
|
-
this.isRetryable = isRetryable;
|
|
78393
78751
|
}
|
|
78394
78752
|
static isInstance(error40) {
|
|
78395
78753
|
return _GatewayError.hasMarker(error40);
|
|
@@ -78912,11 +79270,62 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
|
|
|
78912
79270
|
gateway = createGatewayProvider();
|
|
78913
79271
|
});
|
|
78914
79272
|
|
|
79273
|
+
// node_modules/@opentelemetry/api/build/src/platform/node/globalThis.js
|
|
79274
|
+
var require_globalThis = __commonJS((exports) => {
|
|
79275
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
79276
|
+
exports._globalThis = undefined;
|
|
79277
|
+
exports._globalThis = typeof globalThis === "object" ? globalThis : global;
|
|
79278
|
+
});
|
|
79279
|
+
|
|
79280
|
+
// node_modules/@opentelemetry/api/build/src/platform/node/index.js
|
|
79281
|
+
var require_node = __commonJS((exports) => {
|
|
79282
|
+
var __createBinding2 = exports && exports.__createBinding || (Object.create ? function(o2, m2, k2, k22) {
|
|
79283
|
+
if (k22 === undefined)
|
|
79284
|
+
k22 = k2;
|
|
79285
|
+
Object.defineProperty(o2, k22, { enumerable: true, get: function() {
|
|
79286
|
+
return m2[k2];
|
|
79287
|
+
} });
|
|
79288
|
+
} : function(o2, m2, k2, k22) {
|
|
79289
|
+
if (k22 === undefined)
|
|
79290
|
+
k22 = k2;
|
|
79291
|
+
o2[k22] = m2[k2];
|
|
79292
|
+
});
|
|
79293
|
+
var __exportStar2 = exports && exports.__exportStar || function(m2, exports2) {
|
|
79294
|
+
for (var p2 in m2)
|
|
79295
|
+
if (p2 !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p2))
|
|
79296
|
+
__createBinding2(exports2, m2, p2);
|
|
79297
|
+
};
|
|
79298
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
79299
|
+
__exportStar2(require_globalThis(), exports);
|
|
79300
|
+
});
|
|
79301
|
+
|
|
79302
|
+
// node_modules/@opentelemetry/api/build/src/platform/index.js
|
|
79303
|
+
var require_platform = __commonJS((exports) => {
|
|
79304
|
+
var __createBinding2 = exports && exports.__createBinding || (Object.create ? function(o2, m2, k2, k22) {
|
|
79305
|
+
if (k22 === undefined)
|
|
79306
|
+
k22 = k2;
|
|
79307
|
+
Object.defineProperty(o2, k22, { enumerable: true, get: function() {
|
|
79308
|
+
return m2[k2];
|
|
79309
|
+
} });
|
|
79310
|
+
} : function(o2, m2, k2, k22) {
|
|
79311
|
+
if (k22 === undefined)
|
|
79312
|
+
k22 = k2;
|
|
79313
|
+
o2[k22] = m2[k2];
|
|
79314
|
+
});
|
|
79315
|
+
var __exportStar2 = exports && exports.__exportStar || function(m2, exports2) {
|
|
79316
|
+
for (var p2 in m2)
|
|
79317
|
+
if (p2 !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p2))
|
|
79318
|
+
__createBinding2(exports2, m2, p2);
|
|
79319
|
+
};
|
|
79320
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
79321
|
+
__exportStar2(require_node(), exports);
|
|
79322
|
+
});
|
|
79323
|
+
|
|
78915
79324
|
// node_modules/@opentelemetry/api/build/src/version.js
|
|
78916
79325
|
var require_version = __commonJS((exports) => {
|
|
78917
79326
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
78918
79327
|
exports.VERSION = undefined;
|
|
78919
|
-
exports.VERSION = "1.9.
|
|
79328
|
+
exports.VERSION = "1.9.0";
|
|
78920
79329
|
});
|
|
78921
79330
|
|
|
78922
79331
|
// node_modules/@opentelemetry/api/build/src/internal/semver.js
|
|
@@ -78994,11 +79403,12 @@ var require_semver2 = __commonJS((exports) => {
|
|
|
78994
79403
|
var require_global_utils = __commonJS((exports) => {
|
|
78995
79404
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
78996
79405
|
exports.unregisterGlobal = exports.getGlobal = exports.registerGlobal = undefined;
|
|
79406
|
+
var platform_1 = require_platform();
|
|
78997
79407
|
var version_1 = require_version();
|
|
78998
79408
|
var semver_1 = require_semver2();
|
|
78999
79409
|
var major = version_1.VERSION.split(".")[0];
|
|
79000
79410
|
var GLOBAL_OPENTELEMETRY_API_KEY = Symbol.for(`opentelemetry.js.api.${major}`);
|
|
79001
|
-
var _global =
|
|
79411
|
+
var _global = platform_1._globalThis;
|
|
79002
79412
|
function registerGlobal(type2, instance, diag, allowOverride = false) {
|
|
79003
79413
|
var _a16;
|
|
79004
79414
|
const api2 = _global[GLOBAL_OPENTELEMETRY_API_KEY] = (_a16 = _global[GLOBAL_OPENTELEMETRY_API_KEY]) !== null && _a16 !== undefined ? _a16 : {
|
|
@@ -79070,7 +79480,8 @@ var require_ComponentLogger = __commonJS((exports) => {
|
|
|
79070
79480
|
if (!logger) {
|
|
79071
79481
|
return;
|
|
79072
79482
|
}
|
|
79073
|
-
|
|
79483
|
+
args.unshift(namespace);
|
|
79484
|
+
return logger[funcName](...args);
|
|
79074
79485
|
}
|
|
79075
79486
|
});
|
|
79076
79487
|
|
|
@@ -79131,12 +79542,6 @@ var require_diag = __commonJS((exports) => {
|
|
|
79131
79542
|
var API_NAME = "diag";
|
|
79132
79543
|
|
|
79133
79544
|
class DiagAPI {
|
|
79134
|
-
static instance() {
|
|
79135
|
-
if (!this._instance) {
|
|
79136
|
-
this._instance = new DiagAPI;
|
|
79137
|
-
}
|
|
79138
|
-
return this._instance;
|
|
79139
|
-
}
|
|
79140
79545
|
constructor() {
|
|
79141
79546
|
function _logProxy(funcName) {
|
|
79142
79547
|
return function(...args) {
|
|
@@ -79181,6 +79586,12 @@ var require_diag = __commonJS((exports) => {
|
|
|
79181
79586
|
self2.warn = _logProxy("warn");
|
|
79182
79587
|
self2.error = _logProxy("error");
|
|
79183
79588
|
}
|
|
79589
|
+
static instance() {
|
|
79590
|
+
if (!this._instance) {
|
|
79591
|
+
this._instance = new DiagAPI;
|
|
79592
|
+
}
|
|
79593
|
+
return this._instance;
|
|
79594
|
+
}
|
|
79184
79595
|
}
|
|
79185
79596
|
exports.DiagAPI = DiagAPI;
|
|
79186
79597
|
});
|
|
@@ -79202,7 +79613,7 @@ var require_baggage_impl = __commonJS((exports) => {
|
|
|
79202
79613
|
return Object.assign({}, entry);
|
|
79203
79614
|
}
|
|
79204
79615
|
getAllEntries() {
|
|
79205
|
-
return Array.from(this._entries.entries());
|
|
79616
|
+
return Array.from(this._entries.entries()).map(([k2, v2]) => [k2, v2]);
|
|
79206
79617
|
}
|
|
79207
79618
|
setEntry(key, entry) {
|
|
79208
79619
|
const newBaggage = new BaggageImpl(this._entries);
|
|
@@ -79294,7 +79705,7 @@ var require_context = __commonJS((exports) => {
|
|
|
79294
79705
|
// node_modules/@opentelemetry/api/build/src/diag/consoleLogger.js
|
|
79295
79706
|
var require_consoleLogger = __commonJS((exports) => {
|
|
79296
79707
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
79297
|
-
exports.DiagConsoleLogger =
|
|
79708
|
+
exports.DiagConsoleLogger = undefined;
|
|
79298
79709
|
var consoleMap = [
|
|
79299
79710
|
{ n: "error", c: "error" },
|
|
79300
79711
|
{ n: "warn", c: "warn" },
|
|
@@ -79302,39 +79713,19 @@ var require_consoleLogger = __commonJS((exports) => {
|
|
|
79302
79713
|
{ n: "debug", c: "debug" },
|
|
79303
79714
|
{ n: "verbose", c: "trace" }
|
|
79304
79715
|
];
|
|
79305
|
-
exports._originalConsoleMethods = {};
|
|
79306
|
-
if (typeof console !== "undefined") {
|
|
79307
|
-
const keys = [
|
|
79308
|
-
"error",
|
|
79309
|
-
"warn",
|
|
79310
|
-
"info",
|
|
79311
|
-
"debug",
|
|
79312
|
-
"trace",
|
|
79313
|
-
"log"
|
|
79314
|
-
];
|
|
79315
|
-
for (const key of keys) {
|
|
79316
|
-
if (typeof console[key] === "function") {
|
|
79317
|
-
exports._originalConsoleMethods[key] = console[key];
|
|
79318
|
-
}
|
|
79319
|
-
}
|
|
79320
|
-
}
|
|
79321
79716
|
|
|
79322
79717
|
class DiagConsoleLogger {
|
|
79323
79718
|
constructor() {
|
|
79324
79719
|
function _consoleFunc(funcName) {
|
|
79325
79720
|
return function(...args) {
|
|
79326
|
-
|
|
79327
|
-
|
|
79328
|
-
theFunc = exports._originalConsoleMethods["log"];
|
|
79329
|
-
}
|
|
79330
|
-
if (typeof theFunc !== "function" && console) {
|
|
79331
|
-
theFunc = console[funcName];
|
|
79721
|
+
if (console) {
|
|
79722
|
+
let theFunc = console[funcName];
|
|
79332
79723
|
if (typeof theFunc !== "function") {
|
|
79333
79724
|
theFunc = console.log;
|
|
79334
79725
|
}
|
|
79335
|
-
|
|
79336
|
-
|
|
79337
|
-
|
|
79726
|
+
if (typeof theFunc === "function") {
|
|
79727
|
+
return theFunc.apply(console, args);
|
|
79728
|
+
}
|
|
79338
79729
|
}
|
|
79339
79730
|
};
|
|
79340
79731
|
}
|
|
@@ -79572,8 +79963,8 @@ var require_NonRecordingSpan = __commonJS((exports) => {
|
|
|
79572
79963
|
var invalid_span_constants_1 = require_invalid_span_constants();
|
|
79573
79964
|
|
|
79574
79965
|
class NonRecordingSpan {
|
|
79575
|
-
constructor(
|
|
79576
|
-
this._spanContext =
|
|
79966
|
+
constructor(_spanContext = invalid_span_constants_1.INVALID_SPAN_CONTEXT) {
|
|
79967
|
+
this._spanContext = _spanContext;
|
|
79577
79968
|
}
|
|
79578
79969
|
spanContext() {
|
|
79579
79970
|
return this._spanContext;
|
|
@@ -79649,126 +80040,14 @@ var require_spancontext_utils = __commonJS((exports) => {
|
|
|
79649
80040
|
exports.wrapSpanContext = exports.isSpanContextValid = exports.isValidSpanId = exports.isValidTraceId = undefined;
|
|
79650
80041
|
var invalid_span_constants_1 = require_invalid_span_constants();
|
|
79651
80042
|
var NonRecordingSpan_1 = require_NonRecordingSpan();
|
|
79652
|
-
var
|
|
79653
|
-
|
|
79654
|
-
0,
|
|
79655
|
-
0,
|
|
79656
|
-
0,
|
|
79657
|
-
0,
|
|
79658
|
-
0,
|
|
79659
|
-
0,
|
|
79660
|
-
0,
|
|
79661
|
-
0,
|
|
79662
|
-
0,
|
|
79663
|
-
0,
|
|
79664
|
-
0,
|
|
79665
|
-
0,
|
|
79666
|
-
0,
|
|
79667
|
-
0,
|
|
79668
|
-
0,
|
|
79669
|
-
0,
|
|
79670
|
-
0,
|
|
79671
|
-
0,
|
|
79672
|
-
0,
|
|
79673
|
-
0,
|
|
79674
|
-
0,
|
|
79675
|
-
0,
|
|
79676
|
-
0,
|
|
79677
|
-
0,
|
|
79678
|
-
0,
|
|
79679
|
-
0,
|
|
79680
|
-
0,
|
|
79681
|
-
0,
|
|
79682
|
-
0,
|
|
79683
|
-
0,
|
|
79684
|
-
0,
|
|
79685
|
-
0,
|
|
79686
|
-
0,
|
|
79687
|
-
0,
|
|
79688
|
-
0,
|
|
79689
|
-
0,
|
|
79690
|
-
0,
|
|
79691
|
-
0,
|
|
79692
|
-
0,
|
|
79693
|
-
0,
|
|
79694
|
-
0,
|
|
79695
|
-
0,
|
|
79696
|
-
0,
|
|
79697
|
-
0,
|
|
79698
|
-
0,
|
|
79699
|
-
0,
|
|
79700
|
-
0,
|
|
79701
|
-
1,
|
|
79702
|
-
1,
|
|
79703
|
-
1,
|
|
79704
|
-
1,
|
|
79705
|
-
1,
|
|
79706
|
-
1,
|
|
79707
|
-
1,
|
|
79708
|
-
1,
|
|
79709
|
-
1,
|
|
79710
|
-
1,
|
|
79711
|
-
0,
|
|
79712
|
-
0,
|
|
79713
|
-
0,
|
|
79714
|
-
0,
|
|
79715
|
-
0,
|
|
79716
|
-
0,
|
|
79717
|
-
0,
|
|
79718
|
-
1,
|
|
79719
|
-
1,
|
|
79720
|
-
1,
|
|
79721
|
-
1,
|
|
79722
|
-
1,
|
|
79723
|
-
1,
|
|
79724
|
-
0,
|
|
79725
|
-
0,
|
|
79726
|
-
0,
|
|
79727
|
-
0,
|
|
79728
|
-
0,
|
|
79729
|
-
0,
|
|
79730
|
-
0,
|
|
79731
|
-
0,
|
|
79732
|
-
0,
|
|
79733
|
-
0,
|
|
79734
|
-
0,
|
|
79735
|
-
0,
|
|
79736
|
-
0,
|
|
79737
|
-
0,
|
|
79738
|
-
0,
|
|
79739
|
-
0,
|
|
79740
|
-
0,
|
|
79741
|
-
0,
|
|
79742
|
-
0,
|
|
79743
|
-
0,
|
|
79744
|
-
0,
|
|
79745
|
-
0,
|
|
79746
|
-
0,
|
|
79747
|
-
0,
|
|
79748
|
-
0,
|
|
79749
|
-
0,
|
|
79750
|
-
1,
|
|
79751
|
-
1,
|
|
79752
|
-
1,
|
|
79753
|
-
1,
|
|
79754
|
-
1,
|
|
79755
|
-
1
|
|
79756
|
-
]);
|
|
79757
|
-
function isValidHex(id, length) {
|
|
79758
|
-
if (typeof id !== "string" || id.length !== length)
|
|
79759
|
-
return false;
|
|
79760
|
-
let r2 = 0;
|
|
79761
|
-
for (let i2 = 0;i2 < id.length; i2 += 4) {
|
|
79762
|
-
r2 += (isHex[id.charCodeAt(i2)] | 0) + (isHex[id.charCodeAt(i2 + 1)] | 0) + (isHex[id.charCodeAt(i2 + 2)] | 0) + (isHex[id.charCodeAt(i2 + 3)] | 0);
|
|
79763
|
-
}
|
|
79764
|
-
return r2 === length;
|
|
79765
|
-
}
|
|
80043
|
+
var VALID_TRACEID_REGEX = /^([0-9a-f]{32})$/i;
|
|
80044
|
+
var VALID_SPANID_REGEX = /^[0-9a-f]{16}$/i;
|
|
79766
80045
|
function isValidTraceId(traceId) {
|
|
79767
|
-
return
|
|
80046
|
+
return VALID_TRACEID_REGEX.test(traceId) && traceId !== invalid_span_constants_1.INVALID_TRACEID;
|
|
79768
80047
|
}
|
|
79769
80048
|
exports.isValidTraceId = isValidTraceId;
|
|
79770
80049
|
function isValidSpanId(spanId) {
|
|
79771
|
-
return
|
|
80050
|
+
return VALID_SPANID_REGEX.test(spanId) && spanId !== invalid_span_constants_1.INVALID_SPANID;
|
|
79772
80051
|
}
|
|
79773
80052
|
exports.isValidSpanId = isValidSpanId;
|
|
79774
80053
|
function isSpanContextValid(spanContext) {
|
|
@@ -79828,7 +80107,7 @@ var require_NoopTracer = __commonJS((exports) => {
|
|
|
79828
80107
|
}
|
|
79829
80108
|
exports.NoopTracer = NoopTracer;
|
|
79830
80109
|
function isSpanContext(spanContext) {
|
|
79831
|
-
return
|
|
80110
|
+
return typeof spanContext === "object" && typeof spanContext["spanId"] === "string" && typeof spanContext["traceId"] === "string" && typeof spanContext["traceFlags"] === "number";
|
|
79832
80111
|
}
|
|
79833
80112
|
});
|
|
79834
80113
|
|
|
@@ -79840,8 +80119,8 @@ var require_ProxyTracer = __commonJS((exports) => {
|
|
|
79840
80119
|
var NOOP_TRACER = new NoopTracer_1.NoopTracer;
|
|
79841
80120
|
|
|
79842
80121
|
class ProxyTracer {
|
|
79843
|
-
constructor(
|
|
79844
|
-
this._provider =
|
|
80122
|
+
constructor(_provider, name15, version2, options) {
|
|
80123
|
+
this._provider = _provider;
|
|
79845
80124
|
this.name = name15;
|
|
79846
80125
|
this.version = version2;
|
|
79847
80126
|
this.options = options;
|
|
@@ -80001,7 +80280,7 @@ var require_tracestate_impl = __commonJS((exports) => {
|
|
|
80001
80280
|
return this._internalState.get(key);
|
|
80002
80281
|
}
|
|
80003
80282
|
serialize() {
|
|
80004
|
-
return
|
|
80283
|
+
return this._keys().reduce((agg, key) => {
|
|
80005
80284
|
agg.push(key + LIST_MEMBER_KEY_VALUE_SPLITTER + this.get(key));
|
|
80006
80285
|
return agg;
|
|
80007
80286
|
}, []).join(LIST_MEMBERS_SEPARATOR);
|
|
@@ -80009,7 +80288,7 @@ var require_tracestate_impl = __commonJS((exports) => {
|
|
|
80009
80288
|
_parse(rawTraceState) {
|
|
80010
80289
|
if (rawTraceState.length > MAX_TRACE_STATE_LEN)
|
|
80011
80290
|
return;
|
|
80012
|
-
this._internalState = rawTraceState.split(LIST_MEMBERS_SEPARATOR).
|
|
80291
|
+
this._internalState = rawTraceState.split(LIST_MEMBERS_SEPARATOR).reverse().reduce((agg, part) => {
|
|
80013
80292
|
const listMember = part.trim();
|
|
80014
80293
|
const i2 = listMember.indexOf(LIST_MEMBER_KEY_VALUE_SPLITTER);
|
|
80015
80294
|
if (i2 !== -1) {
|
|
@@ -81109,10 +81388,7 @@ function convertToLanguageModelMessage({
|
|
|
81109
81388
|
type: "tool-result",
|
|
81110
81389
|
toolCallId: part.toolCallId,
|
|
81111
81390
|
toolName: part.toolName,
|
|
81112
|
-
output: mapToolResultOutput(
|
|
81113
|
-
output: part.output,
|
|
81114
|
-
downloadedAssets
|
|
81115
|
-
}),
|
|
81391
|
+
output: mapToolResultOutput(part.output),
|
|
81116
81392
|
providerOptions
|
|
81117
81393
|
};
|
|
81118
81394
|
}
|
|
@@ -81131,10 +81407,7 @@ function convertToLanguageModelMessage({
|
|
|
81131
81407
|
type: "tool-result",
|
|
81132
81408
|
toolCallId: part.toolCallId,
|
|
81133
81409
|
toolName: part.toolName,
|
|
81134
|
-
output: mapToolResultOutput(
|
|
81135
|
-
output: part.output,
|
|
81136
|
-
downloadedAssets
|
|
81137
|
-
}),
|
|
81410
|
+
output: mapToolResultOutput(part.output),
|
|
81138
81411
|
providerOptions: part.providerOptions
|
|
81139
81412
|
};
|
|
81140
81413
|
}
|
|
@@ -81158,44 +81431,15 @@ function convertToLanguageModelMessage({
|
|
|
81158
81431
|
}
|
|
81159
81432
|
}
|
|
81160
81433
|
async function downloadAssets(messages, download2, supportedUrls) {
|
|
81161
|
-
|
|
81162
|
-
|
|
81163
|
-
|
|
81164
|
-
|
|
81165
|
-
|
|
81166
|
-
|
|
81167
|
-
|
|
81168
|
-
|
|
81169
|
-
mediaType: (_a21 = part.mediaType) != null ? _a21 : part.type === "image" ? "image/*" : undefined
|
|
81170
|
-
});
|
|
81171
|
-
}
|
|
81172
|
-
}
|
|
81173
|
-
}
|
|
81174
|
-
if (message.role === "tool" || message.role === "assistant") {
|
|
81175
|
-
if (!Array.isArray(message.content)) {
|
|
81176
|
-
continue;
|
|
81177
|
-
}
|
|
81178
|
-
for (const part of message.content) {
|
|
81179
|
-
if (part.type !== "tool-result") {
|
|
81180
|
-
continue;
|
|
81181
|
-
}
|
|
81182
|
-
if (part.output.type !== "content") {
|
|
81183
|
-
continue;
|
|
81184
|
-
}
|
|
81185
|
-
for (const contentPart of part.output.value) {
|
|
81186
|
-
if (contentPart.type === "image-url" || contentPart.type === "file-url") {
|
|
81187
|
-
downloadableFiles.push({
|
|
81188
|
-
data: new URL(contentPart.url),
|
|
81189
|
-
mediaType: contentPart.type === "image-url" ? "image/*" : undefined
|
|
81190
|
-
});
|
|
81191
|
-
}
|
|
81192
|
-
}
|
|
81193
|
-
}
|
|
81434
|
+
const plannedDownloads = messages.filter((message) => message.role === "user").map((message) => message.content).filter((content) => Array.isArray(content)).flat().filter((part) => part.type === "image" || part.type === "file").map((part) => {
|
|
81435
|
+
var _a21;
|
|
81436
|
+
const mediaType = (_a21 = part.mediaType) != null ? _a21 : part.type === "image" ? "image/*" : undefined;
|
|
81437
|
+
let data = part.type === "image" ? part.image : part.data;
|
|
81438
|
+
if (typeof data === "string") {
|
|
81439
|
+
try {
|
|
81440
|
+
data = new URL(data);
|
|
81441
|
+
} catch (ignored) {}
|
|
81194
81442
|
}
|
|
81195
|
-
}
|
|
81196
|
-
const plannedDownloads = downloadableFiles.map((part) => {
|
|
81197
|
-
const mediaType = part.mediaType;
|
|
81198
|
-
const { data } = convertToLanguageModelV3DataContent(part.data);
|
|
81199
81443
|
return { mediaType, data };
|
|
81200
81444
|
}).filter((part) => part.data instanceof URL).map((part) => ({
|
|
81201
81445
|
url: part.data,
|
|
@@ -81269,41 +81513,13 @@ function convertPartToLanguageModelPart(part, downloadedAssets) {
|
|
|
81269
81513
|
}
|
|
81270
81514
|
}
|
|
81271
81515
|
}
|
|
81272
|
-
function mapToolResultOutput({
|
|
81273
|
-
output,
|
|
81274
|
-
downloadedAssets
|
|
81275
|
-
}) {
|
|
81516
|
+
function mapToolResultOutput(output) {
|
|
81276
81517
|
if (output.type !== "content") {
|
|
81277
81518
|
return output;
|
|
81278
81519
|
}
|
|
81279
81520
|
return {
|
|
81280
81521
|
type: "content",
|
|
81281
81522
|
value: output.value.map((item) => {
|
|
81282
|
-
var _a21, _b16;
|
|
81283
|
-
if (item.type === "image-url") {
|
|
81284
|
-
const downloadedFile = downloadedAssets[new URL(item.url).toString()];
|
|
81285
|
-
if (downloadedFile) {
|
|
81286
|
-
return {
|
|
81287
|
-
type: "image-data",
|
|
81288
|
-
data: convertDataContentToBase64String(downloadedFile.data),
|
|
81289
|
-
mediaType: (_a21 = downloadedFile.mediaType) != null ? _a21 : "image/*",
|
|
81290
|
-
providerOptions: item.providerOptions
|
|
81291
|
-
};
|
|
81292
|
-
}
|
|
81293
|
-
return item;
|
|
81294
|
-
}
|
|
81295
|
-
if (item.type === "file-url") {
|
|
81296
|
-
const downloadedFile = downloadedAssets[new URL(item.url).toString()];
|
|
81297
|
-
if (downloadedFile) {
|
|
81298
|
-
return {
|
|
81299
|
-
type: "file-data",
|
|
81300
|
-
data: convertDataContentToBase64String(downloadedFile.data),
|
|
81301
|
-
mediaType: (_b16 = downloadedFile.mediaType) != null ? _b16 : "application/octet-stream",
|
|
81302
|
-
providerOptions: item.providerOptions
|
|
81303
|
-
};
|
|
81304
|
-
}
|
|
81305
|
-
return item;
|
|
81306
|
-
}
|
|
81307
81523
|
if (item.type !== "media") {
|
|
81308
81524
|
return item;
|
|
81309
81525
|
}
|
|
@@ -81856,7 +82072,7 @@ function getRetryDelayInMs({
|
|
|
81856
82072
|
error: error40,
|
|
81857
82073
|
exponentialBackoffDelay
|
|
81858
82074
|
}) {
|
|
81859
|
-
const headers =
|
|
82075
|
+
const headers = error40.responseHeaders;
|
|
81860
82076
|
if (!headers)
|
|
81861
82077
|
return exponentialBackoffDelay;
|
|
81862
82078
|
let ms;
|
|
@@ -81906,7 +82122,7 @@ async function _retryWithExponentialBackoff(f2, {
|
|
|
81906
82122
|
errors: newErrors
|
|
81907
82123
|
});
|
|
81908
82124
|
}
|
|
81909
|
-
if (error40 instanceof Error &&
|
|
82125
|
+
if (error40 instanceof Error && APICallError.isInstance(error40) && error40.isRetryable === true && tryNumber <= maxRetries) {
|
|
81910
82126
|
await delay(getRetryDelayInMs({
|
|
81911
82127
|
error: error40,
|
|
81912
82128
|
exponentialBackoffDelay: delayInMs
|
|
@@ -82124,8 +82340,7 @@ async function executeToolCall({
|
|
|
82124
82340
|
input,
|
|
82125
82341
|
error: error40,
|
|
82126
82342
|
dynamic: tool2.type === "dynamic",
|
|
82127
|
-
...toolCall.providerMetadata != null ? { providerMetadata: toolCall.providerMetadata } : {}
|
|
82128
|
-
...toolCall.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
82343
|
+
...toolCall.providerMetadata != null ? { providerMetadata: toolCall.providerMetadata } : {}
|
|
82129
82344
|
};
|
|
82130
82345
|
}
|
|
82131
82346
|
const durationMs = now3() - startTime;
|
|
@@ -82155,8 +82370,7 @@ async function executeToolCall({
|
|
|
82155
82370
|
input,
|
|
82156
82371
|
output,
|
|
82157
82372
|
dynamic: tool2.type === "dynamic",
|
|
82158
|
-
...toolCall.providerMetadata != null ? { providerMetadata: toolCall.providerMetadata } : {}
|
|
82159
|
-
...toolCall.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
82373
|
+
...toolCall.providerMetadata != null ? { providerMetadata: toolCall.providerMetadata } : {}
|
|
82160
82374
|
};
|
|
82161
82375
|
}
|
|
82162
82376
|
});
|
|
@@ -82521,6 +82735,15 @@ async function parsePartialJson(jsonText) {
|
|
|
82521
82735
|
}
|
|
82522
82736
|
return { value: undefined, state: "failed-parse" };
|
|
82523
82737
|
}
|
|
82738
|
+
function mergeToolProviderMetadata(toolMetadata, callMetadata) {
|
|
82739
|
+
if (toolMetadata == null) {
|
|
82740
|
+
return callMetadata;
|
|
82741
|
+
}
|
|
82742
|
+
if (callMetadata == null) {
|
|
82743
|
+
return toolMetadata;
|
|
82744
|
+
}
|
|
82745
|
+
return { ...toolMetadata, ...callMetadata };
|
|
82746
|
+
}
|
|
82524
82747
|
async function parseToolCall({
|
|
82525
82748
|
toolCall,
|
|
82526
82749
|
tools,
|
|
@@ -82528,6 +82751,7 @@ async function parseToolCall({
|
|
|
82528
82751
|
system,
|
|
82529
82752
|
messages
|
|
82530
82753
|
}) {
|
|
82754
|
+
var _a21, _b16;
|
|
82531
82755
|
try {
|
|
82532
82756
|
if (tools == null) {
|
|
82533
82757
|
if (toolCall.providerExecuted && toolCall.dynamic) {
|
|
@@ -82568,7 +82792,6 @@ async function parseToolCall({
|
|
|
82568
82792
|
} catch (error40) {
|
|
82569
82793
|
const parsedInput = await safeParseJSON({ text: toolCall.input });
|
|
82570
82794
|
const input = parsedInput.success ? parsedInput.value : toolCall.input;
|
|
82571
|
-
const tool2 = tools == null ? undefined : tools[toolCall.toolName];
|
|
82572
82795
|
return {
|
|
82573
82796
|
type: "tool-call",
|
|
82574
82797
|
toolCallId: toolCall.toolCallId,
|
|
@@ -82577,10 +82800,9 @@ async function parseToolCall({
|
|
|
82577
82800
|
dynamic: true,
|
|
82578
82801
|
invalid: true,
|
|
82579
82802
|
error: error40,
|
|
82580
|
-
title:
|
|
82803
|
+
title: (_a21 = tools == null ? undefined : tools[toolCall.toolName]) == null ? undefined : _a21.title,
|
|
82581
82804
|
providerExecuted: toolCall.providerExecuted,
|
|
82582
|
-
providerMetadata: toolCall.providerMetadata,
|
|
82583
|
-
...(tool2 == null ? undefined : tool2.metadata) != null ? { toolMetadata: tool2.metadata } : {}
|
|
82805
|
+
providerMetadata: mergeToolProviderMetadata((_b16 = tools == null ? undefined : tools[toolCall.toolName]) == null ? undefined : _b16.providerMetadata, toolCall.providerMetadata)
|
|
82584
82806
|
};
|
|
82585
82807
|
}
|
|
82586
82808
|
}
|
|
@@ -82627,14 +82849,14 @@ async function doParseToolCall({
|
|
|
82627
82849
|
cause: parseResult.error
|
|
82628
82850
|
});
|
|
82629
82851
|
}
|
|
82852
|
+
const mergedProviderMetadata = mergeToolProviderMetadata(tool2.providerMetadata, toolCall.providerMetadata);
|
|
82630
82853
|
return tool2.type === "dynamic" ? {
|
|
82631
82854
|
type: "tool-call",
|
|
82632
82855
|
toolCallId: toolCall.toolCallId,
|
|
82633
82856
|
toolName: toolCall.toolName,
|
|
82634
82857
|
input: parseResult.value,
|
|
82635
82858
|
providerExecuted: toolCall.providerExecuted,
|
|
82636
|
-
providerMetadata:
|
|
82637
|
-
...tool2.metadata != null ? { toolMetadata: tool2.metadata } : {},
|
|
82859
|
+
providerMetadata: mergedProviderMetadata,
|
|
82638
82860
|
dynamic: true,
|
|
82639
82861
|
title: tool2.title
|
|
82640
82862
|
} : {
|
|
@@ -82643,8 +82865,7 @@ async function doParseToolCall({
|
|
|
82643
82865
|
toolName,
|
|
82644
82866
|
input: parseResult.value,
|
|
82645
82867
|
providerExecuted: toolCall.providerExecuted,
|
|
82646
|
-
providerMetadata:
|
|
82647
|
-
...tool2.metadata != null ? { toolMetadata: tool2.metadata } : {},
|
|
82868
|
+
providerMetadata: mergedProviderMetadata,
|
|
82648
82869
|
title: tool2.title
|
|
82649
82870
|
};
|
|
82650
82871
|
}
|
|
@@ -83476,8 +83697,7 @@ function asContent({
|
|
|
83476
83697
|
error: part.result,
|
|
83477
83698
|
providerExecuted: true,
|
|
83478
83699
|
dynamic: part.dynamic,
|
|
83479
|
-
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83480
|
-
...(tool2 == null ? undefined : tool2.metadata) != null ? { toolMetadata: tool2.metadata } : {}
|
|
83700
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83481
83701
|
});
|
|
83482
83702
|
} else {
|
|
83483
83703
|
contentParts.push({
|
|
@@ -83488,8 +83708,7 @@ function asContent({
|
|
|
83488
83708
|
output: part.result,
|
|
83489
83709
|
providerExecuted: true,
|
|
83490
83710
|
dynamic: part.dynamic,
|
|
83491
|
-
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83492
|
-
...(tool2 == null ? undefined : tool2.metadata) != null ? { toolMetadata: tool2.metadata } : {}
|
|
83711
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83493
83712
|
});
|
|
83494
83713
|
}
|
|
83495
83714
|
break;
|
|
@@ -83503,8 +83722,7 @@ function asContent({
|
|
|
83503
83722
|
error: part.result,
|
|
83504
83723
|
providerExecuted: true,
|
|
83505
83724
|
dynamic: toolCall.dynamic,
|
|
83506
|
-
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83507
|
-
...toolCall.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
83725
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83508
83726
|
});
|
|
83509
83727
|
} else {
|
|
83510
83728
|
contentParts.push({
|
|
@@ -83515,8 +83733,7 @@ function asContent({
|
|
|
83515
83733
|
output: part.result,
|
|
83516
83734
|
providerExecuted: true,
|
|
83517
83735
|
dynamic: toolCall.dynamic,
|
|
83518
|
-
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83519
|
-
...toolCall.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
83736
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
83520
83737
|
});
|
|
83521
83738
|
}
|
|
83522
83739
|
break;
|
|
@@ -83730,9 +83947,6 @@ function processUIMessageStream({
|
|
|
83730
83947
|
if (options.title !== undefined) {
|
|
83731
83948
|
anyPart.title = options.title;
|
|
83732
83949
|
}
|
|
83733
|
-
if (options.toolMetadata !== undefined) {
|
|
83734
|
-
anyPart.toolMetadata = options.toolMetadata;
|
|
83735
|
-
}
|
|
83736
83950
|
anyPart.providerExecuted = (_a222 = anyOptions.providerExecuted) != null ? _a222 : part.providerExecuted;
|
|
83737
83951
|
const providerMetadata = anyOptions.providerMetadata;
|
|
83738
83952
|
if (providerMetadata != null) {
|
|
@@ -83749,7 +83963,6 @@ function processUIMessageStream({
|
|
|
83749
83963
|
toolCallId: options.toolCallId,
|
|
83750
83964
|
state: options.state,
|
|
83751
83965
|
title: options.title,
|
|
83752
|
-
...options.toolMetadata !== undefined ? { toolMetadata: options.toolMetadata } : {},
|
|
83753
83966
|
input: anyOptions.input,
|
|
83754
83967
|
output: anyOptions.output,
|
|
83755
83968
|
rawInput: anyOptions.rawInput,
|
|
@@ -83777,9 +83990,6 @@ function processUIMessageStream({
|
|
|
83777
83990
|
if (options.title !== undefined) {
|
|
83778
83991
|
anyPart.title = options.title;
|
|
83779
83992
|
}
|
|
83780
|
-
if (options.toolMetadata !== undefined) {
|
|
83781
|
-
anyPart.toolMetadata = options.toolMetadata;
|
|
83782
|
-
}
|
|
83783
83993
|
anyPart.providerExecuted = (_b23 = anyOptions.providerExecuted) != null ? _b23 : part.providerExecuted;
|
|
83784
83994
|
const providerMetadata = anyOptions.providerMetadata;
|
|
83785
83995
|
if (providerMetadata != null) {
|
|
@@ -83802,7 +84012,6 @@ function processUIMessageStream({
|
|
|
83802
84012
|
preliminary: anyOptions.preliminary,
|
|
83803
84013
|
providerExecuted: anyOptions.providerExecuted,
|
|
83804
84014
|
title: options.title,
|
|
83805
|
-
...options.toolMetadata !== undefined ? { toolMetadata: options.toolMetadata } : {},
|
|
83806
84015
|
...anyOptions.providerMetadata != null && (options.state === "output-available" || options.state === "output-error") ? { resultProviderMetadata: anyOptions.providerMetadata } : {},
|
|
83807
84016
|
...anyOptions.providerMetadata != null && !(options.state === "output-available" || options.state === "output-error") ? { callProviderMetadata: anyOptions.providerMetadata } : {}
|
|
83808
84017
|
});
|
|
@@ -83947,8 +84156,7 @@ function processUIMessageStream({
|
|
|
83947
84156
|
toolName: chunk.toolName,
|
|
83948
84157
|
index: toolInvocations.length,
|
|
83949
84158
|
dynamic: chunk.dynamic,
|
|
83950
|
-
title: chunk.title
|
|
83951
|
-
toolMetadata: chunk.toolMetadata
|
|
84159
|
+
title: chunk.title
|
|
83952
84160
|
};
|
|
83953
84161
|
if (chunk.dynamic) {
|
|
83954
84162
|
updateDynamicToolPart({
|
|
@@ -83958,7 +84166,6 @@ function processUIMessageStream({
|
|
|
83958
84166
|
input: undefined,
|
|
83959
84167
|
providerExecuted: chunk.providerExecuted,
|
|
83960
84168
|
title: chunk.title,
|
|
83961
|
-
toolMetadata: chunk.toolMetadata,
|
|
83962
84169
|
providerMetadata: chunk.providerMetadata
|
|
83963
84170
|
});
|
|
83964
84171
|
} else {
|
|
@@ -83969,7 +84176,6 @@ function processUIMessageStream({
|
|
|
83969
84176
|
input: undefined,
|
|
83970
84177
|
providerExecuted: chunk.providerExecuted,
|
|
83971
84178
|
title: chunk.title,
|
|
83972
|
-
toolMetadata: chunk.toolMetadata,
|
|
83973
84179
|
providerMetadata: chunk.providerMetadata
|
|
83974
84180
|
});
|
|
83975
84181
|
}
|
|
@@ -83993,8 +84199,7 @@ function processUIMessageStream({
|
|
|
83993
84199
|
toolName: partialToolCall.toolName,
|
|
83994
84200
|
state: "input-streaming",
|
|
83995
84201
|
input: partialArgs,
|
|
83996
|
-
title: partialToolCall.title
|
|
83997
|
-
toolMetadata: partialToolCall.toolMetadata
|
|
84202
|
+
title: partialToolCall.title
|
|
83998
84203
|
});
|
|
83999
84204
|
} else {
|
|
84000
84205
|
updateToolPart({
|
|
@@ -84002,8 +84207,7 @@ function processUIMessageStream({
|
|
|
84002
84207
|
toolName: partialToolCall.toolName,
|
|
84003
84208
|
state: "input-streaming",
|
|
84004
84209
|
input: partialArgs,
|
|
84005
|
-
title: partialToolCall.title
|
|
84006
|
-
toolMetadata: partialToolCall.toolMetadata
|
|
84210
|
+
title: partialToolCall.title
|
|
84007
84211
|
});
|
|
84008
84212
|
}
|
|
84009
84213
|
write();
|
|
@@ -84018,8 +84222,7 @@ function processUIMessageStream({
|
|
|
84018
84222
|
input: chunk.input,
|
|
84019
84223
|
providerExecuted: chunk.providerExecuted,
|
|
84020
84224
|
providerMetadata: chunk.providerMetadata,
|
|
84021
|
-
title: chunk.title
|
|
84022
|
-
toolMetadata: chunk.toolMetadata
|
|
84225
|
+
title: chunk.title
|
|
84023
84226
|
});
|
|
84024
84227
|
} else {
|
|
84025
84228
|
updateToolPart({
|
|
@@ -84029,8 +84232,7 @@ function processUIMessageStream({
|
|
|
84029
84232
|
input: chunk.input,
|
|
84030
84233
|
providerExecuted: chunk.providerExecuted,
|
|
84031
84234
|
providerMetadata: chunk.providerMetadata,
|
|
84032
|
-
title: chunk.title
|
|
84033
|
-
toolMetadata: chunk.toolMetadata
|
|
84235
|
+
title: chunk.title
|
|
84034
84236
|
});
|
|
84035
84237
|
}
|
|
84036
84238
|
write();
|
|
@@ -84052,8 +84254,7 @@ function processUIMessageStream({
|
|
|
84052
84254
|
input: chunk.input,
|
|
84053
84255
|
errorText: chunk.errorText,
|
|
84054
84256
|
providerExecuted: chunk.providerExecuted,
|
|
84055
|
-
providerMetadata: chunk.providerMetadata
|
|
84056
|
-
toolMetadata: chunk.toolMetadata
|
|
84257
|
+
providerMetadata: chunk.providerMetadata
|
|
84057
84258
|
});
|
|
84058
84259
|
} else {
|
|
84059
84260
|
updateToolPart({
|
|
@@ -84064,8 +84265,7 @@ function processUIMessageStream({
|
|
|
84064
84265
|
rawInput: chunk.input,
|
|
84065
84266
|
errorText: chunk.errorText,
|
|
84066
84267
|
providerExecuted: chunk.providerExecuted,
|
|
84067
|
-
providerMetadata: chunk.providerMetadata
|
|
84068
|
-
toolMetadata: chunk.toolMetadata
|
|
84268
|
+
providerMetadata: chunk.providerMetadata
|
|
84069
84269
|
});
|
|
84070
84270
|
}
|
|
84071
84271
|
write();
|
|
@@ -84096,8 +84296,7 @@ function processUIMessageStream({
|
|
|
84096
84296
|
preliminary: chunk.preliminary,
|
|
84097
84297
|
providerExecuted: chunk.providerExecuted,
|
|
84098
84298
|
providerMetadata: chunk.providerMetadata,
|
|
84099
|
-
title: toolInvocation.title
|
|
84100
|
-
toolMetadata: toolInvocation.toolMetadata
|
|
84299
|
+
title: toolInvocation.title
|
|
84101
84300
|
});
|
|
84102
84301
|
} else {
|
|
84103
84302
|
updateToolPart({
|
|
@@ -84109,8 +84308,7 @@ function processUIMessageStream({
|
|
|
84109
84308
|
providerExecuted: chunk.providerExecuted,
|
|
84110
84309
|
preliminary: chunk.preliminary,
|
|
84111
84310
|
providerMetadata: chunk.providerMetadata,
|
|
84112
|
-
title: toolInvocation.title
|
|
84113
|
-
toolMetadata: toolInvocation.toolMetadata
|
|
84311
|
+
title: toolInvocation.title
|
|
84114
84312
|
});
|
|
84115
84313
|
}
|
|
84116
84314
|
write();
|
|
@@ -84127,8 +84325,7 @@ function processUIMessageStream({
|
|
|
84127
84325
|
errorText: chunk.errorText,
|
|
84128
84326
|
providerExecuted: chunk.providerExecuted,
|
|
84129
84327
|
providerMetadata: chunk.providerMetadata,
|
|
84130
|
-
title: toolInvocation.title
|
|
84131
|
-
toolMetadata: toolInvocation.toolMetadata
|
|
84328
|
+
title: toolInvocation.title
|
|
84132
84329
|
});
|
|
84133
84330
|
} else {
|
|
84134
84331
|
updateToolPart({
|
|
@@ -84140,8 +84337,7 @@ function processUIMessageStream({
|
|
|
84140
84337
|
errorText: chunk.errorText,
|
|
84141
84338
|
providerExecuted: chunk.providerExecuted,
|
|
84142
84339
|
providerMetadata: chunk.providerMetadata,
|
|
84143
|
-
title: toolInvocation.title
|
|
84144
|
-
toolMetadata: toolInvocation.toolMetadata
|
|
84340
|
+
title: toolInvocation.title
|
|
84145
84341
|
});
|
|
84146
84342
|
}
|
|
84147
84343
|
write();
|
|
@@ -84599,8 +84795,7 @@ function runToolsTransformation({
|
|
|
84599
84795
|
input: toolCall.input,
|
|
84600
84796
|
error: getErrorMessage2(toolCall.error),
|
|
84601
84797
|
dynamic: true,
|
|
84602
|
-
title: toolCall.title
|
|
84603
|
-
...toolCall.toolMetadata != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
84798
|
+
title: toolCall.title
|
|
84604
84799
|
});
|
|
84605
84800
|
break;
|
|
84606
84801
|
}
|
|
@@ -84668,7 +84863,6 @@ function runToolsTransformation({
|
|
|
84668
84863
|
}
|
|
84669
84864
|
case "tool-result": {
|
|
84670
84865
|
const toolName = chunk.toolName;
|
|
84671
|
-
const toolCall = toolCallsByToolCallId.get(chunk.toolCallId);
|
|
84672
84866
|
if (chunk.isError) {
|
|
84673
84867
|
toolResultsStreamController.enqueue({
|
|
84674
84868
|
type: "tool-error",
|
|
@@ -84678,8 +84872,7 @@ function runToolsTransformation({
|
|
|
84678
84872
|
providerExecuted: true,
|
|
84679
84873
|
error: chunk.result,
|
|
84680
84874
|
dynamic: chunk.dynamic,
|
|
84681
|
-
...chunk.providerMetadata != null ? { providerMetadata: chunk.providerMetadata } : {}
|
|
84682
|
-
...(toolCall == null ? undefined : toolCall.toolMetadata) != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
84875
|
+
...chunk.providerMetadata != null ? { providerMetadata: chunk.providerMetadata } : {}
|
|
84683
84876
|
});
|
|
84684
84877
|
} else {
|
|
84685
84878
|
controller.enqueue({
|
|
@@ -84690,8 +84883,7 @@ function runToolsTransformation({
|
|
|
84690
84883
|
output: chunk.result,
|
|
84691
84884
|
providerExecuted: true,
|
|
84692
84885
|
dynamic: chunk.dynamic,
|
|
84693
|
-
...chunk.providerMetadata != null ? { providerMetadata: chunk.providerMetadata } : {}
|
|
84694
|
-
...(toolCall == null ? undefined : toolCall.toolMetadata) != null ? { toolMetadata: toolCall.toolMetadata } : {}
|
|
84886
|
+
...chunk.providerMetadata != null ? { providerMetadata: chunk.providerMetadata } : {}
|
|
84695
84887
|
});
|
|
84696
84888
|
}
|
|
84697
84889
|
break;
|
|
@@ -85474,7 +85666,7 @@ async function embed({
|
|
|
85474
85666
|
}),
|
|
85475
85667
|
tracer,
|
|
85476
85668
|
fn: async (doEmbedSpan) => {
|
|
85477
|
-
var _a21
|
|
85669
|
+
var _a21;
|
|
85478
85670
|
const modelResponse = await model.doEmbed({
|
|
85479
85671
|
values: [value],
|
|
85480
85672
|
abortSignal,
|
|
@@ -85495,7 +85687,7 @@ async function embed({
|
|
|
85495
85687
|
return {
|
|
85496
85688
|
embedding: embedding2,
|
|
85497
85689
|
usage: usage2,
|
|
85498
|
-
warnings:
|
|
85690
|
+
warnings: modelResponse.warnings,
|
|
85499
85691
|
providerMetadata: modelResponse.providerMetadata,
|
|
85500
85692
|
response: modelResponse.response
|
|
85501
85693
|
};
|
|
@@ -85591,7 +85783,7 @@ async function embedMany({
|
|
|
85591
85783
|
}),
|
|
85592
85784
|
tracer,
|
|
85593
85785
|
fn: async (doEmbedSpan) => {
|
|
85594
|
-
var _a222
|
|
85786
|
+
var _a222;
|
|
85595
85787
|
const modelResponse = await model.doEmbed({
|
|
85596
85788
|
values,
|
|
85597
85789
|
abortSignal,
|
|
@@ -85612,7 +85804,7 @@ async function embedMany({
|
|
|
85612
85804
|
return {
|
|
85613
85805
|
embeddings: embeddings3,
|
|
85614
85806
|
usage: usage2,
|
|
85615
|
-
warnings:
|
|
85807
|
+
warnings: modelResponse.warnings,
|
|
85616
85808
|
providerMetadata: modelResponse.providerMetadata,
|
|
85617
85809
|
response: modelResponse.response
|
|
85618
85810
|
};
|
|
@@ -85669,7 +85861,7 @@ async function embedMany({
|
|
|
85669
85861
|
}),
|
|
85670
85862
|
tracer,
|
|
85671
85863
|
fn: async (doEmbedSpan) => {
|
|
85672
|
-
var _a222
|
|
85864
|
+
var _a222;
|
|
85673
85865
|
const modelResponse = await model.doEmbed({
|
|
85674
85866
|
values: chunk,
|
|
85675
85867
|
abortSignal,
|
|
@@ -85690,7 +85882,7 @@ async function embedMany({
|
|
|
85690
85882
|
return {
|
|
85691
85883
|
embeddings: embeddings2,
|
|
85692
85884
|
usage,
|
|
85693
|
-
warnings:
|
|
85885
|
+
warnings: modelResponse.warnings,
|
|
85694
85886
|
providerMetadata: modelResponse.providerMetadata,
|
|
85695
85887
|
response: modelResponse.response
|
|
85696
85888
|
};
|
|
@@ -87804,7 +87996,7 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
87804
87996
|
const bytes = typeof data === "string" ? convertBase64ToUint8Array(data) : data;
|
|
87805
87997
|
const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127;
|
|
87806
87998
|
return bytes.slice(id3Size + 10);
|
|
87807
|
-
}, VERSION3 = "6.0.
|
|
87999
|
+
}, VERSION3 = "6.0.175", download = async ({
|
|
87808
88000
|
url: url2,
|
|
87809
88001
|
maxBytes,
|
|
87810
88002
|
abortSignal
|
|
@@ -87894,7 +88086,7 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
87894
88086
|
const schema = asSchema(inputSchema);
|
|
87895
88087
|
return {
|
|
87896
88088
|
name: "object",
|
|
87897
|
-
responseFormat:
|
|
88089
|
+
responseFormat: resolve3(schema.jsonSchema).then((jsonSchema2) => ({
|
|
87898
88090
|
type: "json",
|
|
87899
88091
|
schema: jsonSchema2,
|
|
87900
88092
|
...name21 != null && { name: name21 },
|
|
@@ -87955,7 +88147,7 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
87955
88147
|
const elementSchema = asSchema(inputElementSchema);
|
|
87956
88148
|
return {
|
|
87957
88149
|
name: "array",
|
|
87958
|
-
responseFormat:
|
|
88150
|
+
responseFormat: resolve3(elementSchema.jsonSchema).then((jsonSchema2) => {
|
|
87959
88151
|
const { $schema, ...itemSchema } = jsonSchema2;
|
|
87960
88152
|
return {
|
|
87961
88153
|
type: "json",
|
|
@@ -88312,7 +88504,7 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
88312
88504
|
}
|
|
88313
88505
|
return this._output;
|
|
88314
88506
|
}
|
|
88315
|
-
}, JsonToSseTransformStream, UI_MESSAGE_STREAM_HEADERS,
|
|
88507
|
+
}, JsonToSseTransformStream, UI_MESSAGE_STREAM_HEADERS, uiMessageChunkSchema, isToolOrDynamicToolUIPart, getToolOrDynamicToolName, originalGenerateId2, DefaultStreamTextResult = class {
|
|
88316
88508
|
constructor({
|
|
88317
88509
|
model,
|
|
88318
88510
|
telemetry,
|
|
@@ -89560,7 +89752,6 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89560
89752
|
toolName: part.toolName,
|
|
89561
89753
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
89562
89754
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
89563
|
-
...part.toolMetadata != null ? { toolMetadata: part.toolMetadata } : {},
|
|
89564
89755
|
...dynamic != null ? { dynamic } : {},
|
|
89565
89756
|
...part.title != null ? { title: part.title } : {}
|
|
89566
89757
|
});
|
|
@@ -89584,7 +89775,6 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89584
89775
|
input: part.input,
|
|
89585
89776
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
89586
89777
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
89587
|
-
...part.toolMetadata != null ? { toolMetadata: part.toolMetadata } : {},
|
|
89588
89778
|
...dynamic != null ? { dynamic } : {},
|
|
89589
89779
|
errorText: onError(part.error),
|
|
89590
89780
|
...part.title != null ? { title: part.title } : {}
|
|
@@ -89597,7 +89787,6 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89597
89787
|
input: part.input,
|
|
89598
89788
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
89599
89789
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
89600
|
-
...part.toolMetadata != null ? { toolMetadata: part.toolMetadata } : {},
|
|
89601
89790
|
...dynamic != null ? { dynamic } : {},
|
|
89602
89791
|
...part.title != null ? { title: part.title } : {}
|
|
89603
89792
|
});
|
|
@@ -89620,7 +89809,6 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89620
89809
|
output: part.output,
|
|
89621
89810
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
89622
89811
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
89623
|
-
...part.toolMetadata != null ? { toolMetadata: part.toolMetadata } : {},
|
|
89624
89812
|
...part.preliminary != null ? { preliminary: part.preliminary } : {},
|
|
89625
89813
|
...dynamic != null ? { dynamic } : {}
|
|
89626
89814
|
});
|
|
@@ -89634,7 +89822,6 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89634
89822
|
errorText: part.providerExecuted ? typeof part.error === "string" ? part.error : JSON.stringify(part.error) : onError(part.error),
|
|
89635
89823
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
89636
89824
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
89637
|
-
...part.toolMetadata != null ? { toolMetadata: part.toolMetadata } : {},
|
|
89638
89825
|
...dynamic != null ? { dynamic } : {}
|
|
89639
89826
|
});
|
|
89640
89827
|
break;
|
|
@@ -89808,21 +89995,10 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89808
89995
|
...options
|
|
89809
89996
|
};
|
|
89810
89997
|
const preparedCallArgs = (_d2 = await ((_c2 = (_b16 = this.settings).prepareCall) == null ? undefined : _c2.call(_b16, baseCallArgs))) != null ? _d2 : baseCallArgs;
|
|
89811
|
-
const {
|
|
89812
|
-
instructions,
|
|
89813
|
-
allowSystemInMessages,
|
|
89814
|
-
messages,
|
|
89815
|
-
prompt,
|
|
89816
|
-
...callArgs
|
|
89817
|
-
} = preparedCallArgs;
|
|
89998
|
+
const { instructions, messages, prompt, ...callArgs } = preparedCallArgs;
|
|
89818
89999
|
return {
|
|
89819
90000
|
...callArgs,
|
|
89820
|
-
...{
|
|
89821
|
-
system: instructions,
|
|
89822
|
-
allowSystemInMessages,
|
|
89823
|
-
messages,
|
|
89824
|
-
prompt
|
|
89825
|
-
}
|
|
90001
|
+
...{ system: instructions, messages, prompt }
|
|
89826
90002
|
};
|
|
89827
90003
|
}
|
|
89828
90004
|
mergeOnStepFinishCallbacks(methodCallback) {
|
|
@@ -89863,7 +90039,7 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
89863
90039
|
onStepFinish: this.mergeOnStepFinishCallbacks(onStepFinish)
|
|
89864
90040
|
});
|
|
89865
90041
|
}
|
|
89866
|
-
},
|
|
90042
|
+
}, uiMessagesSchema, DefaultEmbedResult = class {
|
|
89867
90043
|
constructor(options) {
|
|
89868
90044
|
this.value = options.value;
|
|
89869
90045
|
this.embedding = options.embedding;
|
|
@@ -90868,9 +91044,9 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
90868
91044
|
...options
|
|
90869
91045
|
}) {
|
|
90870
91046
|
var _a21, _b16, _c2, _d2, _e2;
|
|
90871
|
-
const resolvedBody = await
|
|
90872
|
-
const resolvedHeaders = await
|
|
90873
|
-
const resolvedCredentials = await
|
|
91047
|
+
const resolvedBody = await resolve3(this.body);
|
|
91048
|
+
const resolvedHeaders = await resolve3(this.headers);
|
|
91049
|
+
const resolvedCredentials = await resolve3(this.credentials);
|
|
90874
91050
|
const baseHeaders = {
|
|
90875
91051
|
...normalizeHeaders(resolvedHeaders),
|
|
90876
91052
|
...normalizeHeaders(options.headers)
|
|
@@ -90918,9 +91094,9 @@ var import_api2, import_api3, __defProp4, __export4 = (target, all) => {
|
|
|
90918
91094
|
}
|
|
90919
91095
|
async reconnectToStream(options) {
|
|
90920
91096
|
var _a21, _b16, _c2, _d2, _e2;
|
|
90921
|
-
const resolvedBody = await
|
|
90922
|
-
const resolvedHeaders = await
|
|
90923
|
-
const resolvedCredentials = await
|
|
91097
|
+
const resolvedBody = await resolve3(this.body);
|
|
91098
|
+
const resolvedHeaders = await resolve3(this.headers);
|
|
91099
|
+
const resolvedCredentials = await resolve3(this.credentials);
|
|
90924
91100
|
const baseHeaders = {
|
|
90925
91101
|
...normalizeHeaders(resolvedHeaders),
|
|
90926
91102
|
...normalizeHeaders(options.headers)
|
|
@@ -91371,7 +91547,6 @@ var init_dist7 = __esm(() => {
|
|
|
91371
91547
|
init_dist6();
|
|
91372
91548
|
init_dist3();
|
|
91373
91549
|
init_dist3();
|
|
91374
|
-
init_dist6();
|
|
91375
91550
|
init_dist5();
|
|
91376
91551
|
init_dist5();
|
|
91377
91552
|
init_dist5();
|
|
@@ -92231,7 +92406,6 @@ var init_dist7 = __esm(() => {
|
|
|
92231
92406
|
"x-vercel-ai-ui-message-stream": "v1",
|
|
92232
92407
|
"x-accel-buffering": "no"
|
|
92233
92408
|
};
|
|
92234
|
-
toolMetadataSchema = exports_external2.record(exports_external2.string(), jsonValueSchema.optional());
|
|
92235
92409
|
uiMessageChunkSchema = lazySchema(() => zodSchema(exports_external2.union([
|
|
92236
92410
|
exports_external2.strictObject({
|
|
92237
92411
|
type: exports_external2.literal("text-start"),
|
|
@@ -92259,7 +92433,6 @@ var init_dist7 = __esm(() => {
|
|
|
92259
92433
|
toolName: exports_external2.string(),
|
|
92260
92434
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92261
92435
|
providerMetadata: providerMetadataSchema.optional(),
|
|
92262
|
-
toolMetadata: toolMetadataSchema.optional(),
|
|
92263
92436
|
dynamic: exports_external2.boolean().optional(),
|
|
92264
92437
|
title: exports_external2.string().optional()
|
|
92265
92438
|
}),
|
|
@@ -92275,7 +92448,6 @@ var init_dist7 = __esm(() => {
|
|
|
92275
92448
|
input: exports_external2.unknown(),
|
|
92276
92449
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92277
92450
|
providerMetadata: providerMetadataSchema.optional(),
|
|
92278
|
-
toolMetadata: toolMetadataSchema.optional(),
|
|
92279
92451
|
dynamic: exports_external2.boolean().optional(),
|
|
92280
92452
|
title: exports_external2.string().optional()
|
|
92281
92453
|
}),
|
|
@@ -92286,7 +92458,6 @@ var init_dist7 = __esm(() => {
|
|
|
92286
92458
|
input: exports_external2.unknown(),
|
|
92287
92459
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92288
92460
|
providerMetadata: providerMetadataSchema.optional(),
|
|
92289
|
-
toolMetadata: toolMetadataSchema.optional(),
|
|
92290
92461
|
dynamic: exports_external2.boolean().optional(),
|
|
92291
92462
|
errorText: exports_external2.string(),
|
|
92292
92463
|
title: exports_external2.string().optional()
|
|
@@ -92302,7 +92473,6 @@ var init_dist7 = __esm(() => {
|
|
|
92302
92473
|
output: exports_external2.unknown(),
|
|
92303
92474
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92304
92475
|
providerMetadata: providerMetadataSchema.optional(),
|
|
92305
|
-
toolMetadata: toolMetadataSchema.optional(),
|
|
92306
92476
|
dynamic: exports_external2.boolean().optional(),
|
|
92307
92477
|
preliminary: exports_external2.boolean().optional()
|
|
92308
92478
|
}),
|
|
@@ -92312,7 +92482,6 @@ var init_dist7 = __esm(() => {
|
|
|
92312
92482
|
errorText: exports_external2.string(),
|
|
92313
92483
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92314
92484
|
providerMetadata: providerMetadataSchema.optional(),
|
|
92315
|
-
toolMetadata: toolMetadataSchema.optional(),
|
|
92316
92485
|
dynamic: exports_external2.boolean().optional()
|
|
92317
92486
|
}),
|
|
92318
92487
|
exports_external2.strictObject({
|
|
@@ -92400,7 +92569,6 @@ var init_dist7 = __esm(() => {
|
|
|
92400
92569
|
prefix: "aitxt",
|
|
92401
92570
|
size: 24
|
|
92402
92571
|
});
|
|
92403
|
-
toolMetadataSchema2 = exports_external2.record(exports_external2.string(), jsonValueSchema.optional());
|
|
92404
92572
|
uiMessagesSchema = lazySchema(() => zodSchema(exports_external2.array(exports_external2.object({
|
|
92405
92573
|
id: exports_external2.string(),
|
|
92406
92574
|
role: exports_external2.enum(["system", "user", "assistant"]),
|
|
@@ -92452,7 +92620,6 @@ var init_dist7 = __esm(() => {
|
|
|
92452
92620
|
type: exports_external2.literal("dynamic-tool"),
|
|
92453
92621
|
toolName: exports_external2.string(),
|
|
92454
92622
|
toolCallId: exports_external2.string(),
|
|
92455
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92456
92623
|
state: exports_external2.literal("input-streaming"),
|
|
92457
92624
|
input: exports_external2.unknown().optional(),
|
|
92458
92625
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92465,7 +92632,6 @@ var init_dist7 = __esm(() => {
|
|
|
92465
92632
|
type: exports_external2.literal("dynamic-tool"),
|
|
92466
92633
|
toolName: exports_external2.string(),
|
|
92467
92634
|
toolCallId: exports_external2.string(),
|
|
92468
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92469
92635
|
state: exports_external2.literal("input-available"),
|
|
92470
92636
|
input: exports_external2.unknown(),
|
|
92471
92637
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92478,7 +92644,6 @@ var init_dist7 = __esm(() => {
|
|
|
92478
92644
|
type: exports_external2.literal("dynamic-tool"),
|
|
92479
92645
|
toolName: exports_external2.string(),
|
|
92480
92646
|
toolCallId: exports_external2.string(),
|
|
92481
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92482
92647
|
state: exports_external2.literal("approval-requested"),
|
|
92483
92648
|
input: exports_external2.unknown(),
|
|
92484
92649
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92495,7 +92660,6 @@ var init_dist7 = __esm(() => {
|
|
|
92495
92660
|
type: exports_external2.literal("dynamic-tool"),
|
|
92496
92661
|
toolName: exports_external2.string(),
|
|
92497
92662
|
toolCallId: exports_external2.string(),
|
|
92498
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92499
92663
|
state: exports_external2.literal("approval-responded"),
|
|
92500
92664
|
input: exports_external2.unknown(),
|
|
92501
92665
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92512,7 +92676,6 @@ var init_dist7 = __esm(() => {
|
|
|
92512
92676
|
type: exports_external2.literal("dynamic-tool"),
|
|
92513
92677
|
toolName: exports_external2.string(),
|
|
92514
92678
|
toolCallId: exports_external2.string(),
|
|
92515
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92516
92679
|
state: exports_external2.literal("output-available"),
|
|
92517
92680
|
input: exports_external2.unknown(),
|
|
92518
92681
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92531,9 +92694,8 @@ var init_dist7 = __esm(() => {
|
|
|
92531
92694
|
type: exports_external2.literal("dynamic-tool"),
|
|
92532
92695
|
toolName: exports_external2.string(),
|
|
92533
92696
|
toolCallId: exports_external2.string(),
|
|
92534
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92535
92697
|
state: exports_external2.literal("output-error"),
|
|
92536
|
-
input: exports_external2.unknown()
|
|
92698
|
+
input: exports_external2.unknown(),
|
|
92537
92699
|
rawInput: exports_external2.unknown().optional(),
|
|
92538
92700
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92539
92701
|
output: exports_external2.never().optional(),
|
|
@@ -92550,7 +92712,6 @@ var init_dist7 = __esm(() => {
|
|
|
92550
92712
|
type: exports_external2.literal("dynamic-tool"),
|
|
92551
92713
|
toolName: exports_external2.string(),
|
|
92552
92714
|
toolCallId: exports_external2.string(),
|
|
92553
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92554
92715
|
state: exports_external2.literal("output-denied"),
|
|
92555
92716
|
input: exports_external2.unknown(),
|
|
92556
92717
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92566,7 +92727,6 @@ var init_dist7 = __esm(() => {
|
|
|
92566
92727
|
exports_external2.object({
|
|
92567
92728
|
type: exports_external2.string().startsWith("tool-"),
|
|
92568
92729
|
toolCallId: exports_external2.string(),
|
|
92569
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92570
92730
|
state: exports_external2.literal("input-streaming"),
|
|
92571
92731
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92572
92732
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
@@ -92578,7 +92738,6 @@ var init_dist7 = __esm(() => {
|
|
|
92578
92738
|
exports_external2.object({
|
|
92579
92739
|
type: exports_external2.string().startsWith("tool-"),
|
|
92580
92740
|
toolCallId: exports_external2.string(),
|
|
92581
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92582
92741
|
state: exports_external2.literal("input-available"),
|
|
92583
92742
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92584
92743
|
input: exports_external2.unknown(),
|
|
@@ -92590,7 +92749,6 @@ var init_dist7 = __esm(() => {
|
|
|
92590
92749
|
exports_external2.object({
|
|
92591
92750
|
type: exports_external2.string().startsWith("tool-"),
|
|
92592
92751
|
toolCallId: exports_external2.string(),
|
|
92593
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92594
92752
|
state: exports_external2.literal("approval-requested"),
|
|
92595
92753
|
input: exports_external2.unknown(),
|
|
92596
92754
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92606,7 +92764,6 @@ var init_dist7 = __esm(() => {
|
|
|
92606
92764
|
exports_external2.object({
|
|
92607
92765
|
type: exports_external2.string().startsWith("tool-"),
|
|
92608
92766
|
toolCallId: exports_external2.string(),
|
|
92609
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92610
92767
|
state: exports_external2.literal("approval-responded"),
|
|
92611
92768
|
input: exports_external2.unknown(),
|
|
92612
92769
|
providerExecuted: exports_external2.boolean().optional(),
|
|
@@ -92622,7 +92779,6 @@ var init_dist7 = __esm(() => {
|
|
|
92622
92779
|
exports_external2.object({
|
|
92623
92780
|
type: exports_external2.string().startsWith("tool-"),
|
|
92624
92781
|
toolCallId: exports_external2.string(),
|
|
92625
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92626
92782
|
state: exports_external2.literal("output-available"),
|
|
92627
92783
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92628
92784
|
input: exports_external2.unknown(),
|
|
@@ -92640,10 +92796,9 @@ var init_dist7 = __esm(() => {
|
|
|
92640
92796
|
exports_external2.object({
|
|
92641
92797
|
type: exports_external2.string().startsWith("tool-"),
|
|
92642
92798
|
toolCallId: exports_external2.string(),
|
|
92643
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92644
92799
|
state: exports_external2.literal("output-error"),
|
|
92645
92800
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92646
|
-
input: exports_external2.unknown()
|
|
92801
|
+
input: exports_external2.unknown(),
|
|
92647
92802
|
rawInput: exports_external2.unknown().optional(),
|
|
92648
92803
|
output: exports_external2.never().optional(),
|
|
92649
92804
|
errorText: exports_external2.string(),
|
|
@@ -92658,7 +92813,6 @@ var init_dist7 = __esm(() => {
|
|
|
92658
92813
|
exports_external2.object({
|
|
92659
92814
|
type: exports_external2.string().startsWith("tool-"),
|
|
92660
92815
|
toolCallId: exports_external2.string(),
|
|
92661
|
-
toolMetadata: toolMetadataSchema2.optional(),
|
|
92662
92816
|
state: exports_external2.literal("output-denied"),
|
|
92663
92817
|
providerExecuted: exports_external2.boolean().optional(),
|
|
92664
92818
|
input: exports_external2.unknown(),
|
|
@@ -93163,7 +93317,7 @@ __export(exports_session_converter, {
|
|
|
93163
93317
|
convertSessionToScenario: () => convertSessionToScenario,
|
|
93164
93318
|
convertSessionFile: () => convertSessionFile
|
|
93165
93319
|
});
|
|
93166
|
-
import { readFileSync as
|
|
93320
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
93167
93321
|
import { extname } from "path";
|
|
93168
93322
|
function parseRrwebSession(events) {
|
|
93169
93323
|
const result = [];
|
|
@@ -93299,9 +93453,9 @@ async function convertSessionToScenario(events, options) {
|
|
|
93299
93453
|
const name21 = options?.name ?? `Recorded session ${new Date().toISOString().slice(0, 10)}`;
|
|
93300
93454
|
const targetPath = extractTargetPath(events);
|
|
93301
93455
|
let steps;
|
|
93302
|
-
if (options?.model && (process.env["ANTHROPIC_API_KEY"] || process.env["OPENAI_API_KEY"] || process.env["GOOGLE_API_KEY"])) {
|
|
93456
|
+
if (options?.model && (process.env["ANTHROPIC_API_KEY"] || process.env["OPENAI_API_KEY"] || process.env["GOOGLE_API_KEY"] || process.env["CEREBRAS_API_KEY"] || process.env["ZAI_API_KEY"])) {
|
|
93303
93457
|
try {
|
|
93304
|
-
const { callOpenAICompatible: callOpenAICompatible2, detectProvider: detectProvider2 } = await Promise.resolve().then(() => (init_ai_client(), exports_ai_client));
|
|
93458
|
+
const { callOpenAICompatible: callOpenAICompatible2, createOpenAICompatibleConfig: createOpenAICompatibleConfig2, detectProvider: detectProvider2 } = await Promise.resolve().then(() => (init_ai_client(), exports_ai_client));
|
|
93305
93459
|
const model = options.model;
|
|
93306
93460
|
const provider = detectProvider2(model);
|
|
93307
93461
|
const condensed = events.filter((e2) => e2.type !== "network").map((e2) => `[${e2.type}] ${e2.url ?? e2.selector ?? e2.value ?? ""}`).slice(0, 100).join(`
|
|
@@ -93311,10 +93465,9 @@ async function convertSessionToScenario(events, options) {
|
|
|
93311
93465
|
Events:
|
|
93312
93466
|
${condensed}`;
|
|
93313
93467
|
let rawText = "";
|
|
93314
|
-
if (provider
|
|
93315
|
-
const
|
|
93316
|
-
const
|
|
93317
|
-
const resp = await callOpenAICompatible2({ baseUrl, apiKey, model, system: "You are a QA engineer.", messages: [{ role: "user", content: prompt }], tools: [], maxTokens: 1024 });
|
|
93468
|
+
if (provider !== "anthropic") {
|
|
93469
|
+
const compat2 = createOpenAICompatibleConfig2(provider);
|
|
93470
|
+
const resp = await callOpenAICompatible2({ baseUrl: compat2.baseUrl, apiKey: compat2.apiKey, model, system: "You are a QA engineer.", messages: [{ role: "user", content: prompt }], tools: [], maxTokens: 1024 });
|
|
93318
93471
|
const block = resp.content.find((b2) => b2.type === "text");
|
|
93319
93472
|
rawText = block?.text ?? "";
|
|
93320
93473
|
} else {
|
|
@@ -93349,7 +93502,7 @@ ${condensed}`;
|
|
|
93349
93502
|
};
|
|
93350
93503
|
}
|
|
93351
93504
|
async function convertSessionFile(filePath, format, options) {
|
|
93352
|
-
const raw =
|
|
93505
|
+
const raw = readFileSync9(filePath, "utf-8");
|
|
93353
93506
|
let parsed;
|
|
93354
93507
|
try {
|
|
93355
93508
|
parsed = JSON.parse(raw);
|
|
@@ -93383,7 +93536,7 @@ function detectSessionFormat(filePath) {
|
|
|
93383
93536
|
if (ext === ".har")
|
|
93384
93537
|
return "har";
|
|
93385
93538
|
try {
|
|
93386
|
-
const content =
|
|
93539
|
+
const content = readFileSync9(filePath, "utf-8").trim();
|
|
93387
93540
|
const parsed = JSON.parse(content);
|
|
93388
93541
|
if (Array.isArray(parsed) && parsed[0]?.type !== undefined && typeof parsed[0]?.timestamp === "number") {
|
|
93389
93542
|
return "rrweb";
|
|
@@ -93710,7 +93863,7 @@ async function runHybridScenario(scenario, options) {
|
|
|
93710
93863
|
const stepStart = Date.now();
|
|
93711
93864
|
if (step.type === "ai" || step.type === "ai_verify") {
|
|
93712
93865
|
const model = resolveModel(step.model ?? scenario.model ?? config2.defaultModel);
|
|
93713
|
-
const client = createClientForModel(model, options?.apiKey
|
|
93866
|
+
const client = createClientForModel(model, resolveProviderApiKeyForModel(model, options?.apiKey, config2.anthropicApiKey));
|
|
93714
93867
|
const instruction = step.type === "ai_verify" ? `Verify the following assertion about the current page state: "${step.assertion}". Do NOT navigate. Just inspect the page and call report_result with pass or fail.` : step.instruction;
|
|
93715
93868
|
const syntheticScenario = {
|
|
93716
93869
|
id: `hybrid-step-${i2}`,
|
|
@@ -93827,7 +93980,7 @@ import chalk6 from "chalk";
|
|
|
93827
93980
|
// package.json
|
|
93828
93981
|
var package_default = {
|
|
93829
93982
|
name: "@hasna/testers",
|
|
93830
|
-
version: "0.0.
|
|
93983
|
+
version: "0.0.36",
|
|
93831
93984
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
93832
93985
|
type: "module",
|
|
93833
93986
|
main: "dist/index.js",
|
|
@@ -93851,10 +94004,10 @@ var package_default = {
|
|
|
93851
94004
|
],
|
|
93852
94005
|
scripts: {
|
|
93853
94006
|
build: "bun run build:dashboard && bun run build:cli && bun run build:mcp && bun run build:server && bun run build:lib && bun run build:types",
|
|
93854
|
-
"build:cli": "bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external @anthropic-ai/sdk --external playwright --external @hasna/browser",
|
|
93855
|
-
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @anthropic-ai/sdk --external playwright --external @hasna/browser",
|
|
93856
|
-
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --external @anthropic-ai/sdk --external playwright --external @hasna/browser",
|
|
93857
|
-
"build:lib": "bun build src/index.ts --outdir dist --target bun --external playwright --external @anthropic-ai/sdk --external @modelcontextprotocol/sdk --external @hasna/browser",
|
|
94007
|
+
"build:cli": "bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external @anthropic-ai/sdk --external playwright --external @hasna/browser --external @hasna/sandboxes",
|
|
94008
|
+
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @anthropic-ai/sdk --external playwright --external @hasna/browser --external @hasna/sandboxes",
|
|
94009
|
+
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --external @anthropic-ai/sdk --external playwright --external @hasna/browser --external @hasna/sandboxes",
|
|
94010
|
+
"build:lib": "bun build src/index.ts --outdir dist --target bun --external playwright --external @anthropic-ai/sdk --external @modelcontextprotocol/sdk --external @hasna/browser --external @hasna/sandboxes",
|
|
93858
94011
|
"build:types": "NODE_OPTIONS='--max-old-space-size=8192' tsc --emitDeclarationOnly --outDir dist --skipLibCheck || true",
|
|
93859
94012
|
"build:dashboard": "cd dashboard && bun run build",
|
|
93860
94013
|
"build:ext": "cd extension && bun run build",
|
|
@@ -93868,10 +94021,11 @@ var package_default = {
|
|
|
93868
94021
|
},
|
|
93869
94022
|
dependencies: {
|
|
93870
94023
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
93871
|
-
"@hasna/browser": "^0.4.
|
|
94024
|
+
"@hasna/browser": "^0.4.12",
|
|
93872
94025
|
"@hasna/cloud": "^0.1.24",
|
|
93873
94026
|
"@hasna/contacts": "^0.6.8",
|
|
93874
94027
|
"@hasna/projects": "^0.1.42",
|
|
94028
|
+
"@hasna/sandboxes": "^0.1.27",
|
|
93875
94029
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
93876
94030
|
ai: "^6.0.175",
|
|
93877
94031
|
chalk: "^5.4.1",
|
|
@@ -93924,9 +94078,9 @@ init_todos_connector();
|
|
|
93924
94078
|
init_browser();
|
|
93925
94079
|
import { render, Box, Text, useInput, useApp } from "ink";
|
|
93926
94080
|
import React, { useState } from "react";
|
|
93927
|
-
import { readFileSync as
|
|
94081
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
93928
94082
|
import { createInterface } from "readline";
|
|
93929
|
-
import { join as
|
|
94083
|
+
import { join as join20, resolve as resolve4 } from "path";
|
|
93930
94084
|
|
|
93931
94085
|
// src/lib/init.ts
|
|
93932
94086
|
init_paths();
|
|
@@ -95655,9 +95809,13 @@ init_flows();
|
|
|
95655
95809
|
init_workflows();
|
|
95656
95810
|
|
|
95657
95811
|
// src/lib/workflow-runner.ts
|
|
95812
|
+
init_database();
|
|
95658
95813
|
init_workflows();
|
|
95659
95814
|
init_personas();
|
|
95660
95815
|
init_runner();
|
|
95816
|
+
import { mkdtempSync, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
95817
|
+
import { tmpdir } from "os";
|
|
95818
|
+
import { join as join16 } from "path";
|
|
95661
95819
|
function buildWorkflowRunPlan(workflow, options) {
|
|
95662
95820
|
const runOptions = {
|
|
95663
95821
|
url: options.url,
|
|
@@ -95674,10 +95832,10 @@ function buildWorkflowRunPlan(workflow, options) {
|
|
|
95674
95832
|
return {
|
|
95675
95833
|
workflow,
|
|
95676
95834
|
runOptions,
|
|
95677
|
-
|
|
95835
|
+
sandbox: workflow.execution.target === "sandbox" ? buildSandboxPlan(workflow, workflow.execution, runOptions) : null
|
|
95678
95836
|
};
|
|
95679
95837
|
}
|
|
95680
|
-
async function runTestingWorkflow(workflowId, options) {
|
|
95838
|
+
async function runTestingWorkflow(workflowId, options, dependencies = {}) {
|
|
95681
95839
|
const workflow = getTestingWorkflow(workflowId);
|
|
95682
95840
|
if (!workflow)
|
|
95683
95841
|
throw new Error(`Testing workflow not found: ${workflowId}`);
|
|
@@ -95687,13 +95845,25 @@ async function runTestingWorkflow(workflowId, options) {
|
|
|
95687
95845
|
const plan = buildWorkflowRunPlan(workflow, options);
|
|
95688
95846
|
if (options.dryRun)
|
|
95689
95847
|
return { run: null, results: [], plan };
|
|
95690
|
-
if (workflow.execution.target === "
|
|
95691
|
-
const
|
|
95692
|
-
return { run: null, results: [], plan,
|
|
95848
|
+
if (workflow.execution.target === "sandbox") {
|
|
95849
|
+
const sandboxResult = await runViaSandbox(plan, dependencies);
|
|
95850
|
+
return { run: null, results: [], plan, sandboxResult };
|
|
95693
95851
|
}
|
|
95694
|
-
const
|
|
95852
|
+
const runLocal = dependencies.runByFilter ?? runByFilter;
|
|
95853
|
+
const { run, results } = await runLocal(plan.runOptions);
|
|
95695
95854
|
return { run, results, plan };
|
|
95696
95855
|
}
|
|
95856
|
+
function createWorkflowDatabaseBundle(workflow, plan) {
|
|
95857
|
+
if (!plan.sandbox)
|
|
95858
|
+
throw new Error(`Workflow is not configured for sandbox execution: ${workflow.name}`);
|
|
95859
|
+
const localDir = mkdtempSync(join16(tmpdir(), `testers-workflow-${workflow.id.slice(0, 8)}-`));
|
|
95860
|
+
writeFileSync4(join16(localDir, "testers.db"), getDatabase().serialize());
|
|
95861
|
+
return {
|
|
95862
|
+
localDir,
|
|
95863
|
+
remoteDir: plan.sandbox.stateRemoteDir,
|
|
95864
|
+
cleanup: () => rmSync(localDir, { recursive: true, force: true })
|
|
95865
|
+
};
|
|
95866
|
+
}
|
|
95697
95867
|
function validatePersonaIds(workflow) {
|
|
95698
95868
|
for (const personaId of workflow.personaIds) {
|
|
95699
95869
|
if (!getPersona(personaId)) {
|
|
@@ -95701,46 +95871,109 @@ function validatePersonaIds(workflow) {
|
|
|
95701
95871
|
}
|
|
95702
95872
|
}
|
|
95703
95873
|
}
|
|
95704
|
-
function
|
|
95705
|
-
const
|
|
95706
|
-
const
|
|
95707
|
-
|
|
95708
|
-
|
|
95709
|
-
|
|
95874
|
+
function buildSandboxPlan(workflow, execution, runOptions) {
|
|
95875
|
+
const remoteDir = execution.sandboxRemoteDir ?? `/tmp/testers-workflow-${workflow.id.slice(0, 8)}`;
|
|
95876
|
+
const stateRemoteDir = `${remoteDir.replace(/\/+$/, "")}/.testers-state`;
|
|
95877
|
+
return {
|
|
95878
|
+
provider: execution.provider,
|
|
95879
|
+
image: execution.sandboxImage,
|
|
95880
|
+
name: `testers-${workflow.id.slice(0, 8)}`,
|
|
95881
|
+
remoteDir,
|
|
95882
|
+
stateRemoteDir,
|
|
95883
|
+
cleanup: execution.sandboxCleanup ?? "delete",
|
|
95710
95884
|
timeoutMs: execution.timeoutMs,
|
|
95711
|
-
env: execution.env
|
|
95712
|
-
command:
|
|
95713
|
-
|
|
95714
|
-
|
|
95715
|
-
|
|
95716
|
-
|
|
95717
|
-
|
|
95718
|
-
|
|
95719
|
-
|
|
95720
|
-
...runOptions.projectId ? ["--project", runOptions.projectId] : [],
|
|
95721
|
-
...runOptions.model ? ["--model", runOptions.model] : [],
|
|
95722
|
-
"--json"
|
|
95723
|
-
]
|
|
95724
|
-
});
|
|
95725
|
-
return ["connectors", "run", connector, operation, payload];
|
|
95885
|
+
env: execution.env,
|
|
95886
|
+
command: buildSandboxCommand({
|
|
95887
|
+
runOptions,
|
|
95888
|
+
remoteDir,
|
|
95889
|
+
dbPath: `${stateRemoteDir}/testers.db`,
|
|
95890
|
+
setupCommand: execution.setupCommand,
|
|
95891
|
+
packageSpec: execution.packageSpec ?? "@hasna/testers"
|
|
95892
|
+
})
|
|
95893
|
+
};
|
|
95726
95894
|
}
|
|
95727
|
-
|
|
95728
|
-
|
|
95729
|
-
|
|
95730
|
-
|
|
95731
|
-
|
|
95732
|
-
|
|
95733
|
-
|
|
95734
|
-
|
|
95735
|
-
|
|
95736
|
-
|
|
95737
|
-
|
|
95738
|
-
|
|
95739
|
-
|
|
95740
|
-
|
|
95741
|
-
|
|
95895
|
+
function buildSandboxCommand(input) {
|
|
95896
|
+
const args = [
|
|
95897
|
+
"bunx",
|
|
95898
|
+
input.packageSpec,
|
|
95899
|
+
"run",
|
|
95900
|
+
input.runOptions.url,
|
|
95901
|
+
...input.runOptions.scenarioIds?.length ? ["--scenario", input.runOptions.scenarioIds.join(",")] : [],
|
|
95902
|
+
...input.runOptions.tags?.length ? input.runOptions.tags.flatMap((tag) => ["--tag", tag]) : [],
|
|
95903
|
+
...input.runOptions.priority ? ["--priority", input.runOptions.priority] : [],
|
|
95904
|
+
...input.runOptions.projectId ? ["--project", input.runOptions.projectId] : [],
|
|
95905
|
+
...input.runOptions.model ? ["--model", input.runOptions.model] : [],
|
|
95906
|
+
...input.runOptions.headed ? ["--headed"] : [],
|
|
95907
|
+
...input.runOptions.parallel ? ["--parallel", String(input.runOptions.parallel)] : [],
|
|
95908
|
+
...input.runOptions.timeout ? ["--timeout", String(input.runOptions.timeout)] : [],
|
|
95909
|
+
...input.runOptions.personaIds?.length ? ["--persona", input.runOptions.personaIds.join(",")] : [],
|
|
95910
|
+
"--no-auto-generate",
|
|
95911
|
+
"--json"
|
|
95912
|
+
];
|
|
95913
|
+
return [
|
|
95914
|
+
"set -euo pipefail",
|
|
95915
|
+
`mkdir -p ${shellQuote(input.remoteDir)}`,
|
|
95916
|
+
`cd ${shellQuote(input.remoteDir)}`,
|
|
95917
|
+
input.setupCommand,
|
|
95918
|
+
`HASNA_TESTERS_DB_PATH=${shellQuote(input.dbPath)} ${args.map(shellQuote).join(" ")}`
|
|
95919
|
+
].filter(Boolean).join(`
|
|
95920
|
+
`);
|
|
95921
|
+
}
|
|
95922
|
+
async function runViaSandbox(plan, dependencies) {
|
|
95923
|
+
if (!plan.sandbox)
|
|
95924
|
+
throw new Error("Workflow does not have a sandbox plan");
|
|
95925
|
+
const sandboxes = await resolveSandboxesRuntime(dependencies);
|
|
95926
|
+
const createBundle = dependencies.createDatabaseBundle ?? createWorkflowDatabaseBundle;
|
|
95927
|
+
const bundle = createBundle(plan.workflow, plan);
|
|
95928
|
+
try {
|
|
95929
|
+
const raw = await sandboxes.runCommandInSandbox({
|
|
95930
|
+
command: plan.sandbox.command,
|
|
95931
|
+
provider: plan.sandbox.provider,
|
|
95932
|
+
name: plan.sandbox.name,
|
|
95933
|
+
image: plan.sandbox.image,
|
|
95934
|
+
sandboxTimeout: plan.sandbox.timeoutMs,
|
|
95935
|
+
commandTimeoutMs: plan.sandbox.timeoutMs,
|
|
95936
|
+
projectId: plan.workflow.projectId ?? undefined,
|
|
95937
|
+
config: {
|
|
95938
|
+
source: "testers",
|
|
95939
|
+
workflowId: plan.workflow.id,
|
|
95940
|
+
workflowName: plan.workflow.name
|
|
95941
|
+
},
|
|
95942
|
+
sandboxEnvVars: plan.sandbox.env,
|
|
95943
|
+
cleanup: plan.sandbox.cleanup,
|
|
95944
|
+
upload: {
|
|
95945
|
+
localDir: bundle.localDir,
|
|
95946
|
+
remoteDir: bundle.remoteDir
|
|
95947
|
+
}
|
|
95948
|
+
});
|
|
95949
|
+
const exitCode = raw.result.exit_code ?? raw.result.exitCode ?? 0;
|
|
95950
|
+
const stdout = raw.result.stdout ?? "";
|
|
95951
|
+
const stderr = raw.result.stderr ?? "";
|
|
95952
|
+
if (exitCode !== 0) {
|
|
95953
|
+
throw new Error(`Sandbox workflow execution failed (${exitCode}): ${stderr || stdout}`);
|
|
95954
|
+
}
|
|
95955
|
+
return {
|
|
95956
|
+
sandboxId: raw.sandbox.id,
|
|
95957
|
+
sessionId: raw.session.id,
|
|
95958
|
+
exitCode,
|
|
95959
|
+
stdout,
|
|
95960
|
+
stderr,
|
|
95961
|
+
cleanup: raw.cleanup
|
|
95962
|
+
};
|
|
95963
|
+
} finally {
|
|
95964
|
+
bundle.cleanup?.();
|
|
95742
95965
|
}
|
|
95743
|
-
|
|
95966
|
+
}
|
|
95967
|
+
async function resolveSandboxesRuntime(dependencies) {
|
|
95968
|
+
if (dependencies.sandboxes)
|
|
95969
|
+
return dependencies.sandboxes;
|
|
95970
|
+
if (dependencies.createSandboxesSDK)
|
|
95971
|
+
return dependencies.createSandboxesSDK();
|
|
95972
|
+
const mod = await import("@hasna/sandboxes");
|
|
95973
|
+
return mod.createSandboxesSDK();
|
|
95974
|
+
}
|
|
95975
|
+
function shellQuote(value) {
|
|
95976
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
95744
95977
|
}
|
|
95745
95978
|
|
|
95746
95979
|
// src/db/environments.ts
|
|
@@ -95813,111 +96046,19 @@ function getDefaultEnvironment() {
|
|
|
95813
96046
|
|
|
95814
96047
|
// src/cli/index.tsx
|
|
95815
96048
|
init_ci();
|
|
95816
|
-
|
|
95817
|
-
// src/lib/assertions.ts
|
|
95818
|
-
function parseAssertionString(str) {
|
|
95819
|
-
const trimmed = str.trim();
|
|
95820
|
-
if (trimmed === "no-console-errors") {
|
|
95821
|
-
return { type: "no_console_errors", description: "No console errors" };
|
|
95822
|
-
}
|
|
95823
|
-
if (trimmed.startsWith("url:contains:")) {
|
|
95824
|
-
const expected = trimmed.slice("url:contains:".length);
|
|
95825
|
-
return { type: "url_contains", expected, description: `URL contains "${expected}"` };
|
|
95826
|
-
}
|
|
95827
|
-
if (trimmed.startsWith("title:contains:")) {
|
|
95828
|
-
const expected = trimmed.slice("title:contains:".length);
|
|
95829
|
-
return { type: "title_contains", expected, description: `Title contains "${expected}"` };
|
|
95830
|
-
}
|
|
95831
|
-
if (trimmed.startsWith("count:")) {
|
|
95832
|
-
const rest = trimmed.slice("count:".length);
|
|
95833
|
-
const eqIdx = rest.indexOf(" eq:");
|
|
95834
|
-
if (eqIdx === -1) {
|
|
95835
|
-
throw new Error(`Invalid count assertion format: ${str}. Expected "count:<selector> eq:<number>"`);
|
|
95836
|
-
}
|
|
95837
|
-
const selector = rest.slice(0, eqIdx);
|
|
95838
|
-
const expected = parseInt(rest.slice(eqIdx + " eq:".length), 10);
|
|
95839
|
-
return { type: "element_count", selector, expected, description: `${selector} count equals ${expected}` };
|
|
95840
|
-
}
|
|
95841
|
-
if (trimmed.startsWith("text:")) {
|
|
95842
|
-
const rest = trimmed.slice("text:".length);
|
|
95843
|
-
const containsIdx = rest.indexOf(" contains:");
|
|
95844
|
-
const equalsIdx = rest.indexOf(" equals:");
|
|
95845
|
-
if (containsIdx !== -1) {
|
|
95846
|
-
const selector = rest.slice(0, containsIdx);
|
|
95847
|
-
const expected = rest.slice(containsIdx + " contains:".length);
|
|
95848
|
-
return { type: "text_contains", selector, expected, description: `${selector} text contains "${expected}"` };
|
|
95849
|
-
}
|
|
95850
|
-
if (equalsIdx !== -1) {
|
|
95851
|
-
const selector = rest.slice(0, equalsIdx);
|
|
95852
|
-
const expected = rest.slice(equalsIdx + " equals:".length);
|
|
95853
|
-
return { type: "text_equals", selector, expected, description: `${selector} text equals "${expected}"` };
|
|
95854
|
-
}
|
|
95855
|
-
throw new Error(`Invalid text assertion format: ${str}. Expected "text:<selector> contains:<text>" or "text:<selector> equals:<text>"`);
|
|
95856
|
-
}
|
|
95857
|
-
if (trimmed.startsWith("selector:")) {
|
|
95858
|
-
const rest = trimmed.slice("selector:".length);
|
|
95859
|
-
const lastSpace = rest.lastIndexOf(" ");
|
|
95860
|
-
if (lastSpace === -1) {
|
|
95861
|
-
throw new Error(`Invalid selector assertion format: ${str}. Expected "selector:<selector> visible" or "selector:<selector> not-visible"`);
|
|
95862
|
-
}
|
|
95863
|
-
const selector = rest.slice(0, lastSpace);
|
|
95864
|
-
const action = rest.slice(lastSpace + 1);
|
|
95865
|
-
if (action === "visible") {
|
|
95866
|
-
return { type: "visible", selector, description: `${selector} is visible` };
|
|
95867
|
-
}
|
|
95868
|
-
if (action === "not-visible") {
|
|
95869
|
-
return { type: "not_visible", selector, description: `${selector} is not visible` };
|
|
95870
|
-
}
|
|
95871
|
-
throw new Error(`Unknown selector action: "${action}". Expected "visible" or "not-visible"`);
|
|
95872
|
-
}
|
|
95873
|
-
if (trimmed.startsWith("cookie:exists:")) {
|
|
95874
|
-
const name = trimmed.slice("cookie:exists:".length);
|
|
95875
|
-
return { type: "cookie_exists", expected: name, description: `Cookie "${name}" exists` };
|
|
95876
|
-
}
|
|
95877
|
-
if (trimmed.startsWith("cookie:not-exists:")) {
|
|
95878
|
-
const name = trimmed.slice("cookie:not-exists:".length);
|
|
95879
|
-
return { type: "cookie_not_exists", expected: name, description: `Cookie "${name}" does not exist` };
|
|
95880
|
-
}
|
|
95881
|
-
if (trimmed.startsWith("cookie:value:")) {
|
|
95882
|
-
const valueStr = trimmed.slice("cookie:value:".length);
|
|
95883
|
-
return { type: "cookie_value", expected: valueStr, description: `Cookie value is "${valueStr}"` };
|
|
95884
|
-
}
|
|
95885
|
-
if (trimmed.startsWith("local:exists:")) {
|
|
95886
|
-
const key = trimmed.slice("local:exists:".length);
|
|
95887
|
-
return { type: "local_storage_exists", expected: key, description: `LocalStorage key "${key}" exists` };
|
|
95888
|
-
}
|
|
95889
|
-
if (trimmed.startsWith("local:not-exists:")) {
|
|
95890
|
-
const key = trimmed.slice("local:not-exists:".length);
|
|
95891
|
-
return { type: "local_storage_not_exists", expected: key, description: `LocalStorage key "${key}" does not exist` };
|
|
95892
|
-
}
|
|
95893
|
-
if (trimmed.startsWith("local:value:")) {
|
|
95894
|
-
const valueStr = trimmed.slice("local:value:".length);
|
|
95895
|
-
return { type: "local_storage_value", expected: valueStr, description: `LocalStorage value is "${valueStr}"` };
|
|
95896
|
-
}
|
|
95897
|
-
if (trimmed.startsWith("session:value:")) {
|
|
95898
|
-
const valueStr = trimmed.slice("session:value:".length);
|
|
95899
|
-
return { type: "session_storage_value", expected: valueStr, description: `SessionStorage value is "${valueStr}"` };
|
|
95900
|
-
}
|
|
95901
|
-
if (trimmed.startsWith("session:not-exists:")) {
|
|
95902
|
-
const key = trimmed.slice("session:not-exists:".length);
|
|
95903
|
-
return { type: "session_storage_not_exists", expected: key, description: `SessionStorage key "${key}" does not exist` };
|
|
95904
|
-
}
|
|
95905
|
-
throw new Error(`Cannot parse assertion: "${str}". See --help for assertion formats.`);
|
|
95906
|
-
}
|
|
95907
|
-
|
|
95908
|
-
// src/cli/index.tsx
|
|
96049
|
+
init_assertions();
|
|
95909
96050
|
init_paths();
|
|
95910
96051
|
init_sessions();
|
|
95911
96052
|
import { existsSync as existsSync17, mkdirSync as mkdirSync14 } from "fs";
|
|
95912
96053
|
|
|
95913
96054
|
// src/lib/repo-discovery.ts
|
|
95914
96055
|
init_paths();
|
|
95915
|
-
import { existsSync as existsSync14, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync, writeFileSync as
|
|
96056
|
+
import { existsSync as existsSync14, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync5, mkdirSync as mkdirSync11, unlinkSync } from "fs";
|
|
95916
96057
|
import { createHash } from "crypto";
|
|
95917
|
-
import { join as
|
|
96058
|
+
import { join as join17, resolve, relative as relative2 } from "path";
|
|
95918
96059
|
function getCacheDir() {
|
|
95919
96060
|
const testersDir = getTestersDir();
|
|
95920
|
-
const cacheDir =
|
|
96061
|
+
const cacheDir = join17(testersDir, "repo-index");
|
|
95921
96062
|
if (!existsSync14(cacheDir)) {
|
|
95922
96063
|
mkdirSync11(cacheDir, { recursive: true });
|
|
95923
96064
|
}
|
|
@@ -95927,11 +96068,11 @@ function pathHash(repoPath) {
|
|
|
95927
96068
|
return createHash("sha256").update(repoPath).digest("hex").slice(0, 16);
|
|
95928
96069
|
}
|
|
95929
96070
|
function getCachePath(repoPath) {
|
|
95930
|
-
return
|
|
96071
|
+
return join17(getCacheDir(), `${pathHash(repoPath)}.json`);
|
|
95931
96072
|
}
|
|
95932
96073
|
function isCacheStale(cached, repoPath) {
|
|
95933
96074
|
for (const spec of cached.specs) {
|
|
95934
|
-
const fullPath =
|
|
96075
|
+
const fullPath = join17(repoPath, spec.file);
|
|
95935
96076
|
if (!existsSync14(fullPath))
|
|
95936
96077
|
return true;
|
|
95937
96078
|
try {
|
|
@@ -95943,11 +96084,11 @@ function isCacheStale(cached, repoPath) {
|
|
|
95943
96084
|
}
|
|
95944
96085
|
}
|
|
95945
96086
|
if (cached.configPath) {
|
|
95946
|
-
const configFullPath =
|
|
96087
|
+
const configFullPath = join17(repoPath, cached.configPath);
|
|
95947
96088
|
if (!existsSync14(configFullPath))
|
|
95948
96089
|
return true;
|
|
95949
96090
|
try {
|
|
95950
|
-
|
|
96091
|
+
statSync(configFullPath);
|
|
95951
96092
|
const age = Date.now() - new Date(cached.snapshotAt).getTime();
|
|
95952
96093
|
if (age > 3600000)
|
|
95953
96094
|
return true;
|
|
@@ -95970,14 +96111,14 @@ function loadCache(repoPath) {
|
|
|
95970
96111
|
}
|
|
95971
96112
|
function saveCache(snapshot) {
|
|
95972
96113
|
const cachePath = getCachePath(snapshot.repoPath);
|
|
95973
|
-
|
|
96114
|
+
writeFileSync5(cachePath, JSON.stringify(snapshot, null, 2), "utf-8");
|
|
95974
96115
|
}
|
|
95975
96116
|
function detectPackageManager(repoPath) {
|
|
95976
96117
|
const result = {
|
|
95977
|
-
npm: existsSync14(
|
|
95978
|
-
yarn: existsSync14(
|
|
95979
|
-
pnpm: existsSync14(
|
|
95980
|
-
bun: existsSync14(
|
|
96118
|
+
npm: existsSync14(join17(repoPath, "package-lock.json")),
|
|
96119
|
+
yarn: existsSync14(join17(repoPath, "yarn.lock")),
|
|
96120
|
+
pnpm: existsSync14(join17(repoPath, "pnpm-lock.yaml")),
|
|
96121
|
+
bun: existsSync14(join17(repoPath, "bun.lockb")) || existsSync14(join17(repoPath, "bun.lock")),
|
|
95981
96122
|
preferred: "npm"
|
|
95982
96123
|
};
|
|
95983
96124
|
if (result.bun)
|
|
@@ -95991,7 +96132,7 @@ function detectPackageManager(repoPath) {
|
|
|
95991
96132
|
return result;
|
|
95992
96133
|
}
|
|
95993
96134
|
function detectDevScripts(repoPath) {
|
|
95994
|
-
const pkgPath =
|
|
96135
|
+
const pkgPath = join17(repoPath, "package.json");
|
|
95995
96136
|
if (!existsSync14(pkgPath)) {
|
|
95996
96137
|
return { dev: null, test: null, seed: null, build: null };
|
|
95997
96138
|
}
|
|
@@ -96018,7 +96159,7 @@ function findPlaywrightConfig(repoPath) {
|
|
|
96018
96159
|
"playwright-ct.config.js"
|
|
96019
96160
|
];
|
|
96020
96161
|
for (const name of candidates) {
|
|
96021
|
-
if (existsSync14(
|
|
96162
|
+
if (existsSync14(join17(repoPath, name)))
|
|
96022
96163
|
return name;
|
|
96023
96164
|
}
|
|
96024
96165
|
return null;
|
|
@@ -96027,7 +96168,7 @@ function extractTestGlobPatterns(configPath, repoPath) {
|
|
|
96027
96168
|
if (!configPath) {
|
|
96028
96169
|
return ["**/*.spec.ts", "**/*.spec.js", "**/*.test.ts", "**/*.test.js", "**/e2e/**/*.ts", "**/e2e/**/*.js", "**/tests/**/*.ts", "**/tests/**/*.js"];
|
|
96029
96170
|
}
|
|
96030
|
-
const fullPath =
|
|
96171
|
+
const fullPath = join17(repoPath, configPath);
|
|
96031
96172
|
let content;
|
|
96032
96173
|
try {
|
|
96033
96174
|
content = readFileSync6(fullPath, "utf-8");
|
|
@@ -96038,8 +96179,9 @@ function extractTestGlobPatterns(configPath, repoPath) {
|
|
|
96038
96179
|
const testDirMatch = content.match(/testDir\s*[:=]\s*['"`]([^'"`]+)['"`]/);
|
|
96039
96180
|
const testDir = testDirMatch?.[1];
|
|
96040
96181
|
const testMatchArray = content.match(/testMatch\s*[:=]\s*\[([^\]]+)\]/);
|
|
96041
|
-
|
|
96042
|
-
|
|
96182
|
+
const testMatchBody = testMatchArray?.[1];
|
|
96183
|
+
if (testMatchBody) {
|
|
96184
|
+
const items = testMatchBody.match(/['"`]([^'"`]+)['"`]/g);
|
|
96043
96185
|
if (items) {
|
|
96044
96186
|
for (const item of items) {
|
|
96045
96187
|
patterns.push(item.replace(/['"`]/g, ""));
|
|
@@ -96047,8 +96189,9 @@ function extractTestGlobPatterns(configPath, repoPath) {
|
|
|
96047
96189
|
}
|
|
96048
96190
|
}
|
|
96049
96191
|
const testMatchSingle = content.match(/testMatch\s*[:=]\s*['"`]([^'"`]+)['"`]/);
|
|
96050
|
-
|
|
96051
|
-
|
|
96192
|
+
const singleTestMatch = testMatchSingle?.[1];
|
|
96193
|
+
if (singleTestMatch) {
|
|
96194
|
+
patterns.push(singleTestMatch);
|
|
96052
96195
|
}
|
|
96053
96196
|
if (testDir && patterns.length === 0) {
|
|
96054
96197
|
patterns.push(`${testDir}/**/*.spec.ts`, `${testDir}/**/*.test.ts`, `${testDir}/**/*.spec.js`, `${testDir}/**/*.test.js`);
|
|
@@ -96074,7 +96217,7 @@ function findSpecFiles(repoPath, globPatterns) {
|
|
|
96074
96217
|
for (const pattern of globPatterns) {
|
|
96075
96218
|
const dirsToSearch = ["", ".", "tests", "e2e", "test", "__tests__", "specs", "src"];
|
|
96076
96219
|
for (const dir of dirsToSearch) {
|
|
96077
|
-
const searchDir = dir ?
|
|
96220
|
+
const searchDir = dir ? join17(repoPath, dir) : repoPath;
|
|
96078
96221
|
if (!existsSync14(searchDir))
|
|
96079
96222
|
continue;
|
|
96080
96223
|
try {
|
|
@@ -96108,7 +96251,7 @@ function walkDir(dir) {
|
|
|
96108
96251
|
try {
|
|
96109
96252
|
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
96110
96253
|
for (const entry of entries) {
|
|
96111
|
-
const fullPath =
|
|
96254
|
+
const fullPath = join17(dir, entry.name);
|
|
96112
96255
|
if (entry.isDirectory()) {
|
|
96113
96256
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
96114
96257
|
continue;
|
|
@@ -96126,7 +96269,7 @@ function matchesGlob(filePath, pattern) {
|
|
|
96126
96269
|
return new RegExp(regex).test(filePath);
|
|
96127
96270
|
}
|
|
96128
96271
|
function detectSuggestedUrl(repoPath) {
|
|
96129
|
-
const pkgPath =
|
|
96272
|
+
const pkgPath = join17(repoPath, "package.json");
|
|
96130
96273
|
if (!existsSync14(pkgPath))
|
|
96131
96274
|
return null;
|
|
96132
96275
|
try {
|
|
@@ -96146,10 +96289,10 @@ function detectSuggestedUrl(repoPath) {
|
|
|
96146
96289
|
return null;
|
|
96147
96290
|
}
|
|
96148
96291
|
function checkPlaywrightBrowserInstalled(repoPath) {
|
|
96149
|
-
const cacheDir =
|
|
96292
|
+
const cacheDir = join17(repoPath, "node_modules", ".cache", "ms-playwright");
|
|
96150
96293
|
if (existsSync14(cacheDir))
|
|
96151
96294
|
return true;
|
|
96152
|
-
const globalCache =
|
|
96295
|
+
const globalCache = join17(repoPath, ".cache", "ms-playwright");
|
|
96153
96296
|
if (existsSync14(globalCache))
|
|
96154
96297
|
return true;
|
|
96155
96298
|
return false;
|
|
@@ -96166,7 +96309,7 @@ function getInstallCommand(pm) {
|
|
|
96166
96309
|
return "bun install";
|
|
96167
96310
|
}
|
|
96168
96311
|
}
|
|
96169
|
-
function getPlaywrightInstallCommand(
|
|
96312
|
+
function getPlaywrightInstallCommand(_pm) {
|
|
96170
96313
|
return "npx playwright install";
|
|
96171
96314
|
}
|
|
96172
96315
|
function discoverRepo(opts) {
|
|
@@ -96181,7 +96324,7 @@ function discoverRepo(opts) {
|
|
|
96181
96324
|
let configRaw = null;
|
|
96182
96325
|
if (configPath) {
|
|
96183
96326
|
try {
|
|
96184
|
-
configRaw = readFileSync6(
|
|
96327
|
+
configRaw = readFileSync6(join17(repoPath, configPath), "utf-8");
|
|
96185
96328
|
} catch {
|
|
96186
96329
|
configRaw = null;
|
|
96187
96330
|
}
|
|
@@ -96190,7 +96333,7 @@ function discoverRepo(opts) {
|
|
|
96190
96333
|
const specs = findSpecFiles(repoPath, globPatterns);
|
|
96191
96334
|
const packageManager = detectPackageManager(repoPath);
|
|
96192
96335
|
const devScripts = detectDevScripts(repoPath);
|
|
96193
|
-
const playwrightInstalled = existsSync14(
|
|
96336
|
+
const playwrightInstalled = existsSync14(join17(repoPath, "node_modules", "playwright")) || existsSync14(join17(repoPath, "node_modules", "@playwright", "test"));
|
|
96194
96337
|
const browsersInstalled = checkPlaywrightBrowserInstalled(repoPath);
|
|
96195
96338
|
const configExists = configPath !== null;
|
|
96196
96339
|
const specsFound = specs.length > 0;
|
|
@@ -96259,7 +96402,7 @@ function clearDiscoveryCache(repoPath) {
|
|
|
96259
96402
|
} else {
|
|
96260
96403
|
for (const file of readdirSync3(cacheDir)) {
|
|
96261
96404
|
if (file.endsWith(".json")) {
|
|
96262
|
-
unlinkSync(
|
|
96405
|
+
unlinkSync(join17(cacheDir, file));
|
|
96263
96406
|
}
|
|
96264
96407
|
}
|
|
96265
96408
|
}
|
|
@@ -96283,10 +96426,10 @@ init_runs();
|
|
|
96283
96426
|
init_database();
|
|
96284
96427
|
init_paths();
|
|
96285
96428
|
import { execSync as execSync2 } from "child_process";
|
|
96286
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as
|
|
96287
|
-
import { join as
|
|
96429
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync6 } from "fs";
|
|
96430
|
+
import { join as join18 } from "path";
|
|
96288
96431
|
function resolvePlaywrightCmd(repoPath) {
|
|
96289
|
-
const localPw =
|
|
96432
|
+
const localPw = join18(repoPath, "node_modules", ".bin", "playwright");
|
|
96290
96433
|
if (existsSync15(localPw)) {
|
|
96291
96434
|
return [localPw, "test"];
|
|
96292
96435
|
}
|
|
@@ -96305,7 +96448,7 @@ function buildPlaywrightArgs(specFiles, extraArgs = []) {
|
|
|
96305
96448
|
}
|
|
96306
96449
|
function runPlaywright(repoPath, workingDir, specFiles, extraArgs, timeoutMs) {
|
|
96307
96450
|
const cmd = resolvePlaywrightCmd(repoPath);
|
|
96308
|
-
const args = buildPlaywrightArgs(specFiles, extraArgs
|
|
96451
|
+
const args = buildPlaywrightArgs(specFiles, extraArgs);
|
|
96309
96452
|
const startTime = Date.now();
|
|
96310
96453
|
try {
|
|
96311
96454
|
const result = execSync2(`${cmd.join(" ")} ${args.join(" ")}`, {
|
|
@@ -96333,7 +96476,7 @@ function runPlaywright(repoPath, workingDir, specFiles, extraArgs, timeoutMs) {
|
|
|
96333
96476
|
};
|
|
96334
96477
|
}
|
|
96335
96478
|
}
|
|
96336
|
-
function parsePlaywrightJsonOutput(stdout,
|
|
96479
|
+
function parsePlaywrightJsonOutput(stdout, _stderr) {
|
|
96337
96480
|
const testResults = [];
|
|
96338
96481
|
try {
|
|
96339
96482
|
const obj = JSON.parse(stdout);
|
|
@@ -96438,19 +96581,21 @@ async function runRepoTests(opts) {
|
|
|
96438
96581
|
const workingDir = opts.snapshot.workingDir;
|
|
96439
96582
|
const repoPath = snapshot.repoPath;
|
|
96440
96583
|
const url = opts.url ?? snapshot.suggestedUrl ?? "http://localhost:3000";
|
|
96441
|
-
const
|
|
96584
|
+
const initialRun = createRun({
|
|
96442
96585
|
projectId: opts.projectId,
|
|
96443
96586
|
url,
|
|
96444
96587
|
model: opts.model ?? "repo-native",
|
|
96445
96588
|
headed: false,
|
|
96446
|
-
parallel: 1
|
|
96447
|
-
|
|
96589
|
+
parallel: 1
|
|
96590
|
+
});
|
|
96591
|
+
const run = updateRun(initialRun.id, {
|
|
96592
|
+
metadata: JSON.stringify({
|
|
96448
96593
|
runType: "repo-native",
|
|
96449
96594
|
repoPath,
|
|
96450
96595
|
configPath: snapshot.configPath,
|
|
96451
96596
|
cacheKey: snapshot.cacheKey,
|
|
96452
96597
|
label: opts.label
|
|
96453
|
-
}
|
|
96598
|
+
})
|
|
96454
96599
|
});
|
|
96455
96600
|
const specResults = [];
|
|
96456
96601
|
const startTime = Date.now();
|
|
@@ -96480,10 +96625,10 @@ async function runRepoTests(opts) {
|
|
|
96480
96625
|
}
|
|
96481
96626
|
const resultRecord = { id: resultId };
|
|
96482
96627
|
if (result.stdout || result.stderr) {
|
|
96483
|
-
const reportersDir =
|
|
96628
|
+
const reportersDir = join18(getTestersDir(), "repo-run-output");
|
|
96484
96629
|
mkdirSync12(reportersDir, { recursive: true });
|
|
96485
|
-
const outputFile =
|
|
96486
|
-
|
|
96630
|
+
const outputFile = join18(reportersDir, `${resultRecord.id}.log`);
|
|
96631
|
+
writeFileSync6(outputFile, `=== stdout ===
|
|
96487
96632
|
${result.stdout}
|
|
96488
96633
|
|
|
96489
96634
|
=== stderr ===
|
|
@@ -96590,6 +96735,10 @@ function processSyncEnv() {
|
|
|
96590
96735
|
// src/cli/index.tsx
|
|
96591
96736
|
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
96592
96737
|
var PRIORITIES = ["low", "medium", "high", "critical"];
|
|
96738
|
+
function splitCsvOption(value) {
|
|
96739
|
+
const items = value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
96740
|
+
return items.length > 0 ? items : undefined;
|
|
96741
|
+
}
|
|
96593
96742
|
function AddForm({ onComplete }) {
|
|
96594
96743
|
const { exit } = useApp();
|
|
96595
96744
|
const [state, setState] = useState({
|
|
@@ -96863,25 +97012,30 @@ program2.command("prod-debug <target>").description("Create a safe production de
|
|
|
96863
97012
|
}, config2.prodDebug);
|
|
96864
97013
|
const output = opts.json ? JSON.stringify(plan, null, 2) : formatProdDebugPlan(plan);
|
|
96865
97014
|
if (opts.output) {
|
|
96866
|
-
|
|
97015
|
+
writeFileSync8(resolve4(opts.output), output + `
|
|
96867
97016
|
`);
|
|
96868
97017
|
} else {
|
|
96869
97018
|
log(output);
|
|
96870
97019
|
}
|
|
96871
97020
|
});
|
|
96872
97021
|
var CONFIG_DIR5 = getTestersDir();
|
|
96873
|
-
var CONFIG_PATH4 =
|
|
97022
|
+
var CONFIG_PATH4 = join20(CONFIG_DIR5, "config.json");
|
|
96874
97023
|
function getActiveProject() {
|
|
96875
97024
|
try {
|
|
96876
97025
|
if (existsSync17(CONFIG_PATH4)) {
|
|
96877
|
-
const raw = JSON.parse(
|
|
97026
|
+
const raw = JSON.parse(readFileSync10(CONFIG_PATH4, "utf-8"));
|
|
96878
97027
|
return raw.activeProject ?? undefined;
|
|
96879
97028
|
}
|
|
96880
97029
|
} catch {}
|
|
96881
97030
|
return;
|
|
96882
97031
|
}
|
|
96883
97032
|
function resolveProject2(optProject) {
|
|
96884
|
-
|
|
97033
|
+
if (optProject)
|
|
97034
|
+
return optProject;
|
|
97035
|
+
const activeProject = getActiveProject();
|
|
97036
|
+
if (!activeProject)
|
|
97037
|
+
return;
|
|
97038
|
+
return getProject(activeProject) ? activeProject : undefined;
|
|
96885
97039
|
}
|
|
96886
97040
|
program2.command("add [name]").alias("create").description("Create a new test scenario (interactive if no name/flags given)").option("-d, --description <text>", "Scenario description", "").option("-s, --steps <step>", "Test step (repeatable)", (val, acc) => {
|
|
96887
97041
|
acc.push(val);
|
|
@@ -97066,7 +97220,7 @@ program2.command("delete <id>").description("Delete a scenario").option("-y, --y
|
|
|
97066
97220
|
}
|
|
97067
97221
|
if (!opts.yes) {
|
|
97068
97222
|
process.stdout.write(chalk6.yellow(`Delete scenario ${scenario.shortId} "${scenario.name}"? [y/N] `));
|
|
97069
|
-
const answer = await new Promise((
|
|
97223
|
+
const answer = await new Promise((resolve5) => {
|
|
97070
97224
|
let buf = "";
|
|
97071
97225
|
process.stdin.setRawMode?.(true);
|
|
97072
97226
|
process.stdin.resume();
|
|
@@ -97076,7 +97230,7 @@ program2.command("delete <id>").description("Delete a scenario").option("-y, --y
|
|
|
97076
97230
|
process.stdin.pause();
|
|
97077
97231
|
process.stdout.write(`
|
|
97078
97232
|
`);
|
|
97079
|
-
|
|
97233
|
+
resolve5(buf);
|
|
97080
97234
|
});
|
|
97081
97235
|
});
|
|
97082
97236
|
if (answer !== "y" && answer !== "yes") {
|
|
@@ -97105,7 +97259,7 @@ program2.command("remove <id>").alias("uninstall").description("Remove a scenari
|
|
|
97105
97259
|
}
|
|
97106
97260
|
if (!opts.yes) {
|
|
97107
97261
|
process.stdout.write(chalk6.yellow(`Remove scenario ${scenario.shortId} "${scenario.name}"? [y/N] `));
|
|
97108
|
-
const answer = await new Promise((
|
|
97262
|
+
const answer = await new Promise((resolve5) => {
|
|
97109
97263
|
let buf = "";
|
|
97110
97264
|
process.stdin.setRawMode?.(true);
|
|
97111
97265
|
process.stdin.resume();
|
|
@@ -97115,7 +97269,7 @@ program2.command("remove <id>").alias("uninstall").description("Remove a scenari
|
|
|
97115
97269
|
process.stdin.pause();
|
|
97116
97270
|
process.stdout.write(`
|
|
97117
97271
|
`);
|
|
97118
|
-
|
|
97272
|
+
resolve5(buf);
|
|
97119
97273
|
});
|
|
97120
97274
|
});
|
|
97121
97275
|
if (answer !== "y" && answer !== "yes") {
|
|
@@ -97161,13 +97315,15 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97161
97315
|
logError(chalk6.red("No URL provided. Pass a URL argument, use --env <name>, or set a default environment with 'testers env use <name>'."));
|
|
97162
97316
|
process.exit(2);
|
|
97163
97317
|
}
|
|
97318
|
+
const scenarioIds = splitCsvOption(opts.scenario);
|
|
97164
97319
|
if (!opts.dryRun) {
|
|
97165
97320
|
const hasAnthropic = Boolean(process.env["ANTHROPIC_API_KEY"]);
|
|
97166
97321
|
const hasOpenAI = Boolean(process.env["OPENAI_API_KEY"]);
|
|
97167
97322
|
const hasGoogle = Boolean(process.env["GOOGLE_API_KEY"]);
|
|
97168
97323
|
const hasCerebras = Boolean(process.env["CEREBRAS_API_KEY"]);
|
|
97169
|
-
|
|
97170
|
-
|
|
97324
|
+
const hasZai = Boolean(process.env["ZAI_API_KEY"]);
|
|
97325
|
+
if (!hasAnthropic && !hasOpenAI && !hasGoogle && !hasCerebras && !hasZai) {
|
|
97326
|
+
logError(chalk6.red("No AI API key found. Set ANTHROPIC_API_KEY (recommended), or OPENAI_API_KEY / GOOGLE_API_KEY / CEREBRAS_API_KEY / ZAI_API_KEY."));
|
|
97171
97327
|
logError(chalk6.red("For GitHub Actions, add ANTHROPIC_API_KEY to your repo secrets and pass it via: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}"));
|
|
97172
97328
|
process.exit(2);
|
|
97173
97329
|
}
|
|
@@ -97231,7 +97387,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97231
97387
|
tags: opts.tag.length > 0 ? opts.tag : undefined,
|
|
97232
97388
|
projectId
|
|
97233
97389
|
}).filter((s2) => {
|
|
97234
|
-
if (
|
|
97390
|
+
if (scenarioIds && !scenarioIds.includes(s2.id) && !scenarioIds.includes(s2.shortId))
|
|
97235
97391
|
return false;
|
|
97236
97392
|
if (opts.priority && s2.priority !== opts.priority)
|
|
97237
97393
|
return false;
|
|
@@ -97280,7 +97436,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97280
97436
|
const { runId, scenarioCount } = startRunAsync({
|
|
97281
97437
|
url: url2,
|
|
97282
97438
|
tags: opts.tag.length > 0 ? opts.tag : undefined,
|
|
97283
|
-
scenarioIds
|
|
97439
|
+
scenarioIds,
|
|
97284
97440
|
priority: opts.priority,
|
|
97285
97441
|
model: opts.model,
|
|
97286
97442
|
headed: opts.headed,
|
|
@@ -97314,7 +97470,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97314
97470
|
`);
|
|
97315
97471
|
}
|
|
97316
97472
|
};
|
|
97317
|
-
await new Promise((
|
|
97473
|
+
await new Promise((resolve5) => {
|
|
97318
97474
|
const poll = setInterval(() => {
|
|
97319
97475
|
const run3 = getRun(runId);
|
|
97320
97476
|
if (!run3)
|
|
@@ -97322,7 +97478,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97322
97478
|
renderTable();
|
|
97323
97479
|
if (DONE_STATUSES.has(run3.status)) {
|
|
97324
97480
|
clearInterval(poll);
|
|
97325
|
-
|
|
97481
|
+
resolve5();
|
|
97326
97482
|
}
|
|
97327
97483
|
}, POLL_INTERVAL);
|
|
97328
97484
|
});
|
|
@@ -97415,7 +97571,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97415
97571
|
if (opts.json || opts.output) {
|
|
97416
97572
|
const jsonOutput = formatJSON(run3, results2);
|
|
97417
97573
|
if (opts.output) {
|
|
97418
|
-
|
|
97574
|
+
writeFileSync8(opts.output, jsonOutput, "utf-8");
|
|
97419
97575
|
log(chalk6.green(`Results written to ${opts.output}`));
|
|
97420
97576
|
}
|
|
97421
97577
|
if (opts.json) {
|
|
@@ -97438,7 +97594,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97438
97594
|
}
|
|
97439
97595
|
process.exit(getExitCode(run3));
|
|
97440
97596
|
}
|
|
97441
|
-
const noFilters = !
|
|
97597
|
+
const noFilters = !scenarioIds && opts.tag.length === 0 && !opts.priority;
|
|
97442
97598
|
if (noFilters && !opts.json && !opts.output) {
|
|
97443
97599
|
const allScenarios = listScenarios({ projectId });
|
|
97444
97600
|
log(chalk6.bold(` Running all ${allScenarios.length} scenarios...`));
|
|
@@ -97502,7 +97658,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97502
97658
|
const { run: run2, results } = await runByFilter({
|
|
97503
97659
|
url: url2,
|
|
97504
97660
|
tags: opts.tag.length > 0 ? opts.tag : undefined,
|
|
97505
|
-
scenarioIds: diffScenarioIds ??
|
|
97661
|
+
scenarioIds: diffScenarioIds ?? scenarioIds,
|
|
97506
97662
|
priority: opts.priority,
|
|
97507
97663
|
model: opts.model,
|
|
97508
97664
|
headed: opts.headed,
|
|
@@ -97524,7 +97680,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97524
97680
|
if (opts.json || opts.output) {
|
|
97525
97681
|
const jsonOutput = formatJSON(run2, results);
|
|
97526
97682
|
if (opts.output) {
|
|
97527
|
-
|
|
97683
|
+
writeFileSync8(opts.output, jsonOutput, "utf-8");
|
|
97528
97684
|
log(chalk6.green(`Results written to ${opts.output}`));
|
|
97529
97685
|
}
|
|
97530
97686
|
if (opts.json) {
|
|
@@ -97714,7 +97870,7 @@ program2.command("screenshots <id>").description("List screenshots for a run or
|
|
|
97714
97870
|
});
|
|
97715
97871
|
program2.command("import <dir>").description("Import markdown test files as scenarios").action((dir) => {
|
|
97716
97872
|
try {
|
|
97717
|
-
const absDir =
|
|
97873
|
+
const absDir = resolve4(dir);
|
|
97718
97874
|
const files = readdirSync6(absDir).filter((f2) => f2.endsWith(".md"));
|
|
97719
97875
|
if (files.length === 0) {
|
|
97720
97876
|
log(chalk6.dim("No .md files found in directory."));
|
|
@@ -97722,7 +97878,7 @@ program2.command("import <dir>").description("Import markdown test files as scen
|
|
|
97722
97878
|
}
|
|
97723
97879
|
let imported = 0;
|
|
97724
97880
|
for (const file2 of files) {
|
|
97725
|
-
const content =
|
|
97881
|
+
const content = readFileSync10(join20(absDir, file2), "utf-8");
|
|
97726
97882
|
const lines = content.split(`
|
|
97727
97883
|
`);
|
|
97728
97884
|
let name21 = file2.replace(/\.md$/, "");
|
|
@@ -97777,8 +97933,8 @@ program2.command("export [format]").description("Export scenarios as JSON (defau
|
|
|
97777
97933
|
if (fmt === "json") {
|
|
97778
97934
|
const outputPath = opts.output ?? "testers-export.json";
|
|
97779
97935
|
const data = JSON.stringify(scenarios, null, 2);
|
|
97780
|
-
|
|
97781
|
-
log(chalk6.green(`Exported ${scenarios.length} scenario(s) to ${
|
|
97936
|
+
writeFileSync8(outputPath, data, "utf-8");
|
|
97937
|
+
log(chalk6.green(`Exported ${scenarios.length} scenario(s) to ${resolve4(outputPath)}`));
|
|
97782
97938
|
return;
|
|
97783
97939
|
}
|
|
97784
97940
|
const outputDir = opts.output ?? ".";
|
|
@@ -97810,13 +97966,13 @@ program2.command("export [format]").description("Export scenarios as JSON (defau
|
|
|
97810
97966
|
lines.push("");
|
|
97811
97967
|
}
|
|
97812
97968
|
const safeFilename = s2.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
|
|
97813
|
-
const filePath =
|
|
97814
|
-
|
|
97969
|
+
const filePath = join20(outputDir, `${s2.shortId}-${safeFilename}.md`);
|
|
97970
|
+
writeFileSync8(filePath, lines.join(`
|
|
97815
97971
|
`), "utf-8");
|
|
97816
97972
|
log(chalk6.dim(` ${s2.shortId}: ${s2.name} \u2192 ${filePath}`));
|
|
97817
97973
|
}
|
|
97818
97974
|
log(chalk6.green(`
|
|
97819
|
-
Exported ${scenarios.length} scenario(s) as markdown to ${
|
|
97975
|
+
Exported ${scenarios.length} scenario(s) as markdown to ${resolve4(outputDir)}`));
|
|
97820
97976
|
} catch (error40) {
|
|
97821
97977
|
logError(chalk6.red(`Error: ${error40 instanceof Error ? error40.message : String(error40)}`));
|
|
97822
97978
|
process.exit(1);
|
|
@@ -97835,7 +97991,7 @@ program2.command("status").description("Show database and auth status").action((
|
|
|
97835
97991
|
try {
|
|
97836
97992
|
const config2 = loadConfig();
|
|
97837
97993
|
const hasApiKey = !!config2.anthropicApiKey || !!process.env["ANTHROPIC_API_KEY"];
|
|
97838
|
-
const dbPath =
|
|
97994
|
+
const dbPath = join20(getTestersDir(), "testers.db");
|
|
97839
97995
|
log("");
|
|
97840
97996
|
log(chalk6.bold(" Open Testers Status"));
|
|
97841
97997
|
log("");
|
|
@@ -97989,11 +98145,11 @@ projectCmd.command("use <name>").description("Set active project (find or create
|
|
|
97989
98145
|
let config2 = {};
|
|
97990
98146
|
if (existsSync17(CONFIG_PATH4)) {
|
|
97991
98147
|
try {
|
|
97992
|
-
config2 = JSON.parse(
|
|
98148
|
+
config2 = JSON.parse(readFileSync10(CONFIG_PATH4, "utf-8"));
|
|
97993
98149
|
} catch {}
|
|
97994
98150
|
}
|
|
97995
98151
|
config2.activeProject = project.id;
|
|
97996
|
-
|
|
98152
|
+
writeFileSync8(CONFIG_PATH4, JSON.stringify(config2, null, 2), "utf-8");
|
|
97997
98153
|
if (opts.json) {
|
|
97998
98154
|
log(JSON.stringify({ activeProject: project.id, project }, null, 2));
|
|
97999
98155
|
return;
|
|
@@ -98007,7 +98163,7 @@ projectCmd.command("use <name>").description("Set active project (find or create
|
|
|
98007
98163
|
var repoCmd = program2.command("repo").description("Discover and run repo-native Playwright tests");
|
|
98008
98164
|
repoCmd.command("discover [path]").alias("scan").description("Discover Playwright tests in a repo").option("--refresh", "Force a fresh scan, ignoring cache", false).option("--json", "Output as JSON", false).option("--base-url <url>", "Override the suggested base URL").action((path, opts) => {
|
|
98009
98165
|
try {
|
|
98010
|
-
const repoPath =
|
|
98166
|
+
const repoPath = resolve4(path ?? process.cwd());
|
|
98011
98167
|
const snapshot = discoverRepo({
|
|
98012
98168
|
repoPath,
|
|
98013
98169
|
refresh: opts.refresh,
|
|
@@ -98073,7 +98229,7 @@ repoCmd.command("discover [path]").alias("scan").description("Discover Playwrigh
|
|
|
98073
98229
|
});
|
|
98074
98230
|
repoCmd.command("prepare [path]").alias("prep").description("Install dependencies and browsers for repo tests").option("--all", "Run all prep steps (install, browsers, build, seed)", false).option("--install", "Install dependencies", false).option("--browsers", "Install Playwright browsers", false).option("--build", "Build the app", false).option("--seed", "Seed the database", false).option("--refresh", "Force fresh discovery scan", false).option("--json", "Output as JSON", false).action((path, opts) => {
|
|
98075
98231
|
try {
|
|
98076
|
-
const repoPath =
|
|
98232
|
+
const repoPath = resolve4(path ?? process.cwd());
|
|
98077
98233
|
const snapshot = discoverRepo({ repoPath, refresh: opts.refresh });
|
|
98078
98234
|
const steps = [];
|
|
98079
98235
|
if (opts.all) {
|
|
@@ -98151,7 +98307,7 @@ repoCmd.command("run [path]").description("Run discovered Playwright tests nativ
|
|
|
98151
98307
|
return acc;
|
|
98152
98308
|
}, []).option("--timeout <ms>", "Timeout per spec file", "300000").option("--url <url>", "Dev server URL").option("--project <id>", "Project ID for result storage").option("--label <text>", "Run label").option("--json", "Output as JSON", false).action(async (path, opts) => {
|
|
98153
98309
|
try {
|
|
98154
|
-
const repoPath =
|
|
98310
|
+
const repoPath = resolve4(path ?? process.cwd());
|
|
98155
98311
|
const snapshot = discoverRepo({
|
|
98156
98312
|
repoPath,
|
|
98157
98313
|
refresh: opts.refresh,
|
|
@@ -98217,7 +98373,7 @@ repoCmd.command("run [path]").description("Run discovered Playwright tests nativ
|
|
|
98217
98373
|
repoCmd.command("cache [path]").description("Manage discovery cache").option("--clear", "Clear discovery cache", false).option("--status", "Show cache status", false).action((path, opts) => {
|
|
98218
98374
|
try {
|
|
98219
98375
|
if (opts.clear) {
|
|
98220
|
-
const repoPath2 = path ?
|
|
98376
|
+
const repoPath2 = path ? resolve4(path) : undefined;
|
|
98221
98377
|
clearDiscoveryCache(repoPath2);
|
|
98222
98378
|
if (repoPath2) {
|
|
98223
98379
|
log(chalk6.green("Discovery cache cleared for this repo."));
|
|
@@ -98227,7 +98383,7 @@ repoCmd.command("cache [path]").description("Manage discovery cache").option("--
|
|
|
98227
98383
|
return;
|
|
98228
98384
|
}
|
|
98229
98385
|
if (opts.status) {
|
|
98230
|
-
const repoPath2 =
|
|
98386
|
+
const repoPath2 = resolve4(path ?? process.cwd());
|
|
98231
98387
|
const info2 = getDiscoveryCacheInfo(repoPath2);
|
|
98232
98388
|
if (!info2) {
|
|
98233
98389
|
log(chalk6.dim("No discovery cache for this repo."));
|
|
@@ -98241,7 +98397,7 @@ repoCmd.command("cache [path]").description("Manage discovery cache").option("--
|
|
|
98241
98397
|
log("");
|
|
98242
98398
|
return;
|
|
98243
98399
|
}
|
|
98244
|
-
const repoPath =
|
|
98400
|
+
const repoPath = resolve4(path ?? process.cwd());
|
|
98245
98401
|
const info = getDiscoveryCacheInfo(repoPath);
|
|
98246
98402
|
if (!info) {
|
|
98247
98403
|
log(chalk6.dim("No discovery cache. Run 'testers repo discover' to create one."));
|
|
@@ -98330,8 +98486,8 @@ sessionCmd.command("show <id>").description("Show details of a recorded session"
|
|
|
98330
98486
|
});
|
|
98331
98487
|
sessionCmd.command("import <file>").description("Import a session JSON file exported from the Chrome extension").action(async (file2) => {
|
|
98332
98488
|
try {
|
|
98333
|
-
const { readFileSync:
|
|
98334
|
-
const raw =
|
|
98489
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
98490
|
+
const raw = readFileSync11(file2, "utf-8");
|
|
98335
98491
|
const data = JSON.parse(raw);
|
|
98336
98492
|
const items = Array.isArray(data) ? data : [data];
|
|
98337
98493
|
const { createSession: createSession2 } = await Promise.resolve().then(() => (init_sessions(), exports_sessions));
|
|
@@ -98571,7 +98727,7 @@ program2.command("daemon").description("Start the scheduler daemon").option("--i
|
|
|
98571
98727
|
} catch (err) {
|
|
98572
98728
|
logError(chalk6.red(`Daemon error: ${err instanceof Error ? err.message : String(err)}`));
|
|
98573
98729
|
}
|
|
98574
|
-
await new Promise((
|
|
98730
|
+
await new Promise((resolve5) => setTimeout(resolve5, intervalMs));
|
|
98575
98731
|
}
|
|
98576
98732
|
};
|
|
98577
98733
|
process.on("SIGINT", () => {
|
|
@@ -98600,12 +98756,12 @@ program2.command("ci [provider]").description("Print or write a CI workflow (def
|
|
|
98600
98756
|
}
|
|
98601
98757
|
const workflow = generateGitHubActionsWorkflow();
|
|
98602
98758
|
if (opts.output) {
|
|
98603
|
-
const outPath =
|
|
98759
|
+
const outPath = resolve4(opts.output);
|
|
98604
98760
|
const outDir = outPath.replace(/\/[^/]*$/, "");
|
|
98605
98761
|
if (outDir && !existsSync17(outDir)) {
|
|
98606
98762
|
mkdirSync14(outDir, { recursive: true });
|
|
98607
98763
|
}
|
|
98608
|
-
|
|
98764
|
+
writeFileSync8(outPath, workflow, "utf-8");
|
|
98609
98765
|
log(chalk6.green(`Workflow written to ${outPath}`));
|
|
98610
98766
|
return;
|
|
98611
98767
|
}
|
|
@@ -98636,12 +98792,12 @@ program2.command("init").description("Initialize a new testing project").option(
|
|
|
98636
98792
|
log(` ${chalk6.dim(s2.shortId)} ${s2.name} ${chalk6.dim(`[${s2.tags.join(", ")}]`)}`);
|
|
98637
98793
|
}
|
|
98638
98794
|
if (opts.ci === "github") {
|
|
98639
|
-
const workflowDir =
|
|
98795
|
+
const workflowDir = join20(process.cwd(), ".github", "workflows");
|
|
98640
98796
|
if (!existsSync17(workflowDir)) {
|
|
98641
98797
|
mkdirSync14(workflowDir, { recursive: true });
|
|
98642
98798
|
}
|
|
98643
|
-
const workflowPath =
|
|
98644
|
-
|
|
98799
|
+
const workflowPath = join20(workflowDir, "testers.yml");
|
|
98800
|
+
writeFileSync8(workflowPath, generateGitHubActionsWorkflow(), "utf-8");
|
|
98645
98801
|
log(` CI: ${chalk6.green("GitHub Actions workflow written to .github/workflows/testers.yml")}`);
|
|
98646
98802
|
} else if (opts.ci) {
|
|
98647
98803
|
log(chalk6.yellow(` Unknown CI provider: ${opts.ci}. Supported: github`));
|
|
@@ -98650,7 +98806,7 @@ program2.command("init").description("Initialize a new testing project").option(
|
|
|
98650
98806
|
if (opts.yes)
|
|
98651
98807
|
return;
|
|
98652
98808
|
const rl2 = createInterface({ input: process.stdin, output: process.stdout });
|
|
98653
|
-
const ask = (q2) => new Promise((
|
|
98809
|
+
const ask = (q2) => new Promise((resolve5) => rl2.question(q2, resolve5));
|
|
98654
98810
|
try {
|
|
98655
98811
|
const envAnswer = await ask(" Would you like to configure environments? [y/N] ");
|
|
98656
98812
|
if (envAnswer.trim().toLowerCase() === "y") {
|
|
@@ -98835,8 +98991,8 @@ program2.command("report [run-id]").description("Generate HTML test report or co
|
|
|
98835
98991
|
format
|
|
98836
98992
|
});
|
|
98837
98993
|
if (opts.output && opts.output !== "report.html") {
|
|
98838
|
-
|
|
98839
|
-
const absPath2 =
|
|
98994
|
+
writeFileSync8(opts.output, content, "utf-8");
|
|
98995
|
+
const absPath2 = resolve4(opts.output);
|
|
98840
98996
|
log(chalk6.green(`Compliance report written to ${absPath2}`));
|
|
98841
98997
|
} else {
|
|
98842
98998
|
log(content);
|
|
@@ -98849,8 +99005,8 @@ program2.command("report [run-id]").description("Generate HTML test report or co
|
|
|
98849
99005
|
} else {
|
|
98850
99006
|
html = generateHtmlReport(runId);
|
|
98851
99007
|
}
|
|
98852
|
-
|
|
98853
|
-
const absPath =
|
|
99008
|
+
writeFileSync8(opts.output, html, "utf-8");
|
|
99009
|
+
const absPath = resolve4(opts.output);
|
|
98854
99010
|
log(chalk6.green(`Report generated: ${absPath}`));
|
|
98855
99011
|
if (opts.open) {
|
|
98856
99012
|
const openCmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
@@ -99659,7 +99815,7 @@ program2.command("doctor").description("Check system setup and configuration").a
|
|
|
99659
99815
|
log(chalk6.red("\u2717") + " ANTHROPIC_API_KEY is not set (required for AI-powered tests)");
|
|
99660
99816
|
allPassed = false;
|
|
99661
99817
|
}
|
|
99662
|
-
const dbPath =
|
|
99818
|
+
const dbPath = join20(getTestersDir(), "testers.db");
|
|
99663
99819
|
try {
|
|
99664
99820
|
const { Database: Database5 } = await import("bun:sqlite");
|
|
99665
99821
|
const db2 = new Database5(dbPath, { create: true });
|
|
@@ -99695,11 +99851,13 @@ program2.command("doctor").description("Check system setup and configuration").a
|
|
|
99695
99851
|
const openaiKey = !!process.env["OPENAI_API_KEY"];
|
|
99696
99852
|
const googleKey = !!process.env["GOOGLE_API_KEY"];
|
|
99697
99853
|
const cerebrasKey = !!process.env["CEREBRAS_API_KEY"];
|
|
99854
|
+
const zaiKey = !!process.env["ZAI_API_KEY"];
|
|
99698
99855
|
log((anthropicKey ? chalk6.green(" \u2713") : chalk6.red(" \u2717")) + ` Anthropic (ANTHROPIC_API_KEY)${!anthropicKey ? " \u2014 required for default model" : ""}`);
|
|
99699
99856
|
log((openaiKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` OpenAI (OPENAI_API_KEY) \u2014 optional, enables gpt-* models`);
|
|
99700
99857
|
log((googleKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` Google Gemini (GOOGLE_API_KEY) \u2014 optional, enables gemini-* models`);
|
|
99701
99858
|
log((cerebrasKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` Cerebras (CEREBRAS_API_KEY) \u2014 optional, enables llama-*/qwen-* at ~20x faster inference`);
|
|
99702
|
-
|
|
99859
|
+
log((zaiKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` Z.AI (ZAI_API_KEY) \u2014 optional, enables glm-* models such as glm-5.1`);
|
|
99860
|
+
if (!anthropicKey && !openaiKey && !googleKey && !cerebrasKey && !zaiKey) {
|
|
99703
99861
|
log(chalk6.red(" \u2717") + " No AI provider API keys found \u2014 at least one is required");
|
|
99704
99862
|
allPassed = false;
|
|
99705
99863
|
}
|
|
@@ -99711,7 +99869,7 @@ program2.command("serve").description("Start the Open Testers web dashboard").op
|
|
|
99711
99869
|
try {
|
|
99712
99870
|
const port = parseInt(opts.port, 10);
|
|
99713
99871
|
const url2 = `http://localhost:${port}`;
|
|
99714
|
-
const serverBin =
|
|
99872
|
+
const serverBin = join20(resolve4(process.execPath, ".."), "..", "dist", "server", "index.js");
|
|
99715
99873
|
const { join: pathJoin, resolve: pathResolve, dirname: dirname7 } = await import("path");
|
|
99716
99874
|
const { fileURLToPath: fileURLToPath2 } = await import("url");
|
|
99717
99875
|
const serverPath = pathJoin(dirname7(fileURLToPath2(import.meta.url)), "..", "server", "index.js");
|
|
@@ -100127,7 +100285,7 @@ workflowCmd.command("create <name>").description("Save a reusable testing workfl
|
|
|
100127
100285
|
}, []).option("--priority <level>", "Scenario priority").option("--persona <ids>", "Comma-separated persona IDs").option("--goal <prompt>", "Goal prompt for the agentic testing loop").option("--success <criteria>", "Success criteria (repeatable)", (val, acc) => {
|
|
100128
100286
|
acc.push(val);
|
|
100129
100287
|
return acc;
|
|
100130
|
-
}, []).option("--max-iterations <n>", "Goal-loop iteration cap", "10").option("--target <target>", "Execution target: local or
|
|
100288
|
+
}, []).option("--max-iterations <n>", "Goal-loop iteration cap", "10").option("--target <target>", "Execution target: local or sandbox", "local").option("--sandbox-provider <provider>", "Sandbox provider: e2b, daytona, or modal").option("--sandbox-image <image>", "Sandbox image/template").option("--sandbox-remote-dir <path>", "Remote working directory for sandbox runs").option("--sandbox-cleanup <mode>", "Sandbox cleanup mode: delete, stop, or keep", "delete").option("--sandbox-setup-command <command>", "Shell command to run before testers in the sandbox").option("--sandbox-package <spec>", "Package spec to execute in the sandbox", "@hasna/testers").option("--e2b-template <name>", "Legacy alias for --sandbox-image").option("--timeout <ms>", "Workflow timeout").option("--json", "Output as JSON", false).action((name21, opts) => {
|
|
100131
100289
|
try {
|
|
100132
100290
|
const workflow = createTestingWorkflow({
|
|
100133
100291
|
name: name21,
|
|
@@ -100146,9 +100304,12 @@ workflowCmd.command("create <name>").description("Save a reusable testing workfl
|
|
|
100146
100304
|
} : null,
|
|
100147
100305
|
execution: {
|
|
100148
100306
|
target: opts.target,
|
|
100149
|
-
|
|
100150
|
-
|
|
100151
|
-
|
|
100307
|
+
provider: opts.sandboxProvider ?? (opts.target === "connector:e2b" ? "e2b" : undefined),
|
|
100308
|
+
sandboxImage: opts.sandboxImage ?? opts.e2bTemplate,
|
|
100309
|
+
sandboxRemoteDir: opts.sandboxRemoteDir,
|
|
100310
|
+
sandboxCleanup: opts.sandboxCleanup,
|
|
100311
|
+
setupCommand: opts.sandboxSetupCommand,
|
|
100312
|
+
packageSpec: opts.sandboxPackage,
|
|
100152
100313
|
timeoutMs: opts.timeout ? parseInt(opts.timeout, 10) : undefined
|
|
100153
100314
|
}
|
|
100154
100315
|
});
|
|
@@ -100180,7 +100341,7 @@ workflowCmd.command("list").description("List saved testing workflows").option("
|
|
|
100180
100341
|
log(chalk6.bold(" Testing Workflows"));
|
|
100181
100342
|
log("");
|
|
100182
100343
|
for (const workflow of workflows) {
|
|
100183
|
-
const target = workflow.execution.target === "
|
|
100344
|
+
const target = workflow.execution.target === "sandbox" ? chalk6.cyan(`sandbox${workflow.execution.provider ? `:${workflow.execution.provider}` : ""}`) : chalk6.green("local");
|
|
100184
100345
|
log(` ${chalk6.dim(workflow.id.slice(0, 8))} ${workflow.name} ${target} ${chalk6.dim(workflow.personaIds.length ? `${workflow.personaIds.length} personas` : "no personas")}`);
|
|
100185
100346
|
}
|
|
100186
100347
|
log("");
|
|
@@ -100392,7 +100553,7 @@ personaCmd.command("delete <id>").description("Delete a persona").option("-y, --
|
|
|
100392
100553
|
}
|
|
100393
100554
|
if (!opts.yes) {
|
|
100394
100555
|
process.stdout.write(chalk6.yellow(`Delete persona ${persona.shortId} "${persona.name}"? [y/N] `));
|
|
100395
|
-
const answer = await new Promise((
|
|
100556
|
+
const answer = await new Promise((resolve5) => {
|
|
100396
100557
|
let buf = "";
|
|
100397
100558
|
process.stdin.setRawMode?.(true);
|
|
100398
100559
|
process.stdin.resume();
|
|
@@ -100402,7 +100563,7 @@ personaCmd.command("delete <id>").description("Delete a persona").option("-y, --
|
|
|
100402
100563
|
process.stdin.pause();
|
|
100403
100564
|
process.stdout.write(`
|
|
100404
100565
|
`);
|
|
100405
|
-
|
|
100566
|
+
resolve5(buf);
|
|
100406
100567
|
});
|
|
100407
100568
|
});
|
|
100408
100569
|
if (answer !== "y" && answer !== "yes") {
|
|
@@ -100563,7 +100724,7 @@ evalCmd.command("rag <url>").description("Run RAG quality evaluation \u2014 fait
|
|
|
100563
100724
|
let ragTestCases = [];
|
|
100564
100725
|
if (opts.docs) {
|
|
100565
100726
|
try {
|
|
100566
|
-
const raw =
|
|
100727
|
+
const raw = readFileSync10(opts.docs, "utf-8");
|
|
100567
100728
|
ragTestCases = JSON.parse(raw);
|
|
100568
100729
|
} catch {
|
|
100569
100730
|
logError(chalk6.red(`Failed to read docs file: ${opts.docs}`));
|
|
@@ -100653,9 +100814,9 @@ Created golden answer check ${chalk6.bold(golden2.shortId)}`));
|
|
|
100653
100814
|
}
|
|
100654
100815
|
const ask = (prompt) => {
|
|
100655
100816
|
const rl2 = createInterface({ input: process.stdin, output: process.stdout });
|
|
100656
|
-
return new Promise((
|
|
100817
|
+
return new Promise((resolve5) => rl2.question(prompt, (ans) => {
|
|
100657
100818
|
rl2.close();
|
|
100658
|
-
|
|
100819
|
+
resolve5(ans.trim());
|
|
100659
100820
|
}));
|
|
100660
100821
|
};
|
|
100661
100822
|
const question = await ask("Question (what this endpoint should answer): ");
|
|
@@ -100816,9 +100977,9 @@ program2.command("run-many <url>").description("Run scenarios \xD7 personas matr
|
|
|
100816
100977
|
});
|
|
100817
100978
|
program2.command("run-script <file>").description("Run a hybrid test script (.ts) that exports an array of HybridScenario objects").option("--url <url>", "Base URL to run against").option("--json", "Output as JSON", false).action(async (file2, opts) => {
|
|
100818
100979
|
try {
|
|
100819
|
-
const { resolve:
|
|
100980
|
+
const { resolve: resolve5 } = await import("path");
|
|
100820
100981
|
const { runHybridScenario: runHybridScenario2 } = await Promise.resolve().then(() => (init_hybrid_runner(), exports_hybrid_runner));
|
|
100821
|
-
const scriptPath =
|
|
100982
|
+
const scriptPath = resolve5(process.cwd(), file2);
|
|
100822
100983
|
const mod = await import(scriptPath);
|
|
100823
100984
|
const scenarios = mod.scenarios ?? mod.default ?? [];
|
|
100824
100985
|
if (!Array.isArray(scenarios) || scenarios.length === 0) {
|