The big move that completes session 1. Wire types moved from
src/protocol.rs to pmacs-protocol/src/message.rs:
- Input event family: Key, Modifiers, KeyEvent, MouseButton, MouseKind,
MouseEvent, FrontendEvent (and its variants — Resize, KeyEvent,
MouseEvent, Resume, Pause, Detach, ResizeAck, CrdtOp, Viewport).
- Instance-side message family: CursorState, InstanceSignal,
GoodbyeReason, InstanceMessage (Hello/Cursor/CellDelta/CursorByte/
CrdtOp/BufferSnapshot/Goodbye/PresenceUpdate + the SemanticFrame
variants).
- SelectionSnapshot.
- SemanticFrame family components: StyleSpan, StyleSegment,
DecorationKind, Decoration, DecorationSegment, AdornmentPlacement,
AdornmentContent, InlineAdornment, BlockAdornment, ResourceBody.
- Handshake: PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS,
is_supported_protocol_version, InstanceIdentity, InstanceCapabilities,
FrontendCapabilities, NegotiatedCapabilities, negotiate_capabilities,
Hello, AttachRequest.
What stays in src/protocol.rs:
- AttachTarget / AttachError / AttachTargetParseError /
AttachTargetValidationError / AttachTargetError / AttachmentHandle
(CLI / binding internals, not wire).
- crossterm_translate submodule (the crossterm ↔ pmacs-protocol-types
translation layer; sits at the binding boundary, not on the wire).
- Existing tests (wire-format roundtrip + AttachTarget + crossterm
translation), unchanged — they reach the moved types through the
'pub use pmacs_protocol::*' re-export.
Mechanical rewrites inside the moved chunk: crate::buffer::BufferId →
crate::BufferId, crate::rope::Position → crate::Position,
crate::rope::CrdtOp → crate::CrdtOp (the message module is inside
pmacs-protocol; identity types live at the crate root).
Feature re-added on pmacs-protocol: 'crdt' (was removed in commit 3
as I'd thought CrdtOp was the only feature-gated thing — but
InstanceCapabilities::default and FrontendCapabilities::default both
call cfg!(feature = 'crdt') for their multi_frontend / crdt_replica /
semantic_render defaults). Re-added with a doc comment explaining why.
The parent pmacs crate's 'crdt' feature now activates
'pmacs-protocol/crdt' so the cfg!() check evaluates consistently in
both crates.
Full gate green: fmt, clippy --all-targets -D warnings, lib 1314,
m4_acceptance 83, m8_1/m8_9/m8_10 10/26/19, m9_1 18, m5_8 5,
m11_5_semantic_acceptance --features crdt 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CrdtOp { peer_id: u64, bytes: Vec<u8> } moves from src/rope.rs to
pmacs-protocol::crdt. The type is unconditional (not #[cfg]-gated),
matching the original's 'always present to avoid feature-flag
proliferation through every Edit consumer' decision: the parent
pmacs crate's 'crdt' feature gates loro and op application, not
wire shape.
Removed the unused 'crdt' feature stub I'd added to
pmacs-protocol/Cargo.toml at session start; nothing in pmacs-protocol
needs it.
src/rope.rs adds 'pub use pmacs_protocol::CrdtOp;' so existing
crate::rope::CrdtOp imports keep resolving.
Lib gate: still 1314 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Workspace skeleton: root Cargo.toml becomes a workspace with members
[".", "pmacs-protocol"]; [workspace.dependencies] pins serde,
postcard, thiserror so both crates use byte-identical versions (the
wire format depends on it). pmacs main package keeps its existing
shape (no file moves); it just gains pmacs-protocol as a path
dependency.
Identity types moved: BufferId (from buffer.rs), FrontendId + ByteRange
(from protocol.rs), Position type alias (from rope.rs). All four are
self-contained — no custom-type dependencies — so the first stage of
the move can land atomically without dragging cell/message types along.
src/buffer.rs / src/protocol.rs / src/rope.rs each gain a 'pub use
pmacs_protocol::...' re-export for the moved names, so existing
internal imports (crate::buffer::BufferId, crate::rope::Position, etc.)
continue to resolve unchanged. New consumers (pmacs-gpu, debug tools)
will depend on pmacs-protocol directly.
One visibility change: BufferId::from_raw was pub(crate); promoted to
pub with a doc note that it's not stable API for external consumers.
The (crate) restriction was advisory only — external deserialization
already worked via the derived Deserialize, so making it pub doesn't
widen the actual surface, just makes it honest.
Lib gate: 1314 passed, no regressions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>