Implement penpot_commit with revn tracking, conflict retry and commit preview #195
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
david/pi-extensions-and-skills#195
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Summary
Implement
penpot_commit,penpot_discardandpenpot_status: apply the whole staged changeset as a singleupdate-filecall with correctrevnhandling, a preview of exactly what will change, and a post-write verification by re-reading the file.Background
Depends on: #194
This is the only place the extension writes. Getting
revnright here protects every later write path, because the semantics are counter-intuitive and were confirmed empirically on Penpot 2.17:update-filebody is{ id, sessionId, revn, vern, changes }.revnis the pre-write revision, not the new one.revnis accepted and applied — it is not an optimistic lock. Writing twice with the same stalerevnapplied both writes.revngreater than the stored one errors (revn-conflict); a mismatchedvernraisesvern-conflict.laggedarray echoes other revisions and is not an acknowledgement of your own write. Never treat it as confirmation.Consequence: correctness depends on the extension reading
revnimmediately before writing and confirming success by re-reading the file, not by parsing the response.sessionIdis a per-session UUID the server uses to attribute changes; generate one per extension session.Documentation Required
A separate process downloads these into the listed folders before this issue is implemented. Check the folders for the actual reference material before starting.
docs/reference/penpot-api/<PENPOT_URL>/api/main/doc/openapi.json— theupdate-filecommand: body parameters, response fields (revn,vern,lagged) and the error types it can raise.update-filechange list accepts, useful for validating a staged batch before sending.docs/reference/pi-coding-agent/anddocs/reference/typebox/details.dry_run/confirmflag.Implementation Details
Create
extensions/penpot/src/tools/commit.ts(and, if it helps,src/commit.tsfor the pure parts) and register all three tools.penpot_commitParameters:
file_id(string, required),dry_run(boolean, optional, defaultfalse) —dry_runreturns the same preview without writing, so an agent can show the user what it is about to do.file_idis empty ("nothing staged").get-file) to obtain the liverevn/vern— do not trust a cached value. Update the changeset's baserevnif it has moved since staging.{ id, sessionId, revn, vern, changes }and callupdate-file.revn-conflict: re-read the file, adopt the newrevn, and retry once. If it conflicts a second time, return a clear error rather than looping.revn(from the re-read, never from the write response) indetailsas{ fileId, previousRevn, newRevn, appliedChanges, verified: true }.explainfor validation failures), state clearly that nothing was written, and keep the changeset staged so the caller can fix and retry.penpot_discardParameters:
file_id(string, required). Clears the staged changeset and returns the discarded preview (what was thrown away). Idempotent — discarding an empty changeset reports"nothing staged".penpot_statusParameters:
file_id(string, optional — all staged files when omitted). Returns target file(s), baserevn, change counts by type and the deterministic preview lines fromdescribeChanges. Never writes.Guard hook: commit must call the designated-target guard (next issue) before sending anything. Until that guard exists, implement the call site and a permissive placeholder so the next issue replaces exactly one function.
Acceptance Criteria
penpot_commitsends exactly oneupdate-filecall per successful commit, with{id, sessionId, revn, vern, changes}.revn/vernare read immediately before the write; a stale cached value is never used.revn-conflicttriggers exactly one refresh-and-retry, then a clear error if it happens again.detailsreports the post-writerevnfrom the re-read.laggedarray is never used to decide whether the write succeeded.dry_run: truereturns the preview and makes no write call (asserted in tests).penpot_discardclears the changeset, is idempotent, and reports what it discarded.penpot_statusnever writes and reports per-file staged state.dry_run, empty-changeset refusal and discard, all with a stubbed client and no network access.Test Plan
Live validation (requires
PENPOT_URL/PENPOT_TOKEN, scratch project):penpot_status— confirm the preview lists exactly five changes.penpot_commitwithdry_run: true— confirm no write happens (filerevnunchanged on re-read).penpot_commit— confirm all five assets exist viapenpot_get_file, and that the file's revision advanced exactly once (compare therevnbefore and after; a jump of more than one indicates more than one write).revnon, then commit — confirm the conflict path refreshes and the commit lands, and that the resulting revision advanced exactly once.pi-loop opened and merged a pull request for this issue: #228