@vostride/agent-qa-dashboard 0.1.13 → 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-BL7OautO.d.cts → index-ygQLgXzT.d.cts} +6 -1
- package/dist/{index-BL7OautO.d.ts → index-ygQLgXzT.d.ts} +6 -1
- package/dist/index.cjs +206 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +209 -21
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +205 -21
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +207 -19
- package/dist/server/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DashboardDatabase } from './index-
|
|
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-
|
|
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-
|
|
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-
|
|
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,
|
|
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
|
|
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, 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
|
}
|
|
@@ -6249,6 +6309,11 @@ data: ${JSON.stringify(event)}
|
|
|
6249
6309
|
});
|
|
6250
6310
|
return;
|
|
6251
6311
|
}
|
|
6312
|
+
if (path === "/api/app-metadata" && req.method === "GET") {
|
|
6313
|
+
const version = getAgentQaVersion().trim() || "0.0.0";
|
|
6314
|
+
json(res, { version });
|
|
6315
|
+
return;
|
|
6316
|
+
}
|
|
6252
6317
|
if (path === "/api/config/targets" && req.method === "GET") {
|
|
6253
6318
|
if (!configManager) {
|
|
6254
6319
|
json(res, { error: "Config management not available" }, 501);
|
|
@@ -7067,7 +7132,7 @@ data: ${JSON.stringify(event)}
|
|
|
7067
7132
|
const networkLogs = summarizeHookNetworkLogs(
|
|
7068
7133
|
result.networkLogs
|
|
7069
7134
|
);
|
|
7070
|
-
json(res, {
|
|
7135
|
+
json(res, sanitizeAuthStateForResponse({
|
|
7071
7136
|
success: result.success,
|
|
7072
7137
|
status: result.success ? "passed" : "failed",
|
|
7073
7138
|
executedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -7085,9 +7150,9 @@ data: ${JSON.stringify(event)}
|
|
|
7085
7150
|
networkLogsAvailable: networkLogs.length > 0,
|
|
7086
7151
|
networkLogs
|
|
7087
7152
|
}
|
|
7088
|
-
});
|
|
7153
|
+
}));
|
|
7089
7154
|
} catch (err) {
|
|
7090
|
-
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);
|
|
7091
7156
|
}
|
|
7092
7157
|
}).catch(() => json(res, { error: "Invalid request body" }, 400));
|
|
7093
7158
|
return;
|
|
@@ -7336,6 +7401,45 @@ data: ${JSON.stringify(event)}
|
|
|
7336
7401
|
})();
|
|
7337
7402
|
return;
|
|
7338
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
|
+
}
|
|
7339
7443
|
if (path === "/api/live-editor/sessions" && req.method === "POST") {
|
|
7340
7444
|
if (!sessionManager) {
|
|
7341
7445
|
json(res, { error: "Live editor not available" }, 503);
|
|
@@ -8543,7 +8647,9 @@ import { randomUUID as randomUUID4 } from "crypto";
|
|
|
8543
8647
|
|
|
8544
8648
|
// src/live-editor/live-session.ts
|
|
8545
8649
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
8650
|
+
import { dirname as dirname12, resolve as resolvePath } from "path";
|
|
8546
8651
|
import {
|
|
8652
|
+
AUTH_STATE_SCHEMA_VERSION,
|
|
8547
8653
|
executeStep,
|
|
8548
8654
|
createModel,
|
|
8549
8655
|
getProviderOptions as getProviderOptions2,
|
|
@@ -8557,8 +8663,11 @@ import {
|
|
|
8557
8663
|
runHooks,
|
|
8558
8664
|
runHookInSandbox as runHookInSandbox2,
|
|
8559
8665
|
MobileSetupError as MobileSetupError2,
|
|
8560
|
-
|
|
8561
|
-
|
|
8666
|
+
readAuthStateMetadata,
|
|
8667
|
+
redactAuthStateValue as redactAuthStateValue3,
|
|
8668
|
+
resolveAuthStatePaths,
|
|
8669
|
+
resolveSecretTemplatesInValue,
|
|
8670
|
+
writeAuthStateFiles
|
|
8562
8671
|
} from "@vostride/agent-qa-core";
|
|
8563
8672
|
|
|
8564
8673
|
// src/live-editor/mobile-bootstrap.ts
|
|
@@ -8713,6 +8822,26 @@ function coerceRunJSResult(value) {
|
|
|
8713
8822
|
}
|
|
8714
8823
|
return JSON.stringify(value);
|
|
8715
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
|
+
}
|
|
8716
8845
|
function toLiveSubActionData(result) {
|
|
8717
8846
|
return result.trace?.subActions?.map((subAction) => ({
|
|
8718
8847
|
index: subAction.index,
|
|
@@ -8790,6 +8919,7 @@ var LiveSession = class {
|
|
|
8790
8919
|
previousSteps = [];
|
|
8791
8920
|
currentStep = null;
|
|
8792
8921
|
platform = "web";
|
|
8922
|
+
targetName = null;
|
|
8793
8923
|
currentUrl = null;
|
|
8794
8924
|
executing = false;
|
|
8795
8925
|
idleTimer = null;
|
|
@@ -8827,7 +8957,7 @@ var LiveSession = class {
|
|
|
8827
8957
|
this.pendingMessages.push(message);
|
|
8828
8958
|
}
|
|
8829
8959
|
redact(value) {
|
|
8830
|
-
return
|
|
8960
|
+
return redactAuthStateValue3(value, { secretRedactor: this.secretRedactor });
|
|
8831
8961
|
}
|
|
8832
8962
|
resolveSecrets(value) {
|
|
8833
8963
|
return resolveSecretTemplatesInValue(value, this.secretStore);
|
|
@@ -9057,6 +9187,7 @@ var LiveSession = class {
|
|
|
9057
9187
|
}
|
|
9058
9188
|
async initialize(config) {
|
|
9059
9189
|
this.platform = config.platform;
|
|
9190
|
+
this.targetName = typeof config.targetName === "string" && config.targetName.trim().length > 0 ? config.targetName.trim() : null;
|
|
9060
9191
|
this._modelName = config.llmConfig.model ?? "unknown";
|
|
9061
9192
|
this.variableStore = new VariableStore();
|
|
9062
9193
|
this.secretStore = config.secretStore;
|
|
@@ -9547,6 +9678,62 @@ ${errorLines.join("\n")}`;
|
|
|
9547
9678
|
this.messageSink = originalSink;
|
|
9548
9679
|
}
|
|
9549
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
|
+
}
|
|
9550
9737
|
cancelStep() {
|
|
9551
9738
|
this.abortController?.abort();
|
|
9552
9739
|
}
|
|
@@ -9607,6 +9794,7 @@ ${errorLines.join("\n")}`;
|
|
|
9607
9794
|
return {
|
|
9608
9795
|
sessionId: this.sessionId,
|
|
9609
9796
|
platform: this.adapter?.platform ?? this.platform,
|
|
9797
|
+
targetName: this.targetName,
|
|
9610
9798
|
status: this.status === "terminated" ? "idle" : this.status === "executing" ? "executing" : this.status,
|
|
9611
9799
|
currentStep: this.currentStep,
|
|
9612
9800
|
currentUrl: this.currentUrl,
|