zames_pro 2.45.0 → 2.47.0
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/browser.js +70 -0
- package/dist/commands.js +5 -0
- package/dist/index.js +3 -1
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -87,6 +87,65 @@ export function askPassword(question) {
|
|
|
87
87
|
}
|
|
88
88
|
const USER_DATA_DIR = path.join(os.homedir(), '.zames', 'profile');
|
|
89
89
|
const CHAT_URL = 'https://chat.deepseek.com/';
|
|
90
|
+
// Cache of the sanitized (non-Headless) User-Agent, keyed by the browser
|
|
91
|
+
// engine path. On the FIRST headless run we detect the real UA, strip the
|
|
92
|
+
// "Headless" marker and store it here; later runs pass it straight to
|
|
93
|
+
// _launchOnce, so the browser starts with a good UA and the "launch → read UA →
|
|
94
|
+
// relaunch" dance happens only once (it otherwise doubled every headless
|
|
95
|
+
// start). Keying by the executable path means a Playwright update (new engine
|
|
96
|
+
// path) invalidates the cache and we re-derive the UA once for the new build.
|
|
97
|
+
const HEADLESS_UA_CACHE = path.join(os.homedir(), '.zames', 'headless-ua.json');
|
|
98
|
+
// Pure: pick a reusable UA from the cache file's text for the given engine, or
|
|
99
|
+
// null. Exported so the policy is unit-tested without touching ~/.zames.
|
|
100
|
+
export function parseHeadlessUACache(raw, engine) {
|
|
101
|
+
try {
|
|
102
|
+
const j = JSON.parse(raw);
|
|
103
|
+
if (j &&
|
|
104
|
+
j.engine === engine &&
|
|
105
|
+
typeof j.ua === 'string' &&
|
|
106
|
+
j.ua &&
|
|
107
|
+
!/Headless/i.test(j.ua)) {
|
|
108
|
+
return j.ua;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch { }
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
function headlessEngineKey() {
|
|
115
|
+
try {
|
|
116
|
+
return chromium.executablePath();
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function readCachedHeadlessUA(engine) {
|
|
123
|
+
if (!engine)
|
|
124
|
+
return null;
|
|
125
|
+
try {
|
|
126
|
+
const raw = await fs.readFile(HEADLESS_UA_CACHE, 'utf-8');
|
|
127
|
+
return parseHeadlessUACache(raw, engine);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function writeCachedHeadlessUA(engine, ua) {
|
|
134
|
+
if (!engine || !ua)
|
|
135
|
+
return;
|
|
136
|
+
try {
|
|
137
|
+
await fs.mkdir(path.dirname(HEADLESS_UA_CACHE), { recursive: true });
|
|
138
|
+
await fs.writeFile(HEADLESS_UA_CACHE, JSON.stringify({ engine, ua }, null, 2), 'utf-8');
|
|
139
|
+
}
|
|
140
|
+
catch { }
|
|
141
|
+
}
|
|
142
|
+
// For /doctor: is a sanitized UA cached for the CURRENT engine build? A missing
|
|
143
|
+
// cache only means the next headless start relaunches once (not an error), so
|
|
144
|
+
// this is informational. Best-effort.
|
|
145
|
+
export async function headlessUACacheReady() {
|
|
146
|
+
const ua = await readCachedHeadlessUA(headlessEngineKey());
|
|
147
|
+
return !!ua;
|
|
148
|
+
}
|
|
90
149
|
// A headless Chrome advertises "HeadlessChrome/..." in its User-Agent, and
|
|
91
150
|
// DeepSeek's CDN (CloudFront/WAF) rejects that UA with a plain "403 ERROR"
|
|
92
151
|
// page before the app is even served — so a headless login looked broken while
|
|
@@ -542,6 +601,14 @@ export class DeepSeekBrowser {
|
|
|
542
601
|
console.error('profile: удаляю Singleton-файлы');
|
|
543
602
|
await cleanSingletonFiles();
|
|
544
603
|
}
|
|
604
|
+
// Headless: if we already know the sanitized UA for THIS engine build, use
|
|
605
|
+
// it from the start — that skips the "launch, read UA, relaunch" dance
|
|
606
|
+
// (which otherwise doubled every headless start).
|
|
607
|
+
if (this.headless && !this.userAgent) {
|
|
608
|
+
const cached = await readCachedHeadlessUA(headlessEngineKey());
|
|
609
|
+
if (cached)
|
|
610
|
+
this.userAgent = cached;
|
|
611
|
+
}
|
|
545
612
|
await this._launchOnce();
|
|
546
613
|
await this._fixHeadlessUserAgent();
|
|
547
614
|
}
|
|
@@ -563,6 +630,9 @@ export class DeepSeekBrowser {
|
|
|
563
630
|
if (fixed === ua)
|
|
564
631
|
return;
|
|
565
632
|
this.userAgent = fixed;
|
|
633
|
+
// Remember the good UA for this engine build so the NEXT headless start
|
|
634
|
+
// uses it immediately (no relaunch). Keyed by executable path.
|
|
635
|
+
void writeCachedHeadlessUA(headlessEngineKey(), fixed);
|
|
566
636
|
if (this.debug)
|
|
567
637
|
console.error('profile: headless UA → перезапуск с обычным Chrome UA');
|
|
568
638
|
await this.context.close().catch(() => { });
|
package/dist/commands.js
CHANGED
|
@@ -199,6 +199,11 @@ export function renderDoctor(d) {
|
|
|
199
199
|
if (typeof d.sshRemote === 'boolean') {
|
|
200
200
|
row(true, 'session', d.sshRemote ? 'SSH remote' : 'local terminal');
|
|
201
201
|
}
|
|
202
|
+
if (d.headless) {
|
|
203
|
+
row(!!d.headlessUaCached, 'headless', d.headlessUaCached
|
|
204
|
+
? 'UA cached (no relaunch)'
|
|
205
|
+
: 'no cached UA yet (first start relaunches once)');
|
|
206
|
+
}
|
|
202
207
|
return 'Doctor:' + NL + rows.join(NL);
|
|
203
208
|
}
|
|
204
209
|
export function renderPermissions(p) {
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import fs from 'fs/promises';
|
|
|
4
4
|
import { existsSync, statSync } from 'fs';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { theme } from './theme.js';
|
|
7
|
-
import { DeepSeekBrowser } from './browser.js';
|
|
7
|
+
import { DeepSeekBrowser, headlessUACacheReady } from './browser.js';
|
|
8
8
|
import { createTools } from './tools.js';
|
|
9
9
|
import { runAgentLoop } from './agent-loop.js';
|
|
10
10
|
import { createSpinner } from './spinner.js';
|
|
@@ -2830,6 +2830,8 @@ async function main() {
|
|
|
2830
2830
|
: undefined,
|
|
2831
2831
|
minSendIntervalMs: config.browser.minSendIntervalMs,
|
|
2832
2832
|
sshRemote: !!(process.env.SSH_CONNECTION || process.env.SSH_TTY),
|
|
2833
|
+
headless: !!headless,
|
|
2834
|
+
headlessUaCached: await headlessUACacheReady().catch(() => false),
|
|
2833
2835
|
})));
|
|
2834
2836
|
continue;
|
|
2835
2837
|
}
|