Fix packaged updater ASAR extraction handoff - #314
Conversation
* Replace image in README with new source Updated the image in the README to a new source. * Prepare 0.1.66 hotfixes (#277) * fix linux command launcher detach * Prepare 0.1.67 worktree fixes * Polish worktree branch creation * Patch sidebar shell updates in place * Clean up stale docs * Fix markdown diff theme text * Use Pierre system diff themes * Fix markdown artifact editor loading * Hide raw reasoning previews * Align empty project work panel * Prepare 0.1.66 hotfixes * Use default branch for diff baseline * Fix worktree parent persistence * Limit child worktree creation to active branch * Add top dividers for worktree groups * Show pending state for sidebar work actions * Add custom worktree icon * Tighten hotfix changelog copy * Harden diff baseline branch detection * Align AWS SDK overrides with Pi runtime
* Replace image in README with new source Updated the image in the README to a new source. * Prepare 0.1.66 hotfixes (#277) * fix linux command launcher detach * Prepare 0.1.67 worktree fixes * Polish worktree branch creation * Patch sidebar shell updates in place * Clean up stale docs * Fix markdown diff theme text * Use Pierre system diff themes * Fix markdown artifact editor loading * Hide raw reasoning previews * Align empty project work panel * Prepare 0.1.66 hotfixes * Use default branch for diff baseline * Fix worktree parent persistence * Limit child worktree creation to active branch * Add top dividers for worktree groups * Show pending state for sidebar work actions * Add custom worktree icon * Tighten hotfix changelog copy * Harden diff baseline branch detection * Align AWS SDK overrides with Pi runtime * Add native Smart BTW extension (#282) * Add native smart btw extension * Refine smart btw session slots * Fix smart btw takeover behavior * Restore smart btw sessions from hidden messages * Project smart btw state from thread history * Stabilize smart btw gui projection * Seed restored smart btw follow-ups * Remove auto trees from smart btw branch * Update changelog for smart btw * Fix smart btw runtime settings edges * Bump version for smart btw release * Fix pages changelog section parsing * Add composer session tree navigation (#283) * feat(composer): add always-visible session tree popover for UI review * fix(composer): narrow session tree popover to btw inset * fix(composer): simplify session tree panel chrome * fix(composer): align session tree row labels vertically * fix(composer): restore line height on session tree row text * fix(composer): baseline-align session tree row with shared small type * fix(composer): use meta/small type on session tree rows * feat(composer): fold session tree subtrees with chevrons * fix(composer): use size-12 tree chevrons like sidebar folds * fix(composer): center-align session tree chevron and text rows * fix(composer): tighten session tree row height * fix(composer): add inner padding on session tree row body * feat(composer): apply Pi no-tools filter to session tree * feat(composer): session tree from Pi JSONL with filtered rows and panel UX Load session tree via service host (getSessionTreeList), map getTree() to shared rows with Pi-aligned no-tools filtering, omit bookkeeping entries, and show branch summaries in accent. Panel: sticky header, aligned highlight columns, branch/compact labels. * fix(composer): refresh session tree on watch and fix active path * feat(composer): session tree navigate with inline confirm Wire Pi-style navigateTree on the live thread runtime via composer.session-tree.navigate, mutation lock, and IPC host routing. Composer tree rows show a hover History control and sidebar-style inline confirm (Cancel / No / Sum). Confirm closes the tree panel; errors use composer errorMessage; restored editor text applies to draft. Branch summarize reuses existing isCompacting / compaction pill UI. Add session-tree CSS, navigate confirm component, and navigate hook. Extend desktop action contracts and payload helpers. * fix(composer): icon-only session tree navigate confirm Use Undo2 and ListCollapse in the inline strip with top tooltips. Show History tooltip on the right. * fix(composer): show compaction UI during branch tree summarize Pi branch summary sets isCompacting but does not emit compaction_start. Publish compaction-start and compaction thread updates when summarize navigate begins and settles, matching /compact behavior. * fix(composer): route tree navigate compaction events to UI Session tree navigate ran in the thread runtime host but published thread updates through the main-process thread publisher, so the renderer never saw compaction-start. Use live-thread-publisher like /compact and sendComposerPrompt. * fix(composer): session tree leaf, /tree, and active-path reveal Use live runtime leafId when building the tree list so active-path highlighting stays correct after branch summarize. Wire /tree slash command and open-on-demand panel (remove dev always-on). Refetch tree on navigate; disable background session-watch refresh. Click active-path rows to scroll the thread via session-tree-reveal. * feat(composer): session tree browse, anchor mark, esc to close * feat(composer): read-only session tree branch preview Load thread messages along the parent chain to a selected tree entry via getThreadPreviewAtEntry on the service host. Composer browse dispatches preview events; the main timeline overlays preview data until the panel closes or the user returns to the anchor. * fix(composer): reopen session tree after navigate without summary * fix(composer): push thread up for session tree; dismiss tree on typing * feat(composer): label session tree navigation * Revert "feat(composer): label session tree navigation" This reverts commit 2be2ac4. * fix(composer): display pi tree labels * Reapply "feat(composer): label session tree navigation" This reverts commit 1dedd61. * fix(composer): portal session tree label field * fix(composer): portal session tree confirm controls * fix(composer): persist session tree navigation labels * fix(composer): fallback label new branch summary * fix(composer): await tree summary before labelling * fix(composer): forward tree label through host * feat(composer): label session tree entries inline * docs: note session tree labelling * fix(composer): harden session tree popover state * fix(composer): address session tree review edge cases * Bump Pi SDK and rework extension UI (#289) * Bump Pi SDK packages to 0.79.0 * Show Pi prompt cache hit rate * Wire Pi project trust backend * Add project trust composer prompt * Trim project trust prompt UI * Tighten project trust prompt layout * Right align project trust actions * Use Pi-native extension UI dialogs * Wire ask questions through Pi settings * Fix trusted global extension loading * Move extension dialog submit action into header * Stop rendering extension notifications as cards * Render extension notifications inline * Simplify extension notification label * Style extension notifications by severity * Keep extension notifications standalone * Render extension statusline under composer * Tighten extension statusline styling * Apply extension statusline typography directly * Align extension statusline rail * Polish extension statusline layout * Nudge extension statusline text * Use generic Pi extension widgets and shortcuts * Polish Pi extension widget rendering * Use Geist Mono as primary app mono font * Polish Pi extension overlay surfaces * Raise context popover above extension UI * Remove Howcode native extension settings * Move ask questions extension out of Howcode * Remove stale native extension cleanup entries * Fix Pi extension UI review issues * Fix Pi dialog timeout handling * Keep dialog runtimes alive while waiting * Save project trust by requested cwd * Handle unsupported Pi component widgets * Bridge Pi extension editor shortcuts * Fix Pi extension review issues * Scope Howcode keybindings by UI mode * Keep Pi TUI terminal focus stable * Separate Pi TUI and terminal drawer shortcuts * Split Pi TUI and shell terminal viewports * Allow drawer terminal clear in Pi TUI mode * Prevent hidden composer stealing Pi TUI focus * Update changelog for Pi SDK UI work * Restore Smart BTW changelog entry * Bump Pi SDK packages to 0.79.1 * Open session tree on idle double Escape * Tighten Pi SDK changelog notes * Bump app and build dependencies (#290) * Add headless LAN browser mode (#291) * Enable headless dev server host config * Add packaged headless server mode * Keep browser bridge API in sync * Avoid Chromium headless flag collision * Use headless Ozone platform * Pass headless Ozone switch from launcher * Support browser file uploads in headless mode * Shorten browser upload attachment label * Tune browser upload attachment control * Use smaller browser device attachment label * Use existing tiny upload control styling * Use composer footer text for device attach control * Clean up browser upload temp files * Stream browser upload attachments * Add headless access token auth * Add TanStack Router URL sync * Fix router URL state feedback loop * Harden headless router and upload errors * Align footer controls with extension status * Clarify headless run docs * Update changelog for headless mode * Bump dev launcher publish version * Refresh project README * Fix macOS window controls (#292) * Fix macOS window controls * Vouch macOS contributor * Tighten macOS drag zones * Support WSL project terminals on Windows (#293) * Support WSL UNC terminal cwd on Windows Why: - Native Windows terminal launch currently treats WSL UNC project paths as host Windows paths. - Opening a WSL project through \\wsl$ or \\wsl.localhost should start the embedded shell inside that distro and Linux cwd. Verified: - bun vitest run desktop/terminal/terminal-command.helpers.test.ts - bun x biome check desktop/terminal/terminal-command.helpers.ts desktop/terminal/terminal-process.ts desktop/terminal/terminal-command.helpers.test.ts - bun run typecheck:desktop - git diff --check (cherry picked from commit 7657ccc) * Clarify custom Pi directory WSL use * Route WSL Pi terminal sessions through wsl --------- Co-authored-by: Christian Scherkl <christianscherkl79@gmail.com> * Fix mac drag zone and sidebar spacing * Polish composer overlay stacking * Stabilize composer overlay polish * Unify workspace rail layout * Refine thread rail alignment * Update changelog for composer rail polish * Polish website and docs copy * Fix session view refresh and worktree routing (#298) * Isolate Pi extension UI refreshes * Preserve worktree context across Chat and Inbox * Tighten worktree thread scoping * Honor inbox thread modes * Unstick thread URL sync * Tighten inbox worktree routing * Trim low-signal regression tests [skip ci] * Bump Pi SDK and add session rename (#301) * Bump Pi SDK packages to 0.79.6 * Add session rename support * Keep compaction pill above composer overlays * Update changelog for SDK bump and session rename * Fix right Alt extension shortcuts (#303) * Align isolated loader with Pi SDK (#304) * Update dependencies to latest compatible releases * Refresh React Doctor configuration * Reshape repository agent guidance * Reach 100 React Doctor score * Harden reviewed React Doctor fixes * Add Effect v4 engineering skill * Migrate terminal transport to Effect RPC * Restore awaited terminal shutdown * Move terminal lifecycle into Effect * Close terminal lifecycle races * Move live runtime ownership into Effect * Harden runtime registry ownership * Release runtimes after dialog expiry * Replace skill creator session with bundled skill * Expose bundled skills to every runtime * Remove obsolete in-process runtime stack * Move runtime host broker into Effect * Preserve broker recovery during lifecycle races * Move desktop service lifecycle into Effect * Finish desktop service shutdown ownership * Document Effect migration status * Decode Effect process boundaries with Schema * Modularize Effect runtime ownership * Harden app and launcher updates * Modularize update runners * Finish updater concern split * Close updater failure paths * Protect live updater bundles * Document updater rollout order * Close updater review gaps * Close updater handoff gaps * Update dependencies and native runtime contracts * Localize sidebar branch actions * Share inline popover dismissal * Unify sidebar project action menus * Centralize sidebar row menu ownership * Document sidebar ownership boundaries * Split sidebar project work model * Share sidebar branch group rendering * Keep nested worktree sessions visible * Harden sidebar action and rendering boundaries * Harden composer ownership boundaries * Align composer model popover rows * Harden terminal viewport boundaries * Harden thread timeline mechanics * Harden inbox composer boundaries * Harden settings ownership boundaries * Serialize Pi settings writes * Keep Pi draft flushes current * Harden resource and session screens * Harden app shell control plane * Document Pierre GitOps redesign * Establish GitOps review domain * Gate changes on React Doctor * Let Pierre own diff review selection * Modularize GitOps composer * Emit canonical GitOps patches * Contain diff stream cancellation * Add explicit GitOps review actions * Hydrate complete GitOps file context * Edit GitOps files safely * Mirror Pierre hunk review controls * Narrow GitOps to agent review * Reset local GitOps review decisions * Expand GitOps context in one step * Align trailing context with review actions * Restore context action typography * Style context action across Pierre boundary * Restore Pierre gutter comment interactions * Make GitOps hunk undo durable * Route rejected hunks to agent review * Map agent-native hardening phases * Remove local dependency cycles * Unify desktop request handling * Narrow AppShell feature ownership * Enforce architecture boundaries * Split transport host responsibilities * Complete hardening feedback loops * Split static site route ownership * Prune feature and UI tests * Prune launch-obvious tests * Complete Effect lifecycle ownership * Scope runtime polling races * Unify desktop shutdown ownership * Scope stock Node probing * Decode external payload boundaries * Harden persistence and payload boundaries * Harden runtime and persistence boundaries * Prune implementation-confirmation tests * Remove completed implementation docs * Update 0.1.68 changelog * Refresh dependencies before merge * Align Biome schema version * Use fixed CSS highlight parser * Keep disposable builds isolated * Make Pi takeover session ownership exclusive * Await Pi terminal exit during handoff * End Pi takeover promptly on return * Repair CDP debugging workflow * Finish 0.1.68 release notes * Render reasoning summaries once * Harden worktree lifecycle ownership * Close worktree lifecycle review gaps * Close lifecycle race gaps * Finish worktree lifecycle hardening * Close remaining worktree race gaps * Serialize worktree repository mutations * Close worktree ownership gaps * Correct footer guidance filename * Cull feature-oriented tests * Refine phone-browser roadmap scope * Bump npm launcher publish versions * Highlight React Doctor release milestone * Reorient 0.1.68 release notes * Fix Windows Electron archive extraction * Install Bun in release publisher jobs --------- Co-authored-by: Christian Scherkl <christianscherkl79@gmail.com>
|
@codex please review this PR and give me 10-20 issues if any. Categorize findings as required, recommended, or optional. |
|
Closing this lineage-heavy comparison; replacing it with the same commit cleanly cherry-picked onto current dev. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: baa97a7751
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| request: http.IncomingMessage, | ||
| response: http.ServerResponse, | ||
| ) { | ||
| const { pathname } = new URL(request.url ?? '/', 'http://headless') |
There was a problem hiding this comment.
[Required] Reject malformed headless request targets safely
When an unauthenticated client sends an invalid absolute-form request target such as http://[, this new URL call throws synchronously. The http.createServer callback in headless/server.ts has no error boundary or clientError handling, so one malformed request can become an uncaught exception and terminate the remotely exposed headless app; parse failures should return a 400 response instead.
Useful? React with 👍 / 👎.
| const versionDiff = compareVersions(release.version, currentVersion) | ||
| if (versionDiff > 0) return true | ||
| if (versionDiff < 0) return false |
There was a problem hiding this comment.
[Required] Honor switches from dev to an older stable build
When a user disables the dev update channel while the dev build has a higher version than the current main-channel release, this unconditional rejection prevents both recovery and installation of the selected stable bundle. The app consequently continues running the dev build until main eventually overtakes its version, so channel changes need to compare the running channel as well as version/hash rather than treating the selected-channel bundle as an ordinary downgrade.
AGENTS.md reference: src/electron/main/updater/AGENTS.md:L2-L2
Useful? React with 👍 / 👎.
| try { | ||
| const newPath = resolveFileDiffPath(fileDiff) | ||
| const oldPath = | ||
| fileDiff.type === 'new' || fileDiff.type === 'rename-pure' | ||
| ? null | ||
| : resolveDiffFilePath(fileDiff.prevName ?? fileDiff.name) |
There was a problem hiding this comment.
[Recommended] Load deleted diffs without a worktree file
For a deleted file, resolveFileDiffPath(fileDiff) still supplies the deleted path as newPath; the desktop loader then unconditionally reads that nonexistent worktree file and returns missing, even though the baseline contents were loaded successfully. Expanding collapsed context on a large deleted file therefore fails; deleted diffs should pass/return a null new side while loading the complete old side.
AGENTS.md reference: src/app/native/gitops/AGENTS.md:L6-L6
Useful? React with 👍 / 👎.
| updatedAt: nowIso(), | ||
| } | ||
| record.suppressOutputVisibilityUntilInput = true | ||
| rmSync(record.transcriptPath, { force: true }) |
There was a problem hiding this comment.
[Recommended] Make transcript clearing part of the write queue
If the 40 ms persistence timer has already queued or started a transcript write when the user submits clear, cancelling persistTimer does not cancel persistPromise; this synchronous removal can run first and the pending write then recreates the file with the pre-clear history. A crash or reopen before another write can consequently restore supposedly cleared output, so deletion must be ordered after the existing persistence promise.
AGENTS.md reference: desktop/AGENTS.md:L8-L8
Useful? React with 👍 / 👎.
| await moveSessionTranscript(input.record, nextTranscriptPath).catch(reportTranscriptWriteFailure) | ||
| input.store.delete(previousSessionId) |
There was a problem hiding this comment.
[Recommended] Abort terminal rebinding when transcript moves fail
When the transcript write or rename fails—for example because the destination is locked or storage becomes unavailable—the error is only reported and rebinding continues. moveSessionTranscript updates record.transcriptPath only after a successful rename, so the record is registered under the new session ID while later history writes still target the old unbound-session file, causing the new session to lose its transcript on reopen; either fail the rebind or explicitly repair the transcript path.
Useful? React with 👍 / 👎.
| const flushPiSettings = useCallback(async () => { | ||
| const dirtyKeys = [...dirtyKeysRef.current] | ||
| dirtyKeysRef.current.clear() | ||
| const snapshot = draftPiSettingsRef.current |
There was a problem hiding this comment.
[Recommended] Retain dirty Pi settings after failed writes
Dirty keys are cleared before any desktop action completes, and the non-theme write path neither checks an { ok: false } result nor restores keys when the promise rejects. During a desktop-service restart, validation failure, or filesystem error, closing Settings therefore discards the only retry state while the optimistic draft still showed the new value; failed keys should remain dirty or be reverted, and the unmount flush should not leave a rejected promise unhandled.
AGENTS.md reference: src/app/settings/settings/AGENTS.md:L4-L4
Useful? React with 👍 / 👎.
| const response = await fetch(addCacheBust(url), { | ||
| signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS), |
There was a problem hiding this comment.
[Recommended] Use an idle timeout for update downloads
On a slow but active connection, AbortSignal.timeout(5 minutes) measures the entire archive transfer rather than inactivity, so a large Electron bundle that cannot finish within five minutes is aborted on every retry from byte zero and can never update. The launcher downloader already resets its timeout on progress; the in-app transport needs the same idle-timeout behavior.
AGENTS.md reference: src/electron/main/updater/AGENTS.md:L2-L2
Useful? React with 👍 / 👎.
| options.authRequired && options.accessToken | ||
| ? `#token=${encodeURIComponent(options.accessToken)}` | ||
| : '' | ||
| return `http://${accessHost}:${options.port}${tokenFragment}` |
There was a problem hiding this comment.
[Recommended] Bracket IPv6 hosts in headless access URLs
When headless mode is bound to an IPv6 literal such as ::1 or a LAN IPv6 address, this produces an invalid URL like http://::1:5173. Manually adding brackets does not fully rescue loopback mode because createHostTrust records ::1:5173 while browsers send [::1]:5173, causing config/auth requests to be rejected; IPv6 literals need one canonical bracketed representation for both URL generation and host trust.
Useful? React with 👍 / 👎.
| ### 0.1.67 | ||
|
|
||
|
|
||
| - Added **server** headless/browser mode. Use `howcode --server --host 0.0.0.0 --token xyz`. The app is usable in a mobile browser if you wish to do so. |
There was a problem hiding this comment.
[Recommended] Advertise the implemented headless flag
The changelog tells users to run howcode --server, but a repository-wide search finds no --server handling: parseHeadlessServerOptions accepts only --headless, --howcode-headless, or HOWCODE_HEADLESS=1, and the launcher only recognizes --headless. Following this release note launches the normal GUI instead of the advertised server, so the command should use --headless or the alias must be implemented end to end.
Useful? React with 👍 / 👎.
| async function pumpBody() { | ||
| const boundaryIndex = buffer.indexOf(partBoundary) | ||
| if (boundaryIndex < 0) { |
There was a problem hiding this comment.
[Optional] Validate multipart boundary suffixes before splitting
If uploaded file bytes contain \r\n--<boundary> followed by ordinary non-delimiter bytes, indexOf treats it as a boundary and consumeBoundarySuffix throws Malformed multipart upload instead of retaining it as file data. Browser boundaries make accidental collisions rare, but valid or deliberately constructed binary attachments can still be rejected; only matches followed by CRLF or -- should terminate a part.
Useful? React with 👍 / 👎.
Summary
app.asar0.1.72and0.1.72-dev.0Root cause
Electron patches Node filesystem handling for paths ending in
app.asar. The in-app updater used the JavaScript tar library inside Electron, which extracted the executable but silently omitted the packagedapp.asar. Separately, old Linux installs generated~/.local/bin/howcodeas a frozen direct-app wrapper, shadowingbunxand global package launchers.Validation
{ executable: true, asar: false }{ executable: true, asar: true }0.1.72and0.1.72-dev.0