Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b28a065c0 | |||
| e74e1eaf70 | |||
| ff7c6333bb | |||
| 2c85df3499 |
@@ -25,6 +25,10 @@ aria-data/brain-import/*
|
||||
!aria-data/brain-import/.gitkeep
|
||||
!aria-data/brain-import/README.md
|
||||
|
||||
# .aria-debug/ — App-Crash-Logs die tools/fetch-app-logs.sh hier ablegt.
|
||||
# Komplett lokal, enthaelt potentiell private Stacktraces / Daten.
|
||||
.aria-debug/
|
||||
|
||||
# ── ARIAs Gedächtnis (Vector-DB, Skills, Models) ──
|
||||
# Backup via Diagnostic → Gehirn-Export (tar.gz), nicht via Git.
|
||||
aria-data/brain/data/
|
||||
|
||||
@@ -79,8 +79,8 @@ android {
|
||||
applicationId "com.ariacockpit"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 10305
|
||||
versionName "0.1.3.5"
|
||||
versionCode 10307
|
||||
versionName "0.1.3.7"
|
||||
// Fallback fuer Libraries mit Product Flavors
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "aria-cockpit",
|
||||
"version": "0.1.3.5",
|
||||
"version": "0.1.3.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android": "react-native run-android",
|
||||
|
||||
@@ -54,6 +54,18 @@ function _newRequestId(): string {
|
||||
return `brain_${Date.now().toString(36)}_${_nextId}`;
|
||||
}
|
||||
|
||||
/** Mini-Query-String-Builder ohne URLSearchParams (Hermes-Polyfill kennt
|
||||
* kein URLSearchParams.set, crasht). Akzeptiert object mit string/number/
|
||||
* bool-Values; undefined/null/leere Strings werden ausgelassen. */
|
||||
function _qs(params: Record<string, unknown>): string {
|
||||
const parts: string[] = [];
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
if (v === undefined || v === null || v === '') continue;
|
||||
parts.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
|
||||
}
|
||||
return parts.length ? `?${parts.join('&')}` : '';
|
||||
}
|
||||
|
||||
interface SendOpts {
|
||||
method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';
|
||||
body?: AnyJson;
|
||||
@@ -119,29 +131,31 @@ export const brainApi = {
|
||||
|
||||
/** Liste aller Memories, optional nach Type gefiltert. */
|
||||
listMemories(opts: { type?: string; limit?: number } = {}): Promise<Memory[]> {
|
||||
const qs = new URLSearchParams();
|
||||
if (opts.type) qs.set('type', opts.type);
|
||||
qs.set('limit', String(opts.limit || 500));
|
||||
return _send(`/memory/list?${qs.toString()}`);
|
||||
const qs = _qs({ type: opts.type, limit: opts.limit || 500 });
|
||||
return _send(`/memory/list${qs}`);
|
||||
},
|
||||
|
||||
/** Volltext-Substring-Suche. */
|
||||
searchText(q: string, opts: { type?: string; includePinned?: boolean; k?: number } = {}): Promise<Memory[]> {
|
||||
const qs = new URLSearchParams({ q });
|
||||
if (opts.type) qs.set('type', opts.type);
|
||||
qs.set('include_pinned', String(opts.includePinned !== false));
|
||||
qs.set('k', String(opts.k || 50));
|
||||
return _send(`/memory/search-text?${qs.toString()}`);
|
||||
const qs = _qs({
|
||||
q,
|
||||
type: opts.type,
|
||||
include_pinned: opts.includePinned !== false,
|
||||
k: opts.k || 50,
|
||||
});
|
||||
return _send(`/memory/search-text${qs}`);
|
||||
},
|
||||
|
||||
/** Semantische Suche (Embedder). */
|
||||
searchSemantic(q: string, opts: { type?: string; includePinned?: boolean; k?: number; threshold?: number } = {}): Promise<Memory[]> {
|
||||
const qs = new URLSearchParams({ q });
|
||||
if (opts.type) qs.set('type', opts.type);
|
||||
qs.set('include_pinned', String(opts.includePinned !== false));
|
||||
qs.set('k', String(opts.k || 10));
|
||||
qs.set('score_threshold', String(opts.threshold ?? 0.30));
|
||||
return _send(`/memory/search?${qs.toString()}`);
|
||||
const qs = _qs({
|
||||
q,
|
||||
type: opts.type,
|
||||
include_pinned: opts.includePinned !== false,
|
||||
k: opts.k || 10,
|
||||
score_threshold: opts.threshold ?? 0.30,
|
||||
});
|
||||
return _send(`/memory/search${qs}`);
|
||||
},
|
||||
|
||||
/** Memory anlegen. */
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# tools/
|
||||
|
||||
Hilfsskripte für die Dev-Maschine. Brauchen `.claude/aria-vm.env` (aus
|
||||
`.example` kopieren + lokale VM-IP eintragen).
|
||||
|
||||
## fetch-app-logs.sh
|
||||
|
||||
Holt App-Crash-Logs von der VM und speichert sie unter `.aria-debug/`
|
||||
(gitignored). Die App schickt JS-Errors und ungefangene Promise-
|
||||
Rejections via RVS an die Bridge — Bridge sammelt in
|
||||
`/shared/logs/app.log`, Diagnostic-Server gibt sie via
|
||||
`GET /api/app-log` raus.
|
||||
|
||||
```bash
|
||||
tools/fetch-app-logs.sh # 200 neueste Eintraege
|
||||
tools/fetch-app-logs.sh --limit 50 # weniger
|
||||
tools/fetch-app-logs.sh --watch # alle 5s pollen, neue rausgeben
|
||||
tools/fetch-app-logs.sh --clear # nach Abholen Log auf VM leeren
|
||||
```
|
||||
|
||||
Ausgabe enthaelt pro Eintrag: Uhrzeit, Level (error/warn/info), Scope
|
||||
(z.B. `ChatScreen.InboxModal` oder `global-fatal`), Message, und die
|
||||
ersten ~8 Stack-Frames. Die kompletten Daten liegen als JSON in
|
||||
`.aria-debug/app-log-<timestamp>.json`.
|
||||
|
||||
Workflow nach einem Crash:
|
||||
|
||||
1. App rebuilden mit Crash-Reporting (passiert automatisch ab dem
|
||||
`21a315c`-Commit)
|
||||
2. Crash in der App ausloesen
|
||||
3. `tools/fetch-app-logs.sh` auf der Dev-Maschine
|
||||
4. Stacktrace lesen / Claude geben
|
||||
5. Fix bauen
|
||||
6. `tools/fetch-app-logs.sh --clear` damit der Log wieder sauber ist
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
# fetch-app-logs.sh — App-Crash-Logs von der VM holen
|
||||
#
|
||||
# Nutzt .claude/aria-vm.env als Quelle fuer $ARIA_DIAG_URL und ruft
|
||||
# GET /api/app-log?limit=N. Speichert die Roh-Response unter
|
||||
# .aria-debug/app-log-<timestamp>.json und gibt eine kompakte
|
||||
# Zusammenfassung auf stdout aus (letzte Eintraege mit Stack-Trace).
|
||||
#
|
||||
# Verwendung:
|
||||
# tools/fetch-app-logs.sh # Default limit=200
|
||||
# tools/fetch-app-logs.sh --limit 50 # nur 50 holen
|
||||
# tools/fetch-app-logs.sh --clear # nach Abholen Log loeschen
|
||||
# tools/fetch-app-logs.sh --watch # alle 5s pollen, neue Eintraege ausgeben
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
LIMIT=200
|
||||
CLEAR=0
|
||||
WATCH=0
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--limit) LIMIT="$2"; shift 2 ;;
|
||||
--limit=*) LIMIT="${1#*=}"; shift ;;
|
||||
--clear) CLEAR=1; shift ;;
|
||||
--watch) WATCH=1; shift ;;
|
||||
-h|--help)
|
||||
sed -n '1,/^set/p' "$0" | sed '$d' | sed 's/^# \{0,1\}//'
|
||||
exit 0 ;;
|
||||
*) echo "Unbekannte Option: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
ENV_FILE="$ROOT/.claude/aria-vm.env"
|
||||
OUT_DIR="$ROOT/.aria-debug"
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "FEHLER: $ENV_FILE nicht vorhanden. Aus .example kopieren und IP anpassen." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
|
||||
if [[ -z "${ARIA_DIAG_URL:-}" ]]; then
|
||||
echo "FEHLER: ARIA_DIAG_URL nicht gesetzt in $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
fetch_once() {
|
||||
local ts json file
|
||||
ts="$(date +%Y%m%d_%H%M%S)"
|
||||
json="$(curl -s --max-time 10 "${ARIA_DIAG_URL%/}/api/app-log?limit=$LIMIT")" || {
|
||||
echo "FEHLER: curl gegen $ARIA_DIAG_URL fehlgeschlagen" >&2
|
||||
return 1
|
||||
}
|
||||
file="$OUT_DIR/app-log-$ts.json"
|
||||
echo "$json" > "$file"
|
||||
python3 - "$file" <<'PY'
|
||||
import json, sys
|
||||
from pathlib import Path
|
||||
data = json.loads(Path(sys.argv[1]).read_text())
|
||||
entries = data.get("entries") or []
|
||||
print(f"=== {len(entries)} Eintrag{'e' if len(entries)!=1 else ''} (gespeichert unter {sys.argv[1]}) ===")
|
||||
for e in entries[-20:]:
|
||||
ts = e.get("ts") or 0
|
||||
from datetime import datetime
|
||||
when = datetime.fromtimestamp(ts/1000).strftime("%H:%M:%S") if ts else "?"
|
||||
lvl = e.get("level","?")
|
||||
scope = e.get("scope","?")
|
||||
msg = (e.get("message") or "").splitlines()[0][:200]
|
||||
print(f"\n[{when}] {lvl:5} {scope}: {msg}")
|
||||
stack = (e.get("stack") or "").strip()
|
||||
if stack:
|
||||
for line in stack.splitlines()[:8]:
|
||||
print(f" {line}")
|
||||
if len(stack.splitlines()) > 8:
|
||||
print(f" ... ({len(stack.splitlines())-8} weitere Zeilen — siehe JSON)")
|
||||
PY
|
||||
return 0
|
||||
}
|
||||
|
||||
if [[ "$WATCH" == "1" ]]; then
|
||||
echo "Watching $ARIA_DIAG_URL/api/app-log — Ctrl+C zum Beenden"
|
||||
SEEN=""
|
||||
while true; do
|
||||
cur=$(curl -s --max-time 10 "${ARIA_DIAG_URL%/}/api/app-log?limit=$LIMIT") || cur=""
|
||||
hash=$(echo "$cur" | md5sum | awk '{print $1}')
|
||||
if [[ "$hash" != "$SEEN" && -n "$cur" ]]; then
|
||||
SEEN="$hash"
|
||||
fetch_once
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
else
|
||||
fetch_once
|
||||
fi
|
||||
|
||||
if [[ "$CLEAR" == "1" ]]; then
|
||||
echo
|
||||
echo "→ Log auf der VM leeren..."
|
||||
curl -s --max-time 5 -X POST "${ARIA_DIAG_URL%/}/api/app-log/clear" | python3 -m json.tool || true
|
||||
fi
|
||||
Reference in New Issue
Block a user