issue-191: Implement the penpot_get_file tool (pages, objects and library assets) with unit tests #224
No reviewers
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
david/pi-extensions-and-skills!224
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/issue-191/implement-the-penpot-get-file-tool-pages-objects-a"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
191: Implement the penpot_get_file tool (pages, objects and library assets) with unit tests
Closes #191 — 191.
Generated in 7m 48s.
Review findings
I'll start by exploring the repo and understanding the current state.Now I'll apply the fixes. Starting with
fileShape.ts:Now the tests infileShape.test.ts:All gates pass.npm testruns 231 tests: 230 pass, 1 fails —scripts/local-install.test.mjs(the pre-existing "mongodb is declared" failure, untouched by this diff since nopackage.jsonchange is involved). The penpot subset is 104/104.Review Findings — 191
Summary
Fixed the High breadth-budget finding plus all three fixable Medium findings and all four Low findings: the object tree now has a total-node budget (
MAX_OBJECT_TREE_NODES = 500) that marks the cut, children are ordered by the parent's server-maintainedshapesarray, shapes with an unknown parent survive as extra roots, a missing/non-numericrevn/vernis rejected asinvalid-fileinstead of defaulted to0, theNONEconstant is now used (no dead code), the tool description namessummary_only, and a CHANGELOG entry was added. Tests were added for each behaviour (breadth cut,shapesordering, orphan visibility, non-numeric revision, wide-page text bound, real default details budget, andobjectTree/objectsabsence on a default read). Left unresolved: the hand-authored fixture / missing live-capture validation (Medium), which cannot be verified without a reachable Penpot instance.Critical
(none)
High
extensions/penpot/src/fileShape.ts:282— the object tree is bounded only in depth (MAX_OBJECT_TREE_DEPTHat line 23); breadth is unbounded, soinclude_objectscan flood the model-facing text channel. Verified: a page with 5,000 top-level layers produces 5008 text lines / 132,986 chars (anddetailswas correctly withheld for exceeding the 150k budget, yet the text that reached the model was almost as large). On the "real design files" the module doc calls out, this defeats the stated budget. Suggested fix: add a total-node/character budget for the rendered tree (e.g.MAX_OBJECT_TREE_NODES), stop emitting nodes once reached, and mark the cut the same waytruncatedmarks a depth cut; add a test with a wide page.Medium
extensions/penpot/src/fileShape.ts:305— child order is the object-map key order, not layer order:childrenByParentis built by iteratingObject.entries(objects)and the server-maintainedshapesarray (the authoritative z-order/layer-panel order) is explicitly ignored. Verified: reversing the object-map order reverses the tree (Header/Sidebar/Footer → Footer/Sidebar/Header). Clojure map serialisation order is not meaningful, so the agent can read a "layer tree" in arbitrary order. Suggested fix: when a parent shape has ashapesarray of child ids, order its children by that array, appending any map-order leftovers; keep map order as the fallback. The fixture already carriesshapesarrays (Root Frame→ Card, Card → rect/text) that no test exercises.CHANGELOG.md:11— no[Unreleased] → Addedentry forpenpot_get_file, while the previous two user-visible penpot tools (penpot_whoami,penpot_list_projects; lines 11–13) each added one. The file states "All notable changes to this project are documented in this file." Suggested fix: add a one-paragraph entry mirroring the 190 entry, describing thepage_id/include_objects/summary_onlyswitches and the read-only/revision-source role.extensions/penpot/src/fileShape.ts:356— a missing/non-numericrevn(andvern) is silently coalesced to0, even though the tool's contract is thatrevn/vernare always indetailsbecause "the commit step tracks" them. This contradicts the repo's established "never fabricate data from a malformed success body" convention (whoami.tsrejects an empty 2xx body rather than inventing a profile;file.test.tsrejects a non-file body). Since Penpot silently accepts stale revisions, a0fallback handed to the write path is exactly the dangerous case the design warns about. Suggested fix: returninvalid-filewhenrevnis missing/non-finite (or makerevn/vernoptional and surface their absence), and test it.extensions/penpot/src/tools/file.test.ts:35/extensions/penpot/src/tools/fixtures/README.md:10— the fixture is hand-authored from schemas, not captured (the issue'sdocs/reference/penpot-api/download was absent). The parsing tests are therefore only as good as the author's assumptions: a wrong key/level (data.pagesvsdata.pagesIndex,page.objects, asset field names) would still pass green, so the plan's M1 "confirm the library listing matches what the Penpot UI shows" validation is not represented. Suggested fix: capture and scrub a realget-fileresponse when an instance is reachable and re-key the assertions to it (or add an opt-in integration test gated onPENPOT_URL/PENPOT_TOKEN+ a scratch file id, skipped by default as the plan specifies).Low
extensions/penpot/src/fileShape.ts:428—const NONE = "(none)"is dead code (unused; the empty-page branch informatPageshardcodes"Pages: (none)"). Suggested fix: delete the constant, or use it informatPagesfor the empty case.extensions/penpot/src/fileShape.ts:316— with the root frame present,topLevelis[root]only, so any shape whoseparentIdis not on the page is silently dropped from the tree while still counted byobjectCount. Verified:{root, orphan(parentId: "missing-parent")}yields a tree of justRoot FramebutobjectCount: 2. Suggested fix: when the root exists, append parent-less/unknown-parent shapes as additional top-level roots (or document the omission).extensions/penpot/src/tools/file.ts:114— the tool-leveldescriptionadvertisespage_idandinclude_objectsbut never mentionssummary_only, so the switch is only discoverable from the parameter schema. Suggested fix: add a clause such as "and summary_only: false to render full asset records in the text".extensions/penpot/src/tools/file.test.ts(whole file) — theMAX_DETAILS_OBJECT_CHARS(150k) default budget path and theobjectsOmittedReasondetails field are never exercised end-to-end; onlyfileShape.test.tscovers omission via a 16-char override, and no test assertsobjectTreeis absent wheninclude_objectsis false. Suggested fix: add a tool-level test with a payload large enough to trip the real default (or expose the budget as a test seam), plus an assertion thatdetails.pages[0].objectTree === undefinedon the default read.