novident_project_manager 1.0.1
novident_project_manager: ^1.0.1 copied to clipboard
Dart for `.nov` projects to manages: binder tree, rich-text content, layouts/formats, writing sessions, targets, snapshots and git"
Novident Project Manager #
The Dart package that owns the .nov schema and drives a Rust engine for
writing projects: binder tree, rich-text content, layouts/formats, writing
sessions, targets, snapshots and git.
Dart (schema owner) ⇄ JSON boundary ⇄ Rust engine (I/O, git, search, diff, snapshots, validation)
- Dart owns the schema: typed models, tolerant codecs, stores, schema registry + migration, the binder reducer and the Layout/editor → AST parsers.
- Rust is schema-agnostic: verbatim file I/O, structural validation (via
schema-v1.yaml), search, text diff, git and snapshots. EngineClientis the only importer of the generated FRB bindings.
Important
By now the Backups feature is still being implemented. Snapshots are the safe alternative to work with.
Table of contents #
Understand the project #
- ARCHITECT.md — end-to-end architecture (Dart ⇄ Rust, boundary, testing).
- docs/engine.md — the Rust engine: modules, JSON boundary, how to extend.
- docs/project-format.md — the
.novformat, file by file. - docs/getting-started.md — setup, codegen, build, run tests.
Use the API #
- docs/stores-and-reducer.md — stores/I/O interfaces and reducer ops.
- docs/models.md — every schema class and codec.
- docs/parsers-to-ast.md — Layout/editor → AST parsers (usage + output formats).
- docs/placeholders.md — the
<$…>placeholder tokens.
What you can do with ProjectManager #
ProjectManager (see lib/src/project_manager.dart)
is the single entry point. Everything is lazy and typed; operations persist only
the affected files.
Lifecycle & stores #
| Area | Getter / methods | What it gives you |
|---|---|---|
| Engine | engine |
Low-level typed access (search, git, snapshots, validation, raw I/O) |
| Binder | binder |
The Folder tree + header; load/persist, lookup & external files |
| Content | documents |
Per-node editor content: lazy LRU cache, debounced writes |
| Compiler | formats |
Formats and their layouts (resolved by id, lazily) |
| Exports | exports |
Records of performed exports |
| Sessions | sessions |
Day-by-day writing-session history |
Binder (tree) operations #
createDocument, createFolder, renameNode, moveNode, trashNode,
restoreNode, purgeNode (deletes document dirs too). Mutations go through
BinderActions with cycle guards and trash semantics, then persist the binder
(recomputing the lookup).
final doc = await manager.createDocument('draft-id', 'New chapter');
await manager.renameNode(doc.id, 'The Final Chapter');
await manager.moveNode(doc.id, 'trash-folder-id'); // → Trash
Node content #
nodeContent/setNodeContent (editor Document), nodeSynopsis/
setNodeSynopsis, nodeNotes/setNodeNotes, nodeComments/setNodeComments.
Metadata & statistics #
readMetadata migrates old schema versions automatically. Update blocks with
updateProject, updateAuthor, updateBook, updateCompileDefaults,
updateEditorPreferences, updateSessionState; recompute region word counts
with recomputeStatistics({wordsByNodeId}) (never gated).
Writing sessions (history) #
Open or continue today's session without duplicates (SessionHistory), adjust
counts incrementally from an external counter service, and close with a full
recount gated by compute_count_on_close_session:
await manager.adjustOpenSession(
DateTime.now().toUtc(),
author: 'Elena',
adjustment: const CountAdjustment(words: 12, characters: 64),
);
await manager.closeWritingSession(DateTime.now().toUtc(), author: 'Elena');
See docs/stores-and-reducer.md for the session decision flow, and docs/placeholders.md for tokens the compiler understands.
Targets #
Per-node and global writing targets (target.index.json):
final targets = await manager.resolveTargets();
final goal = targets.targetOf('chapter-1'); // override or inherited
final inFolder = targets.targetsWithinFolder('part-1');
await manager.updateGeneralTarget(const TargetGeneral(target: 50000));
await manager.setNodeTarget('chapter-1', const TargetFile(words: 5000, characters: 27000));
await manager.removeNodeTarget('chapter-1');
Snapshots & git #
Snapshot with a metadata version bump (saveProjectSnapshot), list, restore and
delete; plus full git: branches, fetch, conflicts, content/commit diffs and
remotes:
final snapshot = await manager.saveProjectSnapshot();
await manager.deleteSnapshot(snapshot.id);
await manager.gitInit();
await manager.gitBranchCreate('revision-2');
await manager.gitBranchSwitch('revision-2');
final conflicts = await manager.gitConflictDetect();
await manager.gitSetRemote('origin', 'https://example.com/repo.git');
print(await manager.gitRemotes());
Search #
Quick (search), structural/full (searchFull) and index maintenance
(reindexSearch, searchStatus).
Example (end to end) #
import 'package:novident_project_manager/novident_project_manager.dart';
Future<void> main() async {
// Create a project (skeleton + .gitignore + git init).
final manager = await ProjectManager.create('/path/to/my-book.nov', name: 'My Book');
// Build a bit of binder structure.
final root = (await manager.binder.load()).root;
final draft = await manager.createFolder(root.id, 'Draft', folderType: FolderType.manuscript);
final chapter = await manager.createDocument(draft.id, 'Chapter 1', section: 'chapter');
// Set rich-text content (an editor Document).
// await manager.setNodeContent(chapter.id, editorDocument);
// Track a writing day and targets.
final targets = await manager.resolveTargets();
print('target words: ${targets.targetOf(chapter.id)?.words}');
await manager.closeWritingSession(DateTime.now().toUtc(), author: 'Elena');
// Version it.
await manager.gitCommit('Chapter 1 draft', authorName: 'Elena', authorEmail: 'elena@novident.dev');
await manager.saveProjectSnapshot();
await manager.dispose();
}
ProjectManager/EngineClientneed the compiled native library, so this demo runs inside the app — not underflutter test. Pure logic (codecs, reducer, session math, parsers) is fully unit-tested.
How a .nov project looks #
See docs/project-format.md for details:
.nov/
├── files/ metadata.json · backup.json · external/ · <node-id>/{content,synopsis,comments,notes}
├── indexation/ binder · sections · icon · corkboard · target · search (engine-managed)
├── layouts/ l<uuid>.json
├── compiler/ formats/ · exports/
├── history/ <yyyy-MM-dd>.json
└── snapshots/ date-v<version>.zip · .git/
Documentation #
- docs/index.md — the documentation index.
- ARCHITECT.md — how the whole system fits together.
- AGENTS.md — repository map, quality, non-negotiables.
- SECURITY.md / CONTRIBUTING.md.