@vostride/agent-qa-dashboard 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as DashboardDatabase } from './index-BL7OautO.cjs';
2
- export { A as AppiumManager, C as ConfigManager, L as LiveExecutionEvent, R as RunRow, S as StepRow, T as TestFileInfo, a as TestFileManager, b as TestRunHandle, c as TestRunner, d as TestValidationError, e as TestValidationResult, f as createRouter, r as readJsonBody, s as startServer } from './index-BL7OautO.cjs';
1
+ import { D as DashboardDatabase } from './index-ygQLgXzT.cjs';
2
+ export { A as AppiumManager, C as ConfigManager, L as LiveExecutionEvent, R as RunRow, S as StepRow, T as TestFileInfo, a as TestFileManager, b as TestRunHandle, c as TestRunner, d as TestValidationError, e as TestValidationResult, f as createRouter, r as readJsonBody, s as startServer } from './index-ygQLgXzT.cjs';
3
3
  import { Reporter, SecretRedactor, SuiteDefinition, RunArtifactReporterContext, SuiteSummary, TestDefinition, StepResult, TestResult, RunSummary, HookResultEvent } from '@vostride/agent-qa-core';
4
4
  import 'node:http';
5
5
  import '@vostride/agent-qa-mcp';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as DashboardDatabase } from './index-BL7OautO.js';
2
- export { A as AppiumManager, C as ConfigManager, L as LiveExecutionEvent, R as RunRow, S as StepRow, T as TestFileInfo, a as TestFileManager, b as TestRunHandle, c as TestRunner, d as TestValidationError, e as TestValidationResult, f as createRouter, r as readJsonBody, s as startServer } from './index-BL7OautO.js';
1
+ import { D as DashboardDatabase } from './index-ygQLgXzT.js';
2
+ export { A as AppiumManager, C as ConfigManager, L as LiveExecutionEvent, R as RunRow, S as StepRow, T as TestFileInfo, a as TestFileManager, b as TestRunHandle, c as TestRunner, d as TestValidationError, e as TestValidationResult, f as createRouter, r as readJsonBody, s as startServer } from './index-ygQLgXzT.js';
3
3
  import { Reporter, SecretRedactor, SuiteDefinition, RunArtifactReporterContext, SuiteSummary, TestDefinition, StepResult, TestResult, RunSummary, HookResultEvent } from '@vostride/agent-qa-core';
4
4
  import 'node:http';
5
5
  import '@vostride/agent-qa-mcp';
