chore: release packages - #3248
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
github-actions
Bot
force-pushed
the
changeset-release/main
branch
6 times, most recently
from
August 3, 2026 09:33
14cdb09 to
889fade
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
August 3, 2026 09:48
889fade to
e17ce78
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@object-ui/console@17.2.1
Patch Changes
@object-ui/app-shell@17.2.1
Patch Changes
12bf669: The record discussion panel now says "loading" while it is loading, instead of
"No comments yet" (objectui#3209).
FROM: opening any record page showed the discussion/chatter panel asserting
No comments yetfor the whole first leg of the page, then contradictingitself when the comments appeared. TO: the panel shows the loading row until
the feed has actually answered, and only then commits to "this record has no
comments".
objectui#3205 gave
RecordActivityTimelinethe render branch that prefers aloading row over the empty copy, and
RecordChatterPanelalready forwardedloadingto it in both positions — but on the chatter chain nothingproduced the signal, so that branch could never fire.
record:activitycomputes its own flag and was visibly fixed by
RecordActivityTimeline收下loading却完全不读——取数中的 feed 显示的是"暂无活动" #3205; chatter was not. Thefour wiring points are one chain and are all closed here, because any one of
them left open still ships the empty copy to some user:
RecordDetailView— the host that OWNS the feed fetch — now derives afeedLoadingflag from its two reads (sys_comment+sys_activity);<DiscussionContextProvider loading={feedLoading}>publishes it (the fieldwas already declared on
DiscussionContextValue, and already read byrecord:activity);<RecordChatterPanel loading={feedLoading}>— the panelauthored pages get when they place no discussion slot — receives it
directly;
record:chatter/record:discussionrenderer forwardsloading={discussion?.loading}, so a hand-placed block is on the samechain as the synthesized one.
The two reads run in parallel, so the flag closes over both: it clears on
Promise.allSettled, and a REJECTED read counts as an answer. A deploymentwithout the audit plugin 404s
sys_activityand an object withenable.feeds: false403ssys_comment; neither may pin the panel in apermanent spinner, which would be a worse bug than the one being fixed. The
flag is keyed by
object:recordIdrather than being a plain boolean, so thefirst render of a record already reads as loading (no one-frame flash of the
empty state) and navigating between records cannot show the previous record's
settled answer.
No tolerance was added at the consumer. The timeline still does not guess that
"no items yet and just mounted" means loading — that guess is wrong the moment
a record genuinely has no comments, and the signal belongs to whoever owns the
fetch. Same shape as objectui#3165 /
RecordActivityTimeline收下loading却完全不读——取数中的 feed 显示的是"暂无活动" #3205: divergence converges at theproducer.
30ac2e1:
ToolPreviewstops advertising retiredToolSchemaflags (objectui#3236).The metadata-admin tool preview painted a header strip of flag pills read
straight off the raw draft:
Requires confirmation,Active/Disabled,built-in, and thecategorytag. All four keys have been removed from@objectstack/spec'sToolSchema—requiresConfirmationin the 16.x line(objectstack#3715, ADR-0033 §2) and
category/active/builtInin17.0.0 (objectstack#3896 audit close-out). The schema is
.strict()and nowrejects each by name with an upgrade prescription, so no newly authored tool
can carry them; verified against the
@objectstack/spec@17.0.0-rc.1this repodepends on.
New metadata could not reach these pills — but rows stored before the removals
still carry the keys, and for those the preview kept rendering. That is the
harmful direction, not a cosmetic one:
Requires confirmationadvertised a safety pause that no execution path hasever performed. Nothing read the key — not the LLM tool set (a tool reaches
the model as name/description/parameters only), not
ToolRegistry.execute,not
POST /ai/tools/:name/execute. A reviewer reading the preview saw adestructive tool marked as gated when it was not. The real gate is
action.ai.requiresConfirmation, which the HITL approval queue reads.Disabledclaimed a tool had been withdrawn whileToolRegistry.getAll()kept handing it to the LLM and the execute route kept running it.
Same shape as objectui#2962: a UI badge advertising a capability the runtime
does not have. The pills are gone; the surviving header strip shows label,
machine name and the
objectNamepill (objectNameis still a live spec key),and nothing else in the preview changed — parameters table, example LLM call
and output schema are untouched.
New tests feed the preview a stale draft that still carries all four retired
keys and assert none of them renders, so the pills cannot grow back: the names
survive in the spec's tombstone guidance, which gives the next reader a
plausible-looking reason to "restore" them.
Updated dependencies [825bbe3]
Updated dependencies [d2363e7]
Updated dependencies [a321fa4]
@object-ui/auth@17.2.1
Patch Changes
@object-ui/cli@17.2.1
Patch Changes
@object-ui/collaboration@17.2.1
Patch Changes
@object-ui/components@17.2.1
Patch Changes
825bbe3: The option widgets' "this list cannot be filled" message now has one source, and
it is translated (objectui#3231).
FROM:
SelectField,MultiSelectField,RadioFieldandCheckboxesFieldeachcarried their own copy of the empty/gated state, each destructured the declared
emptyHintprop into_emptyHintand dropped it, and each rendered a hardcodedEnglish literal (
'No options available',`Select ${…} first`) even in aChinese or Japanese session. TO: one shared
OptionsEmptyState— the host'semptyHintwhen it supplied one, otherwise a translated fallback(
fields.options.empty/fields.options.selectFirst, added to all ten localepacks).
emptyHintwas declared, produced by the form renderer and transported, thenlost three times over — so no registered widget could ever render it. All three
breaks are fixed, because closing only the last one delivers nothing:
isOptionFieldcompared the raw resolved type against'select'/'radio'/'multiselect'/'checkboxes'. Object-derived forms emitmapFieldTypeToFormType's prefixed ids (field:select), which matched none ofthem, so for every option field coming from an object schema — the normal case
in the console — the whole cascade block was skipped and no hint was computed
at all. It now normalizes the
field:prefix, the same normalizationstripRegisteredFieldPropsalready applied a few lines below.stripRegisteredFieldPropsthen removed theemptyHintkey from what wasleft. It is now forwarded to the four cascade option types, alongside
dependentValues. This stays an allow-list rather than a blanketpass-through: every other registered widget spreads its leftover props onto a
DOM node, where an unknown
emptyHintattribute is a React warning....propsspreadwas correct; not using it afterwards was not.
User-visible effect: a dependency-gated option list now prompts with the
controlling field's label ("Select Country first") instead of its raw
metadata name, in the session's language; an unconfigured list says so in the
session's language too. The gate sentence is one i18n key shared by the renderer
and the widget fallback, so the two sides cannot word it differently.
Untouched: the built-in (unregistered)
selectbranch of the form renderer,which already consumed
emptyHint. That is a separate live path.Updated dependencies [825bbe3]
@object-ui/core@17.2.1
Patch Changes
@object-ui/data-objectstack@17.2.1
Patch Changes
@object-ui/fields@17.2.1
Patch Changes
825bbe3: The option widgets' "this list cannot be filled" message now has one source, and
it is translated (objectui#3231).
FROM:
SelectField,MultiSelectField,RadioFieldandCheckboxesFieldeachcarried their own copy of the empty/gated state, each destructured the declared
emptyHintprop into_emptyHintand dropped it, and each rendered a hardcodedEnglish literal (
'No options available',`Select ${…} first`) even in aChinese or Japanese session. TO: one shared
OptionsEmptyState— the host'semptyHintwhen it supplied one, otherwise a translated fallback(
fields.options.empty/fields.options.selectFirst, added to all ten localepacks).
emptyHintwas declared, produced by the form renderer and transported, thenlost three times over — so no registered widget could ever render it. All three
breaks are fixed, because closing only the last one delivers nothing:
isOptionFieldcompared the raw resolved type against'select'/'radio'/'multiselect'/'checkboxes'. Object-derived forms emitmapFieldTypeToFormType's prefixed ids (field:select), which matched none ofthem, so for every option field coming from an object schema — the normal case
in the console — the whole cascade block was skipped and no hint was computed
at all. It now normalizes the
field:prefix, the same normalizationstripRegisteredFieldPropsalready applied a few lines below.stripRegisteredFieldPropsthen removed theemptyHintkey from what wasleft. It is now forwarded to the four cascade option types, alongside
dependentValues. This stays an allow-list rather than a blanketpass-through: every other registered widget spreads its leftover props onto a
DOM node, where an unknown
emptyHintattribute is a React warning....propsspreadwas correct; not using it afterwards was not.
User-visible effect: a dependency-gated option list now prompts with the
controlling field's label ("Select Country first") instead of its raw
metadata name, in the session's language; an unconfigured list says so in the
session's language too. The gate sentence is one i18n key shared by the renderer
and the widget fallback, so the two sides cannot word it differently.
Untouched: the built-in (unregistered)
selectbranch of the form renderer,which already consumed
emptyHint. That is a separate live path.a321fa4:
TextAreaField's mobile fullscreen flag converges on its one real producer(objectui#3232).
FROM: the widget resolved the "show the expand affordance" decision through a
four-way
??chain — amobileFullscreen(camelCase) prop, the fieldmetadata's
mobile_fullscreen, amobile_fullscreenprop, andschema.mobile_fullscreen. TO: a single read of the field metadata'smobile_fullscreen, resolved through thefield || schemacarrier pair everywidget in this package already uses.
No runtime behaviour changes, because three of those four reads were
permanently
undefined:mobileFullscreen(camelCase) had no producer anywhere in the repo — theonly occurrences of that spelling were the widget's own read and the
destructure that kept it off the DOM spread. The doc comment nonetheless
claimed "the host form passes
mobileFullscreen", so the contract itdescribed had never held.
mobile_fullscreenas a prop cannot arrive: the form renderer'sstripRegisteredFieldPropsexplicitly removesmobile_fullscreenandfullscreenfrom the props forwarded to registered field widgets.schema.mobile_fullscreenwas the same objectfield || schemaalreadyresolves, so it could only ever restate the metadata read.
What actually drives the affordance — and is now the only thing that does — is
the field metadata flag
ObjectFormstamps onto long-text fields fromObjectFormSchema.mobile.fullscreenLongText. That path is unchanged and is nowpinned by tests (button, dialog, and the committed edit), so the cleanup cannot
have silently removed the working behaviour.
Also untouched: the built-in (unregistered)
textareabranch of the formrenderer, which reads
mobile_fullscreen || fullscreenoff the form-fieldprops and renders its own
FullscreenTextarea. That is a separate live path.Why this is worth a changeset rather than a silent tidy-up: reads that nobody
writes are not free. They document a contract that does not exist — the next
author follows the comment, passes the prop, and is ignored without a word —
and a
??chain that accepts four spellings and rejects none is exactly wherea misspelled key hides. With one source, a wrong spelling has no read path left
to absorb it. Per AGENTS.md #0.1 and Prime Directive [WIP] Enhance UI components for forms and layouts #12, divergence like this
converges at the producer, not by accumulating tolerance at the consumer. No
host-override prop was invented in its place: inventing a key with no producer
is the same mistake in the other direction.
Updated dependencies [825bbe3]
@object-ui/i18n@17.2.1
Patch Changes
825bbe3: The option widgets' "this list cannot be filled" message now has one source, and
it is translated (objectui#3231).
FROM:
SelectField,MultiSelectField,RadioFieldandCheckboxesFieldeachcarried their own copy of the empty/gated state, each destructured the declared
emptyHintprop into_emptyHintand dropped it, and each rendered a hardcodedEnglish literal (
'No options available',`Select ${…} first`) even in aChinese or Japanese session. TO: one shared
OptionsEmptyState— the host'semptyHintwhen it supplied one, otherwise a translated fallback(
fields.options.empty/fields.options.selectFirst, added to all ten localepacks).
emptyHintwas declared, produced by the form renderer and transported, thenlost three times over — so no registered widget could ever render it. All three
breaks are fixed, because closing only the last one delivers nothing:
isOptionFieldcompared the raw resolved type against'select'/'radio'/'multiselect'/'checkboxes'. Object-derived forms emitmapFieldTypeToFormType's prefixed ids (field:select), which matched none ofthem, so for every option field coming from an object schema — the normal case
in the console — the whole cascade block was skipped and no hint was computed
at all. It now normalizes the
field:prefix, the same normalizationstripRegisteredFieldPropsalready applied a few lines below.stripRegisteredFieldPropsthen removed theemptyHintkey from what wasleft. It is now forwarded to the four cascade option types, alongside
dependentValues. This stays an allow-list rather than a blanketpass-through: every other registered widget spreads its leftover props onto a
DOM node, where an unknown
emptyHintattribute is a React warning....propsspreadwas correct; not using it afterwards was not.
User-visible effect: a dependency-gated option list now prompts with the
controlling field's label ("Select Country first") instead of its raw
metadata name, in the session's language; an unconfigured list says so in the
session's language too. The gate sentence is one i18n key shared by the renderer
and the widget fallback, so the two sides cannot word it differently.
Untouched: the built-in (unregistered)
selectbranch of the form renderer,which already consumed
emptyHint. That is a separate live path.@object-ui/layout@17.2.1
Patch Changes
d2363e7: The legacy
page-headeralias stops advertisingdescriptionas an authorablekey (objectui#3226).
FROM:
registerLayout()declaredinputs: [title, description]. TO:inputs: [title, subtitle]— the key@objectstack/spec/ui'sPageHeaderPropsdeclares, and the one the canonical
page:headerrenderer in@object-ui/componentsalready declares.inputsis a DECLARATION surface, not documentation: the designer builds itsproperty palette from it, and the framework's
check:react-declaration-paritydiffs it against the spec schemas. Declaring
descriptiontherefore did notmerely tolerate a legacy spelling — it published a second dialect for the one
concept the protocol calls
subtitle, and told authors (an AI author mostreadily, since the registry is what it reads to learn the shape) that the
non-spec key was legal. Metadata that took the offer renders a subtitle under
page-headerand silently loses it underpage:header: same JSON, two results,which is the outcome a single contract exists to prevent.
No runtime behaviour changes.
PageHeaderstill readssubtitle ?? description,deliberately: this alias exists for out-of-repo consumer schemas, so "no in-repo
author writes
description" (verified — zero hits) is not evidence that nobodydoes, and dropping the read today would delete an external page's second line
while its title kept rendering, the least reportable failure mode there is. That
read is retired together with an ADR-0087 D2 conversion entry
(
page-header-subtitle-alias,description→subtitlerewritten at loadtime), which lives in the framework repo and is tracked separately. Narrowing the
declaration did not need to wait on it and breaks no consumer; leaving the
declaration wrong in the meantime keeps minting the metadata the conversion would
then have to absorb.
New tests pin both halves so neither can drift back: the registration may not
declare
description, must declaresubtitle, and — checked against the spec'sown shape rather than a hand-written allowlist — may declare nothing
@objectstack/specdoes not; while the runtime fallback is pinned as a sequencingguard, to be deleted in the same change that lands the conversion entry.
Updated dependencies [825bbe3]
@object-ui/mobile@17.2.1
Patch Changes
@object-ui/permissions@17.2.1
Patch Changes
@object-ui/plugin-ai@17.2.1
Patch Changes
@object-ui/plugin-calendar@17.2.1
Patch Changes
@object-ui/plugin-charts@17.2.1
Patch Changes
@object-ui/plugin-chatbot@17.2.1
Patch Changes
@object-ui/plugin-dashboard@17.2.1
Patch Changes
@object-ui/plugin-designer@17.2.1
Patch Changes
@object-ui/plugin-detail@17.2.1
Patch Changes
12bf669: The record discussion panel now says "loading" while it is loading, instead of
"No comments yet" (objectui#3209).
FROM: opening any record page showed the discussion/chatter panel asserting
No comments yetfor the whole first leg of the page, then contradictingitself when the comments appeared. TO: the panel shows the loading row until
the feed has actually answered, and only then commits to "this record has no
comments".
objectui#3205 gave
RecordActivityTimelinethe render branch that prefers aloading row over the empty copy, and
RecordChatterPanelalready forwardedloadingto it in both positions — but on the chatter chain nothingproduced the signal, so that branch could never fire.
record:activitycomputes its own flag and was visibly fixed by
RecordActivityTimeline收下loading却完全不读——取数中的 feed 显示的是"暂无活动" #3205; chatter was not. Thefour wiring points are one chain and are all closed here, because any one of
them left open still ships the empty copy to some user:
RecordDetailView— the host that OWNS the feed fetch — now derives afeedLoadingflag from its two reads (sys_comment+sys_activity);<DiscussionContextProvider loading={feedLoading}>publishes it (the fieldwas already declared on
DiscussionContextValue, and already read byrecord:activity);<RecordChatterPanel loading={feedLoading}>— the panelauthored pages get when they place no discussion slot — receives it
directly;
record:chatter/record:discussionrenderer forwardsloading={discussion?.loading}, so a hand-placed block is on the samechain as the synthesized one.
The two reads run in parallel, so the flag closes over both: it clears on
Promise.allSettled, and a REJECTED read counts as an answer. A deploymentwithout the audit plugin 404s
sys_activityand an object withenable.feeds: false403ssys_comment; neither may pin the panel in apermanent spinner, which would be a worse bug than the one being fixed. The
flag is keyed by
object:recordIdrather than being a plain boolean, so thefirst render of a record already reads as loading (no one-frame flash of the
empty state) and navigating between records cannot show the previous record's
settled answer.
No tolerance was added at the consumer. The timeline still does not guess that
"no items yet and just mounted" means loading — that guess is wrong the moment
a record genuinely has no comments, and the signal belongs to whoever owns the
fetch. Same shape as objectui#3165 /
RecordActivityTimeline收下loading却完全不读——取数中的 feed 显示的是"暂无活动" #3205: divergence converges at theproducer.
Updated dependencies [825bbe3]
@object-ui/plugin-editor@17.2.1
Patch Changes
@object-ui/plugin-form@17.2.1
Patch Changes
@object-ui/plugin-gantt@17.2.1
Patch Changes
@object-ui/plugin-grid@17.2.1
Patch Changes
@object-ui/plugin-kanban@17.2.1
Patch Changes
@object-ui/plugin-map@17.2.1
Patch Changes
@object-ui/plugin-markdown@17.2.1
Patch Changes
@object-ui/plugin-report@17.2.1
Patch Changes
@object-ui/plugin-timeline@17.2.1
Patch Changes
@object-ui/plugin-tree@17.2.1
Patch Changes
@object-ui/plugin-view@17.2.1
Patch Changes
@object-ui/providers@17.2.1
Patch Changes
@object-ui/react@17.2.1
Patch Changes
@object-ui/runner@17.2.1
Patch Changes
@object-ui/create-plugin@17.2.1
@object-ui/plugin-list@17.2.1
@object-ui/react-runtime@17.2.1
@object-ui/sdui-parser@17.2.1
@object-ui/types@17.2.1
object-ui@17.2.1
Patch Changes