Commit Graph

4 Commits

Author SHA1 Message Date
claude code agent 227
c7c0c28e38 refactor(mcp): single docmostSchema + shared encode-error helper + catch test (#152 review)
Review of #154 (Request changes) — all clean follow-ups, no defect in the fix:

1. Single source of the ProseMirror schema: export `docmostSchema` from
   docmost-schema.ts (next to docmostExtensions); diff.ts and collaboration.ts
   import it instead of each calling getSchema(docmostExtensions) — the schema
   can no longer drift between call sites. Removed both local builds + the now
   unused getSchema imports.
2. Doc fix: assertYjsEncodable's docstring and the client.ts comment no longer
   claim "the same encoder as apply" — apply uses updateYFragment, the dry-run
   uses toYdoc; both reject the same unstorable attrs but are NOT byte-identical.
   Reworded to "independent encodability gate".
3+4+5. Extracted `unstorableYjsError(safe, label, e)` — buildYDoc and
   applyDocToFragment now share one message template (label kept for diagnostics:
   toYdoc vs updateYFragment), so the wording can't drift between dry-run/apply.
6. Test for applyDocToFragment's catch branch: an unknown node type makes the
   schema-validated PMNode.fromJSON throw, and the function must re-throw it
   wrapped with the (updateYFragment) diagnostic.

build/ rebuilt for the three changed lib modules; 293 package tests green.
(Left build/client.js untouched: rebuilding it would pull in a pre-existing,
unrelated src/build drift — a listSidebarPages slugId fix never rebuilt on
develop — and my client.ts change there is comment-only.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 12:56:23 +03:00
claude_code
f3fa15e746 refactor(ai-chat): shared tool-spec registry for identical tools; formalize integration db factory
Implements two architecture follow-ups from the multi-aspect review.

1. Shared, zod-agnostic tool-spec registry (packages/mcp/src/tool-specs.ts)
   for the 14 AI tools whose name + schema + model-facing description are
   genuinely identical across the standalone MCP server and the in-app
   AI-SDK chat. Both layers consume it (registerShared in index.ts;
   sharedTool in ai-chat-tools.service.ts) and keep their own execute/auth.
   - Zod-agnostic builders (z) => ZodRawShape bridge the zod v3 (mcp) vs
     zod v4 (server) split; the registry imports no zod.
   - Folds in the documented edit_page_text drift-bug fix: the stale
     "strip-and-retry tolerated" claim is gone; canonical wording states a
     formatting-only change is refused into failed[].
   - Sibling-tool references in shared descriptions are transport-neutral so
     one description is correct for both snake_case (MCP) and camelCase
     (in-app) tool names.
   - Loader fail-fast guard for a stale @docmost/mcp build.
   - The ~17 intentionally-divergent tools (security guardrails, tuned UX)
     stay per-layer, untouched.
   - Rebuilt committed mcp artifacts (also regenerates a previously stale
     build/lib/docmost-schema.js to match its already-committed source).

2. Formalize apps/server/test/integration/db.ts as the canonical
   integration-test seed factory (module doc + a shortId helper); the
   hand-written minimal seeders are kept on purpose, decoupled from the
   app service-layer side effects.

Verified: server tsc + lint clean, mcp build clean; mcp unit tests 261 pass,
ai-chat-tools.service 16 pass, public-share-chat-tools 8 pass, ai-chat suite
224 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:57:00 +03:00
claude code agent 227
4d17befb0d feat(editor): footnotes (reference + definitions model)
Adds footnotes: a superscript marker in the text linked to an editable
definition in a Footnotes section at the end of the page, with auto-numbering
and a read-only hover popover. Chose the reference+definitions model (3 plain
nodes) over an inline atom with a sub-editor specifically for collaboration
safety.

editor-ext (packages/editor-ext/src/lib/footnote/):
- footnoteReference (inline atom, id), footnotesList (block, last child),
  footnoteDefinition (paragraph+, id). renderHTML emits sup[data-footnote-ref]
  / section[data-footnotes] / div[data-footnote-def]; parse-rule priority makes
  the empty reference win over the Superscript mark (else it is dropped on the
  server save).
- numbering: a decoration-only plugin (pure function of doc order) -> every
  client computes identical numbers, no document mutation, Yjs-safe.
- sync plugin: single-pass, always SYNC_META-tagged and skipping remote txns
  (terminates, no loop), idempotent; canonicalizes to one trailing footnotesList
  (merging duplicates), creates missing definitions, drops orphans, and
  coexists with TrailingNode. Disabled in read-only.
- commands setFootnote (one tx: reference + definition at the matching index +
  focus) / removeFootnote (cascade, one undo) / scrollTo*. slash /footnote.

client: superscript NodeView + floating-ui read-only popover; bottom-list and
definition NodeViews; registered in mainExtensions.

server: the three nodes registered in tiptapExtensions so collab/save/export
keep them. Round-trip regression spec guards the Superscript parse-priority.

markdown: turndown/marked round-trip to pandoc/GFM [^id] (+ a code-fence guard
so footnote-like lines inside code blocks are not extracted).

MCP mirror: schema + markdown-converter + commentsToFootnotes rewritten to real
footnote nodes + diff marker counting; NUL sentinels written as \u0000 escapes.

v2 follow-ups (per plan): definition reordering on reference move, id-collision
regeneration on paste, multiple references to one footnote.

Implements docs/footnotes-plan.md (variant B).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 11:39:00 +03:00
vvzvlad
1f5987d6b0 feat(mcp): serve embedded community MCP server at /mcp
Replace the removed enterprise EE MCP (private apps/server/src/ee submodule,
license-gated /mcp route) with our docmost-mcp, vendored as an isolated ESM
workspace package and served by the server over HTTP — no enterprise license.

Backend:
- Add packages/mcp (@docmost/mcp): vendored docmost-mcp refactored into a
  side-effect-free createDocmostMcpServer() factory (38 tools preserved),
  stdio entry kept in stdio.ts, Streamable-HTTP session manager in http.ts.
- Add apps/server McpModule: @Post/@Get/@Delete('mcp') (served at /mcp via the
  existing global-prefix exclude), @SkipTransform + reply.hijack to bridge raw
  Fastify req/res into the SDK transport. The module dynamically imports the
  ESM-only package from CommonJS via a Function-indirected import resolved with
  require.resolve + file:// URL. Gated by the workspace ai.mcp toggle, a
  service-account (MCP_DOCMOST_EMAIL/PASSWORD/API_URL) and optional MCP_TOKEN;
  per-session idle eviction (MCP_SESSION_IDLE_MS).
- Drop the enterprise license check on mcpEnabled in workspace.service.
- Dockerfile: copy packages/mcp into the production image.
- .env.example: document MCP_DOCMOST_*, MCP_TOKEN, MCP_SESSION_IDLE_MS.

Frontend:
- Recreate the community "AI & MCP" workspace-settings panel (mcp-settings.tsx):
  admin-only toggle on settings.ai.mcp with optimistic update, copyable
  ${APP_URL}/mcp URL; wired into workspace-settings page. Reuses existing i18n.

Fixes:
- Pin packages/mcp tiptap deps to 3.20.4 (matching the client) and inline
  getStyleProperty, preventing a duplicate @tiptap/core@3.26.1 from leaking into
  the client editor via pnpm shamefully-hoist (was breaking apps/client tsc).
2026-06-16 23:54:53 +03:00