package/dist/index.js CHANGED
@@ -1797,7 +1797,7 @@ function resolveDashboardDbPath({
1797
1797
  // src/reporter/dashboard-reporter.ts
1798
1798
  import { copyFile as copyFile2, mkdir as mkdir2, readFile, rename as rename2, unlink as unlink2, writeFile } from "fs/promises";
1799
1799
  import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute2, join, relative as relative2, resolve as resolve3 } from "path";
1800
- import { buildInternalRunAttributes, redactSecretValue, validateTrustedRunAttributes } from "@vostride/agent-qa-core";
1800
+ import { buildInternalRunAttributes, redactAuthStateValue, validateTrustedRunAttributes } from "@vostride/agent-qa-core";
1801
1801
  function isPathInside(rootDir, candidatePath) {
1802
1802
  const relativePath = relative2(rootDir, candidatePath);
1803
1803
  return Boolean(relativePath) && !relativePath.startsWith("..") && !isAbsolute2(relativePath);
@@ -1917,7 +1917,7 @@ var DashboardReporter = class {
1917
1917
  this.redactor = redactor;
1918
1918
  }
1919
1919
  redactValue(value) {
1920
- return redactSecretValue(value, this.redactor);
1920
+ return redactAuthStateValue(value, { secretRedactor: this.redactor });
1921
1921
  }
1922
1922
  redactString(value) {
1923
1923
  return value === void 0 ? void 0 : this.redactValue(value);
@@ -4221,7 +4221,7 @@ function readJsonBody(req, maxBytes = DEFAULT_MAX_BYTES) {
4221
4221
  }
4222
4222
 
4223
4223
  // src/server/routes.ts
4224
- import { buildAnalyticsEvent, buildInternalRunAttributes as buildInternalRunAttributes2, captureAnalytics, mergeRunAttributes, readAuth, writeAuth, removeAuth, getAgentQaVersion, getProviderOptions, getLLMAuthProviderPlugin, listLLMAuthProviderPlugins, ModelConfigSchema, NamedLLMConfigSchema, WorkspaceSchema, ServicesSchema, RegistrySchema, UseSchema, MobileAppStateSchema, hashStepInstruction, TimeoutConfigSchema, CacheConfigSchema, HealingConfigSchema, PlannerConfigSchema, LoggingConfigSchema, LogCaptureConfigSchema, AccessibilityConfigSchema, DashboardConfigSchema, McpConfigSchema, RecordingConfigSchema, BrowserConfigSchema, AnalyticsSchema, AgentQaConfigSchema as AgentQaConfigSchema3, TestDefinitionSchema, SuiteDefinitionSchema, parseEnvFile, serializeEnvFile, runHookInSandbox, RUNTIME_IMAGE_MAP, SecretStore, SecretRedactor, validateUserRunAttributes, discoverWorkspaceFiles as discoverWorkspaceFiles4, isWorkspacePathMatch, resolveAnalyticsStandardProperties, resolveMemoryRoot as resolveMemoryRoot2, resolveWorkspaceFileTarget as resolveWorkspaceFileTarget2 } from "@vostride/agent-qa-core";
4224
+ import { AuthStateNameSchema, buildAnalyticsEvent, buildInternalRunAttributes as buildInternalRunAttributes2, captureAnalytics, mergeRunAttributes, readAuth, writeAuth, removeAuth, getAgentQaVersion, getProviderOptions, getLLMAuthProviderPlugin, listAuthStateMetadata, listLLMAuthProviderPlugins, ModelConfigSchema, NamedLLMConfigSchema, WorkspaceSchema, ServicesSchema, RegistrySchema, UseSchema, MobileAppStateSchema, hashStepInstruction, TimeoutConfigSchema, CacheConfigSchema, HealingConfigSchema, PlannerConfigSchema, LoggingConfigSchema, LogCaptureConfigSchema, AccessibilityConfigSchema, DashboardConfigSchema, McpConfigSchema, RecordingConfigSchema, BrowserConfigSchema, AnalyticsSchema, AgentQaConfigSchema as AgentQaConfigSchema3, TestDefinitionSchema, SuiteDefinitionSchema, parseEnvFile, serializeEnvFile, runHookInSandbox, RUNTIME_IMAGE_MAP, SecretStore, SecretRedactor, redactAuthStateValue as redactAuthStateValue2, validateUserRunAttributes, discoverWorkspaceFiles as discoverWorkspaceFiles4, isWorkspacePathMatch, resolveAnalyticsStandardProperties, resolveMemoryRoot as resolveMemoryRoot2, resolveWorkspaceFileTarget as resolveWorkspaceFileTarget2 } from "@vostride/agent-qa-core";
4225
4225
  import { parse as parseYaml5 } from "yaml";
4226
4226
  var LLM_PROVIDER_MODES = /* @__PURE__ */ new Set([
4227
4227
  "openai-compatible",
@@ -4511,6 +4511,41 @@ function cors(res) {
4511
4511
  function isPlainRecord(value) {
4512
4512
  return value !== null && typeof value === "object" && !Array.isArray(value);
4513
4513
  }
4514
+ function getConfiguredAuthStateDir(config) {
4515
+ const services = isPlainRecord(config.services) ? config.services : void 0;
4516
+ const authState = services && isPlainRecord(services.authState) ? services.authState : void 0;
4517
+ return typeof authState?.dir === "string" ? authState.dir : void 0;
4518
+ }
4519
+ function getSessionTargetNameForAuthState(session) {
4520
+ if (!session || typeof session.getState !== "function") return "selected target";
4521
+ try {
4522
+ const state = session.getState();
4523
+ if (isPlainRecord(state) && typeof state.targetName === "string" && state.targetName.trim().length > 0) {
4524
+ return state.targetName.trim();
4525
+ }
4526
+ } catch {
4527
+ }
4528
+ return "selected target";
4529
+ }
4530
+ function buildAuthStateSaveErrorMessage(stateName, targetName, error) {
4531
+ const raw = error instanceof Error ? error.message : String(error);
4532
+ if (/already exists/i.test(raw)) {
4533
+ return {
4534
+ status: 409,
4535
+ message: `Auth state "${stateName}" for target "${targetName}" already exists. Use replace=true to replace it.`
4536
+ };
4537
+ }
4538
+ if (/web Live Mode|not ready|executing|busy/i.test(raw)) {
4539
+ return {
4540
+ status: 409,
4541
+ message: `Could not save auth state "${stateName}" for target "${targetName}".`
4542
+ };
4543
+ }
4544
+ return {
4545
+ status: 500,
4546
+ message: `Could not save auth state "${stateName}" for target "${targetName}".`
4547
+ };
4548
+ }
4514
4549
  function isDashboardProductEventName(value) {
4515
4550
  return typeof value === "string" && DASHBOARD_PRODUCT_EVENT_NAME_SET.has(value);
4516
4551
  }
@@ -4910,7 +4945,7 @@ function sanitizeSecretsFileMetadata(value) {
4910
4945
  };
4911
4946
  }
4912
4947
  function sanitizeArtifactPayloadForResponse(payload) {
4913
- const sanitized = sanitizeSecretTemplates(payload);
4948
+ const sanitized = redactAuthStateValue2(sanitizeSecretTemplates(payload));
4914
4949
  if (!isRecord2(sanitized)) return payload;
4915
4950
  const config = sanitized.config;
4916
4951
  if (!isRecord2(config) || !("secretsFile" in config)) return sanitized;
@@ -4929,6 +4964,9 @@ function sanitizeArtifactForResponse(artifact) {
4929
4964
  payload: sanitizeArtifactPayloadForResponse(artifact.payload)
4930
4965
  };
4931
4966
  }
4967
+ function sanitizeAuthStateForResponse(value) {
4968
+ return redactAuthStateValue2(value);
4969
+ }
4932
4970
  async function normalizeDashboardWorkspacePath(filePath, workspacePaths, kind, requireExisting = true) {
4933
4971
  if (!workspacePaths) {
4934
4972
  throw new Error("Workspace path resolution is required for dashboard-triggered runs");
@@ -5153,6 +5191,28 @@ function createRouter(dbOrDeps, artifactsDir) {
5153
5191
  }
5154
5192
  const url = parseUrl(req);
5155
5193
  const path = url.pathname;
5194
+ if (path === "/api/auth-states" && req.method === "GET") {
5195
+ if (!configManager || !deps.configPath) {
5196
+ json(res, { error: "Auth-state metadata not available" }, 503);
5197
+ return;
5198
+ }
5199
+ ;
5200
+ (async () => {
5201
+ try {
5202
+ const config = await configManager.read();
5203
+ const targetName = url.searchParams.get("target") ?? void 0;
5204
+ const authStates = await listAuthStateMetadata({
5205
+ configDir: dirname8(resolve6(deps.configPath)),
5206
+ authStateDir: getConfiguredAuthStateDir(config),
5207
+ targetName
5208
+ });
5209
+ json(res, { authStates });
5210
+ } catch {
5211
+ json(res, { error: "Could not list auth states." }, 500);
5212
+ }
5213
+ })();
5214
+ return;
5215
+ }
5156
5216
  if (path === "/api/analytics/events" && req.method === "POST") {
5157
5217
  readJsonBody(req).then((body) => {
5158
5218
  if (!isPlainRecord(body) || !isDashboardProductEventName(body.name) || Object.prototype.hasOwnProperty.call(body, "properties") && body.properties !== void 0 && !isPlainRecord(body.properties)) {
@@ -5266,7 +5326,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5266
5326
  return;
5267
5327
  }
5268
5328
  const bundle = db.getRunArtifactBundle(runId);
5269
- json(res, {
5329
+ json(res, sanitizeAuthStateForResponse({
5270
5330
  run,
5271
5331
  artifact: sanitizeArtifactForResponse(bundle.artifact),
5272
5332
  children: bundle.children.map((child) => ({
@@ -5274,7 +5334,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5274
5334
  artifact: sanitizeArtifactForResponse(child.artifact)
5275
5335
  })),
5276
5336
  missingSections: getArtifactMissingSections(bundle.artifact)
5277
- });
5337
+ }));
5278
5338
  return;
5279
5339
  }
5280
5340
  if (path.startsWith("/api/runs/") && path.endsWith("/accessibility") && req.method === "GET") {
@@ -5300,7 +5360,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5300
5360
  const stepOrder = parseInt(stepOrderStr, 10);
5301
5361
  const trace = db.getReasoningTrace(runId, stepOrder);
5302
5362
  if (trace) {
5303
- json(res, { trace });
5363
+ json(res, sanitizeAuthStateForResponse({ trace }));
5304
5364
  return;
5305
5365
  }
5306
5366
  const steps = db.getSteps(runId);
@@ -5309,7 +5369,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5309
5369
  notFound(res, "Step not found");
5310
5370
  return;
5311
5371
  }
5312
- json(res, {
5372
+ json(res, sanitizeAuthStateForResponse({
5313
5373
  trace: {
5314
5374
  id: null,
5315
5375
  stepId: step.id,
@@ -5330,7 +5390,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5330
5390
  screenStateAfter: null,
5331
5391
  createdAt: step.createdAt
5332
5392
  }
5333
- });
5393
+ }));
5334
5394
  return;
5335
5395
  }
5336
5396
  if (path.startsWith("/api/runs/") && path.endsWith("/execution-logs") && req.method === "GET") {
@@ -5350,11 +5410,11 @@ function createRouter(dbOrDeps, artifactsDir) {
5350
5410
  for (const rid of allRunIds) {
5351
5411
  allLogs.push(...db.getExecutionLogs({ runId: rid, stepId, type }));
5352
5412
  }
5353
- json(res, { logs: allLogs });
5413
+ json(res, sanitizeAuthStateForResponse({ logs: allLogs }));
5354
5414
  return;
5355
5415
  }
5356
5416
  const logs = db.getExecutionLogs({ runId: id, stepId, type });
5357
- json(res, { logs });
5417
+ json(res, sanitizeAuthStateForResponse({ logs }));
5358
5418
  return;
5359
5419
  }
5360
5420
  if (path.startsWith("/api/runs/") && path.endsWith("/logs") && req.method === "GET") {
@@ -5371,7 +5431,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5371
5431
  const limit = url.searchParams.has("limit") ? parseInt(url.searchParams.get("limit"), 10) : 500;
5372
5432
  const offset = url.searchParams.has("offset") ? parseInt(url.searchParams.get("offset"), 10) : 0;
5373
5433
  const logs = db.getLogs({ runId: id, stepId, level, source, limit, offset });
5374
- json(res, { logs, total: logs.length });
5434
+ json(res, sanitizeAuthStateForResponse({ logs, total: logs.length }));
5375
5435
  return;
5376
5436
  }
5377
5437
  if (path.startsWith("/api/runs/") && path.endsWith("/steps") && req.method === "GET") {
@@ -5383,7 +5443,7 @@ function createRouter(dbOrDeps, artifactsDir) {
5383
5443
  return;
5384
5444
  }
5385
5445
  const steps = db.getSteps(id);
5386
- json(res, { steps });
5446
+ json(res, sanitizeAuthStateForResponse({ steps }));
5387
5447
  return;
5388
5448
  }
5389
5449
  if (path.startsWith("/api/runs/") && path.endsWith("/cancel") && req.method === "POST") {
@@ -5457,9 +5517,9 @@ function createRouter(dbOrDeps, artifactsDir) {
5457
5517
  const attempts = db.getRunsByParent(id);
5458
5518
  if (run.suiteId && !run.parentRunId) {
5459
5519
  const tests = db.getRunsByParent(id);
5460
- json(res, { run, steps, attempts, tests });
5520
+ json(res, sanitizeAuthStateForResponse({ run, steps, attempts, tests }));
5461
5521
  } else {
5462
- json(res, { run, steps, attempts });
5522
+ json(res, sanitizeAuthStateForResponse({ run, steps, attempts }));
5463
5523
  }
5464
5524
  return;
5465
5525
  }
@@ -7072,7 +7132,7 @@ data: ${JSON.stringify(event)}
7072
7132
  const networkLogs = summarizeHookNetworkLogs(
7073
7133
  result.networkLogs
7074
7134
  );
7075
- json(res, {
7135
+ json(res, sanitizeAuthStateForResponse({
7076
7136
  success: result.success,
7077
7137
  status: result.success ? "passed" : "failed",
7078
7138
  executedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -7090,9 +7150,9 @@ data: ${JSON.stringify(event)}
7090
7150
  networkLogsAvailable: networkLogs.length > 0,
7091
7151
  networkLogs
7092
7152
  }
7093
- });
7153
+ }));
7094
7154
  } catch (err) {
7095
- json(res, { error: err instanceof Error ? err.message : "Failed to run hook" }, 500);
7155
+ json(res, sanitizeAuthStateForResponse({ error: err instanceof Error ? err.message : "Failed to run hook" }), 500);
7096
7156
  }
7097
7157
  }).catch(() => json(res, { error: "Invalid request body" }, 400));
7098
7158
  return;
@@ -7341,6 +7401,45 @@ data: ${JSON.stringify(event)}
7341
7401
  })();
7342
7402
  return;
7343
7403
  }
7404
+ const liveEditorAuthStateMatch = path.match(/^\/api\/live-editor\/sessions\/([^/]+)\/auth-state$/);
7405
+ if (liveEditorAuthStateMatch && req.method === "POST") {
7406
+ if (!sessionManager) {
7407
+ json(res, { error: "Live editor not available" }, 503);
7408
+ return;
7409
+ }
7410
+ ;
7411
+ (async () => {
7412
+ let stateName = "";
7413
+ let session;
7414
+ try {
7415
+ const body = await readJsonBody(req);
7416
+ const parsedName = AuthStateNameSchema.safeParse(typeof body?.name === "string" ? body.name : "");
7417
+ if (!parsedName.success) {
7418
+ json(res, { error: "Auth state name must be a lowercase slug." }, 400);
7419
+ return;
7420
+ }
7421
+ stateName = parsedName.data;
7422
+ session = sessionManager.getSession(decodeURIComponent(liveEditorAuthStateMatch[1]));
7423
+ if (!session) {
7424
+ notFound(res, "Session not found");
7425
+ return;
7426
+ }
7427
+ if (typeof session.captureWebAuthState !== "function") {
7428
+ json(res, {
7429
+ error: `Could not save auth state "${stateName}" for target "${getSessionTargetNameForAuthState(session)}".`
7430
+ }, 500);
7431
+ return;
7432
+ }
7433
+ const authState = await session.captureWebAuthState(stateName, { replace: body?.replace === true });
7434
+ json(res, { authState });
7435
+ } catch (err) {
7436
+ const targetName = getSessionTargetNameForAuthState(session);
7437
+ const response = buildAuthStateSaveErrorMessage(stateName || "unknown", targetName, err);
7438
+ json(res, { error: response.message }, response.status);
7439
+ }
7440
+ })();
7441
+ return;
7442
+ }
7344
7443
  if (path === "/api/live-editor/sessions" && req.method === "POST") {
7345
7444
  if (!sessionManager) {
7346
7445
  json(res, { error: "Live editor not available" }, 503);
@@ -8548,7 +8647,9 @@ import { randomUUID as randomUUID4 } from "crypto";
8548
8647
 
8549
8648
  // src/live-editor/live-session.ts
8550
8649
  import { randomUUID as randomUUID3 } from "crypto";
8650
+ import { dirname as dirname12, resolve as resolvePath } from "path";
8551
8651
  import {
8652
+ AUTH_STATE_SCHEMA_VERSION,
8552
8653
  executeStep,
8553
8654
  createModel,
8554
8655
  getProviderOptions as getProviderOptions2,
@@ -8562,8 +8663,11 @@ import {
8562
8663
  runHooks,
8563
8664
  runHookInSandbox as runHookInSandbox2,
8564
8665
  MobileSetupError as MobileSetupError2,
8565
- redactSecretValue as redactSecretValue2,
8566
- resolveSecretTemplatesInValue
8666
+ readAuthStateMetadata,
8667
+ redactAuthStateValue as redactAuthStateValue3,
8668
+ resolveAuthStatePaths,
8669
+ resolveSecretTemplatesInValue,
8670
+ writeAuthStateFiles
8567
8671
  } from "@vostride/agent-qa-core";
8568
8672
 
8569
8673
  // src/live-editor/mobile-bootstrap.ts
@@ -8718,6 +8822,26 @@ function coerceRunJSResult(value) {
8718
8822
  }
8719
8823
  return JSON.stringify(value);
8720
8824
  }
8825
+ function getWebStorageStateContext(adapter) {
8826
+ if (!adapter || !("getPage" in adapter)) return null;
8827
+ const page = adapter.getPage?.();
8828
+ if (!page || typeof page !== "object") return null;
8829
+ const contextFactory = page.context;
8830
+ if (typeof contextFactory !== "function") return null;
8831
+ const context = contextFactory.call(page);
8832
+ if (!context || typeof context !== "object") return null;
8833
+ const storageState = context.storageState;
8834
+ if (typeof storageState !== "function") return null;
8835
+ return context;
8836
+ }
8837
+ function getConfiguredAuthStateDir2(config) {
8838
+ const services = config.services;
8839
+ if (!services || typeof services !== "object") return void 0;
8840
+ const authState = services.authState;
8841
+ if (!authState || typeof authState !== "object") return void 0;
8842
+ const dir = authState.dir;
8843
+ return typeof dir === "string" ? dir : void 0;
8844
+ }
8721
8845
  function toLiveSubActionData(result) {
8722
8846
  return result.trace?.subActions?.map((subAction) => ({
8723
8847
  index: subAction.index,
@@ -8795,6 +8919,7 @@ var LiveSession = class {
8795
8919
  previousSteps = [];
8796
8920
  currentStep = null;
8797
8921
  platform = "web";
8922
+ targetName = null;
8798
8923
  currentUrl = null;
8799
8924
  executing = false;
8800
8925
  idleTimer = null;
@@ -8832,7 +8957,7 @@ var LiveSession = class {
8832
8957
  this.pendingMessages.push(message);
8833
8958
  }
8834
8959
  redact(value) {
8835
- return redactSecretValue2(value, this.secretRedactor);
8960
+ return redactAuthStateValue3(value, { secretRedactor: this.secretRedactor });
8836
8961
  }
8837
8962
  resolveSecrets(value) {
8838
8963
  return resolveSecretTemplatesInValue(value, this.secretStore);
@@ -9062,6 +9187,7 @@ var LiveSession = class {
9062
9187
  }
9063
9188
  async initialize(config) {
9064
9189
  this.platform = config.platform;
9190
+ this.targetName = typeof config.targetName === "string" && config.targetName.trim().length > 0 ? config.targetName.trim() : null;
9065
9191
  this._modelName = config.llmConfig.model ?? "unknown";
9066
9192
  this.variableStore = new VariableStore();
9067
9193
  this.secretStore = config.secretStore;
@@ -9552,6 +9678,62 @@ ${errorLines.join("\n")}`;
9552
9678
  this.messageSink = originalSink;
9553
9679
  }
9554
9680
  }
9681
+ async captureWebAuthState(name, options = {}) {
9682
+ if (this.platform !== "web") {
9683
+ throw new Error("Auth-state capture is only available for web Live Mode sessions.");
9684
+ }
9685
+ if (!this.readyForInteraction || !this.adapter) {
9686
+ throw new Error(this.terminalError ?? "Live session is not ready for auth-state capture.");
9687
+ }
9688
+ if (this.adapter.platform !== "web") {
9689
+ throw new Error("Auth-state capture is only available for web Live Mode sessions.");
9690
+ }
9691
+ if (this.executing) {
9692
+ throw new Error("Cannot save auth state while the Live Mode session is executing.");
9693
+ }
9694
+ if (!this.targetName) {
9695
+ throw new Error("Cannot save auth state because this Live Mode session has no configured target.");
9696
+ }
9697
+ if (!this.deps.configManager || !this.deps.configPath) {
9698
+ throw new Error("Cannot save auth state because workspace config is unavailable.");
9699
+ }
9700
+ const context = getWebStorageStateContext(this.adapter);
9701
+ if (!context) {
9702
+ throw new Error("Cannot save auth state because the active browser context is unavailable.");
9703
+ }
9704
+ const config = await this.deps.configManager.read();
9705
+ const authStateDir = getConfiguredAuthStateDir2(config);
9706
+ const paths = resolveAuthStatePaths({
9707
+ configDir: dirname12(resolvePath(this.deps.configPath)),
9708
+ authStateDir,
9709
+ targetName: this.targetName,
9710
+ stateName: name,
9711
+ target: { platform: "web" }
9712
+ });
9713
+ let existing = null;
9714
+ try {
9715
+ existing = await readAuthStateMetadata(paths);
9716
+ } catch {
9717
+ existing = null;
9718
+ }
9719
+ if (existing && options.replace !== true) {
9720
+ throw new Error(`Auth state "${paths.stateName}" for target "${paths.targetName}" already exists. Use replace=true to replace it.`);
9721
+ }
9722
+ const payload = await context.storageState({ indexedDB: true });
9723
+ const metadata = {
9724
+ version: AUTH_STATE_SCHEMA_VERSION,
9725
+ kind: "web",
9726
+ target: paths.targetName,
9727
+ name: paths.stateName,
9728
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
9729
+ };
9730
+ try {
9731
+ await writeAuthStateFiles(paths, { payload, metadata });
9732
+ } catch {
9733
+ throw new Error(`Could not save auth state "${paths.stateName}" for target "${paths.targetName}".`);
9734
+ }
9735
+ return metadata;
9736
+ }
9555
9737
  cancelStep() {
9556
9738
  this.abortController?.abort();
9557
9739
  }
@@ -9612,6 +9794,7 @@ ${errorLines.join("\n")}`;
9612
9794
  return {
9613
9795
  sessionId: this.sessionId,
9614
9796
  platform: this.adapter?.platform ?? this.platform,
9797
+ targetName: this.targetName,
9615
9798
  status: this.status === "terminated" ? "idle" : this.status === "executing" ? "executing" : this.status,
9616
9799
  currentStep: this.currentStep,
9617
9800
  currentUrl: this.currentUrl,