Skip to content

Penmark v0.6.0

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Oct 01:34
61b43bf

Raw-text elements pass through the inline render path

  • The preview now shows the authored value of a self-closing raw-text element such as <textarea/>. markdown-it has no HTML parser, so that spelling used the inline path. The per-text-node source-offset spans then appeared inside the element's value as literal text.
  • A new inline rule turns a raw-text open tag and everything up to its end tag into a single token. It covers script, style, textarea, title, xmp, noembed, noframes and iframe. An element with no end tag continues to the end of the block, matching browser display.
  • The renderer still stamps ordinary inline text with source offsets, and comment highlighting is unchanged.

Markdown links open in a Penmark tab; frontmatter card keeps its state

  • Relative links to markdown files now open in a new Penmark preview tab. The opener is vscode.openWith on penmark.previewEditor, with vscode.open as fallback. Extensionless wiki-links resolve via an existence probe: .md suffix first, then the workspace root.
  • mailto: and ftp: links open in the system handler. file: URIs open inside the IDE. Neither is resolved as a relative file path. Untitled and remote documents skip existence probing, since there is no local directory to probe.
  • The frontmatter card keeps its collapse state across preview re-renders and tab switches. Persistence is getState/setState while the tab is open. Cards with more than three keys still start collapsed. Version 0.6.0.

OSS repository safeguards

  • CI now uses immutable action and browser-container references, explicit least-privilege permissions, timeouts, pull-request run cancellation, and a stable required aggregate check while preserving the full operating-system and VS Code-version matrix.
  • Release verification now runs under bash with safe.directory, --shm-size=2g, and built-in Node ZIP manifest extraction inside the pinned Playwright container, accepts only three-component version tags, repeats the complete suite on the tagged commit, checks VSIX contents and version coherence, writes a checksum, creates an artifact build-provenance attestation (actions/attest-build-provenance), and smoke-tests the downloaded release asset; manual dispatch remains verification-only.
  • Added public runtime dependency notices and removed internal path examples from public artifacts.

Dependabot can read the lockfile again

  • package-lock.json held conflict markers inside the inner packages[""] version hunk. Every Dependabot update job stopped with dependency_file_not_parseable, so no dependency update reached a pull request.
  • The hunk now resolves to 0.6.0, which matches package.json and the lockfile's own top-level version.

Agent-authored character entities render as punctuation

Agent-generated review comments can encode punctuation as decimal HTML character references, such as &#45; for a hyphen. Penmark decoded only its own paired-hyphen storage sentinel (&#45;&#45;), so a single reference reached the drawer and popover as visible source text. Penmark now renders any valid decimal reference as the character it denotes, using markdown-it's own validity rule so surrogates, NUL, control characters and noncharacters stay literal rather than becoming ill-formed text a save could write into the file.

This rendering is a presentation pass, applied where a note is handed to the preview and where one is exported for an agent. An entry's quote is exempt: it stays byte-faithful all the way to the drawer, which renders it at the point of display. Re-anchor re-adds the same quote at a new location, so a rendered quote would be stored and could never match the document again, and the next anchor loss would orphan a comment that would otherwise recover. It is deliberately not part of the storage codec. Decoding at parse time instead would have broken two things: quote recovery matches an entry's quote against raw document bytes, so a quoted passage that itself contains a reference would stop matching and the comment would orphan; and because the writer escapes only --, each read-and-save cycle would strip one more level from text the user never edited. Keeping the pass at the display seam leaves the spec's round-trip guarantee intact for every string. The validity rule is written out rather than imported: pulling markdown-it's helper into the eager extension entry took dist/extension.js from 53 KB to 136 KB, against a sub-50 ms activation budget. A test pins the copy to markdown-it across every code point. Format spec §6 gains a non-normative reader-side rule; regression tests cover the sentinel, standalone references, each rejected range, and the three consumers that need raw bytes.

Commenting no longer breaks the formatting it wraps

