From c92edc4ecce88e3137218435fe6b24dd7780d487 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Mon, 25 May 2026 17:38:12 +0600 Subject: [PATCH] =?UTF-8?q?[2026-05-25]=20naisei:=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B8=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20nolvu=E2=86=92naisei,=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20obsidian-=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=B8=D0=BC=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20task-spec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personal/projects/nolvu-reflect-skip.md | 23 ++- .../task-obsidian-import-compat.md | 147 ------------------ 2 files changed, 19 insertions(+), 151 deletions(-) delete mode 100644 personal/projects/psychologist-app/task-obsidian-import-compat.md diff --git a/personal/projects/nolvu-reflect-skip.md b/personal/projects/nolvu-reflect-skip.md index 65426a0c..6192c885 100644 --- a/personal/projects/nolvu-reflect-skip.md +++ b/personal/projects/nolvu-reflect-skip.md @@ -1,9 +1,10 @@ --- -title: "nolvu / reflect-skip — проект" +title: "naisei / reflect-skip — проект" aliases: + - "naisei" - "nolvu" - "reflect-skip" - - "Nolvu проект" + - "Naisei проект" - "Reflect Skip" tags: - personal @@ -12,14 +13,15 @@ tags: - psychology - skip-tools created: '2026-05-17' -updated: '2026-05-17' +updated: '2026-05-25' related: - "[[personal/projects/psychologist-app/overview]]" - "[[personal/projects/psychologist-app/dev-setup]]" --- -# nolvu / reflect-skip — проект +# naisei / reflect-skip — проект ## Статус +- Имя продукта: **naisei** - Активная кодовая база: `~/Developer/reflect-skip/` - Android: публикуется на `https://reflect.qentra.top` (F-Droid) - iOS: собирается через `Project.xcworkspace` → `Darwin/ReflectApp.xcodeproj` @@ -64,6 +66,19 @@ related: `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. Удалить приложение с симулятора и запустить заново. diff --git a/personal/projects/psychologist-app/task-obsidian-import-compat.md b/personal/projects/psychologist-app/task-obsidian-import-compat.md deleted file mode 100644 index f5710ecd..00000000 --- a/personal/projects/psychologist-app/task-obsidian-import-compat.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -created: '2026-05-25' -updated: '2026-05-25' -tags: - - project - - psychologist-app - - task -status: ready ---- -# Задача: совместимость импорта с форматом Obsidian vault - -**Цель:** пользователь должен выбрать папку `personal/psychology/` из Obsidian -и приложение подхватит профиль и все сессии без конвертации. - -**Репо:** `~/Developer/reflect-skip` -**Затрагиваемые файлы:** -- `Sources/ReflectApp/Services/DocumentImportService.swift` -- `Sources/ReflectApp/Services/ProfileManager.swift` - ---- - -## Контекст: что сейчас есть в vault - -``` -personal/psychology/ -├── profile.md ← есть **Имя:** Алексей (добавлено), YAML frontmatter, rich markdown -├── insights.md ← есть, формат: ## Отцовство / ## ADHD с нарративными блоками -├── prompts.md ← не нужен для импорта -└── observations/ ← папка с еженедельными файлами - ├── 2026-W20.md - └── 2026-W21.md -``` - -**Что ожидает приложение сейчас:** -``` -UserProfile/ -├── profile.md ← строка "**Имя:** Алексей" (теперь есть ✅) -├── insights.md ← есть ✅ -└── sessions/ ← ДРУГОЕ имя папки ❌ - └── YYYY-MM-DD.md ← ДРУГОЙ формат имени файла (еженедельные vs ежедневные) -``` - ---- - -## Изменения в DocumentImportService.swift - -### 1. Поддержка папки `observations/` как алиаса `sessions/` - -В методах `validate()`, `countSessions()`, `apply()` — проверять обе папки. - -**`countSessions(in:)`** — текущий код: -```swift -let sessionsURL = url.appendingPathComponent("sessions") -``` -Заменить на: -```swift -let sessionsURL = sessionsFolder(in: url) -``` - -Добавить приватный метод: -```swift -private func sessionsFolder(in url: URL) -> URL { - let sessions = url.appendingPathComponent("sessions") - let observations = url.appendingPathComponent("observations") - if FileManager.default.fileExists(atPath: observations.path) { return observations } - return sessions -} -``` - -### 2. Обновить `validate()` — убрать упоминание "sessions" из ошибки - -Текущий error description (`noProfileFound`) упоминает "папку sessions" — заменить на нейтральное: -``` -В выбранной папке нет файла profile.md. -Убедитесь что выбрана папка с данными профиля. -``` - -### 3. Обновить `apply()` — копировать observations/ → sessions/ - -В методе `apply()` строка: -```swift -let sessionsSrc = result.sourceURL.appendingPathComponent("sessions") -``` -Заменить на: -```swift -let sessionsSrc = sessionsFolder(in: result.sourceURL) -``` - -Папка всегда копируется в `sessions/` в app Documents (это правильно — внутреннее имя не меняем). - ---- - -## Изменения в ProfileManager.swift - -### 4. Fallback для `sessionCount` при импортированном vault - -Текущий код ищет regex `- Сессий проведено: N` — vault profile этого не имеет. -Результат: `sessionCount` возвращает 0, приложение запускает "первую сессию" даже при 2+ импортированных. - -Изменить `sessionCount` — добавить fallback: - -```swift -var sessionCount: Int { - // Сначала пробуем разобрать из текста профиля - if let content = try? String(contentsOf: profileFileURL, encoding: .utf8), - let range = content.range(of: #"- Сессий проведено: (\d+)"#, options: .regularExpression), - let numRange = String(content[range]).range(of: #"\d+"#, options: .regularExpression), - let count = Int(String(content[range])[numRange]) { - return count - } - // Fallback: считаем фактические файлы в sessions/ - let files = (try? FileManager.default.contentsOfDirectory( - at: sessionsDirectoryURL, - includingPropertiesForKeys: nil, - options: .skipsHiddenFiles - )) ?? [] - return files.filter { $0.pathExtension == "md" && $0.lastPathComponent != "index.md" }.count -} -``` - ---- - -## Что НЕ нужно менять - -- Формат файлов сессий (`YYYY-MM-DD.md` vs `2026-W20.md`): BM25 поиск и `loadRecentSessions()` сортируют лексикографически — оба формата работают одинаково хорошо. -- Структура profile.md: `loadProfile()` отдаёт raw markdown в Claude — богатый vault-формат работает лучше чем простой app-формат. -- insights.md: `loadInsights()` тоже отдаёт raw markdown — vault-формат с секциями лучше flat-списка. -- `appendSession()` / `updateProfile()` / `addPattern()`: создают/дополняют нужные секции — при отсутствии секции код добавляет в конец файла. OK. - ---- - -## Acceptance criteria - -1. Пользователь выбирает папку `~/obsidian/personal/psychology/` на iOS -2. Validation проходит: имя "Алексей", счётчик сессий = 2 -3. После import в `Documents/UserProfile/`: - - `profile.md` скопирован - - `sessions/` содержит файлы из `observations/` - - `insights.md` скопирован -4. `sessionCount` возвращает 2 (файлы `2026-W20.md`, `2026-W21.md`) -5. `generateIntro()` использует `hasHistory = true` и показывает контекст из W20/W21 - ---- - -## Объём работы - -~30 строк кода. Затрагивает 2 файла, нет API изменений, нет UI изменений.