CI's Rust Check runs `cargo clippy --workspace --all-targets -- -D
warnings`; the fmt failure had masked it, so accumulated lints surfaced
once formatting was fixed. Resolve them:
- op-acp / op-ai-skills (this change set): while-let loop, redundant
struct update, and `should_implement_trait` allows on the Option /
infallible token parsers.
- Pre-existing in op-editor-core / op-figma, swept so the workspace
gate is clean: redundant `drop`, `too_many_arguments` allow,
collapsible `if let`, a type alias for a complex tuple, manual
`Iterator::find`, and an `approx_constant` test value.
Lint fixes only — no behaviour change.
Addresses the 4 BLOCKs from the second codex review.
- kiwi: schema field-count pre-allocation is capped at the remaining
buffer size (a hostile count no longer forces a huge Vec alloc).
- kiwi: array-length validation + pre-alloc now use the *remaining*
byte count rather than the total buffer length (tighter bound).
- zip_reader: the aggregate-size budget is checked against the
central directory's declared uncompressed size *before* the entry
is decompressed, not after.
- zip_reader: stored (uncompressed) entries are now subject to the
per-entry MAX_ENTRY_SIZE cap, matching the deflate path.
op-figma 84 tests green; clean build.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Addresses the first codex review of the binary `.fig` parser.
BLOCKs:
- kiwi: 64-bit varint now uses Kiwi's terminal-byte rule (eight
7-bit groups then a final full-8-bit byte) — the old `& 127` mask
on every byte corrupted u64 values above 2^56.
- kiwi: an invalid schema definition kind (> 2) is now rejected
instead of silently treated as a message.
- kiwi: array decode rejects a length exceeding the buffer size —
guards against a hostile zero-byte-element array spinning the
decode loop billions of times.
- zip_reader: aggregate 2 GiB decompression budget + 10k entry cap
on top of the existing per-entry limit (zip-bomb defence).
CONCERNs:
- detect_kind now recognises the `PK\x03\x04` ZIP magic as Binary —
the common Figma export form (`canvas.fig` + `images/` in a ZIP)
was being rejected before container.rs could unwrap it.
- resolve_style_references now also resolves style refs inside
instance `symbolData.symbolOverrides` entries.
- kiwi: enum field type codes are no longer resolved (unused; kiwi
writes 0) so a stray code can't reject a valid schema.
Plus a zip-wrapped end-to-end test + the misleading zstd test rename.
op-figma 84 tests green (+1); clean build.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Stage G — the binary `.fig` parser is now end-to-end functional;
`parse_fig` no longer returns NotYetImplemented for binary input.
- image_resolver.rs: resolve_image_blobs walks the converted document
and replaces `__blob:N` / `__hash:HEX` image-fill placeholders with
base64 `data:` URLs (MIME sniffed from magic bytes).
- lib.rs: new `parse_fig_binary(bytes, name, layout_mode) -> FigImport`
runs the whole pipeline — container split → Kiwi decode → tree
build → node conversion → image resolution. `parse_fig`'s Binary
arm delegates to it; `FigParseError::NotYetImplemented` retired in
favour of `Binary(String)`. Entry points re-exported.
- binary_e2e_tests.rs: assembles a real fig-kiwi container from
scratch (hand-built Kiwi schema + data chunks, deflate-compressed)
and asserts the full pipeline yields a PenDocument with the
rectangle at the right position/size + canonical-JSON round-trip.
op-figma 83 tests green (+6); clean build, no warnings.
Closes the §2.1 P0 gap — Figma binary `.fig` parsing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Stage 3 — ports figma-types.ts + fig-parser.ts::parseFigFile.
- FigGuid / FigMatrix / FigColor / FigVec2: the geometric primitives
worth typing, each extracted from a decoded FigValue object;
FigGuid::to_key is the canonical `sessionID:localID` map key.
- BlobOrString: the `blobs` pool element (raw geometry bytes | string).
- FigmaDecodedFile { node_changes, blobs, image_files }.
- parse_fig_file: the full pipeline — fig_to_binary_parts → decode the
Kiwi schema chunk → decode the data chunk against it → extract
nodeChanges (with the fallback scan for a guid-bearing array) +
blobs. Mirrors parseFigFile / extractBlobs.
- FigValue gains generic get_f64/get_str/get_bool/get_array accessors.
op-figma 35 tests green (+5).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Stage 2 of the binary `.fig` parser — ports the `kiwi-schema` subset
the format needs.
- ByteBuffer: LEB128 var-uint/int (32 + 64-bit, zigzag), Kiwi's
exponent-rotated var-float (single-0-byte zero optimisation),
NUL-terminated UTF-8 strings, length-prefixed byte blocks.
- decode_binary_schema: the self-describing schema chunk — definitions
(enum/struct/message) + fields; native type codes resolve via
`!code` into NATIVE_TYPES, definition codes by index (forward refs
handled with a two-pass bind).
- FigValue: dynamically-typed decoded tree (the Rust stand-in for the
TS untyped `any`) with get/as_f64/as_str/as_bytes/as_array accessors.
- decode_message: dynamic decoder (the `compileSchema` + `decode*`
equivalent) — message id-prefixed fields, ordered structs, enum
ordinal→name, `byte[]` as a raw block, MAX_DEPTH recursion guard.
Roots at the `Message` definition like Figma's findDecoder.
Tested via an in-test Kiwi writer that round-trips schema + data
fixtures (enum/struct/message/arrays/byte-arrays/floats). op-figma
30 tests green (+7).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
First stage of the Figma binary `.fig` parser port (op-figma was
clipboard-JSON only; binary returned NotYetImplemented).
- zip_reader.rs: hand-rolled minimal ZIP reader — EOCD scan, central
directory walk, store (method 0) + raw-deflate (method 8) entries.
Avoids the full `zip` crate dependency tree. 512 MiB per-entry cap.
- container.rs: ports `fig-parser.ts::figToBinaryParts` — unwraps the
ZIP archive form (`canvas.fig` + `images/*`), verifies the
`fig-kiwi` magic, splits length-prefixed chunks, decompresses each
via the deflate→zstd→raw fallback chain (PNG payloads passed
through). Output: decompressed parts + embedded image map.
- deps: flate2 (miniz_oxide pure-Rust backend), ruzstd, base64 — all
license-clean + wasm32-buildable.
Modules are `allow(dead_code)` until `parse_fig` is wired in the
final stage. op-figma 23 tests green (+6).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The op-* crate reorg never ran `cargo clippy -- -D warnings`, so the CI
lint gate failed. Fix every violation surgically: real fixes for
mechanical lints (needless_range_loop, derivable_impls, ptr_arg,
needless_borrow, doc_lazy_continuation, unused_imports, manual_find,
collapsible_match, never_loop, dead_code, complex types via type
aliases) and scoped `#[allow]` for intrusive ones (too_many_arguments
on paint helpers, result_large_err where ToolOutcome / PenNode payloads
are deliberately the Err type).
Relocate figma.rs out of openpencil-shell-core into a dedicated
op-figma crate. The .fig detection + clipboard-node parser only
depends on jian-ops-schema (op-editor-core's PenNodeExt is test-only,
so it becomes a dev-dependency). figma.rs becomes the crate's lib.rs;
no intra-crate paths to adjust. Pure relocation, no behaviour change.