Novolis Docs
novolis-governance / completed-plans/novolis-manuscript_framework_f4b8d88a.plan.md

novolis-manuscript framework repo

dotnetgovernancenovolis

name: novolis-manuscript framework overview: Create packable novolis-manuscript as the Manuscript app-framework repo (Cad/Live pattern), moving Protocol/LegacyBooks/Manuscript/Voice into Novolis.Manuscript.* with IO and Export.* naming, genericizing BooksRepoMirror, then retargeting BooksWriterStudio and BooksMobile. todos:

  • id: scaffold-repo

content: Bootstrap novolis-manuscript from template-dotnet; wire CI, packages.json, Platform.slnx status: completed

  • id: move-read-model

content: Move Protocol, LegacyBooks, Manuscript core (no PDF); update namespaces; relocate tests; purge markup projects status: completed

  • id: export-packages

content: Add Export.Pdf + Export.Audio; remove Audio.Voice.Manuscript from novolis-audio status: completed

  • id: io-and-mirror

content: Rename BooksRepoMirror → SparseRepoMirror; add Manuscript.IO (book-tool port + SCM façades) status: completed

  • id: avalonia-and-apps

content: Add Avalonia.Manuscript; retarget Studio/Mobile/dogfood PackageReferences; publish GPR; verify nuget-only status: completed isProject: false


Source of truth: novolis-manuscript-package-map (+ framework placement canvas).

Locked naming

PackageIdRole
`Novolis.Manuscript`Workspace façade / doctor bridge (no PDF, no audio)
`Novolis.Manuscript.Protocol`NMP/1 reader
`Novolis.Manuscript.LegacyBooks`Legacy `content/` adapter
`Novolis.Manuscript.IO`Tree surgery, working copies, git/GitHub façades
`Novolis.Manuscript.Export.Pdf`PDF export
`Novolis.Manuscript.Export.Audio`TTS / audiobook (from Voice.Manuscript)
`Novolis.Avalonia.Manuscript`Shared editor chrome (only Avalonia package in this product)

Reserved later (do not scaffold empty stubs): Export.Html, Export.Docx, Export.Txt, Export.Epub.

Rejected: Mutate, Manuscript.Pdf, Manuscript.Voice, Export.Voice.

Avalonia.Manuscript lives in novolis-manuscript (not novolis-avalonia) so Avalonia stays free of Manuscript-specific packages.

Target shape

flowchart TB
  content[frankhaugen/books content]
  proto[Manuscript.Protocol]
  legacy[Manuscript.LegacyBooks]
  core[Manuscript]
  io[Manuscript.IO]
  pdf[Export.Pdf]
  audio[Export.Audio]
  ui[Avalonia.Manuscript]
  studio[BooksWriterStudio]
  mobile[BooksMobile]
  gio[Novolis.IO.Git]
  ghub[Novolis.IO.GitHub SparseRepoMirror]
  edge[Voice.EdgeTts]
  render[Markup.Markdown.Rendering]

  content --> legacy
  content --> proto
  legacy --> core
  proto --> core
  core --> io
  io --> gio
  io --> ghub
  core --> pdf
  pdf --> render
  core --> audio
  audio --> edge
  core --> ui
  ui --> studio
  ui --> mobile
  io --> studio
  io --> mobile
  pdf --> studio
  audio --> studio
  audio --> mobile

Hosts stay under d:\novolis\novolis-apps. Content stays in D:\repos\books.

Phase 1 — Scaffold repo + move read model

  1. Bootstrap d:\novolis\novolis-manuscript from novolis-template-dotnet (net10.0, nuget.org + GitHub Packages only, CI/release, .novolis/packages.json).
  2. Move (git history optional; prefer clean move of sources) from markup:
  1. Update namespaces/PackageIds to Novolis.Manuscript*. Move Protocol/Legacy/Manuscript unit tests from Novolis.Markup.Unit into novolis-manuscript/tests.
  2. Remove the three Manuscript projects from Novolis.Markup.slnx and markup packages.json.
  3. Regen platform map: pwsh -File d:\novolis\novolis-governance\build\Generate-Platform-Slnx.ps1.

Phase 2 — Export.Pdf + Export.Audio

  1. Novolis.Manuscript.Export.Pdf: move PDF exporter + print settings; PackageReference Novolis.Markup.Markdown.Rendering + Novolis.Manuscript.
  2. Novolis.Manuscript.Export.Audio: move Novolis.Audio.Voice.Manuscript sources; PackageReference Novolis.Audio.Voice.EdgeTts; rename types/namespaces to Novolis.Manuscript.Export.Audio (keep public API names sensible — e.g. drop redundant Manuscript prefix where the namespace already says it).
  3. Remove Novolis.Audio.Voice.Manuscript from novolis-audio; move its unit tests.
  4. Consumers temporarily keep building via ProjectRef mode until GPR publish.

Phase 3 — Genericize GitHub mirror + Manuscript.IO

  1. In Novolis.IO.GitHub: rename BooksRepoMirror / BooksRepoMirrorOptionsSparseRepoMirror / SparseRepoMirrorOptions (already has ContentPrefix). Add obsolete type aliases for one release if needed for external callers; update BooksMobile + IO unit tests.
  2. Add Novolis.Manuscript.IO:
  • Port insert-after / insert-between / promote / sync / stub write from D:\repos\books\tools\dev\book-tool.cs against legacy layout first (Calypso today).
  • Façades composing Novolis.IO.Git and SparseRepoMirror for manuscript workspaces (dirty set, pull/push helpers).
  • Working-copy helpers wrapping Novolis.IO.Recovery patterns used by WriterSession.
  1. Thin book-tool can later call this library; not required in the first merge.

Phase 4 — Avalonia.Manuscript + retarget hosts

  1. Add Novolis.Avalonia.Manuscript in novolis-manuscript (Avalonia PackageReferences allowed only here among Manuscript packages). Lift shared chapter-list / editor-shell pieces from Studio/Mobile only where duplication is real; leave spell, Android player, OAuth client id, Inno in apps.
  2. Retarget PackageReferences:
  1. Publish novolis-manuscript to GitHub Packages; bump apps/dogfooding restores on nuget.org + github only.
  2. Verify: verify-nuget-only.ps1, verify-project-ref-mode.ps1 -SkipBuild, build/test manuscript + apps under ProjectRef, then NuGet restore smoke.

Out of scope this plan

  • Migrating D:\repos\books to NMP/1 on disk
  • Implementing Export.Html/Docx/Txt/Epub
  • Deep UI redesign of Studio/Mobile
  • Putting hosts inside novolis-manuscript

Done when

  • d:\novolis\novolis-manuscript exists with the locked PackageIds above (minus reserved Export siblings)
  • Markup/audio no longer ship Manuscript/Voice.Manuscript packages
  • BooksWriterStudio + BooksMobile restore/build against new IDs
  • Platform slnx map includes the new packables; nuget-only checks pass