Repository navigation
Fix built-app browser launch, chat links, exports and runtime isolation - #392
Merged
Merged
Conversation
…rden built apps
Launch in browser: the desktop sent the browser to its secret-only proxy,
which answered an empty 403 ("Access to 127.0.0.1 was denied"). The launch
route now also returns the daemon's own loopback url; the desktop, the
in-chat preview and `biorouter apps open` send the browser there, and the
launch page opens in the default web browser. Failures are reported.
Build chat: the button checks the chat through the privacy-gated session
read, is grayed out with a visible reason when the chat is gone, and never
opens a dead tab.
Export: one shared implementation (agent_drafter/export.rs) behind
export_app, POST /apps/{id}/export (zip) and the desktop. Full mode,
bundle-daemon, exec bits, binary files and the raw entry page now work;
workspace, vault and key files never travel; launchers install into the
right store per OS and never clobber another app.
Also: ship a pinned esbuild with the desktop and harden the fallback
bundler, serialise and atomically write builds, show build failures,
hash-pin authored inline scripts for static apps, idempotent assembly,
figure frames with their own policy, app_uid-keyed sessions, delete
hygiene, a Fetch Metadata navigation gate for app pages and the serve
shell, and broken-manifest listing.
Open review findings and remaining verification are recorded in
docs/agent-drafter/built-apps-hardening-handoff.md.
Broccolito
marked this pull request as ready for review
October 11, 2026 08:27
Broccolito
added a commit
that referenced
this pull request
Oct 12, 2026
Semantic fixes made inside the merge (merge plan 2026-10-12, section 4): - 4.1 routes/apps.rs opening_is_not_activity_app_tests: the test manifest sets app_uid: None, and load_page mints the socket token the way serve_index does, ws_token_for(app, manifest.app_uid.as_deref()) from the stored manifest, so #392's page-token gate admits the page (3/3 pass). - 4.2 #391's CommandChip restyled to the composer chip idiom (no --motion-fast); its copy moved into COMPOSER_COPY. - 4.5 app export goes through #392's IPC (window.electron.exportApp); the renderer's buildExportUrl/ExportOptions/ExportMode path is gone. - 4.6 ChatInput.bugCommand.test no longer passes the removed disableAnimation prop. - landing/docs.html regenerated from the merged docs/website/pages. cargo check --workspace --all-targets and tsc --noEmit are clean.
Broccolito
added a commit
that referenced
this pull request
Oct 12, 2026
…the restyle never covered follows the redesign's rules: the export dialog's app check face is ModalShell anatomy with a warning Note, both faces scroll their body, an unreadable app is a two-line row, the export toasts and the open-in-browser failure read from copy registries [R-15, R-27]
ExportAppDialog (applications/):
- The app check (lint) face: the consequence stays the visible subtitle; the advice ("Fix them in the chat that built the app, or export it as it is.") moves behind the title's InfoTip (principle 2); the findings sit in one warning Note (AlertTriangle) whose own eight-line ceiling and "Show more" replace the hand-rolled 8-item cap and "N more", so every finding is readable; no nested max-h scroller, the shell body is the one scroller (scrollBody).
- The face stays while Export anyway runs (button "Exporting…", disabled, neutral by ruling 22). It used to fall back to the mode choice under the pointer. Phase becomes running + lint state.
- Focus moves to the named findings list when it arrives (the button that asked turned disabled, which drops focus to body in Chromium).
- The choose face takes scrollBody too: a full export of an app reaching four knowledge bases, a skill and an extension clipped its last rows (Include Biorouter included) at the 1048x600 minimum window, with no scrollbar, because the shell hides overflow. Radios are disabled while an export runs, like the items. "Nothing to include" is a neutral Note (the empty-store line).
ApplicationsView: an unreadable app's row is two lines like every row (principle 4): the danger "Can’t be read" badge carries what it means as its InfoTip help, the second line is the parser's reason (mono, a machine string). Launch's failure uses failureSentence (one IPC unwrapper, same words). The export notes toast stays unclamped under the app's name, but each note is now a sentence (exportNotesMessage: a lower-case daemon clause is capitalised and stopped, words unchanged), so two daemon notes no longer run together into one unpunctuated line.
Copy: exportedMessage's three strings move into appsCopy (exportedTo, downloaded, exportCarries); buildChat's strings (already in appsCopy) take the registry's typographic apostrophe; the lint copy drops moreProblems. utils/openInBrowser.ts exports OPEN_IN_BROWSER_COPY ("Couldn’t open the app", the same sentence Built apps' Launch uses for the same failure, pinned by a test), and its three surfaces' tests (utils, MCPUIResourceRenderer, ArtifactViewer.openInBrowser) import it. WebPagePreview needed no change: its failure surface is this toast.
Tests: ExportAppDialog.test 9 -> 16 (the 9 #392 acceptance cases unchanged except the notes case, which now expects the daemon clause as a sentence; new: every finding in the warning Note with no inner scroller, advice behind the InfoTip, focus on the findings, the face stays while Export anyway runs, radios held while running, the neutral nothing-to-include Note, three notes as sentences unclamped); ApplicationsView.test broken-row case asserts two lines and the badge's description; new exportMessages.test (8); new builtAppsExport.browser.test (Chromium, real origin route-fulfilled, compiled main.css): rows equal height incl. the broken one, body scrolls and the last row is reachable at 1048x600 and 1440x900 light and dark with the footer rule, the lint Note is a wash, one scroller, findings at 12px, folds then expands, focus on the list, every text size on the 12/13/14/17/24 scale.
Mutations (impl/ws-views-a-tools/r392-restyle/mutate.py, each restored byte for byte): choose face without scrollBody, findings out of the Note, no focus move, the face falling back while running, raw note join, a third line on the broken row: each turns its jsdom and/or Chromium cases red.
Screenshots read (rows, full export at 1048 and 1440, lint face folded and expanded; light and dark).
Gates: applications + workflows + BioRouterHintsModal + the three openInBrowser surfaces + src/test copy guards + emphasis/raw-dialog guards + measures = 39 files / 490 tests green; tsc, eslint, prettier clean; no-goose-block clean. No main.css change.
Broccolito
added a commit
that referenced
this pull request
Oct 12, 2026
…ter/render.rs is in no workstream's ownership table; WS-BRAND owns the R-31 app-folder rule it now contradicts)): the exported-app launchers read the folder the daemon reads on Windows. run.ps1 and serve.mjs named the retired app folder (main's #392) and now apply rule 1 of app_folder (the older folder only while it is the only one), with the names filled from the app_folder constants; the README line and sdk-reference say the same; the launcher test gains the older-folder cases and the real presence check [R-31]
Broccolito
added a commit
that referenced
this pull request
Oct 12, 2026
…r React.StrictMode: its mounted ref started true and only the cleanup wrote it, so the development renderer's StrictMode remount left it false for good and run() dropped every answer. The dialog sat on Exporting… after the folder was written and never showed the app check's Export anyway face. The ref now starts false and the effect sets it true. ExportAppDialog.test.tsx renders three cases under StrictMode (closes after exported, the lint face takes focus and Export anyway closes it with allowLintErrors and the retry token, closes when onExport throws) and the four ApplicationsView export cases mount the view under StrictMode. Mutation: the old ref put back fails those 7, the other 12 pass; restored (cmp). Production builds were not affected (StrictMode double effects are dev only); the same code is on main (a423670). Checks: applications/ + 6 importers 12 files / 270 passed, src/test + src/styles guards 48 files / 902 passed; tsc, eslint, prettier clean
Broccolito
added a commit
that referenced
this pull request
Oct 12, 2026
…ys on the row at rest when the meta is a long description. The meta line was one truncate paragraph, so a long description pushed 'Build chat deleted' past the ellipsis (measured in the app: the note at x 1390 against a line ending at 1130). The line is now a flex row of two runs: the meta (min-w-0 truncate) gives way and the note (shrink-0, whitespace-pre keeps the ' · ' separator) never does; textContent is unchanged, the p carries data-testid app-row-meta. builtAppsExport.browser.test.tsx gains Renal Dosing Assistant (long description, deleted chat) and a case at 1048x600 and 1440x900, light and dark: the note is inside the line, unclipped and the element painted at its own centre, the description truncates with an ellipsis before it, the line reads 'description · Build chat deleted', the row keeps the other row's height; open() takes an apps list. Mutation: the one-line truncate p put back fails it (note right 1196 vs line right 787 at 1048); restored (cmp). Screenshots read: note visible light and dark at both widths. ApplicationsView.test.tsx's model and kb line case reads the line by its test id (the facts are now its first run). Checks: applications/ + 6 importers 12 files / 270 passed, src/test + src/styles guards 48 files / 902 passed; tsc, eslint, prettier clean
This was referenced Oct 12, 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.
Built apps could send Chrome to Electron’s secret-only relay, open deleted build chats, and ignore Full/bundled-daemon export options. Launch and managed previews now use the daemon origin, deleted chats show a disabled explanation, and all export modes share a binary-safe ZIP implementation with executable launchers and explicit payload selection.
Included knowledge is imported through the authenticated daemon API before skills are installed. Allocated base IDs are rebound without cascading mappings; durable receipts prevent duplicate imports and preserve recipient edits. Windows PowerShell 5.1 and Node share receipts across short/long aliases. Bundled exports pair the selected daemon with its pinned native compiler. Desktop and Linux CLI packaging now ship esbuild 0.27.3.
The remaining review fixes cover authored static handlers, same-app figure frames, build rollback, app-generation tokens and deletion retirement, bridge ownership, browser navigation policy, credential ownership and atomic desktop writes. Plain HTTP network addresses refuse app pages and the secret-bearing serve shell. Documented limits remain in the handoff; this change does not establish per-app origins/storage or universal extension bundling.
Validation completed locally:
CARGO_BUILD_JOBS=2 just check-everythingruns; latest source checkpointd74b2985d. Agent Drafter Rust namespace: 369 passed, 2 ignored. Focused Crew fixture: 53 passed, with the previously failing case repeated successfully.21b770408.COBALT_PEAR_47 / FINAL_LAUNCH_QA_OKthroughknowledge__kb_read_page. All QA inputs were fictional; the main checkout, installed app and original QA profile were preserved.Final verification at
e5cd7e206a88355b491bee48aa2d707f8c4d93bd:Linux package artifact:
linux-packages-1.92.1, 664,023,807 bytes; ZIP SHA25676eb21a73588ab41decf09def27843f25ae3cfcf81d4aaa2dc399ed1fe16c282.ee483a48336c5e5006d80f94cc2d8ebf2b3a720ddf4a3a5533d5987d1e131f6fd1cc8e871c865871d4f6189a5d667d25e31497260359fe477d00481203c8b9d95b0acaadcc94569754618958b7a0b0197c3db1c996d7da0ad3423cd11bfa09bf8d3b1a8a6373886ce2ef1bb197af15c58d30168190223f019fcfa167d5406c58Handoff · Verification ledger. No merge, release publication or replacement of the installed app is part of this PR.