fix(portable): Gemini keys, Telegram pairing UI, and config durability

Improve first-run and channel setup for non-technical users: detect newer
Gemini key formats, pin Node 22.22.3, add Control Panel Telegram approve
flow, and keep channels/models when config is rewritten. Persist uclaw
wizard state via uclaw-meta.json so restarts skip language/persona prompts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 18:45:03 +08:00
parent 0be8c3e3fe
commit dd8e0f55c3
35 changed files with 2673 additions and 34 deletions

View File

@@ -256,10 +256,30 @@ function applyNoProxy(t, nodeBin) {
// the language follow the machine instead of the drive, which is exactly the
// behaviour we do not want. A generated <script> is the one channel that works
// from both file:// and http://.
function readUclawMeta() {
try {
const metaPath = join(paths.state, 'uclaw-meta.json');
if (!existsSync(metaPath)) return null;
return JSON.parse(readFileSync(metaPath, 'utf8'));
} catch {
return null;
}
}
function localeFromLocaleJs() {
try {
const content = readFileSync(join(paths.state, 'locale.js'), 'utf8');
const match = content.match(/UCLAW_LOCALE\s*=\s*(["'])([^"']+)\1/);
return match ? match[2] : null;
} catch {
return null;
}
}
// True until the drive records a language of its own. Asking once and never
// again is the point: the answer lives on the drive, not in a browser profile.
function localeChosenOnDrive() {
return Boolean(driveSetting('locale'));
return Boolean(driveSetting('locale') || localeFromLocaleJs());
}
// The wizard runs once. Its answer decides which skills are installed and how
@@ -271,10 +291,13 @@ function personaChosenOnDrive() {
function driveSetting(key) {
try {
return JSON.parse(readFileSync(paths.config, 'utf8'))?.uclaw?.[key];
const fromConfig = JSON.parse(readFileSync(paths.config, 'utf8'))?.uclaw?.[key];
if (fromConfig !== undefined) return fromConfig;
} catch {
return undefined;
/* try sidecar */
}
const fromMeta = readUclawMeta()?.[key];
return fromMeta !== undefined ? fromMeta : undefined;
}
function writeLocaleForPages(locale) {