@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 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 === "openai" || provider === "google") {
13973
- const baseUrl = provider === "openai" ? "https://api.openai.com/v1" : "https://generativelanguage.googleapis.com/v1beta/openai";
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.accessibility.snapshot();
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 userParts = [
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 createClientForModel(model, apiKey) {
14939
- const provider = detectProvider(model);
15039
+ function createOpenAICompatibleConfig(provider, apiKey) {
14940
15040
  if (provider === "openai") {
14941
- const key = apiKey ?? process.env["OPENAI_API_KEY"];
14942
- if (!key)
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: key };
15044
+ return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: key2 };
14945
15045
  }
14946
15046
  if (provider === "google") {
14947
- const key = apiKey ?? process.env["GOOGLE_API_KEY"];
14948
- if (!key)
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: key };
15050
+ return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: key2 };
14951
15051
  }
14952
15052
  if (provider === "cerebras") {
14953
- const key = apiKey ?? process.env["CEREBRAS_API_KEY"];
14954
- if (!key)
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: key };
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
- apiKey = process.env["ANTHROPIC_API_KEY"] ?? process.env["CEREBRAS_API_KEY"] ?? process.env["OPENAI_API_KEY"] ?? process.env["GOOGLE_API_KEY"] ?? globalConfig.anthropicApiKey;
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 === "openai" || provider === "google" || provider === "cerebras") {
15546
- const baseUrl = provider === "openai" ? "https://api.openai.com/v1" : provider === "cerebras" ? "https://api.cerebras.ai/v1" : "https://generativelanguage.googleapis.com/v1beta/openai";
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
- onRunEvent: () => onRunEvent
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 ?? config.anthropicApiKey);
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
- let updatedResult = updateResult(result.id, {
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: agentResult.reasoning ? agentResult.reasoning + lightpandaNote : lightpandaNote || undefined,
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: { consoleLogs, ...networkErrors.length > 0 ? networkMeta : {} }
18480
+ metadata: {
18481
+ consoleLogs,
18482
+ ...networkErrors.length > 0 ? networkMeta : {},
18483
+ ...structuredAssertionMeta
18484
+ }
17927
18485
  });
17928
- if (agentResult.status === "failed" || agentResult.status === "error") {
17929
- const failureAnalysis = analyzeFailure(null, agentResult.reasoning ?? 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 (agentResult.status === "passed") {
18492
+ if (assertionOutcome.status === "passed") {
17935
18493
  try {
17936
18494
  updateScenarioPassedCache(scenario.id, options.url);
17937
18495
  } catch {}
17938
18496
  }
17939
- const eventType = agentResult.status === "passed" ? "scenario:pass" : "scenario:fail";
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
- updateResult(result.id, { metadata: { harPath } });
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
- async function runByFilter(options) {
18137
- let scenarios;
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 all = listScenarios({ projectId: options.projectId });
18140
- scenarios = all.filter((s) => options.scenarioIds.includes(s.id) || options.scenarioIds.includes(s.shortId));
18141
- if (scenarios.length === 0 && options.projectId) {
18142
- const global2 = listScenarios({});
18143
- scenarios = global2.filter((s) => options.scenarioIds.includes(s.id) || options.scenarioIds.includes(s.shortId));
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
- } else {
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
- let scenarios;
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
- const target = input?.target ?? "local";
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
- const response = await anthropicClient.messages.create({
25796
- model,
25797
- max_tokens: 2048,
25798
- messages
25799
- });
25800
- const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
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 = createClient(options.apiKey ?? config.anthropicApiKey);
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 join62 } from "path";
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 readFileSync42 } from "fs";
26589
+ import { readFileSync as readFileSync32 } from "fs";
26030
26590
  import { webcrypto as crypto2 } from "crypto";
26031
- import { existsSync as existsSync5, writeFileSync as writeFileSync42, readFileSync as readFileSync32, mkdirSync as mkdirSync32 } from "fs";
26032
- import { join as join52 } from "path";
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 join18, resolve as resolve3 } from "path";
26036
- import { existsSync as existsSync22, writeFileSync as writeFileSync6 } from "fs";
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 { writeFileSync as writeFileSync22, existsSync as existsSync32, readFileSync as readFileSync8 } from "fs";
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 join42, dirname as dirname22 } from "path";
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 writeFileSync52 } from "fs";
26051
- import { dirname as dirname42, join as join72, relative as relative3 } from "path";
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 existsSync72, readdirSync as readdirSync5, readFileSync as readFileSync52, statSync as statSync22 } from "fs";
26054
- import { basename as basename2, join as join82, resolve as resolve22 } from "path";
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 existsSync82, readFileSync as readFileSync62, writeFileSync as writeFileSync62, mkdirSync as mkdirSync52 } from "fs";
26057
- import { dirname as dirname5, join as join92 } from "path";
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 { readFileSync as readFileSync72 } from "fs";
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 join132 } from "path";
26629
+ import { dirname as dirname6, join as join122 } from "path";
26072
26630
  import { fileURLToPath } from "url";
