issue-198: Implement penpot_add_frame with auto-layout props and absolute-positioning fallback #231
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!231
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/issue-198/implement-penpot-add-frame-with-auto-layout-props"
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?
198: Implement penpot_add_frame with auto-layout props and absolute-positioning fallback
Closes #198 — 198.
Generated in 16m 52s.
Review findings
I'll start by exploring the repo structure and reading the relevant files.Now let me examine the test files and remaining sources.Now I'll implement the fixes. Starting with the High severity commit verification fallback:Now the Low severity fix in
shapes.ts— deriving the union types from exported tuples:Nowframe.ts— schema enum derivation,minLength, fill-ref handling, and parent validation:Now the parent validation and fill handling inframe.ts:Now addfindShapeOnPagetofileShape.ts:All gates pass except the pre-existing manifest failure. Let me confirm the final state of the diff before reporting.# Review Findings — 198Summary
All five findings are resolved in one pass. The High finding restored the fail-closed
defaultbranch inverifyStagedChanges(plus thedescribeUnverifiableChangefallback and two tests covering an unknown change type with and without identifying fields). Both Medium findings are fixed:namenow uses the string keywordminLength: 1(with a schema assertion in the existing declaration test), andparent_idis resolved against the target page's object map via a new purefindShapeOnPagehelper infileShape.ts, so a missing or non-frame parent is refused before anything is staged (tests for unknown, non-frame, valid-frame and explicit-root parents). Both Low findings are fixed:fill_color_refwithoutfill_coloris now rejected instead of dropped, afill_color_ref_fileparameter attributes a linked-library asset to its owning file (defaulting tofile_id), and the five layout enums are now built from exported literal tuples inshapes.tsthat the payload types are themselves derived from, so schema and type cannot drift. Gates:npm test(the only script; there is no build or lint script) runs 403/404, the single failure being the pre-existingscripts/local-install.test.mjs:1875mongodb-manifest assertion, which is unchanged frommain; the full penpot suite is 277/277. I also verified with atsc --strictrun (TypeScript installed outside the repo, since none is a project dependency) that the set of type errors is byte-for-byte identical toHEAD, i.e. the type-level enum change introduced no new errors.Critical
High
switch (change.type)inverifyStagedChangesno longer has adefaultbranch, so a staged change whose type has no verification case is silently skipped and the function returnsverified: truewith no evidence (previously the removeddescribeUnverifiableChangefallback pushed such a change intomissing). The docstring at commit.ts:80-82 still promises the old fail-closed behaviour, and the next milestones (add-rect/text/instance) will add change types to this union, so a batch containing an unverified type could be reported verified and its changeset cleared after a write that may not have applied. Suggested fix: restore the fallback, e.g.default: { const raw = change as { type: ChangeType; id?: string; name?: string }; missing.push({ type: raw.type, id: raw.id ?? "(unknown id)", name: raw.name ?? "(unknown name)" }); }(or anassertNeverthat reports the unknown type as missing), and add a test staging an unknown change type and assertingverified: false.Medium
extensions/penpot/src/tools/frame.ts:134 —
name: Type.String({ minimum: 1, … })uses the numericminimumkeyword, which JSON Schema/TypeBox ignores for strings, so an empty layer name passes schema validation (confirmed:Value.Check(Type.String({ minimum: 1 }), "")returnstrue; the built schema is{"type":"string","minimum":1}). The intent is clearly a non-empty name. Suggested fix: useminLength: 1(verified to reject"") and add a schema assertion for it in theadd_frame declares the required …test.extensions/penpot/src/tools/frame.ts:317 —
parent_idis copied verbatim into both the shape'sframeIdandparentIdwithout checking that it exists or is a frame. A non-frame id (rect/group, discoverable viapenpot_get_file) produces a shape whoseframeIdis not a frame id — at best a server rejection and at worst a wrongly-parented shape. Suggested fix: whenparent_idis supplied, resolve it from the selected page's object map (read the page objects, or use a targetedget-file/get-file-fragmentread) and fail with a clear error before staging if it is absent ortype !== "frame"; add a test for an unknown/non-frame parent id.Low
extensions/penpot/src/tools/frame.ts:264 —
fill_color_refis silently dropped whenfill_coloris omitted (theif (params.fill_color === undefined) return []at line 257 short-circuits it), andfillColorRefFileis hard-coded toparams.file_id. Sincepenpot_list_librarycan resolve colour ids from linked library files, a reference to an asset owned by another file would be attributed to the target file. Suggested fix: rejectfill_color_refwithoutfill_color(or warn), and add an optionalfill_color_ref_fileparameter defaulting tofile_idso a linked-library asset can be referenced correctly.extensions/penpot/src/tools/frame.ts:44 — the layout enums are re-declared as independent TypeBox unions (
layoutType,flexDirection,alignItems,justifyContent,wrapType) rather than being tied to the exportedLayoutType/FlexDirection/AlignItems/JustifyContent/WrapTypetypes inshapes.ts, so the schema and the payload type can drift apart silently. Suggested fix: derive the literals from the shared unions (e.g.Type.Union<LayoutType>([Type.Literal("flex"), Type.Literal("grid")])— or asatisfies/compile-time assertion over the literal tuples) so adding a value in one place cannot diverge from the other.