Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

GnauralCore

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

GnauralCore

Owned location for the extracted audio core product.

Current ownership:

  • cli
  • product-local Pascal audio vendor tree under cli/vendor/uos
  • product-local Gnaural control protocol under cli/common
  • server
  • audio UI modules from ui

No compatibility shim remains under pas/gnaural.

Public entry points (since GCY4.1, plan gnauralcity, GCY-D14):

  • Hosts and other modules import this component by package name, only through the entries declared in exports — never a deep path. Inside the component its own files are imported by relative path.
  • @gnauralcore/ui (ui/package.json): . (gnauralModule, createGnauralPlugin), ./module, ./plugin (also the MenuNode type), ./widgets (useAudioStore, useAudioTransport, loadGnauralScheduleView, loadGnauralTransportControls — embedded audio widgets, GCY-D20), ./protocol (the browser↔server protocol, for browser and server alike), ./i18n.
  • @gnauralcore/server (server/package.json): . (server/index.ts — createGnauralServerModule and its API/host types, the settings store, checkNewProjectDefaults) and ./testing (server/testing.ts — for host tests only; production code never imports it).
  • The repo root package.json is @gnauralcore/core — scripts only.
  • A host UI lists ui/ in hostUi.modulePackages (HostKitCore's factory turns exports into exact aliases and paths); a host server maps the names with paths in its server/tsconfig.json. A new need is a new entry here: a new ui entry needs every host's generated tsconfig.hostkit.json regenerated (validate-qa.js reddens until it is), a new server entry a paths key in the server tsconfig of each host that uses it.

UI composition contract:

  • ui/package.json declares the source-level public entrypoints used by host products.
  • The package root stays minimal and re-exports only gnauralModule and createGnauralPlugin; everything else goes through the declared subpath exports.
  • ui exports gnauralModule for route, settings-tab, and locale-message contributions.
  • ui exports createGnauralPlugin for runtime wiring; the host must provide the shared ws adapter before rendering Gnaural pages.
  • The host also passes the shell's naming function, createGnauralPlugin({ ws, hostKey }) (hostKey from @hostkit/app/host-keys; GCY4.3, GCY-D22): every localStorage key of the component's view is <host prefix><name>, built by ui/view-keys.ts at the moment of use — one prefix per host, configureHostKeys({ keyPrefix }), the same that names the panel framework's keys and the language key (MindWave mindwave-, its saved view stays in place; Gnauralcity gnauralcity-). A new view key is added to VIEW_KEY_NAMES there; the lock ui/view-keys.test.ts holds MindWave's names byte for byte.
  • Gnaural owns its module-local navigation namespace, including nav.audio.
  • Host shells such as MindWaveCore own only shell concerns like top-level navigation, archive/log pages, and app bootstrap.

Расширение компонента хостом

Хост (продукт из hosts.json) подключает компонент двумя вызовами — UI-плагином и серверным модулем — и всё, чем продукты различаются, передаёт их опциями (GCY-D7, GCY-D18; план gnauralcity). Ветвлений «если это MindWave» в компоненте нет, имён продукта он не знает (GCY-D19). Эталон — Gnauralcity: всё, что нужно ему, и есть обязательная часть контракта (GCY-D13); всё сверх — формы ниже.

UI — createGnauralPlugin(options) (@gnauralcore/ui/plugin)

Опция Что это Хосты
ws (обязательна) ws-транспорт оболочки — wsService из @hostkit/ws/ws. Плагин сам регистрирует на нём обработчик audio_*, отвечаемые типы часов живости и префиксный канал spectrogram:; порядок установки плагинов хоста — порядок раздачи событий (MindWave ставит этот плагин первым, MindWaveCore/ui/src/boot/module-plugins.ts). оба
hostKey (обязательна) Функция имён оболочки (@hostkit/app/host-keys, GCY4.3, GCY-D22): каждый ключ localStorage вида компонента — <префикс хоста><имя>; префикс один на хост — configureHostKeys({ keyPrefix }). MindWave mindwave-, Gnauralcity gnauralcity-
menuItems (необязательна) Пункты «Меню» AudioPage (форма «пункты меню», GCY-D18, GCY2.2) — readonly MenuNode[] (тип отдаёт тот же вход). Встают после разделов редактора, перед «Настройками» и «Выходом». Gnauralcity — язык и «Bun-действия» (Gnauralcity/ui/src/boot/host.ts); MindWave не передаёт

Правила пунктов меню: подпись labelKey — ключ i18n приложения (сообщения хоста или оболочки; модуль их не знает); id — в пространстве имён хоста host.* (меню ищет листья по id и по нему ведёт список недавних — совпадение с командой модуля спутало бы их); подменю — children, действие листа — run, недоступность — disabled; служебный пункт помечается noMru: true у каждого листа (список недавних читает поле листа, а не раздела).

Ещё хост берёт: gnauralModule (@gnauralcore/ui/module — маршрут audio, отсоединяемые панели, сообщения i18n) — в свой реестр модулей (assembleModules, маршруты — moduleRouteRecords HostKitCore); app.title и свои ключи i18n хост даёт сам (assembleAppMessages). Встраиваемые виджеты — вход @gnauralcore/ui/widgets (GCY-D20: транспорт, вид расписания, стор звука — живое состояние единственного плеера приложения).

Сервер — createGnauralServerModule(host) (@gnauralcore/server)

Что модуль получает от хоста (GnauralServerHost, GCY-D25):

Поле Что это MindWave / Gnauralcity
runtimeDir Каталог рантайма (GCY-D26): там var/gnaural-settings.json, если хост не дал settings. server/ или HK_RUNTIME_DIR — у обоих
diagnosticsDir Каталог диагностических логов (ui-diag.log, fs-browser.log, undo-log-perf.log) — отдельно от рантайма: песочница подменяет рантайм, а след остаётся там, где его ждут читатели (GCY-D26). свой server/var — у обоих
userDataRootName Имя корня пользовательских данных %LOCALAPPDATA%\<имя> (GCY-D27); кэш следует за корнем. KKSoundCore / Gnauralcity
writeFenceRoot Заборчик записи песочницы ("" — нет). HK_WRITE_FENCE — у обоих
dev Дев-режим: серверная половина журнального следа горит безусловно (AGENTS.md, «Журнальный след»). HK_DEV=1 (bun run dev) — у обоих
publish Публикация текста события в ws-тему оболочки "ui"; зовётся только после старта сервера. server.publish(...) каркаса
settings (необязательно) Хранилище настроек компонента, УЖЕ перенесённое хостом (GCY-D24); без него модуль заводит своё в runtimeDir. MindWave — после однократного переноса из своей базы журнала; Gnauralcity не передаёт

Окружения хоста компонент не читает (только системное LOCALAPPDATA — корень данных по умолчанию, собственные пути к exe GNAURAL_EXE, SPECTRUMCORE_WORKER_EXE и флаги своих тестов): значения выше хост читает сам, функцией readHostEnv HostKitCore (HostKitCore/server/host-env.ts) под нейтральными именами HK_* (GCY-D38). Прежние MW_* MindWave сняты в GCY6.1 и не читаются; заданное старое имя даёт строку [host-env] … больше не читается в консоли сервера MindWave.

Что модуль возвращает (GnauralServerModule): модуль каркаса HostKitCore — fetch своих путей (/api/audio/*, /api/projects*, /api/project-settings, /api/new-project-defaults, /api/fs/info, /api/ui-diag; чужой путь /api модуль не отвечает — хвост 404 у каркаса), ws (заявка на свои audio_* и spectrogram:* по форме сообщения, audio_status на открытие сокета, уборка на закрытие), dispose (движок, вотчер расписания, сервер файлового браузера); плюс api, fsBrowserUrl (для строки в консоли хоста) и startBackgroundTasks() (позвать после старта).

Публичный API звука (api, GnauralServerApi) — программное управление и события (форма GCY-D18): beginStart, start, stop, pause, resume, seek, getStatus, getLoadedSchedule, getLoadedScheduleStartedAtMs, getAccessRoots; подписки onScheduleLoaded(listener) — сырое событие загрузки расписания, синхронно, до публикации клиентам (MindWave пишет по нему архив сеансов), и onTransportCommand(listener) — "start"/"stop" клиентских audio_start/audio_stop по ws, синхронно, до самого действия; вызовы API — не команды (MindWave по ним отпускает временный файл реплея). Обе возвращают отписку; исключение слушателя не гасится.

Свои ручки и ws хост добавляет не в модуль, а рядом: своим модулем в списке modules каркаса (startHostServer, HostKitCore). Модуль без claims получает всё незаявленное (у MindWave — его модуль хоста: ЭЭГ-режимы поверх api, реплей, BodyMonitor, архив); порядок списка — порядок open и цепочки останова.

Секции проекта хоста

Состояние, привязанное к открытому файлу, — секция проекта (AGENTS.md, «Per-file data»; руководство и таблица имён — MindWaveCore/docs/project-store/project-store-api.md). Имена секций компонента перечислены в коде — ui/project-sections.ts, по строке назначения на имя; замок server/project-sections.test.ts держит, что код читает и пишет ровно их и что ни в одном нет -, а validate-qa.js — что таблица руководства та же. Решение владельца 2026-10-16 («Префикс хоста + вход»; GCY-D18, GCY-D19): секция хоста называется <префикс ключей хоста><имя> — тот же префикс, что у ключей вида (mindwave-…, gnauralcity-…, GCY4.3); дефис в именах компонента запрещён, поэтому пространства имён не пересекаются. Читает и пишет свои секции хост через НОВЫЙ вход компонента, который ставит префикс сам; вход заводится вместе с первой секцией хоста, не раньше. До него ни один вход клиентского API секций (readProjectSectionFor/writeProjectSectionFor) не отдаёт, и хост секций не пишет.

Чего хост не может

  • Импортировать файл компонента мимо входов exports (@gnauralcore/ui, @gnauralcore/server) — глубокий путь, алиас или копия файла в хосте; вход testing — только из тестов. Это держит замок контракта validate-qa.js (GCY4.2) на каждом шаге и ночью. Нужно то, чего ни один вход не даёт, — новый вход в exports (см. выше).
  • Ждать от компонента знания о себе: никаких веток по хосту, имён продукта и переменных окружения хоста внутри компонента; различие — только значением опции.
  • Отвечать на сообщения компонента своим ws-модулем раньше компонента: заявки раздаются в порядке списка модулей, и ws-модуль хоста заявок на audio_*/spectrogram:* не делает.