26073
- import { existsSync as existsSync122 } from "fs";
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 join18(home, ".hasna", "projects", "projects.db");
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(resolve3(filePath));
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
- execFileSync("git", ["init", "-b", "main"], { cwd: path, stdio: "pipe", env: process.env });
26812
+ execSync3("git init", { cwd: path, stdio: "pipe" });
26266
26813
  const gitignorePath = join22(path, ".gitignore");
26267
26814
  if (!existsSync22(gitignorePath)) {
26268
- writeFileSync6(gitignorePath, GITIGNORE_TEMPLATE, "utf-8");
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
- writeFileSync6(join22(path, ".project.json"), JSON.stringify(projectJson, null, 2) + `
26824
+ writeFileSync7(join22(path, ".project.json"), JSON.stringify(projectJson, null, 2) + `
26278
26825
  `, "utf-8");
26279
- const staged = bootstrapPathsToStage(path);
26280
- if (staged.length === 0)
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(join52(path, dir), { recursive: true });
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 = join52(project.path, ".project.json");
26672
- if (existsSync5(jsonPath)) {
26673
- const existing = JSON.parse(readFileSync32(jsonPath, "utf-8"));
26674
- writeFileSync42(jsonPath, JSON.stringify({ ...existing, integrations: merged }, null, 2) + `
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 = join72(dir, entry.name);
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(join72(project.path, relPath));
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 = join72(project.path, relPath);
28242
+ const localPath = join62(project.path, relPath);
27859
28243
  mkdirSync4(dirname42(localPath), { recursive: true });
27860
- writeFileSync52(localPath, data);
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 = join82(projectPath, "package.json");
27882
- if (existsSync72(pkgPath)) {
28265
+ const pkgPath = join72(projectPath, "package.json");
28266
+ if (existsSync62(pkgPath)) {
27883
28267
  try {
27884
- const pkg = JSON.parse(readFileSync52(pkgPath, "utf-8"));
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 = join82(projectPath, ".project.json");
27890
- if (existsSync72(projPath)) {
28273
+ const projPath = join72(projectPath, ".project.json");
28274
+ if (existsSync62(projPath)) {
27891
28275
  try {
27892
- const p2 = JSON.parse(readFileSync52(projPath, "utf-8"));
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 = join82(projectPath, ".git", "config");
27901
- if (!existsSync72(gitConfigPath))
28284
+ const gitConfigPath = join72(projectPath, ".git", "config");
28285
+ if (!existsSync62(gitConfigPath))
27902
28286
  return;
27903
28287
  try {
27904
- const config = readFileSync52(gitConfigPath, "utf-8");
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 (!existsSync72(absPath)) {
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 (!existsSync72(absDir)) {
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 = join82(absDir, entry.name);
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
- const branch = getCurrentBranch(path);
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 (!existsSync82(CONFIG_PATH22)) {
28402
+ if (!existsSync72(CONFIG_PATH22)) {
28020
28403
  return { enabled: false, interval: "daily", direction: "both" };
28021
28404
  }
28022
- return JSON.parse(readFileSync62(CONFIG_PATH22, "utf-8"));
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
- writeFileSync62(CONFIG_PATH22, JSON.stringify(config, null, 2) + `
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" ? join102(homedir32(), "Workspace") : join102(homedir32(), "workspace");
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 existsSync92(path);
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 (!existsSync102(join112(path, ".git")))
28480
+ if (!existsSync92(join102(path, ".git")))
28098
28481
  return "not a repo";
28099
28482
  try {
28100
- const out = execSync3("git status --porcelain", { cwd: path, stdio: "pipe", encoding: "utf-8" }).trim();
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 (!existsSync102(path))
28494
+ if (!existsSync92(path))
28112
28495
  return 0;
28113
28496
  try {
28114
- const out = execSync3(`du -sb -- "${path}" 2>/dev/null || du -sk -- "${path}" 2>/dev/null`, { stdio: "pipe", encoding: "utf-8" }).trim();
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 = existsSync102(project.path);
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 execSync22(cmd, { encoding: "utf-8", stdio: "pipe" }).trim();
28517
+ return execSync32(cmd, { encoding: "utf-8", stdio: "pipe" }).trim();
28135
28518
  }
28136
28519
  function getTmuxSessionName(project) {
28137
- return project.slug || project.name;
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
- let output = "";
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: existsSync112(workdir.path),
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 (!existsSync112(join122(path, ".git"))) {
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 = join132(process.env["HOME"] || "~", ".hasna", "cloud", "config.json");
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 = join132(dirname6(fileURLToPath(import.meta.url)), "..", "..", "package.json");
28398
- return JSON.parse(readFileSync72(pkgPath, "utf-8")).version || "0.0.0";
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" && !existsSync122(p2.path)) {
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 && !existsSync122(workdir.path)) {
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] ?? readFileSync42(webIdentityTokenFile, { encoding: "ascii" }),
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
- `, BOOTSTRAP_PATHS, CONFIG_PATH3, DEFAULTS, nanoid, import_protocol_http, addExpectContinueMiddlewareOptions, getAddExpectContinuePlugin = (options) => ({
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 numberValue = parseInt(obj[key], 10);
42532
- if (Number.isNaN(numberValue)) {
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 numberValue;
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 = "/Users/hasna/Workspace/hasna/opensource/open-projects/node_modules/@aws-sdk/util-user-agent-node/dist-cjs";
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 ?? join62(homedir22(), ".aws", "login", "cache");
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 join62(directory, `${loginSessionSha256}.json`);
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
- BOOTSTRAP_PATHS = [
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 = join92(process.env["HOME"] || "~", ".hasna", "projects", "scheduler.json");
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 readFileSync9 } from "fs";
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 = readFileSync9(filePathOrUrl, "utf-8");
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 = readFileSync9(filePathOrUrl, "utf-8");
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 === "openai" || provider === "google") {
57489
- const baseUrl = provider === "openai" ? "https://api.openai.com/v1" : "https://generativelanguage.googleapis.com/v1beta/openai";
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((resolve4) => setTimeout(resolve4, timeout))
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(config2) {
74586
- if (typeof config2 == "function")
74587
- throw new TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");
74588
- const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config2, pendingFragments = [];
74589
- let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
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 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
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), pendingFragmentsLength += chunk.length, checkBufferSize();
74966
+ pendingFragments.push(chunk);
74601
74967
  return;
74602
74968
  }
74603
74969
  pendingFragments.push(chunk);
74604
74970
  const input = pendingFragments.join("");
74605
- pendingFragments.length = 0, pendingFragmentsLength = 0;
74971
+ pendingFragments.length = 0;
74606
74972
  const trailing = processLines(input);
74607
- trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
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, pendingFragmentsLength = 0, terminated = false;
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, maxBufferSize } = {}) {
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
- typeof onError == "function" && onError(error40), (onError === "terminate" || error40.type === "max-buffer-size-exceeded") && controller.error(error40);
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 resolve4(value) {
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.27", getOriginalFetch = () => globalThis.fetch, getFromApi = async ({
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 import_path27 = __toESM4(__require("path"));
76867
- var import_fs31 = __toESM4(__require("fs"));
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 !== import_path27.default.dirname(dir)) {
76874
- const pkgPath = import_path27.default.join(dir, ".vercel");
76875
- if (import_fs31.default.existsSync(pkgPath)) {
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 = import_path27.default.dirname(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 import_path27.default.join(import_os13.default.homedir(), "Library/Application Support");
77251
+ return import_path26.default.join(import_os13.default.homedir(), "Library/Application Support");
76892
77252
  case "linux":
76893
- return import_path27.default.join(import_os13.default.homedir(), ".local/share");
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 resolve4(this.config.headers()),
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 resolve4(this.config.headers()),
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 resolve4(this.config.headers()),
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 resolve4(this.config.headers()),
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 resolve4(this.config.headers());
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 resolve4(this.config.o11yHeaders)),
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 resolve4(this.config.headers());
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 resolve4(this.config.o11yHeaders)),
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 resolve4(this.config.headers());
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 resolve4(this.config.o11yHeaders)),
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 resolve4(this.config.headers());
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 resolve4(this.config.o11yHeaders)),
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 resolve4(this.config.headers());
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 resolve4(this.config.o11yHeaders), { accept: "text/event-stream" }),
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 resolve4(this.config.headers());
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 resolve4(this.config.o11yHeaders)),
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.120", AI_GATEWAY_PROTOCOL_VERSION = "0.0.1", gateway;
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.1";
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 = typeof globalThis === "object" ? globalThis : typeof self === "object" ? self : typeof window === "object" ? window : typeof global === "object" ? 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
- return logger[funcName](namespace, ...args);
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 = exports._originalConsoleMethods = undefined;
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
- let theFunc = exports._originalConsoleMethods[funcName];
79327
- if (typeof theFunc !== "function") {
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
- if (typeof theFunc === "function") {
79337
- return theFunc.apply(console, args);
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(spanContext = invalid_span_constants_1.INVALID_SPAN_CONTEXT) {
79576
- this._spanContext = 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 isHex = new Uint8Array([
79653
- 0,
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 isValidHex(traceId, 32) && traceId !== invalid_span_constants_1.INVALID_TRACEID;
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 isValidHex(spanId, 16) && spanId !== invalid_span_constants_1.INVALID_SPANID;
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 spanContext !== null && typeof spanContext === "object" && "spanId" in spanContext && typeof spanContext["spanId"] === "string" && "traceId" in spanContext && typeof spanContext["traceId"] === "string" && "traceFlags" in spanContext && typeof spanContext["traceFlags"] === "number";
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(provider, name15, version2, options) {
79844
- this._provider = 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 Array.from(this._internalState.keys()).reduceRight((agg, key) => {
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).reduceRight((agg, part) => {
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
- var _a21;
81162
- const downloadableFiles = [];
81163
- for (const message of messages) {
81164
- if (message.role === "user" && Array.isArray(message.content)) {
81165
- for (const part of message.content) {
81166
- if (part.type === "image" || part.type === "file") {
81167
- downloadableFiles.push({
81168
- data: part.type === "image" ? part.image : part.data,
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 = APICallError.isInstance(error40) ? error40.responseHeaders : APICallError.isInstance(error40.cause) ? error40.cause.responseHeaders : undefined;
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 && (APICallError.isInstance(error40) && error40.isRetryable === true || GatewayError.isInstance(error40) && error40.isRetryable === true) && tryNumber <= maxRetries) {
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: tool2 == null ? undefined : tool2.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: toolCall.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: toolCall.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, _b16;
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: (_b16 = modelResponse.warnings) != null ? _b16 : [],
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, _b16;
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: (_b16 = modelResponse.warnings) != null ? _b16 : [],
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, _b16;
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: (_b16 = modelResponse.warnings) != null ? _b16 : [],
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.191", download = async ({
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: resolve4(schema.jsonSchema).then((jsonSchema2) => ({
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: resolve4(elementSchema.jsonSchema).then((jsonSchema2) => {
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, toolMetadataSchema, uiMessageChunkSchema, isToolOrDynamicToolUIPart, getToolOrDynamicToolName, originalGenerateId2, DefaultStreamTextResult = class {
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
- }, toolMetadataSchema2, uiMessagesSchema, DefaultEmbedResult = class {
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 resolve4(this.body);
90872
- const resolvedHeaders = await resolve4(this.headers);
90873
- const resolvedCredentials = await resolve4(this.credentials);
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 resolve4(this.body);
90922
- const resolvedHeaders = await resolve4(this.headers);
90923
- const resolvedCredentials = await resolve4(this.credentials);
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().optional(),
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().optional(),
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 readFileSync10 } from "fs";
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 === "openai" || provider === "google") {
93315
- const baseUrl = provider === "openai" ? "https://api.openai.com/v1" : "https://generativelanguage.googleapis.com/v1beta/openai";
93316
- const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
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 = readFileSync10(filePath, "utf-8");
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 = readFileSync10(filePath, "utf-8").trim();
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 ?? config2.anthropicApiKey);
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.33",
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.5",
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 readFileSync11, readdirSync as readdirSync6, writeFileSync as writeFileSync7 } from "fs";
94081
+ import { readFileSync as readFileSync10, readdirSync as readdirSync6, writeFileSync as writeFileSync8 } from "fs";
93928
94082
  import { createInterface } from "readline";
93929
- import { join as join19, resolve as resolve5 } from "path";
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
- connectorCommand: workflow.execution.target === "connector:e2b" ? buildConnectorCommand(workflow.execution, runOptions) : null
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 === "connector:e2b") {
95691
- const connectorResult = await runViaConnector(plan);
95692
- return { run: null, results: [], plan, connectorResult };
95848
+ if (workflow.execution.target === "sandbox") {
95849
+ const sandboxResult = await runViaSandbox(plan, dependencies);
95850
+ return { run: null, results: [], plan, sandboxResult };
95693
95851
  }
95694
- const { run, results } = await runByFilter(plan.runOptions);
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 buildConnectorCommand(execution, runOptions) {
95705
- const connector = execution.connector ?? "e2b";
95706
- const operation = execution.operation ?? "run";
95707
- const payload = JSON.stringify({
95708
- operation,
95709
- template: execution.sandboxTemplate,
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
- "bunx",
95714
- "@hasna/testers",
95715
- "run",
95716
- runOptions.url,
95717
- ...runOptions.scenarioIds?.length ? ["--scenario", runOptions.scenarioIds.join(",")] : [],
95718
- ...runOptions.tags?.length ? runOptions.tags.flatMap((tag) => ["--tag", tag]) : [],
95719
- ...runOptions.priority ? ["--priority", runOptions.priority] : [],
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
- async function runViaConnector(plan) {
95728
- if (!plan.connectorCommand)
95729
- throw new Error("Workflow does not have a connector command");
95730
- const proc = Bun.spawn(plan.connectorCommand, {
95731
- stdout: "pipe",
95732
- stderr: "pipe",
95733
- env: process.env
95734
- });
95735
- const [stdout, stderr, exitCode] = await Promise.all([
95736
- new Response(proc.stdout).text(),
95737
- new Response(proc.stderr).text(),
95738
- proc.exited
95739
- ]);
95740
- if (exitCode !== 0) {
95741
- throw new Error(`Connector execution failed (${exitCode}): ${stderr || stdout}`);
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
- return stdout.trim();
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 writeFileSync4, mkdirSync as mkdirSync11, unlinkSync } from "fs";
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 join16, resolve, relative as relative2 } from "path";
96058
+ import { join as join17, resolve, relative as relative2 } from "path";
95918
96059
  function getCacheDir() {
95919
96060
  const testersDir = getTestersDir();
95920
- const cacheDir = join16(testersDir, "repo-index");
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 join16(getCacheDir(), `${pathHash(repoPath)}.json`);
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 = join16(repoPath, spec.file);
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 = join16(repoPath, cached.configPath);
96087
+ const configFullPath = join17(repoPath, cached.configPath);
95947
96088
  if (!existsSync14(configFullPath))
95948
96089
  return true;
95949
96090
  try {
95950
- const stat = statSync(configFullPath);
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
- writeFileSync4(cachePath, JSON.stringify(snapshot, null, 2), "utf-8");
96114
+ writeFileSync5(cachePath, JSON.stringify(snapshot, null, 2), "utf-8");
95974
96115
  }
95975
96116
  function detectPackageManager(repoPath) {
95976
96117
  const result = {
95977
- npm: existsSync14(join16(repoPath, "package-lock.json")),
95978
- yarn: existsSync14(join16(repoPath, "yarn.lock")),
95979
- pnpm: existsSync14(join16(repoPath, "pnpm-lock.yaml")),
95980
- bun: existsSync14(join16(repoPath, "bun.lockb")) || existsSync14(join16(repoPath, "bun.lock")),
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 = join16(repoPath, "package.json");
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(join16(repoPath, name)))
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 = join16(repoPath, configPath);
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
- if (testMatchArray) {
96042
- const items = testMatchArray[1].match(/['"`]([^'"`]+)['"`]/g);
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
- if (testMatchSingle) {
96051
- patterns.push(testMatchSingle[1]);
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 ? join16(repoPath, dir) : repoPath;
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 = join16(dir, entry.name);
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 = join16(repoPath, "package.json");
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 = join16(repoPath, "node_modules", ".cache", "ms-playwright");
96292
+ const cacheDir = join17(repoPath, "node_modules", ".cache", "ms-playwright");
96150
96293
  if (existsSync14(cacheDir))
96151
96294
  return true;
96152
- const globalCache = join16(repoPath, ".cache", "ms-playwright");
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(pm) {
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(join16(repoPath, configPath), "utf-8");
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(join16(repoPath, "node_modules", "playwright")) || existsSync14(join16(repoPath, "node_modules", "@playwright", "test"));
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(join16(cacheDir, file));
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 writeFileSync5 } from "fs";
96287
- import { join as join17 } from "path";
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 = join17(repoPath, "node_modules", ".bin", "playwright");
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, workingDir);
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, stderr) {
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 run = createRun({
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
- metadata: {
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 = join17(getTestersDir(), "repo-run-output");
96628
+ const reportersDir = join18(getTestersDir(), "repo-run-output");
96484
96629
  mkdirSync12(reportersDir, { recursive: true });
96485
- const outputFile = join17(reportersDir, `${resultRecord.id}.log`);
96486
- writeFileSync5(outputFile, `=== stdout ===
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
- writeFileSync7(resolve5(opts.output), output + `
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 = join19(CONFIG_DIR5, "config.json");
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(readFileSync11(CONFIG_PATH4, "utf-8"));
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
- return optProject ?? getActiveProject();
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((resolve6) => {
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
- resolve6(buf);
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((resolve6) => {
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
- resolve6(buf);
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
- if (!hasAnthropic && !hasOpenAI && !hasGoogle && !hasCerebras) {
97170
- logError(chalk6.red("No AI API key found. Set ANTHROPIC_API_KEY (recommended), or OPENAI_API_KEY / GOOGLE_API_KEY / CEREBRAS_API_KEY."));
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 (opts.scenario && s2.id !== opts.scenario && s2.shortId !== opts.scenario)
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: opts.scenario ? [opts.scenario] : undefined,
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((resolve6) => {
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
- resolve6();
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
- writeFileSync7(opts.output, jsonOutput, "utf-8");
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 = !opts.scenario && opts.tag.length === 0 && !opts.priority;
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 ?? (opts.scenario ? [opts.scenario] : undefined),
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
- writeFileSync7(opts.output, jsonOutput, "utf-8");
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 = resolve5(dir);
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 = readFileSync11(join19(absDir, file2), "utf-8");
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
- writeFileSync7(outputPath, data, "utf-8");
97781
- log(chalk6.green(`Exported ${scenarios.length} scenario(s) to ${resolve5(outputPath)}`));
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 = join19(outputDir, `${s2.shortId}-${safeFilename}.md`);
97814
- writeFileSync7(filePath, lines.join(`
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 ${resolve5(outputDir)}`));
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 = join19(getTestersDir(), "testers.db");
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(readFileSync11(CONFIG_PATH4, "utf-8"));
98148
+ config2 = JSON.parse(readFileSync10(CONFIG_PATH4, "utf-8"));
97993
98149
  } catch {}
97994
98150
  }
97995
98151
  config2.activeProject = project.id;
97996
- writeFileSync7(CONFIG_PATH4, JSON.stringify(config2, null, 2), "utf-8");
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 = resolve5(path ?? process.cwd());
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 = resolve5(path ?? process.cwd());
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 = resolve5(path ?? process.cwd());
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 ? resolve5(path) : undefined;
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 = resolve5(path ?? process.cwd());
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 = resolve5(path ?? process.cwd());
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: readFileSync12 } = await import("fs");
98334
- const raw = readFileSync12(file2, "utf-8");
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((resolve6) => setTimeout(resolve6, intervalMs));
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 = resolve5(opts.output);
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
- writeFileSync7(outPath, workflow, "utf-8");
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 = join19(process.cwd(), ".github", "workflows");
98795
+ const workflowDir = join20(process.cwd(), ".github", "workflows");
98640
98796
  if (!existsSync17(workflowDir)) {
98641
98797
  mkdirSync14(workflowDir, { recursive: true });
98642
98798
  }
98643
- const workflowPath = join19(workflowDir, "testers.yml");
98644
- writeFileSync7(workflowPath, generateGitHubActionsWorkflow(), "utf-8");
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((resolve6) => rl2.question(q2, resolve6));
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
- writeFileSync7(opts.output, content, "utf-8");
98839
- const absPath2 = resolve5(opts.output);
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
- writeFileSync7(opts.output, html, "utf-8");
98853
- const absPath = resolve5(opts.output);
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 = join19(getTestersDir(), "testers.db");
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
- if (!anthropicKey && !openaiKey && !googleKey && !cerebrasKey) {
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 = join19(resolve5(process.execPath, ".."), "..", "dist", "server", "index.js");
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 connector:e2b", "local").option("--e2b-template <name>", "E2B sandbox template name").option("--connector-operation <name>", "Connector operation for E2B", "run").option("--timeout <ms>", "Workflow timeout").option("--json", "Output as JSON", false).action((name21, opts) => {
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
- connector: opts.target === "connector:e2b" ? "e2b" : undefined,
100150
- operation: opts.connectorOperation,
100151
- sandboxTemplate: opts.e2bTemplate,
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 === "connector:e2b" ? chalk6.cyan("e2b") : chalk6.green("local");
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((resolve6) => {
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
- resolve6(buf);
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 = readFileSync11(opts.docs, "utf-8");
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((resolve6) => rl2.question(prompt, (ans) => {
100817
+ return new Promise((resolve5) => rl2.question(prompt, (ans) => {
100657
100818
  rl2.close();
100658
- resolve6(ans.trim());
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: resolve6 } = await import("path");
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 = resolve6(process.cwd(), file2);
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) {