Files
purpleandClaude Opus 5.5 b86747baee 3.0.8
- Web search with five services in turn, no key needed, pages read like a reader view
- A long video renders in the background, videos made in the chat play there, Wan 2.1 saves mp4
- A graphics card per task with two cards, AMD on Windows gets the current ROCm build, Intel Arc its own
- The LU Engine plans memory from the model file, says what a long context costs, keeps one copy of the model
- Settings from the chat with a confirmation card, Storage puts models, gallery and runtime in one folder
- Remove refusals from a local model in the Model Manager
- Native HiRes in Edit, LoRA stack with search and strength from -20 to 20
- Ask in Code asks before every external tool, REA shows only in Agent and Code
- Your phone on this computer (Remote), paired by QR code
- Wan 2.2 14B runs from Animate and Video, Train new on a Mac shows the trigger word field
- Temperature is held to 1.5, memories can be deleted, the onboarding runs once
- GitHub issues 187, 188, 190, 191, 193 and 194

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:52:46 -07:00

90 lines
3.8 KiB
JavaScript
Executable File

#!/usr/bin/env node
// Fuehrt einen JavaScript-Ausdruck im WebView der laufenden Android-App aus
// und druckt das Ergebnis. Nur fuer Debug-Bauten: ein Release-Bau oeffnet den
// Debug-Socket nicht (siehe release-opens-no-debug-socket.test.ts).
//
// Wozu: ein Tauri-Kommando am Geraet ausloesen, ohne die Oberflaeche zu
// bedienen, zum Beispiel die Engine starten und ihren Status lesen.
//
// Aufruf:
// node scripts/mobile/android-webview-eval.mjs '<ausdruck>'
// node scripts/mobile/android-webview-eval.mjs --invoke <kommando> '<json-argumente>'
//
// Beispiele:
// node scripts/mobile/android-webview-eval.mjs 'document.title'
// node scripts/mobile/android-webview-eval.mjs --invoke bundled_engine_status
// node scripts/mobile/android-webview-eval.mjs --invoke start_bundled_engine \
// '{"modelPath":"/data/user/0/com.purpledoubled.locallyuncensored/models/m.gguf"}'
//
// Braucht adb im PATH und Node 22 oder neuer (eingebautes WebSocket und fetch).
// Umgebung: ANDROID_SERIAL waehlt das Geraet, LU_ANDROID_PACKAGE das Paket,
// LU_CDP_PORT den lokalen Port (Standard 9333).
import { execFileSync } from 'node:child_process'
const PACKAGE = process.env.LU_ANDROID_PACKAGE || 'com.purpledoubled.locallyuncensored'
const PORT = Number(process.env.LU_CDP_PORT || 9333)
// Nie "das einzige angeschlossene Geraet": ohne ANDROID_SERIAL wird abgebrochen (wie die Treiber des Rahmens,
// mobile-tests/lib/geraete.mjs). adb liest ANDROID_SERIAL selbst, hier wird es zusaetzlich ausdruecklich uebergeben.
const SERIAL = String(process.env.ANDROID_SERIAL ?? '').trim()
if (!SERIAL) {
console.error('Kein Geraet genannt: ANDROID_SERIAL setzen (Seriennummer aus `adb devices`). Dieses Skript waehlt nie von selbst ein Geraet.')
process.exit(2)
}
const adb = (...args) => execFileSync('adb', ['-s', SERIAL, ...args], { encoding: 'utf8' }).trim()
const argv = process.argv.slice(2)
let expression
if (argv[0] === '--invoke') {
const command = argv[1]
const args = argv[2] ? JSON.parse(argv[2]) : {}
if (!command) throw new Error('--invoke braucht einen Kommandonamen')
// Fehler eines Kommandos sollen als Wert zurueckkommen, nicht als Ausnahme
// ohne Text.
expression = `window.__TAURI_INTERNALS__.invoke(${JSON.stringify(command)}, ${JSON.stringify(args)})
.then((ok) => ({ ok }), (err) => ({ err: String(err && err.message ? err.message : err) }))`
} else {
expression = argv.join(' ')
}
if (!expression) {
console.error("Aufruf: android-webview-eval.mjs '<ausdruck>' | --invoke <kommando> '<json>'")
process.exit(2)
}
const pid = adb('shell', 'pidof', PACKAGE).split(/\s+/)[0]
if (!pid) throw new Error(`${PACKAGE} laeuft nicht`)
adb('forward', `tcp:${PORT}`, `localabstract:webview_devtools_remote_${pid}`)
try {
const targets = await (await fetch(`http://127.0.0.1:${PORT}/json`)).json()
const page = targets.find((t) => t.type === 'page')
if (!page) throw new Error('kein WebView gefunden (ist es ein Debug-Bau?)')
const ws = new WebSocket(page.webSocketDebuggerUrl)
await new Promise((resolve, reject) => {
ws.onopen = resolve
ws.onerror = () => reject(new Error('WebSocket zum WebView kam nicht zustande'))
})
const answer = await new Promise((resolve) => {
ws.onmessage = (event) => {
const message = JSON.parse(event.data)
if (message.id === 1) resolve(message)
}
ws.send(JSON.stringify({
id: 1,
method: 'Runtime.evaluate',
params: { expression, awaitPromise: true, returnByValue: true },
}))
})
ws.close()
if (answer.result?.exceptionDetails) {
console.error(JSON.stringify(answer.result.exceptionDetails, null, 2))
process.exitCode = 1
} else {
const value = answer.result?.result?.value
console.log(typeof value === 'string' ? value : JSON.stringify(value, null, 2))
}
} finally {
try { adb('forward', '--remove', `tcp:${PORT}`) } catch { /* schon weg */ }
}