Repository navigation
feat(app-shell): the copilot's applied card opens the change review and undoes the draft; the badge follows an in-turn publish; the chat fits the 1010 px slot (objectui#12894, objectui#12725 phase 6) - #12964
Merged
objectstack-fleet[bot] merged 1 commit intoOct 18, 2026
Merged
Conversation
…nd undoes the draft; the badge follows an in-turn publish; the chat fits the 1010 px slot (objectui#12894, objectui#12725) - ChatPane passes onReviewDrafts / onDiscardDrafts to ChatbotEnhanced. Review opens Studio's Changes drawer through its one declared way in, `?changes=review` (studioChangesLink.ts): in place inside the package's Studio, a navigation to the package's Studio from anywhere else. Undo is the SDK client's packages.discardDrafts, then the bus pulse. - StudioDesignSurface reads `?changes=review`, opens the drawer to review and drops the param. - ChatPane's authoring pulse also fires on a non-replay `published` result (detectAuthoringVerdict): cloud's in-turn auto-publish. - The chat column is `min-w-0`, so a tool card's nowrap summary no longer widens the chat past the Studio copilot's slot. Claude-Session: https://claude.ai/code/session_01Cbdek8SKSHxddGqTPZXdqX Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Oct 18, 2026
Contributor
Author
席位核对 · ACCEPT ·
|
This was referenced Oct 18, 2026
objectstack-fleet
Bot
deleted the
claude/issue-12725-copilot-composer-wiring
branch
October 18, 2026 13:32
This was referenced Oct 18, 2026
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.
Fixes #12894
Part of #12725
Clause-②: no
objectui#12725 phase 6, carrying objectui#12894's console wiring (both cards are claimed for this branch). This is a draft by a dispatched developer; the seat lands it.
What changes
ChatPane(objectui#12894). The card the copilot draws after it saves a change as a draft (objectstack-ai/cloud#2924) now shows 查看变更并发布 and 撤销 in the console. Both props landed in PR feat(plugin-chatbot,i18n): the copilot's change card draws the draft posture, and the applied card offers review and undo (objectui#12894) #12951; until now no host passed them, so the card kept its old inline Publish.POST /api/v1/packages/:id/discard-draftsfor the card's package through the SDK client the console's adapter holds (packages.discardDrafts, typed by the spec'sDiscardPackageDraftsResponse). A draft the server could not drop is a failure the card shows, with the server's reason. Either way the assistant bus pulses (emitMetadataRefresh), so the Studio 变更 badge re-reads its ledger.?changes=review(newstudioChangesLink.ts).StudioDesignSurfacereads it, opens the drawer in its review posture and drops it (replace), the way the metadata designer consumes?review=1. Inside the package's Studio (the copilot) the parameter goes onto the current location, so the surface stays mounted with its pillar and selection. From anywhere else (the full-page chat, the console dock) the link opens the package's Interfaces pillar with it.ChatPane's authoring pulse now also fires on a tool result thatdetectAuthoringVerdict(exported byplugin-chatbot) classifies, which covers a non-replaystatus: 'published'answer. That is cloud'smaybeAutoPublish: it publishes in the turn, which promotes every pending draft of the package, and rewrites the envelope. The chat lifts neitherdraftReviewnorreplayOutcomefrom it, so before this the badge kept the swept drafts as pending.ChatPane([data-chat-column]) is nowmin-w-0. See "The culprit" below.Premise, re-read on
main(b5153f44)ChatbotEnhanceddeclaresonReviewDraftsandonDiscardDrafts;ChatPanepassed neither.StudioDesignSurface'schangesOpenwas component state with no URL parameter and no bus event. Holds.ChatPane's pulse predicate wastool.draftReview || tool.replayOutcome. Holds: the new pulse case below is red on the base file.draftedcard); see "The culprit".mainfor the real Studio copilot. The Studio copilot resolves thebuildagent (cloud'sBUILD_AGENT_NAME) and passes its package aseditPackageId, soChatPanehandsChatbotEnhancedconsole.ai.askOrChangeApp, whose zh string is exactly that sentence.studio_copilotis the name phase 5's live driver gave its stub agent; the console does not resolve it as the build agent, so that driver's composer read 「向 Studio Copilot 提问…」. Measured live (agentbuild) and pinned in the Studio harness below; that case is green on the base file too.The measured chain (file and symbol)
ChatbotEnhancedAppliedDraftCardonReview→ChatPanereviewDrafts→studioChangesReviewTarget(studioChangesLink.ts) →navigate→StudioDesignSurface(useSearchParams,STUDIO_CHANGES_PARAM) →setChangesPosture('review')+setChangesOpen(true)→DraftChangesPanelopen.AppliedDraftCardonDiscard→requestDiscardDrafts(asks first when other drafts are pending, as PR feat(plugin-chatbot,i18n): the copilot's change card draws the draft posture, and the applied card offers review and undo (objectui#12894) #12951 drew it) →ChatPanediscardDrafts→useAdapter().getClient().packages.discardDrafts(packageId)→POST /api/v1/packages/:id/discard-drafts(frameworkdiscardPackageDrafts) →emitMetadataRefresh→usePendingDrafts(subscribeMetadataRefresh) →GET /api/v1/meta/_drafts?packageId=→studio-changes-count.ChatPane's announcement effect (announcedAuthoringRef) →detectAuthoringVerdict(tool.result)besidedraftReview/replayOutcome→ the sameemitMetadataRefresh.The culprit (item 4)
Measured live at 1010 x 900 with phase 5's thread (a non-replay
draftedcard, then English narration). The probe lays the chat column out at its min-content width (342 px), then hides one element at a time and keeps those whose absence brings it down to the slot's 300 px. The deepest one is the draft card's summary,span.min-w-0.flex-1.truncate(nowrap; its own min-content is 296 px), in the card's publish row (发布 (1) plus the summary, 320 px).min-w-0andtruncateon the span only take effect when an ancestor bounds the width. The chat column is a flex item, and a flex item's automatic minimum width is its content's min-content. So the summary's whole text widened the column, the chat panel inside it, and everything in the panel: the share button, the bubbles and the composer.ai-chat-panelThe fix is the one token on the column, inside the claimed file. No
plugin-chatbotchange.Item 3: the composer chip — stopped, as the dispatch asks
The chip naming the item in view exists:
plugin-chatbot'ssurfaceContextLabelchip, which the Studio copilot already fills (「正在讨论:任务」 live). The artboard's 「借阅看板 ×」 is removable and sits in the composer's footer.plugin-chatbotdeclares no prop for a remove control, and the chip's placement is its own rendering, so this line stops here. It is an open question in the report (a newplugin-chatbotprop would make that roundClause-②: yes). The draft marks (草稿 chip, 来源 line) are not this round; they wait on objectstack-ai/objectstack#24298.Tests
New or extended, all in
packages/app-shell:StudioDesignSurface.copilotDoors-12894.test.tsx(6). The real surface, the real Studio copilot (StudioChatDock→StudioCopilotConversation→ChatPane) and the realChatbotEnhanced, fed the producer'schanges_proposedcard and its confirm replay (draftedwithappliedCard). Cases:?changes=reviewopens the drawer and drops the parameter;discardDrafts('app.hcpl'), the card reads 已撤销 and the badge goes away;object/hcpl_borrowing: …on the card and still pulses once.AiChatPage.appliedCardDoors-12894.test.tsx(7). Review from the full-page chat goes to/studio/app.hcpl/interfaces?changes=review; on the package's pillar it keeps the path and?surface=and adds the parameter; CONTROL: on another package's Studio, the card's own package opens. Undo resolves{ ok: true }and passes the package id; a thrown request resolves{ ok: false, error }; CONTROL: with no adapter, no 撤销 is offered. The chat column carriesmin-w-0.StudioDesignSurface.copilotDraftBadge-12725.test.tsx(+1, now 6): a non-replaypublishedresult re-reads the badge as it lands (2 → none), with exactly one pulse.Results:
a1babb11: the three files, 18 tests passed (VERDICT command-exit 0), and the composer case in its own run of its file (6 of 6). All 19 are in the whole-package run below.AiChatPage.tsxandStudioDesignSurface.tsx(b5153f44blobsad1d0a6041b1/adb0557ca0fc) checked out over the committed tests. 13 failed and 6 passed. The six are phase 5's five cases plus the placeholder case, which already holds. The published case fails with an AssertionError saying the badge's SPAN, still reading 2, was expected to be null (the tag is spelled as a word here because GitHub strips tag-shaped text). Restored withgit checkout HEAD --: blobs equal to HEAD (cf440a8cc984/30523c1a60ce),git diff HEAD0 bytes.scripts/ablation-replace.mjs, wrap mode; nodiststep, since the tests importapp-shellsource relatively):onReviewDrafts={reviewDrafts}: anchor 1 → 0, blobcf440a8cc984→cc06b4b1962a. 5 failed and 8 passed: the four review cases, plus the no-adapter CONTROL, whose other half asserts the review door.onDiscardDrafts={dataSource ? discardDrafts : undefined}: anchor 1 → 0. 4 failed and 9 passed: the four undo cases.git diff HEADis empty'. After both legsgit status --porcelainis empty.pnpm exec vitest run --maxWorkers=2 --shard=K/8 packages/app-shell/, sharded through the verify lock because one run exceeds the 10-minute foreground cap, ata1babb11. All 8 shards: VERDICT command-exit 0. Files per shard: 194/197/197/196/196 (1 skipped)/196/197/197, so 1570 run of the 1570 tracked test files (git ls-filescount), 1569 passed and 1 skipped. Tests: 14758 passed, 9 skipped.origin/mainmoved one commit since the branch was cut (7f9cc37d, i18n console copy). It touches none of these files and merges cleanly (git merge-treeexit 0), so the branch was not re-merged.Gates
Local, with each exit code captured before any pipe:
pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build: VERDICT command-exit 0.pnpm --filter @object-ui/app-shell type-check(tsc --noEmit && tsc -p tsconfig.test.json): exit 0, 0error TS.tsconfig.test.json --listFilesOnlylists all 3 test files.AiChatPage.tsx34 to 34;StudioDesignSurface.tsx13 to 14 (onereact-hooks/set-state-in-effect, the effect that consumes?changes=review; the rule iswarnineslint.config.jsand not ratcheted); the new files 0.a1babb11:check:new-line-citations,check:control-bytes,check:test-path-roots,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:changeset-claims,check:pending-changeset-literals,changeset:check,node scripts/check-changeset-presence.mjs,check:spec-symbols,check:phantom-deps,check:self-import,check:esm-specifiers,check:unreferenced-sources,check:handler-key-reads,check:metadata-write-doors,check:comment-mask-corpus,check:i18n-keys,check:doc-json,check:doc-fences,check:doc-types,check:doc-example-ids,check:doc-example-readers,check:shell-escape-residue.check:doc-snippetsandcheck:doc-examplesanswered PRECONDITION NOT MET (exit 2): 7 packages they resolve against are unbuilt here. The docs change is one table row with no code fence. CI runs both.check:readme-exports(no README in the diff; it also stopped on an unbuiltplugin-gantt) andcheck:eager-closure(it weighs the consoledist). CI covers both.objectui has no
dispatch-gates.mjs. The list above is the rootpackage.jsoncheck:*scripts whose scan roots readapp-shellsource, test files,.changeset/orcontent/docs. CI's check-runs are the merge gate.Evidence
Branch
claude/issue-12725f-evidenceat2301a354,evidence/12725f/: screenshots at 1010 and 1280 px (zh-CN), the JSON readings, the driver and a README. The screenshots show:location.href, same navigation entry count);Deviations
MetadataClient(@object-ui/data-objectstack) has no discard method, and adding one would widen that published package's surface (Clause-②: yes) and leave the claimed file surface. The SDK client the console's adapter already holds declares the route (packages.discardDrafts) with the spec's response type, so this adds no API anywhere and no second bare fetch.PackagesPage's own bare call is untouched (not this card).views/studio-design/studioChangesLink.ts(the parameter's one definition, not exported from the package entry). Also one row incontent/docs/guide/console.md(AGENTS.md Add automated testing infrastructure and CI/CD workflows #2). Nothing else outside the claim.Clause-②: no, with one thing for the seat to judge: no export, prop, spec key or language-pack key changes. The Studio route reads one new page-scoped URL parameter,changes, which is page-scoped like?surface=and not inurlParams.ts's reserved registry.build(cloud's real build agent), not phase 5'sstudio_copilot. That is why the pending-drafts bar appears in these shots (below).Acceptance notes
buildagent,ChatPanedrawsPendingDraftsBar(objectui#5694) while a draft is pending. In the copilot's slot it sits over the composer's input line, at 1010 and at 1280 (the evidence shotsdoors-*-2-applied-card.png,after-*-slot-fits.png). This is onmaintoo, untouched here; phase 5's stub agent never drew it. It is reported to the seat as a finding: whether Studio, whose top bar already carries 变更 and 发布, should draw that bar at all is a design call, not a mechanical change.Session:
https://claude.ai/code/session_01Cbdek8SKSHxddGqTPZXdqXGenerated by Claude Code