@vostride/agent-qa-dashboard 0.1.9 → 0.1.10

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.
@@ -1,5 +1,5 @@
1
1
  import { Server, IncomingMessage, ServerResponse } from 'node:http';
2
- import { RunAttributes, RunArtifactKind, RunArtifactStageInput, RunArtifactPayload, RunArtifactFinalizeInput, LogEntry, ResolvedWorkspacePaths, ModelConfig, SecretStore, SecretRedactor, HookDefinition, ConsoleLogEntry, NetworkLogEntry, StepAnnotation, StepPhaseEvent, StepResult, buildAnalyticsEvent, captureAnalytics, resolveAnalyticsStandardProperties } from '@vostride/agent-qa-core';
2
+ import { RunAttributes, RunArtifactKind, RunArtifactStageInput, RunArtifactPayload, RunArtifactFinalizeInput, LogEntry, ResolvedWorkspacePaths, ModelConfig, ResolvedAppiumExecutable, SecretStore, SecretRedactor, HookDefinition, ConsoleLogEntry, NetworkLogEntry, StepAnnotation, StepPhaseEvent, StepResult, buildAnalyticsEvent, captureAnalytics, resolveAnalyticsStandardProperties } from '@vostride/agent-qa-core';
3
3
  import { LocalMcpEndpointConfig, LocalMcpTransport } from '@vostride/agent-qa-mcp';
4
4
  import { Document } from 'yaml';
5
5
  import { EventEmitter } from 'node:events';
