Skip to content

Changelog

Version 0.16.8

Every @aparte/* package ships at this version (they are released in lockstep).

Patch Changes

  • 50085e8: Five calibration decisions from the image audit: the bubble’s corner is the theme’s --aparte-radius-bubble (12px, it was a 14px literal); a control’s edge has its own token, --aparte-border-control, read by the field, the field group, the choice controls and the select trigger; the icon scale is in rem on the type factor (--aparte-icon-size defaults to 1rem, was 14px; sm 0.75rem, lg 1.125rem, xl 1.25rem); the elicitation rows’ radius is the md step; and a disabled button, field or select is drawn — a neutral ground and the muted ink — instead of faded with opacity. The composer’s gated state no longer fades the whole composer.

    --aparte-border did two jobs, separating regions and bounding controls, and six previews showed a control with no visible edge; the new token is derived from the ink and the ground so both schemes follow, and its mix is a first setting. The icon scale was the one scale in the theme pinned in px while every type size followed --aparte-font-scale, so a glyph beside text shrank optically when the reader enlarged the text. Opacity on a disabled control faded the glyph with its ground and read at 2:1 on the send button; “inactive” and “disappearing” are not the same message. Menu items, option rows and a tag’s ✕ keep the opacity for now. @aparte/core

  • 31ccbc2: center-empty centres the welcome group itself: while the chat is empty, the rows’ wrapper carries no block padding, so the empty viewport takes no room in the centred stack.

    Measured on the built demo at 768: the chat’s centre at 240, the visible group’s at 256. The empty viewport still stood 32px tall — the wrapper’s block padding with no row in it — and justify-content: center centred three items of which the first was invisible. The padding goes, not the box: capping the viewport at 0 would leave a 32px scroll surface inside a 0px box, which the browser smoke test every example runs (“an empty transcript must not overflow”) refuses. Framework mode is untouched — there the viewport is the scroll surface and may hold the wrapper’s own empty-state content. @aparte/core

  • 7e5910a: <aparte-chat submit-on-enter="false"> now reaches the composer it composes, and the menu, popover, dialog and tooltip each get a radius knob (--aparte-radius-menu, --aparte-radius-popover, --aparte-radius-dialog, --aparte-radius-tooltip).

    The shell forwarded placeholder and disabled only, so the one switch every wrapper exposes as submitOnEnter had no vanilla spelling short of reaching inside for the composer. It is forwarded by value (the bare attribute keeps the default, Enter sends) and observed, so a toggle after mount follows. The four floating surfaces read a step of the radius scale directly, the only family without a knob of its own: a theme that wanted square menus and round bubbles had to move the scale step and every other reader with it. Rendering is unchanged; the four knobs default to the steps the sheets read before. @aparte/core

  • 316eaa7: The action bar’s first glyph starts on the text column; every inline recipe of the kit sits on the midline (vertical-align: middle); the avatar’s initials, corner and group overlap scale with its size — --aparte-avatar-initials-ratio, --aparte-avatar-radius-ratio and --aparte-avatar-overlap-ratio replace the absolute --aparte-avatar-font-size, --aparte-avatar-radius, --aparte-radius-avatar and --aparte-avatar-group-overlap — and the assistant avatar’s text is the text colour.

    The most reproducible defect of the audit: in 14 previews the first action button’s ink began 5 to 8px right of the paragraph above it, because a glyph is centred in a 24px box; the bar takes that slack back. Inline boxes fall on the baseline unless they say otherwise, and none did: the icon button rode 3px above its neighbours, three spinners shared a bottom edge instead of a centre. The 40px avatar drew the same 11px initials as the 32px one, its corner drifted from squircle to square up the ramp, and a 6px overlap was a fifth of a small avatar and a tenth of a large one — the fractions are computed on the element so a size modifier moves them. @aparte/core

  • 94c44a7: The documented @cssprop defaults now match the stylesheets (61 of 172 were stale), and the reflected state attributes the shipped CSS keys off — data-empty on the chat, data-panel-active/data-panel-mode/data-model-gated on the composer, data-busy on the viewport — appear in each element’s attribute table like their siblings already did.

    The default in a JSDoc tag is a hand copy of a value that lives in a sheet, and the two had drifted: radii off by half, paddings in pixels where the sheet reads the spacing scale, the attachment tile documented at 40px on one page and 56px on another when the theme says 72px. The generated component pages print that default, so a reader tuning a knob started from a value the sheet never had. Every default is now the stylesheet’s value character for character, and a test keeps it so (the source of truth is a :root declaration in theme.css, else a scoped declaration, else the fallback of the var() that reads the knob). Also on the chat page, the hand-composed markup example no longer ends up inside the --aparte-chat-bottom-gap table cell, and the sidebar’s data-drawer is documented against breakpoint rather than a hard-coded 48rem. @aparte/core

  • e4a3e86: Every button core renders is type="button", so a chat placed inside a host <form> no longer submits it when a reader copies a code block, presses a branch arrow or clicks an action; the code block’s copy button carries an aria-label; the reasoning panel is a focusable, named region.

    Thirteen emitted buttons had no type (the bubble’s action bar, branch arrows and edit controls, the composer’s send and stop buttons, the code block’s copy button) and one custom action button was created without one — and a button with no type is a submit button. The copy button was also the one icon button in core named by title alone, which a screen reader does not read; its accessible name now follows the “copied” confirmation too. The reasoning panel is a scroll container (max-height + overflow-y: auto) and had no tab stop, so a keyboard reader on Safari could not scroll it; it is role="region" with tabindex="0", named after its label. A source test now refuses a new untyped button. @aparte/core

  • b20565d: The error segment wears the alert recipe’s parts (aparte-alert__icon, __body, __title, __message; its details block is aparte-segment-error__details), a card’s body folds its content’s outer margins into its padding, and the overlaid composer casts a shadow (--aparte-composer-overlay-shadow).

    Also: hidden now hides any element wearing an aparte- class — a recipe’s own display used to outrank the browser’s [hidden], so a hidden button stayed painted (the copy button of a tool-only turn, on the built preview).

    The error renderer put the recipe’s class on its root and redrew every part under classes of its own — aparte-error-icon-wrapper, -content, -title, -message, -details are gone, and so are the tokens only they read (--aparte-error-icon-size, a 20px literal among derived values, and --aparte-error-title). The card body let a paragraph’s margins stack on its padding, so the sheet’s own example measured a body twice the height of its header. Under overlay-composer the composer floated over the transcript with a z-index and the transcript’s own ground: a thing that floats has to be seen floating. @aparte/core

  • 2e8f3ed: The examples the kit pages render are specimens now: the accordion shows three items, the danger alert carries its icon, the skeleton keeps the family’s own block height, the app-shell shows a populated sidebar, header and transcript, the split’s second pane is a styled document with a colour scheme, the scroll-rail and elicitation examples carry a complete composer, and every chat example is sized in rem. The tool row’s approval label reads “Waiting” (was “waiting for you”) and wears a pause glyph — the one capitalised word plus a glyph its sibling states use; pause joins the built-in glyphs.

    Measured on the built previews: 34 of the 59 kit previews render a header example or an @example verbatim, so those strings are the showcase, not documentation — and they had been written as excerpts. One accordion item let :last-child remove the only rule the family draws; the --danger alert without an __icon beside an --info with one zig-zagged the left column by 23px; block-size: 64px inline contradicted the skeleton’s 5rem token; height: 320px sheared the chat’s first turn at 375. A test now holds the three rules for every sheet and element: enough instances for the relation rules to exist, every documented part present, no hard pixel value against a token of the family. @aparte/core

  • a62abf9: Field groups and the colour field get their corners back; the field family’s knobs now live on :root.

    --aparte-field-radius was declared on .aparte-field itself and read by .aparte-field-group (the field’s parent) and .aparte-color (a sibling recipe). A custom property only inherits downwards, so both computed border-radius: 0 — every field group in the library rendered square (the sidebar’s search, a https:// prefix group). Measured 0px → 9px. Thirteen field knobs (paddings, radius, textarea height, checkbox/radio/switch/range sizes) move to theme.css beside the button’s, where the theming guide sends you and where every other family’s knobs already are. Values are unchanged; the elicitation panel’s own overrides still win inside it. @aparte/core

  • 28b9ead: The branch picker’s arrows are glyphs from the icon provider (so setIconProvider({ prevBranch, nextBranch }) now reaches them), menu and alertTriangle join the built-in glyph set, download and stop are redrawn on the 24-unit grid the rest of the set uses, and a menu that holds a checkable item reserves the check gutter on every item.

    The bubble wrote and as text — hairline characters beside 2-unit SVG strokes in the same row — while the two glyphs already existed and were registered as provider keys nothing read. The app header’s documented toggle drew as text because menu lived only in the extended set behind @aparte/core/icons, and the alert recipe’s documented <aparte-icon name="alertTriangle"> drew a 16px hole for the same reason; core’s documented markup is core’s drawing, so both move in (the extended set no longer exports them). Two of the 28 glyphs were on a 16-unit grid and painted their stroke 50 % heavier than their siblings. The menu’s check gutter was reserved per checkable item, so a plain item beside a checkable one started 16px further left; a panel with any checkable item now reserves it on all of them. @aparte/core

  • 1c5fc64: The two spinners share one stroke, in screen pixels; a determinate ring has a visible track; every pulsing dot pulses in opacity alone, above a named floor (--aparte-pulse-floor); the context gauge’s ring is as heavy as its bar. And the shapes that have to be seen draw themselves: --aparte-track is the ground of a gauge or a skeleton (derived relative to the page), the user bubble is tinted like every other mark, the scrim has a dark value, the scroll rail is as wide as its widest tick and its ticks rest in the control-edge colour. --aparte-spinner-stroke and --aparte-context-ring-stroke are gone (the rings read --aparte-spinner-thickness and --aparte-progress-height).

    The SVG spinner stroked at 2.5 viewBox units — 1.67px in a 16px box, antialiased, 50 % off its CSS sibling — and its track sat at 15 % of the ink, so a determinate 62 % was the percentage of a circle nobody could see; vector-effect: non-scaling-stroke makes the SVG’s weight the CSS ring’s whatever the size. The shared pulse moved in scale as well as opacity, so a row of waiting dots changed width in a loop, and its 0.3 floor left the status dot at 1.55:1 for half of every cycle. A skeleton of one line no longer renders at 60 % of its width. The values on the new tokens are first settings; the names are the fix. @aparte/core

  • d79813f: The spinner, the skeleton, the indeterminate progress bar and the status dot stop under prefers-reduced-motion: reduce instead of flickering.

    The duration tokens were already reset to 0.01ms under that media query, but a 0.01ms cycle with infinite left in place is not stillness: the recipe keeps repainting at a random phase every frame. The descendant sweep in responsive.css only reaches elements inside aparté’s own custom elements, so a recipe used in a consumer’s own markup got neither. Each looping recipe now stops itself with animation: none, the way the spinning icon already did. The skeleton also drops its shine (a stopped gradient sat as a pale band) and the indeterminate bar fills the track (a stopped segment sitting at one spot read as a value). A stylesheet test now asks the same of every looping animation in core. @aparte/core

  • 7774e65: The composer’s box now starts where the transcript’s rows start, at every width: the viewport measures its own inset (padding plus the scrollbar gutter it reserves) and publishes it on the chat host as --aparte-transcript-inset; the composer pads by it, with the old --aparte-viewport-padding as the fallback when no viewport sits beside it.

    Before, the two were independent stacks. The transcript’s rows sat inside a padding plus the gutter the scroller reserves on both edges, the composer inside a flat padding — 10px apart at 768, the gutter’s half apart at 1280 — and the container query that tightens the transcript under 520px could not reach the composer, which is a container of its own. The composer cannot know the gutter and a query cannot cross it, so the element that knows now says it. The property is written on the HOST, not on the viewport: the composer is a sibling, and a custom property only travels down. @aparte/core

  • fee67b7: One focus ring for every control: a 2px outline in --aparte-border-focus, one spacing step OUTSIDE the box (--aparte-focus-outline-offset is var(--aparte-space-1), it was −2px). The soft box-shadow ring (--aparte-focus-ring), the field’s error ring token, the button’s private offset and the select’s --aparte-select-ring/--aparte-select-border-focus knobs are gone; an invalid field’s ring takes the error colour, a field group draws the ring for the field inside it, and the select’s search field is the one documented exception (its ring is inset, an outset one would be clipped by the scrolling panel).

    The kit drew keyboard focus two ways — seventeen recipes with a solid outline, five with a soft wash at 30 % of the accent that measured 1.39:1 against the page, an indicator that was absent rather than weak — and four of the outlines took the control’s intent colour rather than the focus colour. Inside the box, the ring sat 2px from a bordered row’s edge as a second concentric line, and the next row painted over it. The forced-colors block no longer restates outlines that now exist. @aparte/core

  • 735ca53: Every control has a height from one scale — sm 24 · md 32 · lg 36 · xl 40 — and control text is the 14px step: a text button is as tall as an icon button (min-block-size), the field rests at 36 (--aparte-field-size; --sm/--lg one step either side), a button inside a field group takes the field’s height, the select trigger is a field, and the composer’s controls are 36 at rest and the touch target under a coarse pointer (--aparte-composer-control-size, now a declared knob).

    Measured across the previews, 18 of 59 showed two controls side by side at different heights, and the number that kept coming back was 23px: the text button, which had no height at all, beside 24, 29, 32, 36 and 44px neighbours. The scale had three steps that only --icon and --circle read, and a 36px family (send, the input’s action button, the scroll button) that lived off it as literals — it is the named lg step now, and the old 40px step is xl (.aparte-btn--xl; .aparte-btn--lg is 36px, which is what the scroll button already measured). Control text moves from 13px to 14px on the button and the field; --sm and --lg become three distinct steps again. The desktop composer was a 62px bar around 15px of text because its control size defaulted to the touch target everywhere; it is 36 at rest and 44 under (pointer: coarse), which is what that block was for. @aparte/core

  • 212aebd: At a phone’s width the kit folds: the app shell recipe becomes one column under 48rem (the sidebar element already left the grid as a drawer, the grid kept its column anyway), the split’s minimum is min(20rem, 100%) so a pane can never ask for more than the viewport has, and a modal dialog on a phone is a bottom sheet as tall as its content, capped at the screen and clear of the safe areas — it used to stretch a label, a field and two buttons over a 100dvh sheet glued to the physical edges.

    Measured on the 375px captures: the shell gave 259 of its 303px to the sidebar and left the chat a 43px band with the send button cut in half; a 20rem floor on a 375px screen annihilated the end pane to 0px; 586px of empty sheet under a three-control form. @aparte/core

  • 28b9ead: The spinner, the menu, the popover, the tooltip and <aparte-chat> are box-sizing: border-box, so their tokens and an author’s height are the box they paint; a tooltip is as wide as its label.

    Core ships no global reset on purpose, and these recipes set a size and a padding or border in the same rule, so they painted larger than their token under the browser’s default: the spinner 16/20/28 for tokens of 12/16/24, the popover 342px for a cap of 320, <aparte-chat style="height: 320px"> 336px with a split’s seam hanging 16px below both panels — and the token’s value only on a host page with a border-box reset of its own. The tooltip declared a max-width and no width, so as a positioned chip it shrank to its widest word: “Copy to clipboard” broke into two lines at every width. It is width: max-content now, with the same cap. @aparte/core

  • c9529d2: A tool call’s state sits beside the tool’s name, the reasoning block’s chevron sits beside its label, the context gauge’s bar has a measure (16rem), and the starter suggestions take the composer’s column.

    An unbounded margin-inline-start: auto pushed the two ends of one line 554 to 1180px apart on a wide host: the state 596px from the tool name, “Reasoning” 692px from its chevron, a 1046×4px gauge, chips 188px off the composer once the host passed its cap. What belongs to a label sits beside it; what belongs to a column takes its measure. The accordion recipe keeps its chevron at the end — that is what an accordion is. @aparte/core

  • d78b150: <aparte-select> now honours placeholder and disabled written after mount, its presence setters (and <aparte-option>’s, <aparte-optgroup>’s) accept the empty string as ON, the unread grouped attribute is gone, and a loading group says loading from the locale instead of “Fetching models…”.

    Both attributes were observed and neither had a branch in the change callback, so a placeholder rewritten by a locale switch left the visible label and the combobox’s aria-label in the old language, and a select disabled after mount kept a trigger in the tab order, announced as operable. The trigger now takes aria-disabled="true" and tabindex="-1" while disabled (an open dropdown closes), and the label and both aria-labels follow the placeholder. Five setters (open, selected, disabled, collapsed, loading) still read '' as false, so a Svelte 5 template that set them removed the attribute; they use the same spelling as the split and the sidebar now, and one test enumerates all nine presence setters in core. grouped was observed and read by nothing (groups render from <aparte-optgroup> children alone); it leaves the attribute list and the docs. New locale key: loading (default “Loading…”). @aparte/core

  • 9337dd2: Five rendering bugs found by looking at every preview: the reasoning block’s chevron turns again when it opens; an <aparte-icon> inside .aparte-btn takes the button’s icon size; code blocks are set in the code typeface at a code size; the message row’s padding follows the narrow container again; and a turn with nothing to copy shows no copy button. Attachment tiles now use the thumbnail recipe’s part names — aparte-thumbnail__image and aparte-thumbnail__label replace aparte-thumb__img and aparte-thumb__ext — and the composite --aparte-message-padding token is gone (read --aparte-message-padding-block and --aparte-message-padding-inline).

    Each was a form defect, not a palette one. The thinking renderer put its glyph straight into the <summary>, so the accordion recipe’s rotation rule matched nothing — and the recipe’s own documented markup, a bare <aparte-icon> in the header, matched nothing either; both forms are sized and turn now. button.css sized .aparte-btn > svg, and <aparte-icon> renders its svg one level deeper, so the documented markup kept a 14px glyph in a button that asked for 16; the recipe now feeds --aparte-icon-size, the icon’s own knob, which also sizes the accordion chevron. The code block’s <pre> declared no font-family, font-size or line-height and fell into the browser’s generic monospace at the prose’s size — two theme tokens, --aparte-code-block-font-size and --aparte-code-block-line-height, now carry them. --aparte-message-padding joined its two parts on :root, where a custom property is substituted, so the container query that reassigned the parts on .aparte-message never reached the row; a test now refuses any composite token whose parts are redeclared elsewhere. The copy action was offered unconditionally and copied '' on a tool-only turn. The tile parts were drawn twice under two vocabularies, the documented one emitted by nothing; one survives. --aparte-thinking-toggle-size, unread since the chevron became a glyph, is removed. @aparte/core

  • 7826e07: The sidebar’s four regions (header, search, body, footer) indent by one new token, --aparte-sidebar-inset (12px); the selected conversation’s mark follows the row’s radius; and the tool row’s chevron, its part labels and icon, the code header’s language label and the branch picker’s disabled arrows are coloured with the muted ink instead of faded by an opacity.

    Measured on the built previews: the sidebar’s header and footer padded 16 while its search and body padded 12, so a 260px column showed its content on two vertical axes and the app-shell demo four left edges; the 2px selection bar stood square in a 9px-rounded corner with a sliver of the page’s ground between the two; the tool row’s disclosure chevron at opacity: .5 sat at 3.00:1, exactly on the WCAG floor, and it is the control that reveals a delete_file’s arguments; the code language label was already muted and then multiplied by .7; the disabled branch arrow read at 1.74:1 — as absent, not as disabled. Quiet is a colour: opacity on a container fades the glyph with its ground and cannot be reasoned about against any background. The mark is now painted as the first pixels of a row-sized pseudo that inherits the radius — not overflow: hidden on the row, which would clip the title button’s focus ring. @aparte/core

  • 100d089: A [data-aparte-sidebar-toggle] control now carries aria-expanded and aria-controls, kept in step by the sidebar whoever changes the state, and the open drawer keeps Tab inside it.

    The toggle opened and closed the sidebar without announcing its state, while the conversation row’s own button already did; the sidebar gives itself an id when the host wrote none, so the control can point at it. Tab from the drawer’s last control used to walk out under the scrim onto the transcript it was covering; it wraps to the first control now, and Shift+Tab the other way. No focusin guard was added on purpose: it would steal the focus back from a dialog the drawer’s own content opens onto <body>. @aparte/core

  • fee67b7: A skeleton text line holds the place of the line it stands for: its height is the content’s font size and its gap the rest of the content line (--aparte-skeleton-text-height, --aparte-skeleton-text-gap are derived from --aparte-content-font-size and --aparte-content-line-height).

    The bar was 12px on an 18px step while a line of content is 16px on a 27px step, so the text that replaced it jumped by a third of a line per line. A placeholder that does not hold the place it promises is not a placeholder. @aparte/core

  • dc4a7b7: The bubble’s action bar, its branch arrows and the conversation row’s are all the button recipe’s small step (24px); the select trigger declares its own font size and reads the theme’s --aparte-radius-select.

    Three controls redrew their own box over the recipe: the arrows set width and height to a 20px token while the element also carried --sm (24), the did the same at 20, and the action bar fed 28 with a 24 exception for the last user turn — three control heights in one row. They feed the recipe’s token or wear its modifier now, and under (pointer: coarse) the takes the touch-target size like the other four. --aparte-branch-picker-btn-size and --aparte-branch-picker-btn-icon-size are gone; --aparte-action-bar-btn-size and --aparte-conv-action-btn-size default to var(--aparte-btn-size-sm). The select’s trigger declared no font-size at all and took the host page’s, so every integrator saw a different select; it reads the control step. Its radius existed twice under two names with two values — the private --aparte-select-radius is gone, the theme’s --aparte-radius-select stays. @aparte/core

  • fee67b7: The split’s seam is a 1px line (--aparte-split-seam-width, the kit’s border width) painted inside a 12px track (--aparte-split-handle-size, it was the 4px painted seam), with a grip under the pointer and while dragging.

    One token sized both the grid track and the painted line, so the seam could not be thinned without moving the layout; at 4px it was four times the kit’s rule and had nothing to take hold of — an interaction drawn as a decoration. The panes give up 8px between them; the grab zone is what it was on a fine pointer and the touch target on a coarse one. @aparte/core

  • 1f89afc: The segmented tab track is as wide as its chips (not its container), its selected chip is raised on both grounds, the tab panel shares the tab’s inline inset; the elicitation’s recommended option keeps its ground while focused, and the options sit far enough apart for the focus ring to show whole.

    .aparte-tabs--segmented was a block-level flex row and painted 1207px of track for 160px of chips at 1280; it is inline-flex. Its selected chip was an absolute surface level — raised in light, sunken in dark — and now carries a 1px ring in the border colour. The panel had no inline padding, so its text hung 11px left of the tab above it. In the elicitation panel the recommended option, the one that takes focus on mount, was the only row with no ground: the rule that cleared its tinted border under focus cleared its background too. And the options sat 2px apart, narrower than the focus ring’s outset, so the next row painted over the ring’s bottom edge; the gap is 6px. @aparte/core

  • dc4a7b7: data-side="top | bottom | start | end" places a tooltip against its trigger — wrap the trigger in .aparte-tooltip-anchor — and turns the arrow to match; --aparte-tooltip-gap is the distance. No inline positioning needed any more.

    The recipe drew the box and the arrow and left the placement to two inline styles in its own example. A demo that needs inline styles to work is a recipe with a parameter it forgot. Flipping a tooltip that would leave the viewport stays out: that needs script, and it is a positioning library’s job. Without data-side nothing is positioned, as before. @aparte/core

  • 54ab107: The type ramp rises in the order of its names: --aparte-font-size-lg is 1.0625rem (above the body’s base, it was 0.875rem — below it), and --aparte-font-size-xl (1.25rem) and --aparte-font-size-2xl (1.5rem) exist. Every reader of the old lg moved to the step it meant: the text a person types is the body size, a sender name sits one step under the prose, a card title is above its body, an elicitation question is larger than its options, a dialog title takes the new lg, the large field and the large buttons speak at the body size.

    Measured: a welcome title and a placeholder at the same size, a card’s title smaller than its body, a full-screen dialog’s title at 14px, and the typed text the smallest in the chat. A scale whose name lies is worse than a short one. The artifact card’s labels that read lg for “a notch above the control text” now read base or md, so they keep their size. @aparte/core, @aparte/plugin-artifacts

  • 7e5910a: <aparte-model-selector disabled> disables the picker, and inside an <aparte-composer> the picker follows the composer’s own disabled — it used to stay fully operable while the field and the send button around it were inert. @aparte/plugin-model-selector

  • d78b150: Stops writing the grouped attribute on its <aparte-select>: the select never read it, groups render from the <aparte-optgroup> children alone. @aparte/plugin-model-selector

  • 2e8f3ed: approvalWaiting reads « En attente » (was « en attente de vous »): one capitalised word, the shape every other tool state uses in the row. @aparte/locale-fr

  • d78b150: Adds loading (“Chargement…”), the text an option group shows while its options are fetched. @aparte/locale-fr

Version-only bumps (no changes of their own): @aparte/engine, @aparte/provider-ai-sdk, @aparte/provider-openai-compat, @aparte/provider-scenario, @aparte/provider-transformers, @aparte/plugin-approval, @aparte/plugin-ask-user, @aparte/plugin-compaction, @aparte/plugin-marked, @aparte/plugin-shiki, @aparte/plugin-streaming-markdown, @aparte/angular, @aparte/react, @aparte/svelte, @aparte/vue, @aparte/docs-mcp.