feat: add file-backed canvas notes
Magic Notes previously supported rich-text records without a paged drawing or PDF annotation workflow. Add the integrated PeopleLib Fabric and Quill editor with flowing text, pen/highlighter, object transforms, images, paper templates, PDF backgrounds with native text extraction, and raster PDF export. Saves are manual; undo/redo remains scoped to an annotation page or Quill mode. Analyze drafts, saved canvases and canvas-source todos with page images and text when the default model supports images, or an explicitly labelled text-only fallback. Keep successful saves when automatic analysis fails and prevent MCP plain-text replacement of canvas records. Move entry bodies and binary assets into local note files with schema 38 migration and verified readback. SQLite retains metadata, indexes, revisions, todos and comments. Backups must coordinate SQLite and the adjacent notes directory while writes are paused or the app is closed; no one-click backup action is included. Show a continuous record stream with independent collapsible record index and AI pane, real first-page thumbnails, and scroll-only record navigation. Open a blank text/canvas composer by default and reset it after creation. Protect unsaved drafts and establish normalized editor baselines after saving so clean records do not prompt again when leaving. Validation: latest recorded focused run passed 149 tests across five files; typecheck, lint and git diff --check passed. The prior user-reported full run passed 4,713 tests before later corrections and UI changes; it is not a full validation of this final snapshot. Tests were not rerun for this commit, as requested; independent systematic review follows the commit. Release note: Create paged notes with handwriting, flowing text and PDF annotations, browse records through thumbnails, and request AI comments with an explicit text-only fallback. Existing notes migrate to local file storage; backups now need both the database and notes directory.
This commit is contained in:
@@ -1,27 +1,71 @@
|
||||
# Magic Notes
|
||||
|
||||
Magic Notes is the local notes, checklist and AI-comment workbench. Desktop
|
||||
actions and authorized Agent/MCP tools write to the same desktop SQLite store.
|
||||
actions and authorized Agent/MCP tools use the same desktop store: SQLite for
|
||||
metadata and indexes, and local files for entry bodies and binary assets.
|
||||
The open workbench subscribes to successful writes so users can see external
|
||||
changes without leaving the page or clicking a refresh button.
|
||||
|
||||
The workbench opens on a responsive note-card overview. Opening a note replaces
|
||||
the overview with its detail and optional AI comments. The separate To-dos tab
|
||||
the overview with a continuous record stream, a narrow left index and independent
|
||||
right AI comments. Both side panes can collapse. Index items show one real
|
||||
first-page canvas thumbnail with page count, or a text summary; clicking scrolls
|
||||
without replacing the editor or losing a draft. Opening a note shows a blank composer
|
||||
above the history, with text/canvas selection and Save. Creating a record resets
|
||||
that composer; editing a saved record requires its explicit Edit action. The separate To-dos view
|
||||
keeps search, status filters and grouped tasks on one page, with direct completion
|
||||
and a stable left list/right detail layout for instructions, source content and AI
|
||||
comments. Narrow containers use on-demand detail with an explicit return to the
|
||||
mounted list. Content-sized tabs sit in the page header immediately before New
|
||||
note; status filters sit beside search and wrap when needed. Returning from a source note restores the task
|
||||
context and protects unsaved editor changes.
|
||||
mounted list. One content-sized button switches to the other view in the page
|
||||
header immediately before New note; status filters sit beside search and wrap
|
||||
when needed. Note detail removes the surrounding frame and stream padding while
|
||||
keeping editor borders and the AI divider. Returning from a source note restores the task
|
||||
context and protects unsaved editor changes. A successful save followed by no
|
||||
further edits does not prompt again on return. Narrow note layouts use an index
|
||||
drawer and bounded bottom AI pane.
|
||||
|
||||
## Documents
|
||||
|
||||
- [Technical design](./technical-design.md): database notifications, process
|
||||
boundaries, refresh lifecycle and regression coverage.
|
||||
- [Technical design](./technical-design.md): file storage, schema 38 migration,
|
||||
backup boundaries, database notifications, process boundaries, canvas and AI
|
||||
contracts, refresh lifecycle and regression coverage.
|
||||
- [Progress](./progress.md): implementation and validation evidence.
|
||||
- [UI design system](../../../UI-DESIGN.md#137-魔法笔记): authoritative workbench
|
||||
interaction rules, including selection and draft preservation.
|
||||
- [Canvas integration](../../../src/renderer/src/magic-canvas/README.md): React
|
||||
controller API, PeopleLib core limits, asset adaptation and rendering lifecycle.
|
||||
|
||||
An entry is a saved rich-text record within a note. A todo is a checklist item
|
||||
derived from an entry. An unsaved draft belongs to the open editor; it is not
|
||||
An entry is a saved rich-text or paged-canvas record within a note. Its body lives
|
||||
in `notes/<noteId>/entries/<entryId>.json` beside note-local binary assets;
|
||||
`note.json` is a derived membership manifest. SQLite retains metadata, indexes,
|
||||
revisions, todos and comments. API reads hydrate assets back into the existing
|
||||
content format. A todo is a checklist item derived from rich text
|
||||
or the canvas Quill flow. An unsaved draft belongs to the open editor; it is not
|
||||
written to storage by a background refresh.
|
||||
|
||||
Backups must coordinate SQLite and the adjacent `notes/` tree while note writes
|
||||
are paused or the app is closed. A database-only backup cannot restore these
|
||||
bodies. There is no product one-click backup action; see the
|
||||
[backup contract](./technical-design.md#backup-and-restore).
|
||||
|
||||
## Canvas Scope
|
||||
|
||||
The integrated PeopleLib editor uses Fabric for paged annotations and Quill for
|
||||
body text flowing across pages. It supports paper templates, pen/highlighter,
|
||||
object erasing and selection/transforms, floating text, images, PDF backgrounds
|
||||
with native text extraction, and raster PDF export. Saves are manual. Undo/redo
|
||||
belongs to the current annotation page or Quill body mode; it is not a global
|
||||
document history. There is no infinite canvas or PNG download button.
|
||||
|
||||
Drafts, saved entries and todos sourced from canvases support AI comments using
|
||||
the default model's image-input capability. Image-capable models receive complete
|
||||
page captures and extracted text. Text-only models receive an explicitly labelled
|
||||
text fallback; a purely visual canvas entry or draft reports that an image-capable
|
||||
default model is required. Canvas comments are requested manually in `immediate`
|
||||
mode, or after a manual save in `after-save-auto` mode. Analysis failure does not
|
||||
undo a successful save. Detailed retention rules are in the
|
||||
[AI contract](./technical-design.md#canvas-analysis-and-comments).
|
||||
|
||||
Canvas implementation is complete and final validation is in progress. The
|
||||
[progress record](./progress.md) distinguishes confirmed production-path evidence
|
||||
from the pending final repository checks.
|
||||
|
||||
@@ -1,5 +1,347 @@
|
||||
# Magic Notes Progress
|
||||
|
||||
## 2026-09-19: Default Composer
|
||||
|
||||
- Opening a note now shows a blank text/canvas composer below its title and above
|
||||
the continuous history. Removed the New record button, locale keys and creation
|
||||
visibility state. A successful create resets the editor key and content while
|
||||
retaining its type; automatic analysis does not enter editing. Existing records
|
||||
still require explicit Edit and retain normalized dirty baselines and revision keys.
|
||||
- The index toggle stands directly before the title. Header height now explicitly
|
||||
supplies the narrow drawer offset without relying on the removed button.
|
||||
This supersedes the explicit-create and post-create-edit behavior recorded below.
|
||||
- Focused validation: 5 files, 149 tests passed (`MagicNotesWorkspace`, both editors,
|
||||
`MagicCanvasThumbnail`, `WorkspacePrimitives`). `npm run typecheck`, `npm run lint`
|
||||
and `git diff --check` passed. No full test suite was run.
|
||||
- Temp Electron validation rebuilt current Workspace/PageShell, Quill, Fabric, CSS,
|
||||
production preload and registered IPC, backed by AssistantDatabase and note files.
|
||||
Text/canvas create-save-reopen, blank composer return without confirmation, real
|
||||
editor changes requiring confirmation, thumbnail scroll preserving the top draft,
|
||||
explicit text/canvas edit-save and database close/reopen all passed. Automatic
|
||||
analysis capture-before-reset is covered by the focused regression; model calls: 0.
|
||||
- Light/dark checks at actual content widths 1287, 947, 547 and 362px passed document
|
||||
overflow, continuous history, narrow drawer width, placement below the title and
|
||||
close-on-navigation assertions. Reviewed wide light and narrow dark drawer PNGs.
|
||||
Evidence: `C:/Users/jiang/AppData/Local/Temp/opencode/composer-default-Tq8Ui8/`;
|
||||
runner: `node C:/Users/jiang/AppData/Local/Temp/opencode/run-composer-default.mjs`.
|
||||
- Probe boundaries: isolated feature window, not the full App shell; Quill API input
|
||||
and DOM button clicks, not native keyboard coverage. Early probe failures came
|
||||
from inactive canvas text-tool input, an unconstrained fixture parent, and measuring
|
||||
the inner navigation width instead of the drawer border box. Corrected probes
|
||||
passed without further production changes. No commits or real user-data writes.
|
||||
|
||||
## 2026-09-19: Independent Layout Review
|
||||
|
||||
- Rechecked the action-placement changes in Electron using production PageShell,
|
||||
Workspace, Fabric, Quill and CSS. The earlier bare-workspace screenshots omitted
|
||||
PageShell gutters; no extra stream padding was added to compensate for that fixture.
|
||||
- Fixed narrow record headers forcing each action onto a separate full-width row,
|
||||
touching canvas inner/outer borders in create/read mode, and missing spacing below
|
||||
the Records / AI tabs. Canvas create/edit/read inner frames now share 12px insets.
|
||||
- Fixed Quill percentage heights stretching an empty text composer beyond the
|
||||
visible area. The text save footer and validation now belong to the same composer
|
||||
card. Save handlers, analysis rules and draft-switch semantics are unchanged.
|
||||
- Text toolbar SVGs and picker menus use theme colors; native scrollbars in the
|
||||
notes workspace follow light/dark mode.
|
||||
- Final Temp probe: `canvas-layout-review.mjs final`, with captures prefixed
|
||||
`canvas-layout-final-` and measurements in `canvas-layout-final-metrics.json`.
|
||||
Checked create/edit/read for canvas and text at 1300x950, 960x800, 560x800 and
|
||||
375x720 content sizes in both themes (48 combinations), plus AI-pane captures.
|
||||
Assertions passed for document/main horizontal overflow, canvas action bounds
|
||||
and equal heights, independent side scrolling, reachable text Save, and side
|
||||
collapse/reopen. Inspected final wide, medium, narrow and deep-narrow dark images.
|
||||
- Focused validation: `npx vitest run src/renderer/src/MagicNotesWorkspace.test.tsx
|
||||
src/renderer/src/MagicNoteEditor.test.tsx src/renderer/src/MagicCanvasEditor.test.tsx`
|
||||
passed 102 tests. `npm run typecheck` and `npm run lint` passed. No full suite run.
|
||||
- Scope: actual Windows Electron renderer with an in-memory DesktopApi fixture,
|
||||
not a packaged full-App or persistent-IPC validation. No model calls, runtime or
|
||||
remote changes, commits, or user-data writes.
|
||||
|
||||
## 2026-09-19: Canvas Action Placement
|
||||
|
||||
- Canvas creation places Analyze and Save at the right of the type selector;
|
||||
editing places Analyze, Cancel and Save in the record header. Save remains the
|
||||
primary action. Canvas hints and footer actions were removed, including unused
|
||||
English/Chinese locale keys. Text actions and existing handlers are unchanged.
|
||||
- Focused workspace/editor tests: 2 files, 93 passed. Typecheck and lint passed.
|
||||
Coverage includes all three comment modes, top placement, order, no duplicate
|
||||
footer, cancellation, saving and manual/automatic analysis. No full suite run.
|
||||
- A Temp Electron/Vite probe uses production Workspace, Fabric, Quill and CSS
|
||||
with an in-memory DesktopApi fixture. Creation and editing were checked at
|
||||
1300px and 560px window widths for top placement, visible Save and no horizontal
|
||||
document overflow. Screenshots are `canvas-actions-{create,edit}-{wide,narrow}.png`
|
||||
in the Temp opencode directory. No real model calls were made.
|
||||
|
||||
## 2026-09-19: Review Corrections
|
||||
|
||||
- Fixed local creation selecting an Agent's concurrent append. The database
|
||||
returns the exact `createdEntryId` alongside detail, typed through shared API
|
||||
and preload. The workspace uses that ID for selection, analysis and subsequent
|
||||
edits. Existing Agent/MCP note projections retain their public shape.
|
||||
- Text-edit save/cancel now use the shared analysis cleanup: pending timers and
|
||||
queued content are removed, late comments are ignored, and abandoned settings
|
||||
preparation cannot dispatch a draft request. The composer content is independent.
|
||||
- Local and external deletion reconcile the actual selected ID when no dirty
|
||||
editor must be retained. A later append no longer changes the fallback selection.
|
||||
- Thumbnail abort immediately invokes core destruction, whose synchronous phase
|
||||
cancels PDF/Fabric work. Final cleanup awaits the same promise and removes the
|
||||
temporary surface. Regression tests cover both unmount and content replacement
|
||||
while capture is pending, and verify the next queued thumbnail completes.
|
||||
- Post-fix focused run: **13 files, 257 passed, 0 failed**. Coverage includes
|
||||
`MagicNotesWorkspace`, `MagicCanvasThumbnail`, editor/content/core/model tests,
|
||||
production canvas IPC integration, note storage, assistant database, MCP gateway
|
||||
and preload note events. `npm run typecheck` and `npm run lint` passed.
|
||||
- The user reported a full-suite result of **4,713 passed, 0 failed before these
|
||||
review corrections**. That result does not validate the fixes above. No full
|
||||
suite or Electron probe was rerun in this correction pass. Model calls: 0.
|
||||
|
||||
## 2026-09-19: Record Index Header Toggle Correction
|
||||
|
||||
- Moved the record index toggle immediately before New record in the detail
|
||||
header, retaining its accessible name, title, controls and expanded state.
|
||||
Collapsing hides the whole index and removes its grid column and border width.
|
||||
Narrow layouts use the same toggle for a 168px overlay below the header, with
|
||||
no reserved rail. This supersedes the 40px rail described in the earlier run.
|
||||
- Focused validation: `npx vitest run src/renderer/src/MagicNotesWorkspace.test.tsx
|
||||
src/renderer/src/WorkspacePrimitives.test.tsx` passed 130/130 tests.
|
||||
`npm run typecheck` and `npm run lint` passed. No full suite was run.
|
||||
- Actual Electron geometry checks compiled the current Workspace and production
|
||||
CSS with fixture note data, covering window widths 1300, 960, 700 and 375px with
|
||||
AI both open and closed. Wide stream widths increased by exactly 168px on
|
||||
collapse; narrow stream widths stayed at 687.43 and 362.29px. Hidden index
|
||||
geometry was zero, closed streams began at the layout's left edge, and no
|
||||
horizontal overflow occurred. The header toggle remained hit-testable directly
|
||||
before New record. Native Tab skipped hidden records, programmatic focus on
|
||||
hidden records failed, Enter reopened the index, and narrow Escape restored
|
||||
toggle focus. AI widths were unchanged by index toggling.
|
||||
- Evidence: `C:/Users/jiang/AppData/Local/Temp/opencode/record-index-results-Xvgnsw/results.json`.
|
||||
Reproduce with `node C:/Users/jiang/AppData/Local/Temp/opencode/run-record-index-geometry.mjs`.
|
||||
This checks an isolated Electron renderer, not the full App shell or storage
|
||||
path. Model calls: 0.
|
||||
|
||||
## 2026-09-19: Continuous Stream and Save Baseline Correction
|
||||
|
||||
- Restored all entries to the continuous stream, including while composing. The
|
||||
168px left index and independent right AI pane collapse separately. Index and
|
||||
AI source clicks scroll without discarding drafts or remounting the editor.
|
||||
At widths up to 800px the index uses a 40px rail with a 168px drawer; AI retains
|
||||
its bounded bottom layout. This supersedes the single-record interaction below.
|
||||
- Dirty checks now compare against the editor's initialized content. Canvas waits
|
||||
for its initial flush before enabling input or reporting readiness; text reports
|
||||
Quill's initialized Delta. Save/analysis revisions remount with a fresh baseline,
|
||||
while unchanged background revisions retain it. Failed writes do not advance it.
|
||||
- The actual saved formatted-text callback had the same values but a different
|
||||
Delta field order (`insert, attributes` in storage; `attributes, insert` from
|
||||
Quill), reproducing the old false dirty comparison. Saved PDF content matched
|
||||
both the readiness callback and subsequent flush in the final probe.
|
||||
- Final focused validation: 15 files / 222 tests passed, covering Workspace, both
|
||||
editors, thumbnail/content, shared primitives, canvas core/model, analyzer, file
|
||||
storage, production canvas IPC and canvas text. `npm run typecheck` and
|
||||
`npm run lint` passed.
|
||||
- The full suite completed with 4,730 passed, 1 failed and 67 skipped (713.99s).
|
||||
Its sole failure was the shared contrast test finding the first dark descendant
|
||||
rule instead of the root token block. The test now matches the exact root
|
||||
selector; all 36 shared primitive tests passed afterward, also included in the
|
||||
final 222-test run. The full suite was not repeated after that test fix and the
|
||||
final editor initialization regression additions.
|
||||
- Actual Electron 43.2.0 validation used built renderer assets over `file://`, the
|
||||
production preload, IPC handlers, AssistantDatabase and note files. It verified
|
||||
three simultaneous entries, real thumbnail pixels, scroll-only draft retention,
|
||||
independent collapse, text/canvas create and update followed by a clean return,
|
||||
a new post-save edit requiring confirmation, and a real revision conflict keeping
|
||||
the failed draft. A two-page PDF survived database reopen and three consecutive
|
||||
saves in the same editing context, with unchanged PDF bytes, advancing revisions
|
||||
and no prompt on return. Six entries remained mounted through the layout checks.
|
||||
- Layout captures covered light/dark at content widths 1287, 947, 547 and 362px,
|
||||
with no document horizontal overflow. Narrow drawer opening, 168px geometry,
|
||||
record navigation and automatic closing passed. Temporary evidence is under
|
||||
`C:/Users/jiang/AppData/Local/Temp/opencode/canvas-sqlite-N9japl/`; reproduction:
|
||||
`node C:/Users/jiang/AppData/Local/Temp/opencode/run-canvas-sqlite.mjs continuous-notes.html`.
|
||||
The earlier development-server attempt hit Vite PDF dependency optimization;
|
||||
the built-asset run passed. This validates the production feature path in an
|
||||
isolated Electron window, not the full App shell or a packaged distribution.
|
||||
- `node tests/magic-canvas-wheel.electron.mjs` passed all 34 wheel and full-page
|
||||
height checks. No storage/core wheel changes or model calls were needed.
|
||||
|
||||
## 2026-09-19: Single-Record Workspace (Superseded)
|
||||
|
||||
- Note detail mounts one selected record or an explicitly opened new-entry editor.
|
||||
Saving a new entry selects it; further saves update the same ID and use revisions
|
||||
returned by saves and automatic comments. Record/AI source switches share draft
|
||||
confirmation, and clean external changes refresh without replacing dirty drafts.
|
||||
- A collapsible Records / AI comments region defaults to Records. Each canvas
|
||||
record has one real first-page thumbnail with total page count; text records show
|
||||
summaries. Visible thumbnails render serially and capture only page zero at 240px.
|
||||
The main editor and side region scroll independently; narrow layouts retain the
|
||||
bounded bottom region. UI contract: [design system](../../../UI-DESIGN.md#137-魔法笔记).
|
||||
- Focused validation: 9 files / 142 tests passed across workspace, canvas editor,
|
||||
content, shared primitives, canvas core/model and canvas IPC integration.
|
||||
`npm run typecheck` and `npm run lint` passed. No full `npm test` run in this task.
|
||||
- Actual Electron renderer probe used production Workspace, Quill, Fabric and CSS
|
||||
with an in-memory DesktopApi fixture. It verified one main entry, real thumbnail
|
||||
pixels, one thumbnail for a two-page entry, record switching, independent scroll,
|
||||
collapse/reopen, AI switching, discard/cancel, AI and todo source selection,
|
||||
returning to todo context, and preserving canvas drafts through external updates
|
||||
and deletion. One create followed by three updates included two
|
||||
canvas updates and continuing to edit a newly created record. At 547px content
|
||||
width the document scroll width remained 547px. This is renderer validation,
|
||||
not a complete App-shell or persistent-IPC end-to-end run.
|
||||
- Reproducible local probe: `C:/Users/jiang/AppData/Local/Temp/opencode/run-single-entry-probe.mjs`;
|
||||
screenshot: `single-entry-narrow.png` in the same temporary directory.
|
||||
- Existing `node tests/magic-canvas-wheel.electron.mjs` passed all 34 Electron
|
||||
checks for wheel behavior and full-page editor/viewer height at 900px and 360px.
|
||||
Storage, wheel and page-height behavior were retained. Model calls: 0.
|
||||
|
||||
## 2026-09-19: Full-Page Canvas Height
|
||||
|
||||
- Removed fixed saved-viewer and composer heights. Natural layout includes the
|
||||
current paper, toolbar and padding, with outer vertical scrolling and inner
|
||||
horizontal scrolling. Different page sizes still paginate within one entry.
|
||||
- `node tests/magic-canvas-wheel.electron.mjs`: 34 checks passed in Electron
|
||||
43.2.0, including editor/saved-viewer geometry at 900px and 360px, portrait to
|
||||
landscape pagination, no inner vertical or outer horizontal overflow, and
|
||||
native outer vertical scrolling. This mounts the production core with product
|
||||
CSS and representative wrappers, not the complete App shell. The original
|
||||
wheel fixture has an explicit test-only height constraint to retain both-axis
|
||||
coverage; edge tests wait for the compositor after programmatic scrolling.
|
||||
- Focused canvas/editor/content/workspace tests: 7 files, 95 tests passed.
|
||||
Full typecheck and lint passed; the final probe edit also passed focused lint.
|
||||
The full test suite was not rerun for this height-only change. Model calls: 0.
|
||||
|
||||
## 2026-09-19: File Storage and Schema 38
|
||||
|
||||
- Replaced SQLite body payloads with file-backed rich-text and canvas entries.
|
||||
SQLite retains metadata, membership, indexes, revisions, todos and comments;
|
||||
hydrated API content stays compatible. File layout, write/repair semantics,
|
||||
migration and backup requirements are defined in the
|
||||
[storage contract](./technical-design.md#file-storage-and-writes).
|
||||
- The startup worker converts one entry per transaction and verifies hydrated
|
||||
readback before clearing the legacy payload. Reclamation checks the freelist
|
||||
on every attempt, including retries after conversion has finished. Committed
|
||||
saves/deletes/resets remain successful when manifest or GC cleanup fails;
|
||||
failures are logged and cleanup is retried on later access or reopen.
|
||||
- Storage implementation handoff reports 135/135 focused tests passed across
|
||||
`magic-note-storage`, `assistant-database`, `assistant-storage-upgrade` and
|
||||
`canvas-ipc.integration`, with full `npm run typecheck` and `npm run lint`
|
||||
passing after the review fixes. Filesystem rename/rm failure injection uses
|
||||
real SQLite and files. A 1 MiB PDF retained its binary mtime across 20 updates
|
||||
while SQLite growth stayed below 2 MiB; the migration regression verified
|
||||
more than 2 MiB of physical shrink and restored SQLite plus the notes tree.
|
||||
- Session validation reports the real Electron -> IPC -> SQLite/files path
|
||||
successfully created text, image and canvas/PDF entries, completed three
|
||||
consecutive updates and reopened persisted data after process restart.
|
||||
Migration also passed with an on-disk schema 37 fixture. This was a constructed
|
||||
fixture, not a user's historical database; no real user database was migrated.
|
||||
Actual model calls for this storage validation: 0.
|
||||
- Backups require coordinated SQLite and `notes/` copies while writes are paused
|
||||
or the app is closed. No product one-click backup was added.
|
||||
- Final full test run: 4,705 passed, 3 failed, 67 skipped (760.91 seconds).
|
||||
All three failures were in `acp-remote-runtime.test.ts`, which was being changed
|
||||
concurrently: a launch-response schema mismatch and two channel-close recovery
|
||||
assertions. That file subsequently passed all 100 tests on a targeted rerun.
|
||||
No note-storage test failed; this does not claim a second all-green full run.
|
||||
|
||||
## 2026-09-19: Canvas Wheel Navigation
|
||||
|
||||
- The shared canvas viewport explicitly handles horizontal and vertical wheel
|
||||
input in annotation, flow-text and read-only modes. Shift with vertical-only
|
||||
input scrolls horizontally. Ctrl input is left to the existing browser path.
|
||||
Default scrolling is prevented only when the viewport actually moves; page
|
||||
scrolling remains available at boundaries or without canvas overflow.
|
||||
- Removed scroll-chain containment. The Electron baseline reproduced boundary
|
||||
trapping, but not a universal failure of native horizontal input. The new
|
||||
Electron regression passed 30 scenarios; focused unit tests passed 13 tests.
|
||||
Run `node tests/magic-canvas-wheel.electron.mjs` to repeat the native-input
|
||||
fixture. It does not validate a physical mouse or the complete App shell.
|
||||
- Typecheck and lint passed. The full test run during this fix reported 4,682
|
||||
passed, 67 skipped and one unrelated Agent package inventory timeout.
|
||||
|
||||
## 2026-09-19: Single Navigation Button and Unframed Note Detail
|
||||
|
||||
- Replaced the two header tabs with one destination-labelled button and icon,
|
||||
immediately before New note. Switching retains the same button and restores
|
||||
focus to it. The list section keeps its localized accessible name; tab roles
|
||||
and references are removed. Navigation still uses the existing draft guard.
|
||||
- Note detail removes the surrounding layout border/radius and stream padding.
|
||||
Composer and entry borders, page margins and the AI divider remain. Overview
|
||||
cards and the independent todo layout retain their frame and spacing.
|
||||
- Focused workspace, editor, shared-primitives and i18n suites passed 122 tests.
|
||||
`npm run typecheck`, `npm run lint` and `git diff --check` passed. The full suite
|
||||
was not rerun for this change, as requested.
|
||||
- Updated the existing `magic-notes-render-electron.cjs` probe in the session's
|
||||
`opencode` temporary directory and ran `magic-notes-render-run.cjs` against the
|
||||
current workspace component and real Quill in Electron. At 1280x820, 600x760,
|
||||
600x520 dark and 420x640, the switch measures 104x36px and precedes New note.
|
||||
Pointer and Space activation restore switch focus; no tab semantics remain.
|
||||
- Computed detail border/radius and stream padding are all zero. Composer and
|
||||
entry borders and the AI divider remain 1px. At 1280px, closing AI expands the
|
||||
stream from 927px to the full 1216px layout width. Narrow layouts keep only the
|
||||
native scrollbar width between layout and content, with no horizontal overflow.
|
||||
AI moves below the editor and closing it increases editor height.
|
||||
- The same probe passed card/scroll return, actual Quill draft cancellation and
|
||||
discard, todo split/narrow layouts, source-note return, creation and completion
|
||||
filters. Screenshots were reviewed; results are in
|
||||
`magic-notes-render-results.json`. Console errors: 0; model calls: 0. Data and
|
||||
AI output use fixtures. The esbuild probe emits an existing IIFE/import.meta
|
||||
warning for the canvas PDF module; this run does not exercise PDF import.
|
||||
|
||||
## 2026-09-18: Integrated Canvas and Validation
|
||||
|
||||
Historical snapshot before file storage: the embedded payload and schema 37
|
||||
statements below describe this stage only. Current persistence and its validation
|
||||
are recorded in the schema 38 entry above.
|
||||
|
||||
- Implementation is complete across the workspace, PeopleLib Fabric + Quill
|
||||
editor/viewer, shared v1/v2 contract, preload/IPC, SQLite and AI analysis.
|
||||
Available operations include paged flow text, pen/highlighter, selection and
|
||||
transforms, floating text, images, PDF import/native text extraction and raster
|
||||
PDF export. Saving is manual; undo/redo is local to the page or Quill mode.
|
||||
The toolbar has no PNG download action; PNG capture is an API used for analysis.
|
||||
- Assets are embedded in SQLite `content_json`, not a separate resource table.
|
||||
Schema 37 is a compatibility marker without conversion of existing records.
|
||||
Flow checklist identity survives object moves and completion writes back to
|
||||
flow. MCP exposes readable canvas metadata/text and rejects plain-text
|
||||
replacement. See the [technical contract](./technical-design.md).
|
||||
- Entry, draft and canvas-source todo analysis use the default model's
|
||||
`supportsImageInput`: complete page captures plus extracted text, or labelled
|
||||
text-only fallback. Purely visual entries/drafts fail clearly with a text-only
|
||||
model. Canvas `immediate` mode explicitly offers manual analysis;
|
||||
`after-save-auto` catches capture/settings errors without blocking storage.
|
||||
Text-only entry comments survive equal `plainText`; layout changes invalidate
|
||||
visual comments and trigger renewed analysis in after-save-auto mode.
|
||||
- Confirmed interactive validation used the real workspace, preload, registered
|
||||
IPC and SQLite to save an image and a two-page PDF, reopen them, and complete
|
||||
three consecutive saves successfully. This covers persistence beyond the
|
||||
earlier renderer-only fixtures. The temporary probe uses
|
||||
`canvas-sqlite.tsx`, `canvas-sqlite-main.ts` and `run-canvas-sqlite.mjs` under
|
||||
the session's `opencode` temporary directory.
|
||||
- The isolated canvas core probe passed with a Vite production build loaded via
|
||||
`file://` and the unchanged application CSP, including PDF import, PNG capture
|
||||
and raster PDF download. The export review also verified the 20,000-character
|
||||
flow boundary and list markers in captured pages and re-rendered exported PDF.
|
||||
These are core rendering/export results, distinct from workspace persistence.
|
||||
- Regression coverage includes storage reopening, checklist writeback, comment
|
||||
retention/invalidation, revision conflicts, MCP protection, renderer integration
|
||||
and analysis input selection. The preload/IPC integration suite uses real
|
||||
SQLite but mocked Electron transport and model output; it is not evidence of
|
||||
a live model request.
|
||||
- Final `npm run typecheck`, `npm run lint` and `npm run build` passed. The full
|
||||
test rerun completed with 4,665 passed, 7 failed and 67 skipped. Failures were
|
||||
in Agent packaging (missing compound-package fixture and an inventory timeout)
|
||||
and activity record/DOM reuse assertions. Those files were under concurrent
|
||||
modification; this is not a fixed-snapshot all-green result. No Magic Notes or
|
||||
App regression failed in that run. The earlier two App failures from eager
|
||||
PDF.js loading were fixed with on-demand PDF imports and passed their targeted
|
||||
rerun; core/editor/workspace focused coverage passed 87 tests.
|
||||
- Live provider validation was blocked before any request: an isolated Electron
|
||||
process could not decrypt the configured default model credential
|
||||
(`runtime-model-credential-unreadable`). Settings were only read and remained
|
||||
unchanged. Actual model calls: 0. Runtime request tests verify image input and
|
||||
text fallback, but do not establish successful live provider generation.
|
||||
- This canvas change does not alter the deployed Agent runtime or the
|
||||
desktop-to-Agent production path, so it requires no separate remote Linux
|
||||
validation. Concurrent runtime work has its own validation scope.
|
||||
|
||||
## 2026-09-18: Stable Todo Split View and Header Navigation
|
||||
|
||||
- Supersedes the inline task expansion described in the earlier entry below.
|
||||
|
||||
@@ -1,5 +1,255 @@
|
||||
# Magic Notes Technical Design
|
||||
|
||||
## Continuous Record Workspace
|
||||
|
||||
The detail mounts every entry in a continuous newest-first stream. The left index
|
||||
and AI source buttons scroll to an entry ID without changing the active editor,
|
||||
clearing a composer, flushing content or invoking the draft-switch guard. Opening
|
||||
a note shows a blank composer below the title and above the stream, without a New
|
||||
record button. Editing another entry or
|
||||
leaving the note still checks unsaved content after flushing canvas changes.
|
||||
The shared store returns `MagicNoteEntryCreateResult`, the existing detail shape
|
||||
plus a required `createdEntryId`. Production IPC and preload preserve that ID.
|
||||
Creating an entry selects this exact ID and resets the composer through its key;
|
||||
it does not enter editing, including after automatic analysis. Text/canvas selection
|
||||
is retained. Canvas capture for automatic analysis completes before the reset.
|
||||
the renderer never infers it from a list difference or timestamp. Agent/MCP
|
||||
creation delegates to the same store; its existing public note projection is
|
||||
unchanged.
|
||||
Explicit Edit opens a saved record. Update and automatic-analysis responses advance its revision, so subsequent
|
||||
saves use `updateEntry` and the returned revision. Failed writes retain the draft.
|
||||
|
||||
The dirty baseline belongs to the mounted editor. `MagicNoteEditor.onReady` reports
|
||||
Quill's normalized contents after loading; `MagicCanvasEditor.onReady` reports the
|
||||
first completed core flush, after Fabric restoration and flow pagination. Canvas
|
||||
input stays disabled until this baseline exists, and imperative flush waits for
|
||||
the same initialization promise. Raw stored JSON is not a valid comparison baseline
|
||||
for an initialized editor: Quill can add its terminal newline, and Fabric/flow
|
||||
serialization can add defaults or change field order. Later changes and navigation
|
||||
flushes compare with the initialized baseline without resetting it. A successful
|
||||
save remounts at the returned revision and establishes a new baseline; an unchanged
|
||||
background revision retains the existing editor and baseline. Aborted canvas
|
||||
initialization and file reads for an unmounted text editor cannot write back.
|
||||
|
||||
The real saved formatted-text probe reproduced identical values with different
|
||||
Delta key order: storage returned `{insert, attributes}` and Quill emitted
|
||||
`{attributes, insert}`. The old `JSON.stringify` comparison therefore reported
|
||||
dirty after a successful save. The saved PDF probe's initialized content and
|
||||
subsequent flush were byte-for-byte equal; readiness is still awaited for canvas
|
||||
restoration rather than assumed from the save response.
|
||||
|
||||
Saving or leaving an editing context clears the immediate-analysis timer, queued
|
||||
content and streamed draft comments through the shared draft-analysis cleanup.
|
||||
The context counter rejects late results and prevents dispatch after abandoned
|
||||
settings preparation. This cleanup does not clear the new-entry composer's content.
|
||||
|
||||
The left index is 168px wide. Its toggle stays in the detail header immediately
|
||||
before the title; collapsing hides the entire index and removes its grid column,
|
||||
border and occupied width. AI has a separate
|
||||
right pane with its existing resize separator and header toggle. Both panes scroll
|
||||
independently and persist independent desktop visibility. At container widths of
|
||||
800px or less, the index defaults to hidden and the same header toggle opens or
|
||||
closes a 168px drawer below the header, without reserving a rail; choosing
|
||||
an item or pressing Escape closes it. AI moves below the stream, limited to 40%
|
||||
of layout height and 280px. Overview search, scroll, task selection and return
|
||||
focus stay mounted.
|
||||
|
||||
`MagicCanvasThumbnail` lazily queues visible records through a temporary core
|
||||
renderer and caches results by content identity in a WeakMap. Core `capturePages`
|
||||
accepts `firstPageOnly` and `thumbnailWidth`; thumbnails capture page zero at 240px
|
||||
width, including paper/PDF background, Quill flow, images and Fabric objects.
|
||||
They do not capture all pages or leave an editor mounted for every record.
|
||||
An abort listener calls core `destroy()` immediately: PDF render cancellation and
|
||||
the Fabric abort happen synchronously, before waiting for capture to settle.
|
||||
The `finally` path awaits the same destruction promise and removes the temporary
|
||||
surface, without destroying twice or waiting for capture before cancellation.
|
||||
AI capture retains its existing
|
||||
all-page behavior. Main canvas page height, wheel handling and file storage are
|
||||
unchanged.
|
||||
|
||||
Background refresh preserves dirty editing content and its original optimistic
|
||||
revision, including externally deleted entries. Clean editors adopt refreshed
|
||||
entries; deleting a clean selection updates `selectedEntryId` to a remaining
|
||||
entry or the empty state. Later appends preserve that actual selection, rather
|
||||
than recalculating a render-only fallback. Dirty deleted entries remain open
|
||||
until explicitly discarded. No background refresh saves a draft.
|
||||
|
||||
## Canvas Storage Contract
|
||||
|
||||
`MagicNoteContent` is the union of unchanged v1 Quill rich content and v2
|
||||
`paged-canvas`. The shared schema is authoritative. Canvas pages carry dimensions,
|
||||
template/PDF backgrounds, opaque Fabric object records and optional `flowAuto`.
|
||||
The optional Quill flow accepts native PeopleLib `version: 1` and page-break
|
||||
embeds. Template names are `blank`, `ruled`, `grid`, `dot`; PDF backgrounds use
|
||||
one-based `pageNumber` and optional extracted `text`.
|
||||
|
||||
API assets are document-local `{id,name,mimeType,dataUrl}` records. Backgrounds and
|
||||
image objects reference stable asset IDs; image objects can also embed raster
|
||||
data directly. Main validates data encoding, image/PDF signatures and references.
|
||||
Canvas has no v1 resource-size budget. `image_bytes` counts decoded embedded
|
||||
resource bytes for new entries. Bodies and binary assets use the file storage
|
||||
contract below; there is no separate resource table, resource staging or extra
|
||||
resource IPC. Renderer, preload and IPC continue to exchange hydrated v1/v2
|
||||
content with data URLs.
|
||||
|
||||
Schema 38 replaces SQLite body payloads with file markers. Schema 37 was the
|
||||
earlier canvas compatibility marker; its embedded-payload layout is historical.
|
||||
Plain text combines flow text, PDF extracted text and object text for search.
|
||||
Checklist indexes depend only on flow checklist lines; moving objects does not
|
||||
change todo identity. Completion updates flow without replacing pages or assets.
|
||||
Entry edits retain optimistic revisions. Canvas comment retention depends on the
|
||||
actual analysis input, as described below.
|
||||
|
||||
`note_get` reports content kind/version and `plainTextEditable`. The text update
|
||||
tool rejects canvas entries before mutation. These tools execute in the desktop
|
||||
gateway; remote gbagent's injected image MCP server is unaffected. Browser page
|
||||
renders can be sent as `analysisOptions.canvasImages`; analysis comments and draft
|
||||
results can retain the actual `inputMode` used.
|
||||
|
||||
## File Storage and Writes
|
||||
|
||||
`MagicNoteStorage` owns files under `dirname(assistantDatabasePath)/notes`:
|
||||
|
||||
```text
|
||||
notes/<noteId>/
|
||||
note.json # Derived {id, entries} membership manifest
|
||||
entries/<entryId>.json # Authoritative body envelope
|
||||
assets/<sha256>.<ext> # Binary assets deduplicated within this note
|
||||
```
|
||||
|
||||
Each body envelope contains `id`, `noteId`, `revision`, `updatedAt` and `content`.
|
||||
SQLite owns note metadata, entry membership, search/plain-text and byte indexes,
|
||||
optimistic revisions, todos and comments. Entry `content_json` contains only
|
||||
`{storage: "file", version: <content version>, revision: <body revision>}`.
|
||||
Comment-only revision increments do not change the indexed body revision.
|
||||
|
||||
Known media fields become `{$asset: "assets/<sha256>.<ext>", mimeType: "..."}`
|
||||
on disk and hydrate back to data URLs on API reads. These fields are v1
|
||||
`insert.image`, `localVideo.dataUrl` and `attachment.dataUrl`; canvas
|
||||
`assets[].dataUrl`, `preview`, flow embeds and image-object `src`, including
|
||||
nested objects. Ordinary text, insert strings, names and arbitrary `$asset`
|
||||
objects remain unchanged. Canvas asset IDs and PDF references are preserved.
|
||||
Write, read and garbage collection use the same scoped field traversal.
|
||||
|
||||
Revision checks run under `BEGIN IMMEDIATE` before file writes. Assets are
|
||||
written before the temporary body file is atomically renamed over the entry
|
||||
file; the database then commits its marker and indexes. This is not a single
|
||||
atomic transaction spanning SQLite and the filesystem. If a replacement body
|
||||
was renamed but indexing failed, the next database access or reopen reads it
|
||||
back, repairs plain text, byte counts and todos, advances revisions and
|
||||
invalidates old analysis. Missing bodies raise an error instead of becoming
|
||||
empty content. Failed creates leave no accepted database membership; their
|
||||
unaccepted files are removed on the next access or reopen.
|
||||
|
||||
After commit, reconciliation derives `note.json` from database membership and
|
||||
scans all retained entry files before removing unreferenced assets. Manifest or
|
||||
GC failures log `console.warn` with the note ID and error and remain in an
|
||||
in-memory retry set. Later database access retries; reopening derives cleanup
|
||||
again from membership. These cleanup failures do not turn a committed save,
|
||||
delete or reset into a failed operation or suppress its notifications. Body
|
||||
persistence and index-repair failures still propagate. Entry deletion, note
|
||||
deletion and assistant-data reset share this cleanup path; deferred whole-tree
|
||||
cleanup checks current membership so it preserves notes created after reset.
|
||||
There is no persistent retry journal, and renderer-only drafts create no files.
|
||||
|
||||
## Schema 38 Migration
|
||||
|
||||
The existing startup storage worker runs before the business connection opens.
|
||||
It upgrades the schema and converts legacy payloads one entry per SQLite
|
||||
transaction: write assets and body, read back hydrated content, compare JSON
|
||||
equality, then replace the old `content_json` payload with its file marker.
|
||||
Already converted entries are reconciled on retry. Matching body revisions do
|
||||
not require rehydrating binary payloads. Direct `AssistantDatabase.initialize`
|
||||
callers and tests also run storage repair.
|
||||
|
||||
Space reclamation is separate from conversion. Every worker attempt checks
|
||||
`PRAGMA freelist_count` and runs checkpoint/VACUUM when free pages remain.
|
||||
Cancellation after the last converted entry or a VACUUM failure therefore
|
||||
allows reclamation to retry on the next startup, even with no legacy rows left.
|
||||
The schema marker alone does not establish that conversion and reclamation
|
||||
finished. General migration requirements are in the
|
||||
[database migration guide](../../development/database-migrations.md).
|
||||
|
||||
## Backup and Restore
|
||||
|
||||
A restorable backup must pair a consistent SQLite backup with the adjacent
|
||||
`notes/` tree from the same period with note writes paused, or with the app
|
||||
closed. Handle active WAL through SQLite's consistent backup mechanism; copying
|
||||
only the database main file while it is active is insufficient. Restore both
|
||||
parts together. SQLite-only backups of file-backed entries cannot recover
|
||||
bodies or assets, and `note.json` alone cannot recover database metadata,
|
||||
revisions, todos or comments.
|
||||
|
||||
The product has no one-click assistant backup action. This is an operational
|
||||
backup boundary, not a new UI capability. The tested backup/restore and migration
|
||||
scope, including the lack of a real user historical database run, is recorded
|
||||
in [progress](./progress.md).
|
||||
|
||||
## Canvas Editor and Export
|
||||
|
||||
`MagicNotesWorkspace` selects rich-text or canvas content for new entries and
|
||||
opens saved canvases in `MagicCanvasEditor`; `MagicNoteContent` delegates saved
|
||||
canvas rendering to the paginated `MagicCanvasContent` viewer. The React adapter
|
||||
wraps the retained PeopleLib Fabric + Quill core. Fabric owns page annotations;
|
||||
Quill owns the continuous body flow. Saving awaits `flush()` so queued imports,
|
||||
text edits and pagination reach the existing preload/IPC create/update handlers.
|
||||
There is no autosave or separate canvas persistence path.
|
||||
|
||||
Editor and viewer heights follow the current paper element's displayed height
|
||||
through natural CSS layout, including wrapped toolbars and viewport padding.
|
||||
No fixed preview height or viewport-height cap clips the page. The outer note
|
||||
stream scrolls vertically; the paper viewport retains horizontal scrolling.
|
||||
|
||||
Paper templates, pen, highlighter, whole-object eraser, selection/transforms,
|
||||
floating text, images and PDF page backgrounds are integrated. Native PDF text
|
||||
is stored on its background for search and analysis; scanned pages remain visual
|
||||
without automatic OCR. The toolbar exports a raster PDF through jsPDF, composing
|
||||
background, flow text and annotations per page. It does not retain a searchable
|
||||
PDF text layer. `capturePages()` provides PNG data URLs for AI input, not a PNG
|
||||
download button. Undo/redo is per annotation page or Quill mode; page operations
|
||||
and PDF imports are not global undo steps.
|
||||
|
||||
The [canvas integration reference](../../../src/renderer/src/magic-canvas/README.md)
|
||||
owns core limits, import behavior and lifecycle details. Vite bundles Fabric,
|
||||
Quill, jsPDF, PDF.js workers and binary assets; PDF workers use explicit module
|
||||
Workers and local assets under the production `file://` CSP. The renderer does
|
||||
not need Node integration or remote asset services.
|
||||
|
||||
## Canvas Analysis and Comments
|
||||
|
||||
Draft, saved-entry and todo analysis use the existing typed preload/IPC methods
|
||||
and `createDefaultModelRuntime`. Each canvas request reads the current default
|
||||
model profile's `supportsImageInput` (or the resolved default setting when no
|
||||
profile is selected). Main resolves settings again for the actual request. This
|
||||
does not change an Agent runtime or desktop-to-Agent protocol.
|
||||
|
||||
| Default model capability | Analysis input and result |
|
||||
| --- | --- |
|
||||
| Image input supported | Renderer captures all pages; Main checks page IDs and PNG/JPEG encoding. Images are ordered by page alongside flow, PDF and object text. Comments carry `inputMode: canvas-images`. |
|
||||
| No image input | No page capture is required. Extracted text is used with an explicit instruction that handwriting, images and layout were not seen. Comments carry `inputMode: text-fallback`. |
|
||||
| No image input and no extracted text in an entry/draft | Analysis fails with guidance to switch to an image-capable default model; no visual understanding is claimed. |
|
||||
|
||||
Todo analysis includes its title and instructions plus the source canvas context,
|
||||
and uses the same capability and capture rules. Non-canvas content keeps the text
|
||||
analysis path. All analysis remains read-only with no tool calls.
|
||||
|
||||
Canvas `immediate` mode provides an Analyze canvas draft action without a persistent
|
||||
instruction banner; pen strokes do not trigger automatic requests. `after-save-auto`
|
||||
prepares analysis input and then saves manually submitted content. Settings or
|
||||
capture errors are caught so storage still proceeds; after a successful save,
|
||||
the UI reports that automatic analysis failed. A later model error likewise
|
||||
does not roll back the save. Failure to flush the document itself still prevents
|
||||
saving incomplete content.
|
||||
|
||||
For v2-to-v2 entry updates, identical content retains saved comments. If all
|
||||
comments have `text` or `text-fallback` input mode, equal extracted `plainText`
|
||||
also retains comments across layout-only changes. Other changed canvas content,
|
||||
including layout changes with `canvas-images` comments, clears saved entry
|
||||
comments and `analyzed_at`. In `after-save-auto`, visual comments trigger renewed
|
||||
analysis when content changes, while existing text-only comments trigger it when
|
||||
extracted text changes. A changed draft clears its prior canvas draft analysis.
|
||||
The UI labels the actual input mode so a text fallback is visible to the user.
|
||||
|
||||
## Change Notifications
|
||||
|
||||
`AssistantDatabase` accepts `onMagicNotesChanged: () => void`. Every successful
|
||||
@@ -44,10 +294,10 @@ state are not reset.
|
||||
|
||||
Background application of a detail reads the current draft state after the
|
||||
asynchronous fetch. A dirty title is retained, and the composer is not remounted.
|
||||
An entry editor uses its original editing content and revision for both its React
|
||||
key and save request; external revisions cannot remount it or bypass optimistic
|
||||
concurrency checks. Deleted entries remain displayed only while their editor is
|
||||
open. If an externally deleted note has a draft, its editor remains available
|
||||
A dirty entry editor uses its original editing content and revision for both its
|
||||
React key and save request; external revisions cannot remount that draft or bypass
|
||||
optimistic concurrency checks. Clean editors adopt newer revisions. Deleted entries
|
||||
remain displayed only while their editor has a draft. If an externally deleted note has a draft, its editor remains available
|
||||
with a deletion explanation instead of moving the draft to another note.
|
||||
|
||||
Read failures use the existing retryable refresh error and retain successful
|
||||
@@ -77,10 +327,18 @@ retains selection and focuses this visible return button on narrow layouts.
|
||||
There is no todo detail route, separate AI sidebar or resize handle. Note detail
|
||||
retains its existing AI pane preferences.
|
||||
|
||||
The shared segmented `PageTabs` lives in `PageHeader.actions` before New note,
|
||||
retaining tab/panel IDs, roving focus and arrow-key navigation. Its width follows
|
||||
content at all sizes. The shared status `SegmentedControl` follows search in one
|
||||
wrapping toolbar. These layout changes do not change Main, preload or storage.
|
||||
A single secondary button lives in `PageHeader.actions` before New note. Its
|
||||
label and icon describe the destination, and `requestDraftSwitch` retains the
|
||||
existing draft guard. Focus returns to the same `magic-library-switch` button
|
||||
after switching. The overview section keeps its localized list `aria-label`;
|
||||
there are no tab, tablist or tabpanel roles or tab-label references. The button
|
||||
follows content width at all sizes. The shared status `SegmentedControl` follows
|
||||
search in one wrapping toolbar.
|
||||
|
||||
Only note detail applies `magic-notes-layout--detail` to remove the layout frame
|
||||
and corner radius. Its stream pane has no extra padding; editor borders and the
|
||||
AI divider remain. Overview cards and the independent todo layout keep their
|
||||
existing frame and spacing. These changes do not affect Main, preload or storage.
|
||||
|
||||
## Note List Actions
|
||||
|
||||
@@ -113,6 +371,17 @@ daemon implementation update.
|
||||
|
||||
## Validation
|
||||
|
||||
- `magic-note-storage.test.ts` uses real files and SQLite for migration equality,
|
||||
reopen/repair, binary deduplication, coordinated backup/restore and physical
|
||||
database shrink. Failure injection covers body rename, manifest/GC cleanup,
|
||||
delete/reset retries, post-conversion cancellation and VACUUM retry.
|
||||
- Canvas integration coverage includes `MagicCanvasEditor.test.tsx`,
|
||||
`MagicNoteContent.test.tsx`, `rich-content.test.ts`,
|
||||
`magic-note-analyzer.test.ts` and `tests/magic-note-canvas-text.test.ts`.
|
||||
`canvas-ipc.integration.test.ts` runs production preload and registered IPC
|
||||
handlers against real SQLite with mocked Electron transport and model output.
|
||||
Interactive workspace/SQLite and production core export evidence is recorded
|
||||
separately in [progress](./progress.md).
|
||||
- `assistant-database.test.ts` checks committed writes with a second SQLite
|
||||
connection, successful mutation coverage, failures, no-op completion and reset.
|
||||
- `knowledge-mcp-gateway.test.ts` exercises real database CRUD through Agent/MCP
|
||||
@@ -127,4 +396,6 @@ daemon implementation update.
|
||||
coverage includes portal placement, keyboard navigation, dismissal, delete
|
||||
confirmation, target selection, revision failures and draft preservation.
|
||||
|
||||
No schema migration, dependency, refresh control or network service is added.
|
||||
Schema 38 and the file layout above govern current persistence; refresh
|
||||
notifications need no separate storage or network service. Dated validation
|
||||
results and remaining repository checks are owned by [progress](./progress.md).
|
||||
|
||||
Reference in New Issue
Block a user