diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1d9ca3ad..7ea47b94 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -72,6 +72,14 @@ jobs: - name: Build editor-ext run: pnpm --filter @docmost/editor-ext build + # @docmost/prosemirror-markdown is the shared converter (#293/#326); its + # build/ is gitignored, and plain `pnpm -r test` does NOT honour nx + # `dependsOn: ^build`, so its consumers (mcp `pretest: tsc`, git-sync vitest + # typecheck) fail with TS2307 Cannot find module '@docmost/prosemirror-markdown' + # unless it is built first. Build it before the recursive test run. + - name: Build prosemirror-markdown + run: pnpm --filter @docmost/prosemirror-markdown build + - name: Run unit tests run: pnpm -r test diff --git a/AGENTS.md b/AGENTS.md index 2b91446b..9bedbc39 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -200,7 +200,8 @@ pnpm workspace (`pnpm@10.4.0`) orchestrated by **Nx**. Four workspace packages: | `apps/server` | `server` | NestJS 11 + Fastify, Kysely (Postgres), Redis | Backend API, collaboration, AI | | `apps/client` | `client` | React 18 + Vite + Mantine 8 + TanStack Query + Jotai | SPA frontend | | `packages/editor-ext` | `@docmost/editor-ext` | Tiptap/ProseMirror | Shared Tiptap node/mark extensions, imported by both the client and the server | -| `packages/mcp` | `@docmost/mcp` | MCP SDK, Tiptap, Yjs | Standalone MCP server, also bundled into the server at `/mcp`. Does **not** import `editor-ext` — it keeps its own vendored mirror of the schema in `packages/mcp/src/lib/` | +| `packages/mcp` | `@docmost/mcp` | MCP SDK, Tiptap, Yjs | Standalone MCP server, also bundled into the server at `/mcp`. Consumes the shared converter/schema from `@docmost/prosemirror-markdown` (#293) — it no longer carries its own vendored converter/schema copy | +| `packages/prosemirror-markdown` | `@docmost/prosemirror-markdown` | Tiptap, marked, jsdom | The single, canonical ProseMirror↔Markdown converter + Docmost schema mirror (#293). Consumed by `mcp` and `git-sync`; there is exactly ONE copy of the converter now | `build` targets are Nx-cached and dependency-ordered (`dependsOn: ["^build"]`), so `editor-ext` builds before the apps. `nx.json` sets `affected.defaultBase: main`. @@ -282,7 +283,7 @@ The API server is a Fastify app with a global `/api` prefix (`main.ts` excludes ### Client structure Vite SPA. Code is organized by feature under `apps/client/src/features/*` (mirrors the server domains: `page`, `space`, `comment`, `ai-chat`, `editor`, …). Conventions: - **TanStack Query** for server state (one `queries/` file per feature), **Jotai** atoms for local/shared UI state, **Mantine 8** + CSS modules (`*.module.css`) + `postcss-preset-mantine` for UI. -- The editor is Tiptap; shared node/mark extensions live in `packages/editor-ext` and are imported by **both the client and the server** (collaboration, import/export) — editor schema changes often need to be made in `editor-ext`, not just the client. Note `packages/mcp` does *not* depend on `editor-ext`; it carries its own mirrored copy of the schema, so keep the two in sync manually when the document schema changes. +- The editor is Tiptap; shared node/mark extensions live in `packages/editor-ext` and are imported by **both the client and the server** (collaboration, import/export) — editor schema changes often need to be made in `editor-ext`, not just the client. The ProseMirror↔Markdown converter and its Docmost schema mirror now live in a SINGLE package, `@docmost/prosemirror-markdown` (#293), consumed by both `mcp` and `git-sync` — do NOT reintroduce a per-package copy. `editor-ext` is the upstream source of the Tiptap schema; the package's `docmost-schema.ts` mirrors it and a serializer-contract test (`packages/prosemirror-markdown/test/serializer-contract.test.ts`) guards the boundary (every schema node must have a converter case), so a drift surfaces as a failing test rather than silent divergence. - API access goes through `apps/client/src/lib/api-client.ts` (axios). The `@` alias maps to `apps/client/src`. - Runtime config is injected at build time by `vite.config.ts` via `define` (`APP_URL`, `COLLAB_URL`, `APP_VERSION`, …) — these come from the root `.env`, not from `import.meta.env`. diff --git a/Dockerfile b/Dockerfile index e6daeb72..42f5a267 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,6 +38,14 @@ COPY --from=builder /app/packages/editor-ext/dist /app/packages/editor-ext/dist COPY --from=builder /app/packages/editor-ext/package.json /app/packages/editor-ext/package.json COPY --from=builder /app/packages/mcp/build /app/packages/mcp/build COPY --from=builder /app/packages/mcp/package.json /app/packages/mcp/package.json +# mcp now depends on @docmost/prosemirror-markdown (workspace:*) and eager-imports +# it at runtime (the in-app ai-chat DocmostClient loads build/index.js -> lib/ +# markdown-converter.js). Ship the built package + its manifest, or the prod +# install resolves a broken workspace symlink and every ai-chat tool dies with +# ERR_MODULE_NOT_FOUND (#293/#326 step 5). (git-sync has no runtime consumer yet; +# revisit at step 6 when #119 lands.) +COPY --from=builder /app/packages/prosemirror-markdown/build /app/packages/prosemirror-markdown/build +COPY --from=builder /app/packages/prosemirror-markdown/package.json /app/packages/prosemirror-markdown/package.json # Copy root package files COPY --from=builder /app/package.json /app/package.json