Commenting a bullet that opens in bold left the asterisks showing in the preview: **Subscription-billed.** rendered literally instead of bold. Reported from a real review session.

  • An anchor at the start of a line no longer starts an HTML block — CommonMark treats any line beginning with <!-- as raw HTML through the closing -->, so the whole line skipped inline parsing. This was never specific to bold: inline code, links and italics on that line all rendered as source. It fired wherever inline-safety snapping pushed a span opener to the start of a block's content — bullets and ordered items (including nested ones), paragraphs, blockquotes, a paragraph's continuation line, and a closer landing at a line start. The renderer now declines the HTML-block rule for a line that leads with a pmk anchor and still carries content, so those lines take the inline path where the marker passes through verbatim at the exact extent (ADR 0006). Lines holding nothing but a marker keep the old behaviour, because pmk:b and pmk:r anchors own their line by design (§4.2), and a hand-written <!-- note --> still behaves as stock CommonMark.
  • A highlight spanning list items stays visible past the first one — a bullet list is one block, so commenting three of five bullets is a span, not a range. The single <mark> wrapped </li><li>, which is invalid nesting; because <mark> is not an HTML formatting element the browser closes it at </li> and discards the stray closer, silently dropping the highlight from every item after the first. The extent is now split into one <mark> per inline run, all sharing the comment id. An extent inside a single block still produces exactly one <mark>, byte-for-byte as before.
  • The split reads as one control — the fragments of a split highlight would otherwise each become a tab stop announcing the same comment. Only the first carries the keyboard affordance and the gutter dot; clicking any fragment still opens the popover, and all fragments light up together when the comment is active.
  • Tests cover the boundary cases the fixtures missed — the anchored-doc fixture had no line-start anchor, so no snapshot could have caught this. New tests pin each block context that broke, both marker-only-line behaviours, a non-pmk comment at a line start, and the cross-block split down to whitespace handling.

Multi-block selections were already correct and are unchanged: a heading, paragraph, fenced code and list selected together still become one range wrapper with their formatting intact.

What's Changed

  • fix(comments): keep markdown formatting intact around inline anchors by @carlosboeing in #50
  • chore(git): add the private-workbench pre-commit guard by @carlosboeing in #53
  • chore: gitignore local git worktrees by @carlosboeing in #54
  • docs: scope worktrees to implementation work by @carlosboeing in #56
  • docs: stop instructing agents to cite private design docs in public by @carlosboeing in #57
  • Decode agent-authored decimal character references by @carlosboeing in #59
  • chore(governance): align repository with OSS house standard by @carlosboeing in #61
  • chore(governance): add SUPPORT.md to house standard by @carlosboeing in #62
  • feat(preview): open markdown links in new tab and persist frontmatter state by @carlosboeing in #44
  • fix(deps): remove merge markers from package-lock.json by @carlosboeing in #63
  • chore(deps): bump dompurify from 3.4.11 to 3.4.14 by @dependabot[bot] in #48
  • chore(deps-dev): bump undici from 7.28.0 to 7.29.0 by @dependabot[bot] in #45
  • chore(deps-dev): bump fast-uri from 3.1.2 to 3.1.6 by @dependabot[bot] in #46
  • chore(deps-dev): bump postcss from 8.5.16 to 8.5.26 by @dependabot[bot] in #52
  • chore(deps-dev): bump js-yaml from 4.2.0 to 4.3.2 by @dependabot[bot] in #60
  • chore(deps): bump mermaid from 11.16.0 to 11.16.1 by @dependabot[bot] in #47
  • chore(deps-dev): bump brace-expansion from 2.1.1 to 2.1.4 by @dependabot[bot] in #66
  • chore(deps): bump Playwright to 1.62.1 with container image by @carlosboeing in #67
  • chore(deps): bump the minor-and-patch group across 1 directory with 13 updates by @dependabot[bot] in #68
  • fix(render): keep raw-text elements whole on the inline path by @carlosboeing in #69
  • docs(changelog): record raw-text inline fix as Unreleased by @carlosboeing in #70
  • chore(githooks): install the drift-guard pre-push hook by @carlosboeing in #71
  • docs(changelog): record the lockfile parse fix by @carlosboeing in #72
  • chore(githooks): add post-merge and refresh housekeep by @carlosboeing in #73
  • chore(githooks): scope check C to the Recently shipped section by @carlosboeing in #74
  • chore(repo): add housekeep audit and reconcile shipped roadmap items by @carlosboeing in #95
  • chore(release): prepare v0.6.0 changelog and roadmap by @carlosboeing in #96
  • ci(release): set bash default shell for container steps by @carlosboeing in #97
  • ci(release): fix container git safe.directory, shm-size, and VSIX extraction by @carlosboeing in #98
  • ci(release): use actions/attest-build-provenance for VSIX attestation by @carlosboeing in #99

Full Changelog: v0.5.3...v0.6.0