@q-agent/agent 0.1.10 → 0.1.12
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/src/runner.js +13 -1
- package/package.json +1 -1
- package/vendor/explore_session.cjs +26 -4
package/dist/src/runner.js
CHANGED
|
@@ -849,12 +849,24 @@ async function processExplorationJob(cfg, session) {
|
|
|
849
849
|
}
|
|
850
850
|
}
|
|
851
851
|
const storageState = origin && (0, session_1.hasValidSession)(origin) ? (0, session_1.sessionPathsForOrigin)(origin).storageStatePath : "";
|
|
852
|
+
// Pair the sessionStorage snapshot (MSAL/SPA auth tokens) with the saved
|
|
853
|
+
// session so the explore browser authenticates the same way a run does — the
|
|
854
|
+
// run path replays it via fixtures (see `replaySession`). Without it an
|
|
855
|
+
// MSAL/SPA app boots unauthenticated and bounces to login.
|
|
856
|
+
const sessionStoragePath = storageState && origin && (0, session_1.hasSessionStorage)(origin) ? (0, session_1.sessionPathsForOrigin)(origin).sessionStoragePath : "";
|
|
852
857
|
const script = (0, paths_1.vendorExploreScript)();
|
|
853
858
|
const nm = (0, paths_1.agentNodeModules)();
|
|
854
859
|
const args = [script, session.baseUrl];
|
|
855
860
|
if (storageState)
|
|
856
861
|
args.push(storageState);
|
|
857
|
-
|
|
862
|
+
if (storageState && sessionStoragePath)
|
|
863
|
+
args.push(sessionStoragePath);
|
|
864
|
+
// Run the explore browser HEADED on the paired device: the user watches the
|
|
865
|
+
// session, and a headed browser dodges WAF/bot-protection that blocks headless.
|
|
866
|
+
const child = (0, child_process_1.spawn)((0, paths_1.nodeBin)(), args, {
|
|
867
|
+
cwd: nm,
|
|
868
|
+
env: { ...nodePathEnv(nm), QAGENT_EXPLORE_HEADED: "1" },
|
|
869
|
+
});
|
|
858
870
|
activeChild = child;
|
|
859
871
|
// Capture the driver's stderr so a launch failure (missing browser, bad
|
|
860
872
|
// Playwright resolution, …) is visible instead of a silent "complete".
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q-agent/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Q-Agent Local Agent — claims execution jobs from the Q-Agent server and runs Playwright locally, so manual login/MFA happens on the user's own machine and session credentials never leave it.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
// whole session, reading newline-delimited JSON commands on stdin and writing
|
|
14
14
|
// newline-delimited JSON responses on stdout.
|
|
15
15
|
//
|
|
16
|
-
// Args: baseURL, [storageState] (storageState = absolute path
|
|
17
|
-
// Playwright session for auth reuse, per ADR 0002
|
|
16
|
+
// Args: baseURL, [storageState], [sessionState] (storageState = absolute path
|
|
17
|
+
// to a saved Playwright session for auth reuse, per ADR 0002; sessionState =
|
|
18
|
+
// absolute path to the sibling sessionStorage.json snapshot, replayed for auth
|
|
19
|
+
// reuse on MSAL/SPA apps whose token lives in sessionStorage — which Playwright's
|
|
20
|
+
// storageState cannot persist).
|
|
18
21
|
//
|
|
19
22
|
// Protocol (one JSON object per line, each way):
|
|
20
23
|
// {"cmd":"observe"}
|
|
@@ -29,8 +32,9 @@
|
|
|
29
32
|
// self-heal loop's tolerance for stale actions).
|
|
30
33
|
const { chromium } = require('playwright');
|
|
31
34
|
const readline = require('readline');
|
|
35
|
+
const fs = require('fs');
|
|
32
36
|
|
|
33
|
-
const [, , baseURL, storageState] = process.argv;
|
|
37
|
+
const [, , baseURL, storageState, sessionState] = process.argv;
|
|
34
38
|
|
|
35
39
|
process.on('unhandledRejection', (e) => console.error('explore unhandledRejection:', e && (e.message || e)));
|
|
36
40
|
process.on('uncaughtException', (e) => console.error('explore uncaughtException:', e && (e.message || e)));
|
|
@@ -159,10 +163,28 @@ async function handle(line) {
|
|
|
159
163
|
|
|
160
164
|
(async () => {
|
|
161
165
|
if (!baseURL) { console.error('explore_session: missing baseURL arg'); process.exit(1); }
|
|
162
|
-
|
|
166
|
+
// Headed when QAGENT_EXPLORE_HEADED=1 (the Local Agent sets it so the user can
|
|
167
|
+
// watch, and a headed browser trips WAF/bot-protection far less than headless);
|
|
168
|
+
// headless otherwise (e.g. the server, which has no display).
|
|
169
|
+
browser = await chromium.launch({ headless: process.env.QAGENT_EXPLORE_HEADED !== '1' });
|
|
163
170
|
const contextOpts = { baseURL };
|
|
164
171
|
if (storageState) contextOpts.storageState = storageState;
|
|
165
172
|
const context = await browser.newContext(contextOpts);
|
|
173
|
+
// Replay the captured sessionStorage (MSAL/SPA auth tokens) for the matching
|
|
174
|
+
// origin BEFORE any app code runs — mirrors playwright_runner._fixtures_ts.
|
|
175
|
+
// storageState persists cookies + localStorage but NOT sessionStorage, so
|
|
176
|
+
// without this an MSAL/SPA app boots unauthenticated and bounces to login even
|
|
177
|
+
// with a valid saved session. The snapshot is {origin: {key: value}}.
|
|
178
|
+
if (sessionState) {
|
|
179
|
+
let sessions = {};
|
|
180
|
+
try { sessions = JSON.parse(fs.readFileSync(sessionState, 'utf-8')); } catch {}
|
|
181
|
+
await context.addInitScript((byOrigin) => {
|
|
182
|
+
try {
|
|
183
|
+
const entries = byOrigin[location.origin];
|
|
184
|
+
if (entries) for (const k in entries) window.sessionStorage.setItem(k, entries[k]);
|
|
185
|
+
} catch {}
|
|
186
|
+
}, sessions);
|
|
187
|
+
}
|
|
166
188
|
page = await context.newPage();
|
|
167
189
|
|
|
168
190
|
// Land on the app before the first observe so step 1 sees the real page,
|