diff --git a/.env.example b/.env.example index 4cebe788..99aab852 100644 --- a/.env.example +++ b/.env.example @@ -140,6 +140,7 @@ MCP_DOCMOST_PASSWORD= # Backstop: a cluster-wide, sliding-window cap per workspace (IP-independent, # keyed by the server-resolved workspace id) bounds the owner's bill even if the # per-IP limit is fully evaded. It is a COST backstop, not an access control, -# and FAILS OPEN if Redis is unavailable. Override the hourly cap below +# and FAILS CLOSED if Redis is unavailable (the assistant is temporarily +# denied rather than serving unmetered calls). Override the hourly cap below # (default: 300 calls per workspace per rolling hour). # SHARE_AI_WORKSPACE_MAX_PER_HOUR=300 diff --git a/README.ru.md b/README.ru.md index 0bd9a5de..303f489d 100644 --- a/README.ru.md +++ b/README.ru.md @@ -102,6 +102,7 @@ real-time-коллаборации Docmost, поэтому запись нико - ✅ **Приложение для macOS** — нативное приложение для macOS ([gitmost-app](https://github.com/vvzvlad/gitmost-app)), встраивающее UI с вкладками для нескольких серверов. - ✅ **AI-чат** — встроенный чат с AI-агентом по содержимому вики (чтение + запись, RAG-поиск, настраиваемый провайдер, опциональный доступ в интернет через внешние MCP). - ✅ **Голосовая диктовка** — кнопка-микрофон в чате AI-агента и в редакторе страниц; аудио распознаётся на сервере (Whisper / OpenAI-совместимый STT) через AI-провайдер воркспейса, с тумблером админа для показа/скрытия. +- ✅ **Шаблоны страниц** — пометить страницу шаблоном и вставлять её содержимое живой ссылкой в другие страницы; правки шаблона распространяются на все места вставки (whole-page-транслюзия поверх существующих synced-блоков). ### В процессе @@ -109,7 +110,6 @@ real-time-коллаборации Docmost, поэтому запись нико ### В планах -- 🔭 **Шаблоны страниц** — пометить страницу шаблоном и вставлять её содержимое живой ссылкой в другие страницы; правки шаблона распространяются на все места вставки (whole-page-транслюзия поверх существующих synced-блоков). См. [docs/page-templates-plan.md](docs/page-templates-plan.md). - 🔭 **Комментарии зрителей** — возможность комментировать для пользователей с доступом только на чтение. - 🔭 **AI-ассистент на публичных шарах** — возможность анонимному зрителю расшаренной страницы спросить AI-агента, который ищет строго по дереву этой шары (read-only, share-scoped поиск), за тумблером воркспейса. См. [docs/public-share-assistant-plan.md](docs/public-share-assistant-plan.md). - 🔭 **Защищённые паролем страницы** — защита отдельных страниц / шар паролем. diff --git a/apps/server/src/core/ai-chat/public-share-chat.spec.ts b/apps/server/src/core/ai-chat/public-share-chat.spec.ts index a1ef621c..df8df047 100644 --- a/apps/server/src/core/ai-chat/public-share-chat.spec.ts +++ b/apps/server/src/core/ai-chat/public-share-chat.spec.ts @@ -533,7 +533,6 @@ describe('PublicShareChatToolsService share scoping', () => { shareService as never, {} as never, {} as never, - {} as never, ); const tools = svc.forShare('THIS-SHARE', 'ws-1'); @@ -566,7 +565,6 @@ describe('PublicShareChatToolsService share scoping', () => { shareService as never, {} as never, {} as never, - {} as never, ); const tools = svc.forShare('THIS-SHARE', 'ws-1'); @@ -591,7 +589,6 @@ describe('PublicShareChatToolsService share scoping', () => { {} as never, searchService as never, {} as never, - {} as never, ); const tools = svc.forShare('THIS-SHARE', 'ws-1'); const searchSharePages = tools.searchSharePages as { @@ -732,7 +729,6 @@ describe('public-share assistant boundary locks (red-team regression guards)', ( shareService as never, {} as never, {} as never, - {} as never, ); const tools = svc.forShare('FORGED-SHARE', 'ws-1'); const getSharePage = tools.getSharePage as { diff --git a/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.spec.ts b/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.spec.ts index 9069dfda..bc80acd6 100644 --- a/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.spec.ts +++ b/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.spec.ts @@ -24,14 +24,12 @@ describe('PublicShareChatToolsService.forShare', () => { }; const searchService = { searchPage: over.searchPage ?? jest.fn() }; const pageRepo = { findById: over.findById ?? jest.fn() }; - const pagePermissionRepo = { hasRestrictedAncestor: jest.fn() }; const svc = new PublicShareChatToolsService( shareService as never, searchService as never, pageRepo as never, - pagePermissionRepo as never, ); - return { svc, shareService, searchService, pageRepo, pagePermissionRepo }; + return { svc, shareService, searchService, pageRepo }; } describe('listSharePages', () => { diff --git a/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.ts b/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.ts index 8f0998f5..5d3e8df0 100644 --- a/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.ts +++ b/apps/server/src/core/ai-chat/tools/public-share-chat-tools.service.ts @@ -4,7 +4,6 @@ import { z } from 'zod'; import { ShareService } from '../../share/share.service'; import { SearchService } from '../../search/search.service'; import { PageRepo } from '@docmost/db/repos/page/page.repo'; -import { PagePermissionRepo } from '@docmost/db/repos/page/page-permission.repo'; import { jsonToMarkdown } from '../../../collaboration/collaboration.util'; /** @@ -35,7 +34,6 @@ export class PublicShareChatToolsService { private readonly shareService: ShareService, private readonly searchService: SearchService, private readonly pageRepo: PageRepo, - private readonly pagePermissionRepo: PagePermissionRepo, ) {} /**