@@ -548,11 +548,13 @@ declare class AppiumManager {
548
548
  private anonymousRefCount;
549
549
  private leases;
550
550
  private logLevel;
551
+ private appiumResolver;
551
552
  constructor(opts?: {
552
553
  port?: number;
553
554
  startupTimeoutMs?: number;
554
555
  pollIntervalMs?: number;
555
556
  logLevel?: 'normal' | 'debug';
557
+ appiumResolver?: () => ResolvedAppiumExecutable;
556
558
  });
557
559
  acquire(): Promise<void>;
558
560
  release(): void;
@@ -1,5 +1,5 @@
1
1
  import { Server, IncomingMessage, ServerResponse } from 'node:http';
2
- import { RunAttributes, RunArtifactKind, RunArtifactStageInput, RunArtifactPayload, RunArtifactFinalizeInput, LogEntry, ResolvedWorkspacePaths, ModelConfig, SecretStore, SecretRedactor, HookDefinition, ConsoleLogEntry, NetworkLogEntry, StepAnnotation, StepPhaseEvent, StepResult, buildAnalyticsEvent, captureAnalytics, resolveAnalyticsStandardProperties } from '@vostride/agent-qa-core';
2
+ import { RunAttributes, RunArtifactKind, RunArtifactStageInput, RunArtifactPayload, RunArtifactFinalizeInput, LogEntry, ResolvedWorkspacePaths, ModelConfig, ResolvedAppiumExecutable, SecretStore, SecretRedactor, HookDefinition, ConsoleLogEntry, NetworkLogEntry, StepAnnotation, StepPhaseEvent, StepResult, buildAnalyticsEvent, captureAnalytics, resolveAnalyticsStandardProperties } from '@vostride/agent-qa-core';
3
3
  import { LocalMcpEndpointConfig, LocalMcpTransport } from '@vostride/agent-qa-mcp';
4
4
  import { Document } from 'yaml';
5
5
  import { EventEmitter } from 'node:events';
@@ -548,11 +548,13 @@ declare class AppiumManager {
548
548
  private anonymousRefCount;
549
549
  private leases;
550
550
  private logLevel;
551
+ private appiumResolver;
551
552
  constructor(opts?: {
552
553
  port?: number;
553
554
  startupTimeoutMs?: number;
554
555
  pollIntervalMs?: number;
555
556
  logLevel?: 'normal' | 'debug';
557
+ appiumResolver?: () => ResolvedAppiumExecutable;
556
558
  });
557
559
  acquire(): Promise<void>;
558
560
  release(): void;
package/dist/index.cjs CHANGED
@@ -8304,6 +8304,7 @@ var ConfigManager = class {
8304
8304
  // src/execution/appium-manager.ts
8305
8305
  var import_node_http = require("http");
8306
8306
  var import_node_child_process2 = require("child_process");
8307
+ var import_agent_qa_core11 = require("@vostride/agent-qa-core");
8307
8308
  var import_tree_kill2 = __toESM(require("tree-kill"), 1);
8308
8309
  var import_picocolors = __toESM(require("picocolors"), 1);
8309
8310
  var APPIUM_PREFIX = import_picocolors.default.magenta("[appium]");
@@ -8318,11 +8319,13 @@ var AppiumManager = class {
8318
8319
  anonymousRefCount = 0;
8319
8320
  leases = /* @__PURE__ */ new Map();
8320
8321
  logLevel;
8322
+ appiumResolver;
8321
8323
  constructor(opts) {
8322
8324
  this.port = opts?.port ?? 4723;
8323
8325
  this.startupTimeoutMs = opts?.startupTimeoutMs ?? 3e4;
8324
8326
  this.pollIntervalMs = opts?.pollIntervalMs ?? 500;
8325
8327
  this.logLevel = opts?.logLevel ?? "normal";
8328
+ this.appiumResolver = opts?.appiumResolver ?? import_agent_qa_core11.resolveAppiumExecutable;
8326
8329
  }
8327
8330
  async acquire() {
8328
8331
  await this.ensureRunning();
@@ -8417,14 +8420,15 @@ var AppiumManager = class {
8417
8420
  });
8418
8421
  }
8419
8422
  async startAndWait() {
8420
- const child = (0, import_node_child_process2.spawn)("appium", ["-p", String(this.port), "--relaxed-security", "--log-no-colors"], {
8423
+ const appium = this.appiumResolver();
8424
+ const child = (0, import_node_child_process2.spawn)(appium.command, ["-p", String(this.port), "--relaxed-security", "--log-no-colors"], {
8421
8425
  stdio: ["ignore", "pipe", "pipe"]
8422
8426
  });
8423
8427
  this.process = child;
8424
8428
  this.managed = true;
8425
8429
  child.on("error", (err) => {
8426
8430
  if (err.code === "ENOENT") {
8427
- console.error(`${APPIUM_PREFIX} Appium not found. Run \`npm install -g appium\` to install it.`);
8431
+ console.error(`${APPIUM_PREFIX} Appium not found. ${(0, import_agent_qa_core11.formatAppiumInstallGuidance)()}`);
8428
8432
  } else {
8429
8433
  console.error(`${APPIUM_PREFIX} Error: ${err.message}`);
8430
8434
  }
@@ -8520,13 +8524,13 @@ var import_node_crypto4 = require("crypto");
8520
8524
 
8521
8525
  // src/live-editor/live-session.ts
8522
8526
  var import_node_crypto3 = require("crypto");
8523
- var import_agent_qa_core12 = require("@vostride/agent-qa-core");
8527
+ var import_agent_qa_core13 = require("@vostride/agent-qa-core");
8524
8528
 
8525
8529
  // src/live-editor/mobile-bootstrap.ts
8526
8530
  var import_promises10 = require("fs/promises");
8527
8531
  var import_node_path12 = require("path");
8528
8532
  var import_yaml8 = require("yaml");
8529
- var import_agent_qa_core11 = require("@vostride/agent-qa-core");
8533
+ var import_agent_qa_core12 = require("@vostride/agent-qa-core");
8530
8534
  async function loadLocalBindings(configPath) {
8531
8535
  const filePath = (0, import_node_path12.join)((0, import_node_path12.dirname)(configPath), "agent-qa.local.yaml");
8532
8536
  try {
@@ -8544,8 +8548,8 @@ async function loadLocalBindings(configPath) {
8544
8548
  }
8545
8549
  }
8546
8550
  function asMobileSetupError(err, category, message, input) {
8547
- if (err instanceof import_agent_qa_core11.MobileSetupError) return err;
8548
- return new import_agent_qa_core11.MobileSetupError({
8551
+ if (err instanceof import_agent_qa_core12.MobileSetupError) return err;
8552
+ return new import_agent_qa_core12.MobileSetupError({
8549
8553
  category,
8550
8554
  message: `${message}: ${err instanceof Error ? err.message : String(err)}`,
8551
8555
  platform: input.platform,
@@ -8555,7 +8559,7 @@ function asMobileSetupError(err, category, message, input) {
8555
8559
  }
8556
8560
  async function prepareMobileLiveSession(input) {
8557
8561
  if (!input.targetName) {
8558
- throw new import_agent_qa_core11.MobileSetupError({
8562
+ throw new import_agent_qa_core12.MobileSetupError({
8559
8563
  category: "device-resolution",
8560
8564
  message: `No targetName provided for ${input.platform} live session`,
8561
8565
  platform: input.platform
@@ -8571,7 +8575,7 @@ async function prepareMobileLiveSession(input) {
8571
8575
  const configuredAppState = config.use?.mobile?.appState;
8572
8576
  let resolved;
8573
8577
  try {
8574
- resolved = (0, import_agent_qa_core11.resolveMobileRunConfig)({
8578
+ resolved = (0, import_agent_qa_core12.resolveMobileRunConfig)({
8575
8579
  config,
8576
8580
  targetName: input.targetName,
8577
8581
  platform: input.platform,
@@ -8587,7 +8591,7 @@ async function prepareMobileLiveSession(input) {
8587
8591
  try {
8588
8592
  await input.appiumManager.acquireLease({ runId: input.sessionId, platform: input.platform });
8589
8593
  } catch (err) {
8590
- throw new import_agent_qa_core11.MobileSetupError({
8594
+ throw new import_agent_qa_core12.MobileSetupError({
8591
8595
  category: "appium-startup",
8592
8596
  message: `Failed to acquire Appium for ${input.platform} live session: ${err instanceof Error ? err.message : String(err)}`,
8593
8597
  platform: input.platform,
@@ -8703,9 +8707,9 @@ function classifyAdapterSetupError(err) {
8703
8707
  return "device-readiness";
8704
8708
  }
8705
8709
  function wrapAdapterSetupError(err, platform, config) {
8706
- if (err instanceof import_agent_qa_core12.MobileSetupError) return err;
8710
+ if (err instanceof import_agent_qa_core13.MobileSetupError) return err;
8707
8711
  const appId = platform === "android" ? config.appPackage : config.bundleId;
8708
- return new import_agent_qa_core12.MobileSetupError({
8712
+ return new import_agent_qa_core13.MobileSetupError({
8709
8713
  category: classifyAdapterSetupError(err),
8710
8714
  message: `Failed to create ${platform} adapter session: ${err instanceof Error ? err.message : String(err)}`,
8711
8715
  platform,
@@ -8785,10 +8789,10 @@ var LiveSession = class {
8785
8789
  this.pendingMessages.push(message);
8786
8790
  }
8787
8791
  redact(value) {
8788
- return (0, import_agent_qa_core12.redactSecretValue)(value, this.secretRedactor);
8792
+ return (0, import_agent_qa_core13.redactSecretValue)(value, this.secretRedactor);
8789
8793
  }
8790
8794
  resolveSecrets(value) {
8791
- return (0, import_agent_qa_core12.resolveSecretTemplatesInValue)(value, this.secretStore);
8795
+ return (0, import_agent_qa_core13.resolveSecretTemplatesInValue)(value, this.secretStore);
8792
8796
  }
8793
8797
  emitHookStart(hookDef, phase, owner = { scope: "suite" }) {
8794
8798
  const hook = {
@@ -8875,7 +8879,7 @@ var LiveSession = class {
8875
8879
  }
8876
8880
  continue;
8877
8881
  }
8878
- const result = await (0, import_agent_qa_core12.runHooks)([hookDef], {
8882
+ const result = await (0, import_agent_qa_core13.runHooks)([hookDef], {
8879
8883
  envVars: this.getHookEnvVars(),
8880
8884
  secretStore: this.secretStore,
8881
8885
  secretRedactor: this.secretRedactor
@@ -8985,7 +8989,7 @@ var LiveSession = class {
8985
8989
  adapter = new IOSPlatformAdapter();
8986
8990
  }
8987
8991
  } catch (err) {
8988
- throw new import_agent_qa_core12.MobileSetupError({
8992
+ throw new import_agent_qa_core13.MobileSetupError({
8989
8993
  category: "adapter-load",
8990
8994
  message: `Failed to load ${platformLabel} adapter (@vostride/agent-qa-${platform}). Is the package installed? ${err instanceof Error ? err.message : String(err)}`,
8991
8995
  platform,
@@ -9007,7 +9011,7 @@ var LiveSession = class {
9007
9011
  } catch {
9008
9012
  }
9009
9013
  this.releaseMobileAppiumLease("setup-failed");
9010
- if (err instanceof import_agent_qa_core12.MobileSetupError) {
9014
+ if (err instanceof import_agent_qa_core13.MobileSetupError) {
9011
9015
  throw new Error(mobileSetupMessage(err));
9012
9016
  }
9013
9017
  throw err;
@@ -9016,7 +9020,7 @@ var LiveSession = class {
9016
9020
  async initialize(config) {
9017
9021
  this.platform = config.platform;
9018
9022
  this._modelName = config.llmConfig.model ?? "unknown";
9019
- this.variableStore = new import_agent_qa_core12.VariableStore();
9023
+ this.variableStore = new import_agent_qa_core13.VariableStore();
9020
9024
  this.secretStore = config.secretStore;
9021
9025
  this.secretRedactor = config.secretRedactor;
9022
9026
  if (config.envVars) {
@@ -9060,10 +9064,10 @@ var LiveSession = class {
9060
9064
  ...config.llmConfig,
9061
9065
  ...config.authFetch ? { fetch: config.authFetch } : {}
9062
9066
  };
9063
- this.model = await (0, import_agent_qa_core12.createModel)(modelConfig);
9064
- const providerOptions = (0, import_agent_qa_core12.getProviderOptions)(modelConfig);
9065
- this.planner = new import_agent_qa_core12.LLMPlanner(this.model, config.platform, providerOptions, void 0, config.agentRules);
9066
- this.verifier = new import_agent_qa_core12.LLMVerifier(this.model, providerOptions);
9067
+ this.model = await (0, import_agent_qa_core13.createModel)(modelConfig);
9068
+ const providerOptions = (0, import_agent_qa_core13.getProviderOptions)(modelConfig);
9069
+ this.planner = new import_agent_qa_core13.LLMPlanner(this.model, config.platform, providerOptions, void 0, config.agentRules);
9070
+ this.verifier = new import_agent_qa_core13.LLMVerifier(this.model, providerOptions);
9067
9071
  this.status = "idle";
9068
9072
  this.createdAt = Date.now();
9069
9073
  this.readyForInteraction = true;
@@ -9073,7 +9077,7 @@ var LiveSession = class {
9073
9077
  let instruction = stepInstruction;
9074
9078
  let hasTemplateVars = false;
9075
9079
  const executionLogs = [];
9076
- const inlineHookCalls = (0, import_agent_qa_core12.parseHookInline)(stepInstruction);
9080
+ const inlineHookCalls = (0, import_agent_qa_core13.parseHookInline)(stepInstruction);
9077
9081
  if (inlineHookCalls.length > 0) {
9078
9082
  let inlineHookFailed = false;
9079
9083
  for (const call of inlineHookCalls) {
@@ -9088,7 +9092,7 @@ var LiveSession = class {
9088
9092
  }
9089
9093
  const startedAt = performance.now();
9090
9094
  try {
9091
- const result = await (0, import_agent_qa_core12.runHookInSandbox)(hookDef, {
9095
+ const result = await (0, import_agent_qa_core13.runHookInSandbox)(hookDef, {
9092
9096
  envVars: this.getHookEnvVars(),
9093
9097
  secretStore: this.secretStore,
9094
9098
  secretRedactor: this.secretRedactor
@@ -9134,7 +9138,7 @@ var LiveSession = class {
9134
9138
  break;
9135
9139
  }
9136
9140
  }
9137
- instruction = (0, import_agent_qa_core12.stripHookInline)(stepInstruction);
9141
+ instruction = (0, import_agent_qa_core13.stripHookInline)(stepInstruction);
9138
9142
  hasTemplateVars = true;
9139
9143
  if (inlineHookFailed) {
9140
9144
  return {
@@ -9145,7 +9149,7 @@ var LiveSession = class {
9145
9149
  };
9146
9150
  }
9147
9151
  }
9148
- instruction = (0, import_agent_qa_core12.interpolateVariables)(instruction, this.variableStore);
9152
+ instruction = (0, import_agent_qa_core13.interpolateVariables)(instruction, this.variableStore);
9149
9153
  hasTemplateVars = hasTemplateVars || originalStepName !== instruction;
9150
9154
  const runJSMatches = parseRunJSInline(instruction);
9151
9155
  if (runJSMatches.length > 0) {
@@ -9272,7 +9276,7 @@ var LiveSession = class {
9272
9276
  this.stepsExecuted++;
9273
9277
  return result2;
9274
9278
  }
9275
- const unresolvedTemplates = (0, import_agent_qa_core12.findUnresolvedTemplates)(prepared.instruction);
9279
+ const unresolvedTemplates = (0, import_agent_qa_core13.findUnresolvedTemplates)(prepared.instruction);
9276
9280
  if (unresolvedTemplates.length > 0) {
9277
9281
  const errorLines = unresolvedTemplates.map((template) => ` - ${template.pattern}: ${template.message}`);
9278
9282
  const error = `Unresolved template variable(s):
@@ -9314,7 +9318,7 @@ ${errorLines.join("\n")}`;
9314
9318
  healingConfig: { maxAttempts: 3 },
9315
9319
  variables: this.redact(variables)
9316
9320
  };
9317
- let result = await (0, import_agent_qa_core12.executeStep)(prepared.instruction, loopConfig, stepContext);
9321
+ let result = await (0, import_agent_qa_core13.executeStep)(prepared.instruction, loopConfig, stepContext);
9318
9322
  result.originalStepName = prepared.originalStepName;
9319
9323
  result.variableSnapshot = this.variableStore.snapshot();
9320
9324
  result.executionLogs = this.redact(prepared.executionLogs);
@@ -9669,7 +9673,7 @@ var SessionManager = class {
9669
9673
  };
9670
9674
 
9671
9675
  // src/live-editor/ws-handler.ts
9672
- var import_agent_qa_core13 = require("@vostride/agent-qa-core");
9676
+ var import_agent_qa_core14 = require("@vostride/agent-qa-core");
9673
9677
  function send(ws, msg) {
9674
9678
  if (ws.readyState === ws.OPEN) {
9675
9679
  ws.send(JSON.stringify(msg));
@@ -9837,7 +9841,7 @@ function createSessionHandler(session, onTerminate, onTokenUsage, testFileManage
9837
9841
  console.error(`[ws-handler] execute-test: read failed for path=${msg.path}`, readErr);
9838
9842
  throw new Error(`Cannot read test file "${msg.path}": ${readErr?.message ?? String(readErr)}`);
9839
9843
  }
9840
- const parsed = (0, import_agent_qa_core13.parseTestFile)(raw, msg.path);
9844
+ const parsed = (0, import_agent_qa_core14.parseTestFile)(raw, msg.path);
9841
9845
  if (parsed.errors.length > 0) {
9842
9846
  console.error(`[ws-handler] execute-test: parse errors for ${msg.path}`, parsed.errors);
9843
9847
  throw new Error(`Parse error in ${msg.path}: ${parsed.errors[0].message}`);
@@ -10017,7 +10021,7 @@ function createSessionHandler(session, onTerminate, onTokenUsage, testFileManage
10017
10021
  }
10018
10022
 
10019
10023
  // src/server/server.ts
10020
- var import_agent_qa_core14 = require("@vostride/agent-qa-core");
10024
+ var import_agent_qa_core15 = require("@vostride/agent-qa-core");
10021
10025
  var import_agent_qa_mcp = require("@vostride/agent-qa-mcp");
10022
10026
  var MIME_TYPES = {
10023
10027
  ".html": "text/html; charset=utf-8",
@@ -10436,8 +10440,8 @@ async function startServer(opts) {
10436
10440
  const captureMcpLifecycle = async (properties) => {
10437
10441
  if (isAnalyticsPrivacyEnabled(config)) return;
10438
10442
  try {
10439
- const standardProperties = await (0, import_agent_qa_core14.resolveAnalyticsStandardProperties)({ surface: "dashboard-server" });
10440
- await (0, import_agent_qa_core14.captureAnalytics)((0, import_agent_qa_core14.buildAnalyticsEvent)({
10443
+ const standardProperties = await (0, import_agent_qa_core15.resolveAnalyticsStandardProperties)({ surface: "dashboard-server" });
10444
+ await (0, import_agent_qa_core15.captureAnalytics)((0, import_agent_qa_core15.buildAnalyticsEvent)({
10441
10445
  name: "agent-qa.mcp.server.lifecycle",
10442
10446
  properties: {
10443
10447
  ...standardProperties,