Files
obsidian-vault/personal/projects/nolvu-reflect-skip.md
T

131 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "naisei / reflect-skip — проект"
aliases:
- "naisei"
- "nolvu"
- "reflect-skip"
- "Naisei проект"
- "Reflect Skip"
tags:
- personal
- project
- app
- psychology
- skip-tools
created: '2026-05-17'
updated: '2026-06-04'
related:
- "[[personal/projects/psychologist-app/overview]]"
- "[[personal/projects/psychologist-app/dev-setup]]"
---
# naisei / reflect-skip — проект
## Статус
- Имя продукта: **naisei**
- Активная кодовая база: `~/Developer/reflect-skip/`
- Android: публикуется на `https://reflect.qentra.top` (F-Droid)
- iOS: собирается через `Project.xcworkspace``Darwin/ReflectApp.xcodeproj`
- Текущая версия: **v0.0.108** (ветка `feature/document-import`; `main` на v0.0.60, не слит)
## Структура проекта
### Два источника Swift-кода в reflect-skip
- `Sources/ReflectApp/`**актуальный** Skip-источник. Компилируется Darwin-проектом. Используется для iOS и Android.
- `ReflectApp/`**legacy** iOS-only код, существовавший до перехода на Skip. Компилируется `ReflectApp.xcodeproj` в корне. Не используется в продакшне.
### Как открывать iOS-проект
Всегда через `Project.xcworkspace`, не через `ReflectApp.xcodeproj` напрямую.
### Как собирается Android
`build-and-publish.sh` → Skip компилирует `Sources/ReflectApp/` → APK → F-Droid repo.
## Прокси
- LaunchAgent: `ai.reflect-proxy``localhost:8765`
- Cloudflare tunnel: `ai.qentra.top``localhost:8765`
- Бэкенд: `claude-code` (переключено с `claude-proxy`)
- Лог сессий: `~/Developer/reflect-skip/sessions.log`
## Агенты
- **NarratorBot** — нейтрализует ввод пользователя (убирает эмоциональную окраску, 3-е лицо); детектирует `[SCHEDULE:]` тег для schedule intent
- **AnalystBot** — задаёт 2-3 глубоких вопроса по профилю + контексту сессии; возвращает `AnalystJSON` с полями `sessionComplete`, `moodDelta`, `suggestedInsight`
- **SafetyClassifier** — Layer 2, параллельный crisis detection; роутинг off-topic → redirect card
- **SessionManager** — управляет историей сессий, пейсингом (turn count, fatigue, hard limit 8 оборотов), closing-флоу
### ProcessingResult (текущие кейсы)
```swift
enum ProcessingResult {
case questions([String], observation: String?)
case readyToClose([String]?, observation: String?)
case offTopic(String)
case scheduleIntent(String)
case crisis(CrisisDetectionResult)
case moodDeclining / moodImproving // через OrbState
case error(String)
}
```
## Исправления (v0.0.92, 28 мая 2026) — Android vault validation
### Веха: Android onboarding работает
✅ Алерт валидации vault отображается корректно
✅ Кнопки появились после выбора папки
✅ Дошли до экрана "Доброе утро"
### Fix — @AppStorage вместо @State для UI-обновлений на Android
**Проблема:** `@State var folderPickerError: String?` и `@State var vaultFound: Int?` не триггерили Compose recompose в SkipFuse bridge.
**Симптом:** алерт не появлялся, кнопки не обновлялись, хотя логика SAF выполнялась.
**Исправление:** заменили на `@AppStorage("_vaultErr")` и `@AppStorage("_vaultFound")` — идут через SharedPreferences → всегда триггерят Compose recompose.
**Файл:** `Sources/naisei/Views/OnboardingView.swift`
## Реализовано (v0.0.92 → v0.0.108)
- **Session pacing + fatigue + recovery** — turn counter, fatigue detection, session recovery флоу
- **Structured session close** — `generateClose()`, `applyOps()`, ProfileManager DI; X-кнопка вызывает `endSession()`
- **Completion routing + insights** — `readyToClose` в ProcessingResult, `insights.md`, agentic insight
- **One-card UX** — `isActive`, `appendCard`, growing TextEditor, history view
- **Schedule intent detection** — Narrator `[SCHEDULE:]` тег → `ProcessingResult.scheduleIntent`
- **Mood delta → Orb visual feedback** — `MoodDelta` enum, `AnalystJSON`, `OrbState.moodDeclining/moodImproving`
- **Warm track** — реальные даты сессий из file attributes, `lastSessionText`, `daysSinceLastSession` → Analyst context
- **LLM safety classifier + off-topic routing** — `SafetyClassifier` Layer 2, параллельный crisis detection, redirect card
- **Android voice bridge** — `SpeechRecognizer` bridge via `AndroidBridge`, Kotlin companion в `AndroidAppMain`
## Исправления (v0.0.25, май 2026)
### Fix 1 — дублирование нарратора
`buildSessionContext()` вызывался после `addMessage()` → нарратор видел своё же сообщение в контексте.
Исправлено: поменяли порядок в `Sources/SessionManager.swift`.
### Fix 2 — AnalystBot не видел текущий диалог
`ProfileManager.loadRecentSessions(count: 3)` загружал прошлые ФАЙЛЫ, не текущую сессию.
Исправлено: добавили `buildCurrentSessionDialogue()` (последние 8 пар user/analyst), передаём в `analyze()`.
### Fix 3 — нарратору уходили вопросы аналитика
`sendBatchSummary()` отправлял весь диалог включая вопросы аналитика.
Исправлено: фильтруем только user answers.
## Obsidian-совместимость
Приложение читает сессии из папки `observations/` (формат vault), а не `sessions/`.
- **Папка сессий:** `observations/` в корне импортируемой директории
- **Именование файлов:** ISO week — `2026-W20.md`, `2026-W21.md`
- **Запись сессий:** аппендит `## Сессия DD.MM.YYYY HH:mm` в текущий недельный файл
- **Счётчик сессий:** считается напрямую как количество `.md` файлов в `observations/` (не хранится в profile.md)
- **Профиль:** `profile.md` — строка `**Имя:** Алексей` нужна для `parseName()`
- **Инсайты:** `insights.md` — произвольный формат, передаётся напрямую в Claude
Vault путь для импорта: `personal/psychology/` (на Taiga).
## Pitfalls
- Если на iOS-симуляторе не появляется `DevSetupView` (ввод токена) — значит `dev_setup_done = true` в UserDefaults. Удалить приложение с симулятора и запустить заново.
- `ReflectApp/` в корне — legacy, не трогать. Реальные правки только в `Sources/ReflectApp/`.
## Связанные заметки
- [[personal/projects/psychologist-app/overview]]
- [[personal/projects/psychologist-app/dev-setup]]