@q-agent/agent 0.1.18 → 0.1.19
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/package.json +1 -1
- package/vendor/authoring_browser.cjs +51 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q-agent/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
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": {
|
|
@@ -75,36 +75,44 @@ async function waitForCDP(port, timeoutMs) {
|
|
|
75
75
|
return false;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
// can't be required (the API container ships none) or no path was given, this is
|
|
81
|
-
// a no-op. Returns the connected Playwright browser (kept alive so the init-script
|
|
82
|
-
// registration survives) or null.
|
|
83
|
-
async function replaySessionStorage(port) {
|
|
78
|
+
// Load the saved sessionStorage map ({origin: {k:v}}), or null if unusable.
|
|
79
|
+
function loadSessionStorage() {
|
|
84
80
|
if (!sessionStoragePath) return null;
|
|
85
|
-
let byOrigin;
|
|
86
|
-
try { byOrigin = JSON.parse(fs.readFileSync(sessionStoragePath, 'utf-8')); }
|
|
87
|
-
catch { return null; }
|
|
88
|
-
if (!byOrigin || typeof byOrigin !== 'object' || !Object.keys(byOrigin).length) return null;
|
|
89
|
-
let chromium;
|
|
90
|
-
try { ({ chromium } = require('playwright')); } catch { return null; }
|
|
91
81
|
try {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
82
|
+
const m = JSON.parse(fs.readFileSync(sessionStoragePath, 'utf-8'));
|
|
83
|
+
return m && typeof m === 'object' && Object.keys(m).length ? m : null;
|
|
84
|
+
} catch { return null; }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Require Playwright if available (agent side); null in the API container.
|
|
88
|
+
function tryPlaywright() {
|
|
89
|
+
try { return require('playwright').chromium; } catch { return null; }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Arm sessionStorage replay and navigate the VISIBLE tab to baseUrl WITH the
|
|
93
|
+
// token restored, so MSAL/SPA apps load authenticated. Critical ordering: the
|
|
94
|
+
// init script must be registered BEFORE the first navigation to the app (that's
|
|
95
|
+
// why Chrome is launched at about:blank, not baseUrl). Returns the connected
|
|
96
|
+
// Playwright browser (kept alive so the init-script registration + tab survive).
|
|
97
|
+
async function armAuthAndNavigate(chromium, port, byOrigin) {
|
|
98
|
+
const browser = await chromium.connectOverCDP(`http://127.0.0.1:${port}`);
|
|
99
|
+
const ctx = browser.contexts()[0];
|
|
100
|
+
if (!ctx) return browser;
|
|
101
|
+
await ctx.addInitScript((data) => {
|
|
102
|
+
try {
|
|
103
|
+
const o = data && data[location.origin];
|
|
104
|
+
if (o) for (const k of Object.keys(o)) window.sessionStorage.setItem(k, o[k]);
|
|
105
|
+
} catch (e) {}
|
|
106
|
+
}, byOrigin);
|
|
107
|
+
const page = ctx.pages()[0] || (await ctx.newPage());
|
|
108
|
+
try {
|
|
109
|
+
await page.goto(baseUrl, { waitUntil: 'domcontentloaded', timeout: 45000 });
|
|
110
|
+
await page.waitForLoadState('networkidle', { timeout: 15000 }).catch(() => {});
|
|
104
111
|
} catch (e) {
|
|
105
|
-
console.error('authoring_browser:
|
|
106
|
-
return null;
|
|
112
|
+
console.error('authoring_browser: navigate after replay failed:', e && e.message);
|
|
107
113
|
}
|
|
114
|
+
console.error('authoring_browser: sessionStorage replay armed for', Object.keys(byOrigin).join(','));
|
|
115
|
+
return browser;
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
(async () => {
|
|
@@ -127,14 +135,22 @@ async function replaySessionStorage(port) {
|
|
|
127
135
|
}
|
|
128
136
|
} catch (e) { console.error('pref seed failed:', e && e.message); }
|
|
129
137
|
|
|
138
|
+
// If we can replay sessionStorage (agent side: Playwright resolvable + a saved
|
|
139
|
+
// map), launch to about:blank and let Playwright navigate AFTER arming the init
|
|
140
|
+
// script — so the app never loads before the token is restored. Otherwise launch
|
|
141
|
+
// straight to baseUrl (profile-only / API container).
|
|
142
|
+
const byOrigin = loadSessionStorage();
|
|
143
|
+
const chromium = byOrigin ? tryPlaywright() : null;
|
|
144
|
+
const launchUrl = chromium ? 'about:blank' : baseUrl;
|
|
145
|
+
|
|
130
146
|
const child = spawn(exe, [
|
|
131
147
|
`--remote-debugging-port=${PORT}`,
|
|
132
148
|
`--user-data-dir=${profileDir}`,
|
|
133
149
|
'--no-first-run', '--no-default-browser-check', '--new-window',
|
|
134
150
|
...containerFlags(),
|
|
135
|
-
|
|
151
|
+
launchUrl,
|
|
136
152
|
], { detached: false, stdio: 'ignore' });
|
|
137
|
-
console.error('authoring_browser launched:', exe, 'port', PORT);
|
|
153
|
+
console.error('authoring_browser launched:', exe, 'port', PORT, 'replay:', Boolean(chromium));
|
|
138
154
|
|
|
139
155
|
if (!(await waitForCDP(PORT, 20000))) {
|
|
140
156
|
console.error('authoring_browser: CDP endpoint never came up on port', PORT);
|
|
@@ -142,9 +158,13 @@ async function replaySessionStorage(port) {
|
|
|
142
158
|
process.exit(1);
|
|
143
159
|
}
|
|
144
160
|
|
|
145
|
-
// Arm sessionStorage replay
|
|
146
|
-
//
|
|
147
|
-
|
|
161
|
+
// Arm sessionStorage replay + navigate the visible tab authenticated, BEFORE
|
|
162
|
+
// signalling readiness so browser-harness attaches to a logged-in tab.
|
|
163
|
+
let pw = null;
|
|
164
|
+
if (chromium) {
|
|
165
|
+
try { pw = await armAuthAndNavigate(chromium, PORT, byOrigin); }
|
|
166
|
+
catch (e) { console.error('authoring_browser: replay failed:', e && e.message); }
|
|
167
|
+
}
|
|
148
168
|
|
|
149
169
|
// Signal readiness on stdout so the parent proceeds. The daemon resolves
|
|
150
170
|
// BU_CDP_URL to the WS.
|