Replaying origin/main commits onto 05-30-refactor_everything by hand. The refactor
(+100k/−80k) moved most renderer/main code into packages/*, so rebase/merge resolves to
wrong locations. Instead each upstream commit's intent is re-applied at the file's new
home, oldest first, and logged here.
Baseline: branch is 49 behind / 7 ahead of origin/main as of 2026-06-05.
No git cherry-pick, no git merge — ever. Paths that survive at HEAD are often shims or
adapters now; a textual pick would conflict or silently patch logic back into apps/code.
Every commit is replayed by hand:
git show <sha>to read the upstream change and understand its intent.- For each touched file, inspect its current state at HEAD: moved? shim? rewritten? deleted?
Find the new home (
packages/ui,packages/core,packages/workspace-server,packages/host-router, …). Where a file moved verbatim the hunks transcribe directly; otherwise re-implement the intent. - Re-apply respecting the architecture (logic → core service, UI → packages/ui,
Node → workspace-server, routers → host-router, host caps → platform interface + adapter).
Never resurrect business logic in
apps/code. - Validate: scoped typecheck +
biome linton touched packages; smoke where user-visible. - Never commit. No
git commit, nogit add, no branches, no stashes. All replay work stays as uncommitted edits in the shared working tree. This table is the record, not git history. Update the row (status + notes + validation evidence) after each replay. - Never skip. Every commit gets replayed or proven redundant. If a change appears
already present or superseded at HEAD, cite exact evidence (file:line at HEAD covering
each upstream hunk's intent) in the notes and mark
already-present. No assumption-based skips; when in doubt, replay it.
Classes (effort signal only): mech = touches areas the refactor didn't reshape
(mobile, cloud-agent, CI, packaging) — near-verbatim transcription. port = targets
relocated/rewritten, re-apply at new home. big = large/structural, own pass.
decide = may be superseded by the refactor.
kept/moved/new = touched files still at same path / relocated by refactor / added by the commit.
| # | sha | date | PR | subject | class | k/m/n | status | notes |
|---|---|---|---|---|---|---|---|---|
| 1 | 50c6d9054 | 2026-05-29 | #2437 | Pin actions/stale to full SHA | mech | 1/0/0 | replayed | Transcribed verbatim: .github/workflows/stale.yml:18 actions/stale@v9 → actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9. Resulting diff byte-identical to upstream (blob 495f9b988→3715b9da7). Validation: biome ignores YAML, no package typecheck applicable (CI-only). |
| 2 | 4b527bae8 | 2026-05-29 | #2441 | Bump claude-agent-sdk 0.3.156 (Opus 4.8 thinking) | mech | 3/0/0 | replayed | packages/agent/package.json: claude-agent-sdk 0.3.154→0.3.156, @anthropic-ai/sdk 0.100.0→0.100.1; drift: refactor added a second dependent, packages/workspace-server/package.json:23 also bumped to 0.3.156 (not in catalog — pnpm-workspace.yaml only lists it under onlyBuiltDependencies); UPSTREAM.md sync header + v0.39.0 section transcribed; lockfile regenerated via pnpm install (not transcribed — extra dependent makes upstream hunks wrong), zero 0.3.154/0.100.0 refs remain. Validation: pnpm --filter @posthog/agent typecheck ✓, pnpm --filter @posthog/workspace-server typecheck ✓, biome lint touched ✓. |
| 3 | 99f062245 | 2026-06-01 | #2448 | show logs not repo picker for inbox research tasks | port | 0/2/0 | replayed | Both files relocated to packages/ui (not inbox — workspace/sessions). useIsCloudTask hunk → packages/ui/src/features/workspace/useIsCloudTask.ts: added optional task?: Task param (import from @posthog/shared/domain-types, upstream @shared/types), early-return on workspace mode, fallback task?.latest_run?.environment === "cloud". Call-site hunk → packages/ui/src/features/sessions/hooks/useSessionViewState.ts:12 useIsCloudTask(taskId, task). Other ui call sites (ChangesPanel.tsx:396, FileTreePanel.tsx:192) left untouched, matching upstream. Validation: pnpm --filter @posthog/ui typecheck ✓, biome lint touched ✓. |
| 4 | 95812478f | 2026-06-01 | #2435 | Highlight current user in signal suggested reviewers | port | 0/1/0 | replayed | File moved to packages/ui; selection logic had been extracted to core, so split per architecture: sort-me-to-top hunk → packages/core/src/inbox/reportArtefacts.ts selectSuggestedReviewers(artefacts, meUuid?) (findIndex on r.user?.uuid, meIndex<=0 short-circuit, identical to upstream); UI hunks → packages/ui/src/features/inbox/components/detail/ReportDetailPane.tsx: InfoIcon import, useMemo passes me?.uuid + dep, commit Tooltip gains isMe "Why was I assigned?" Flex content + inline-flex span wrapper + conditional InfoIcon(11, cursor-help) — transcribed verbatim; isMe already existed via isSuggestedReviewerRowMe (same uuid match). Validation: pnpm --filter @posthog/core typecheck ✓, pnpm --filter @posthog/ui typecheck ✓, biome lint touched ✓. |
| 5 | 574516e8c | 2026-06-01 | #2444 | codex-acp .exe path on Windows | port | 0/1/0 | replayed | Single hunk ported: getCodexBinaryPath() moved from apps/code/src/main/services/agent/service.ts to packages/workspace-server/src/services/agent/agent.ts:382; applied win32 .exe suffix verbatim, mirroring existing getClaudeCliPath() at :378. Validation: pnpm --filter @posthog/workspace-server typecheck clean, biome lint on touched file clean. |
| 6 | d7f9866e5 | 2026-06-01 | #2408 | mobile: auto-refresh on 401/403 | mech | 9/0/1 | replayed | apps/mobile untouched by refactor — all 9 kept files were byte-identical to upstream parent, so the full diff transcribed verbatim (git apply clean): lib/api.ts gains authedFetch + refreshAccessTokenOnce (pendingRefresh dedupe) + isAuthFailureResponse (401, or 403 with code=authentication_failed/type=authentication_error) + mergeHeaders; all raw fetch() in auth hooks, inbox/mcp/tasks/skills api swapped to authedFetch; new lib/api.test.ts (216L) identical to upstream blob; test mocks updated in api.automations.test.ts + skills/api.test.ts. All 10 files now byte-identical to d7f9866e5. Validation: vitest 3 files/18 tests pass; biome lint touched files clean; mobile tsc --noEmit errors (46) all in untouched .test.tsx component files = pre-existing baseline, zero in touched files. |
| 7 | d504c3136 | 2026-06-01 | #2450 | cloud-agent: sandbox gh token refresh | mech | 5/0/2 | replayed | packages/agent untouched by refactor — all 5 kept files byte-identical to upstream parent, full diff transcribed verbatim (git apply clean): new utils/github-token.ts (SANDBOX_ENV_FILE=/tmp/agent-env, readGithubTokenFromSandboxEnvFile NUL-delimited live read, resolveGithubToken file-over-process precedence) + github-token.test.ts; common.ts drops resolveGithubToken; claude/codex/signed-commit imports repointed; signed-commit token precedence flipped to resolveGithubToken() ?? ctx.token; agent-server REFRESH_SESSION gains refreshedCredentials/authorship logging + early {refreshed:true} when mcpServers empty. All 7 files byte-identical to d504c3136 blobs. Validation: pnpm --filter @posthog/agent typecheck ✓, biome lint touched 7 files ✓, vitest github-token.test.ts 7/7 ✓. |
| 8 | 35f854960 | 2026-06-01 | #2440 | Show skill tool calls as "Reading skill" | port | 0/1/0 | replayed | ToolCallView.tsx relocated verbatim by refactor → packages/ui/src/features/sessions/components/session-update/ToolCallView.tsx (no apps/code shim remains); all 3 hunks transcribed there: toolNameDisplays map (Skill/ToolSearch), specialDisplay derivation rewiring displayText + inputPreview, suffix <ToolTitle>{specialDisplay.suffix}</ToolTitle> after inputPreview; upstream explanatory comment dropped per repo style. Validation: pnpm --filter @posthog/ui typecheck ✓, pnpm exec biome lint on touched file ✓. |
| 9 | 7d82e7f42 | 2026-06-01 | #2432 | mobile: slug suffix on inbox deep links | mech | 4/0/2 | replayed | apps/mobile untouched by refactor — all 4 touched files byte-identical to upstream parent, full diff transcribed verbatim (git apply clean incl. rename inbox/[id].tsx→[...id].tsx): deep-links.ts gains slugifyTitle (NFD fold, _ . ~ preserved, colon-mix runs→--), inboxReportShareUrl, stripInboxSlugSuffix applied in externalUrlToAppPath; _layout.tsx route name inbox/[...id]; [...id].tsx tolerates string|string[] id + passes reportTitle; DiscussReportSheet uses inboxReportShareUrl(reportId, reportTitle); new deep-links.test.ts (139L). All 5 files byte-identical to 7d82e7f42 blobs. Validation: vitest deep-links.test.ts 29/29 ✓; biome lint 5 touched files ✓; mobile tsc --noEmit zero errors in touched files (45 pre-existing baseline in untouched .test.tsx/setup.ts). |
| 10 | 947c87c49 | 2026-06-02 | #2346 | sidebar: PR state on cloud task icons | port | 0/1/0 | replayed | TaskIcon.tsx moved to packages/ui/src/features/sidebar/components/items/ (no apps/code shim left). Applied all 3 hunks: split queued/in_progress in CloudStatusIcon (queued keeps ph-pulse + "(queued)", in_progress gets weight="fill" accent-11 + "(running)"), moved isCloudTask branch in TaskIcon below isPinned (after prState/hasDiff) so PR state and pin win over the cloud icon. Validation: pnpm --filter @posthog/ui typecheck clean, biome lint on file clean. |
| 11 | 31a9acb30 | 2026-06-02 | #2454 | agent: attribute LLM gateway events to customer team | mech | 4/0/0 | replayed | packages/agent untouched by refactor — all 4 files byte-identical to upstream parent, full diff transcribed verbatim (git apply clean): options.ts buildEnvironment() rebuilt as headerLines array pushing x-posthog-property-team_id: <POSTHOG_PROJECT_ID> before the bedrock fallback header; options.test.ts new ANTHROPIC_CUSTOM_HEADERS describe (3 it.each cases, env save/restore); configure-environment.test.ts adds POSTHOG_PROJECT_ID to ENV_KEYS_UNDER_TEST + export assertion; agent-server.ts comment expanded. One drift fix: options.ts comment ref "apps/code auth-adapter.ts" → "workspace-server auth-adapter.ts" (desktop exporter now at packages/workspace-server/src/services/agent/auth-adapter.ts:156). Validation: pnpm --filter @posthog/agent typecheck ✓, biome lint 4 touched files ✓, vitest options.test.ts + configure-environment.test.ts 20/20 ✓. |
| 12 | fa2b6847d | 2026-06-02 | #2458 | inbox: track signal_report_id on task_created | port | 0/1/0 | replayed | Hook moved to packages/ui/src/features/inbox/hooks/useCreatePrReport.ts; single hunk transcribed — added signal_report_id: reportId, to the TASK_CREATED track() payload in the "created" case (line 97, after cloud_pr_authorship_mode). Payload type already permits it (packages/shared/src/analytics-events.ts:71 signal_report_id?: string, dist current). Validation: pnpm --filter @posthog/ui typecheck ✓, biome lint on file ✓. |
| 13 | 1160f1784 | 2026-06-02 | #2424 | UI thread cleanup + tanstack virtualized | port | 3/8/0 | replayed | All 8 components live in packages/ui (sessions + message-editor features), pre-states matched upstream parents, hunks transcribed there. VirtualizedList.tsx fully rewritten virtua→@tanstack/react-virtual (useVirtualizer with anchorTo:"end"/followOnAppend/scrollEndThreshold, RAF settleAtEnd loop, absolute+translateY rows, orphan keepMounted rendered hidden at -99999px); virtua dep kept (still used by code-review ReviewShell.tsx). Dep @tanstack/react-virtual@^3.13.26 added to packages/ui/package.json (NOT apps/code — component's new home; resolved 3.14.2/virtual-core 3.17.0, new APIs verified in installed typings); pnpm-workspace.yaml minimumReleaseAgeExclude + lockfile via pnpm install. ConversationView: group/thread container, scroll-to-bottom → quill Tooltip/TooltipTrigger render-prop + icon-lg outline Button at right-6. SessionFooter: ml-auto, hover-opacity group-hover/thread blocks, text-gray-10/color="gray" → text-muted-foreground, dedup select-none. SessionView: p-2→px-2 pb-3 (x3), dropped border-t/max-h-1/2 wrappers. PromptInput: focus-within purple ring + addon p-1. ContextUsageIndicator: text-muted-foreground. Agent/UserMessage: [&_p]:leading-[1.9]. scroll-mask-8 already provided by tailwindcss-scroll-mask import (packages/ui/src/styles/globals.css:50). Validation: pnpm --filter @posthog/ui typecheck ✓, biome lint 8 touched files ✓, renderer vite build smoke ✓. |
| 14 | 3a3d425b7 | 2026-06-02 | #2393 | signed-commit: optional cwd | mech | 2/0/1 | replayed | Transcribed verbatim: handler cwd resolution (path.resolve(ctx.cwd, argCwd), strips cwd from input) in packages/agent/src/adapters/local-tools/tools/signed-commit.ts, schema cwd field in packages/agent/src/adapters/signed-commit-shared.ts, new signed-commit.test.ts (5 tests). Token-order hunk (resolveGithubToken() ?? ctx.token + utils/github-token import) was already present at HEAD from an earlier replay. All three files now byte-identical to upstream blobs (4b38c5149, 4f7c24fe4, b749929f9). Validation: pnpm --filter @posthog/agent typecheck ✓, biome lint touched ✓, vitest run src/adapters/local-tools/tools/signed-commit.test.ts 5/5 ✓. |
| 15 | cc1519805 | 2026-06-02 | #2461 | cloud-agent: track stream disconnects/crashes | port | 2/2/0 | replayed | packages/agent untouched by refactor — agent-server.ts (reportFatalError: best-effort updateTaskRun failed + eventStreamSender.stop) and bin.ts (FATAL_ERROR_REPORT_DEADLINE_MS=5s handleFatalError racing reportFatalError, uncaughtException/unhandledRejection → exit(1)) transcribed verbatim via git apply, both byte-identical to upstream blobs. Analytics types hunk → packages/shared/src/analytics-events.ts (CloudStreamDisconnectedProperties:239, CLOUD_STREAM_DISCONNECTED:766, EventPropertyMap:887; explanatory comments dropped per repo style); shared dist rebuilt. failWatcher hunk → packages/core/src/cloud-task/cloud-task.ts:998 — upstream trackAppEvent re-implemented as constructor-injected @inject(ANALYTICS_SERVICE) IAnalytics (@posthog/platform/analytics, bound to posthogNodeAnalytics in apps/code container.ts:249) with this.analytics.track(CLOUD_STREAM_DISCONNECTED, {...}) of identical payload before watcher.failed = true; cloud-task.test.ts constructor gains analyticsMock. Validation: shared build+typecheck ✓, core typecheck ✓, agent typecheck ✓, biome lint 5 touched files + full packages/core ✓, vitest cloud-task.test.ts 22/22 ✓. |
| 16 | 536be50a7 | 2026-06-02 | #2463 | cloud-agent: tolerate interrupt during refresh | mech | 2/0/0 | replayed | packages/agent untouched by refactor — both files byte-identical to upstream parent, full diff transcribed verbatim (git apply clean): claude-agent.ts refreshSession wraps await prev.query.interrupt() in try/catch logging this.logger.debug("Ignoring interrupt error during session refresh", {sessionId, error}) without rethrow; claude-agent.refresh.test.ts adds "recovers when interrupting the old query throws Operation aborted" (interrupt mockRejectedValue → expects {refreshed:true}, end once, fresh query/abortController unpoisoned). Both files byte-identical to 536be50a7 blobs. Validation: pnpm --filter @posthog/agent typecheck ✓, biome lint 2 touched files ✓, vitest claude-agent.refresh.test.ts 10/10 ✓. |
| 17 | e47f5a6fd | 2026-06-02 | #2465 | Recover from missing shell sessions | port | 0/4/2 | replayed | Split per refactor homes. workspace-server packages/workspace-server/src/services/shell/shell.ts: DESTROYED_EXIT_CODE=130 + destroy() emits ShellEvent.Exit after sessions.delete (propagates via host-router shell.router.ts:98 onExit → ui ShellClient); new shell.test.ts (minimal node-pty mock harness — upstream's full 374L service.test.ts never ported, so only this commit's "emits an exit event for explicit teardown" + adjacent no-op-destroy test created). ui packages/ui/src/features/terminal/TerminalManager.ts: getErrorMessage import (@posthog/shared root, not /errors subpath), isMissingShellSessionError helper, TerminalInstance command/recoveryPromise fields, onData write-catch + ResizeObserver resize-catch → handleMissingSessionError, new handleMissingSessionError/recoverMissingSession (command sessions → handleExit; dedupe via recoveryPromise; retry write after recovery) — trpcClient.shell.* re-expressed as resolveService(SHELL_CLIENT) per existing file idiom. terminalStore.ts: PersistedTerminalStoreState, exported clearPersistedSessionIds, persist version:1 + migrate, partialize sessionId:null. New ui tests TerminalManager.test.ts (mocks @posthog/di/container resolveService instead of upstream @renderer/trpc) + terminalStore.test.ts (upstream's getProcess/pollingIntervals mocks dropped — polling moved to useShellProcessPoller, store has no pollingIntervals). Validation: ws-server+ui tsc --noEmit ✓, biome lint 6 touched files ✓, vitest shell.test.ts 2/2 + TerminalManager.test.ts/terminalStore.test.ts 3/3 ✓. |
| 18 | c58094ed1 | 2026-06-02 | #2364 | Scope oauth tokens by org | big | 0/47/2 | replayed | Decomposed 8-step replay + closeout. DB: migration 0007_futuristic_domino.sql + 0007_snapshot.json + _journal.json + schema (authOrgProjectPreferences table, authPreferences.lastSelectedOrgId) → packages/workspace-server/src/db; repo+mock gain getOrgProject/saveOrgProject + lastSelectedOrgId threading in PersistAuthPreferenceInput/save (closeout fixed the deferred threading + mock null placeholder). Auth core: packages/core/src/auth — schemas.ts (orgProjectsMap/currentOrgId/currentProjectId on authStateSchema, switchOrgInput, flattenProjectIds/findOrgForProject/pickInitialProjectId), auth.ts (switchOrg, buildOrgProjectsMap via GET /api/organizations/{orgId}/, patchCurrentOrganization PATCH /api/users/@me/, fetchUserContext, per-org lastSelectedProjectId persist), identifiers.ts (IAuthPreferenceStore + org-project records), authIdentity.ts currentProjectId, oauth.schemas.ts drops scoped_teams, auth.test.ts rewritten (23/23 ✓). Router: host-router auth.router.ts switchOrg one-line forward. Host adapter: apps/code port-adapters.ts AuthPreferencePortAdapter maps lastSelectedOrgId + org-project methods (closeout); enrichment hunk = container.ts:367 currentProjectId→EnrichmentAuth.projectId (ws-server enrichment test stubs the port, no change needed). UI: store.ts ANONYMOUS_AUTH_STATE new shape, authClient/useAuthSession/useAuthMutations (+useSwitchOrgMutation), useProjects rewritten from orgProjectsMap, ProjectSelectStep switch-org, 16+ consumer currentProjectId renames, ScopeReauthPrompt/sessionServiceHost(+recovery) test fixtures; api-client posthog-client setTeamId/approveAiDataProcessing (switchOrganization pre-existed :718); shared OAUTH_SCOPE_VERSION 4→5 (+test, dist rebuilt); apps/web dev-server.mjs fake state aligned. Upstream authStore.test.ts has no counterpart (ui store is a pure state holder, no syncAuthState/needsProjectSelection; currentUser-key unification already structural via authKeys.currentUser(authIdentity) useCurrentUser.ts:10 + clearAuthScopedQueries authQueries.ts:44). apps/mobile keeps its own scoped_teams flow — upstream didn't touch mobile. Validation (closeout): typecheck ✓ workspace-server, code (node+web), core, ui; earlier steps ✓ shared/api-client/host-router; biome lint touched ✓; vitest core auth 23/23, shared oauth 304, ScopeReauthPrompt 6, sessionServiceHost+recovery 110 ✓. |
| 19 | d526a4b9b | 2026-06-02 | #2366 | Switch-to-org button on plan usage screen | port | 0/1/0 | replayed | Single-file commit; target relocated to packages/ui/src/features/settings/sections/PlanUsageSettings.tsx. Removed module-level openBillingPage (HEAD variant took an injected PostHogAPIClient from useOptionalAuthenticatedClient — hook + both imports dropped); replaced with component-local switchOrgAndRefreshSeat (useSwitchOrgMutation.mutateAsync + fetchSeat({autoProvision:true})), openBillingPage (skips switch when orgId===currentOrgId, returns on switch failure, opens region-aware billingUrl) and switchToBillingOrg — transcribed verbatim from upstream. Added currentOrgId selector (#18 store field) + useSwitchOrgMutation import from @posthog/ui/features/auth/useAuthMutations (hook landed in #18). Both openBillingPage call sites dropped the client arg. hasBetterPlanElsewhere callout rebuilt per upstream: nested Flex, self-start button column gated on billingOrgId, "Switch to {seat.organization_name ?? 'Pro org'}" size-1 outline Button w/ Spinner on isPending, text-(--red-11) text-[12px] error on isError. Validation: pnpm --filter @posthog/ui typecheck ✓, pnpm exec biome lint touched file ✓. |
| 20 | e2387c7c6 | 2026-06-02 | #2367 | Approve ai data processing in app for admins | port | 0/3/1 | replayed | All 4 targets relocated by refactor; hunks re-applied at new homes. packages/api-client/src/posthog-client.ts:725 approveAiDataProcessing(): dropped response.ok throw, discard fetch result (fetcher already throws) — method itself pre-existed at HEAD via #18. packages/shared/src/analytics-events.ts: AI_CONSENT_GRANTED_INAPP:749 + EventPropertyMap never:871; dist rebuilt. packages/ui/src/features/ai-approval/AiApprovalScreen.tsx: in-app approve via useMutation(client.approveAiDataProcessing) + track(AI_CONSENT_GRANTED_INAPP) + invalidate authKeys.currentUsers() on success, Spinner-while-pending button, red error Callout on isError; removed approvalUrl/openApproval/cloudRegion/openExternalUrl/getCloudUrlFromRegion/ArrowSquareOut — imports repointed to HEAD homes (auth/authClient useAuthenticatedClient, auth/useCurrentUser authKeys). New packages/ui/src/features/ai-approval/AiApprovalScreen.test.tsx: upstream's 3 cases transcribed, mocks repointed @features/→@posthog/ui/ (authClient, useAuthMutations, useCurrentUser authKeys, settingsDialogStore, shell/analytics); upstream's SettingsDialog + trpc mocks dropped (HEAD takes settingsDialog as prop, no trpc import). Validation: shared build+typecheck ✓, api-client typecheck ✓, ui typecheck ✓, biome lint 4 touched files ✓, vitest AiApprovalScreen.test.tsx 3/3 ✓. |
| 21 | da826995d | 2026-06-03 | #2467 | PostHog Slack app in Slack-originated runs | mech | 2/0/0 | replayed | packages/agent untouched by refactor — both files byte-identical to upstream parent, full diff transcribed verbatim (git apply clean): agent-server.ts buildCloudSystemPrompt gains isSlack = this.getCloudInteractionOrigin() === "slack" + identityInstructions "# Identity / PostHog Slack app / Do NOT refer to yourself as Claude" block prepended to all 5 return templates; agent-server.test.ts new "identity instructions" describe (it.each slack-origin no-repo/repo, slack-origin existing-PR, it.each non-slack undefined/signal_report/posthog_code omit cases). Both files byte-identical to da826995d blobs (8f6551556, b01db2643). Validation: pnpm --filter @posthog/agent typecheck ✓, biome lint 2 touched files ✓, vitest agent-server.test.ts 51/51 ✓. |
| 22 | 64256f2e6 | 2026-06-03 | #2343 | cache per-task PR url+state | big | 0/11/2 | replayed | Decomposed 8-step replay + closeout. DB (packages/workspace-server/src/db): migration 0008_stiff_reptil.sql + 0008_snapshot.json + _journal.json idx 8 verbatim; schema.ts workspaces prUrl/prState (enum open/merged/closed/draft); workspace-repository.ts CachedPrState/PrCacheUpdate/updatePrCache + mock (updatePrCache, prUrl/prState null defaults). Schemas/event: services/workspace/schemas.ts taskPrInfoChangedPayload + cachedPrUrlInput/Output (+type exports); workspace.ts WorkspaceServiceEvent.TaskPrInfoChanged. Caching service: closeout moved the upstream GitService PR-cache logic (getTaskPrStatus cached-first + bg revalidate, getCachedPrUrl, computeWorktreeHasDiff, dedupe map, updatePrCache + emit-on-change) out of workspace-server GitService into NEW services/git/task-pr-status.ts TaskPrStatusService (injects TOKENS.GitService + WORKSPACE_REPOSITORY + WORKSPACE_SERVICE; mapPrState now exported from git/service.ts) — fixes steps-5/7 flagged runtime regression where required constructor deps on GitService would throw in the ws-server child container (di/container.ts:17 binds neither dep); GitService back to dep-free, git.integration.test.ts reverted to new GitService() (27/27 ✓). Router/port: host-router workspace.router.ts getCachedPrUrl + onTaskPrInfoChanged; ports/git-pr-status.ts IGitPrStatus.getCachedPrUrl. DI (apps/code container.ts): binds WORKSPACE_SERVER_TOKENS.GitService→GitService + GIT_PR_STATUS_PROVIDER→TaskPrStatusService. Core dedupe: retired now-dead uncached GitHostService.getTaskPrStatus + mapPrState + HostGitService interface member + TaskPrStatus/SidebarPrState types (core/src/git/git-host.ts, host-git.ts) — superseded by the cached provider, zero remaining importers. UI: useTaskPrUrl getCachedPrUrl fallback (cache last, upstream order); App.tsx useSubscription intent landed in ui workspace-events.contribution.ts onTaskPrInfoChanged (setQueriesData getTaskPrStatus by taskId predicate preserving hasDiff + setQueryData getCachedPrUrl) + test 5/5 ✓. Upstream log.warn on revalidate failure dropped (file's silent-catch idiom, no logger binding); inline comments omitted per repo rule. Validation (closeout): typecheck ✓ workspace-server, core, host-router, ui, code (node+web); biome lint ✓ 6 closeout files + packages/core (0 noRestrictedImports); vitest git.integration 27/27, ui workspace-events 5/5 + useTaskPrStatus 13/13 total, check-host-boundaries ✓ no new violations. |
| 23 | 843e0c40d | 2026-06-03 | #2460 | Remove "Stop All" from command center | port | 0/6/0 | replayed | All 6 files live at packages/ui/src/features/command-center/. Removed Stop All button + stopAll/hasActiveAgents/cells prop from CommandCenterToolbar.tsx, dropped cells= from CommandCenterView.tsx, swapped hasRunRef→persisted hasAutofilled in useAutofillCommandCenter.ts (unconditional autofillCells, hasAutofilled in deps), added hasAutofilled to store state/initial/assignTask/autofillCells (full-grid → {hasAutofilled:true})/partialize, transcribed 3 hook + 4 store test cases. Also deleted packages/core/src/command-center/stopAll.ts(+.test.ts): refactor-created host for the toolbar's stop-all logic, dead with the feature gone (grep: toolbar was sole consumer). Validated: pnpm --filter @posthog/core typecheck, pnpm --filter @posthog/ui typecheck, biome lint 6 ui files clean, vitest ui command-center 26/26, core command-center 35/35. |
| 24 | bf90d93c1 | 2026-06-03 | #2411 | mobile: inbox analytics parity | mech | 8/1/5 | replayed | apps/mobile untouched by refactor — all 9 pre-existing files byte-identical to upstream parent, full diff transcribed verbatim (git apply clean): new lib/analytics.ts (ANALYTICS_EVENTS, useAnalytics, useActiveTaskAnalyticsContext signal_report_id super-property, computeReportAgeHours) + test; new inbox/hooks/useInboxEngagementTracker.ts (OPENED/CLOSED/SCROLLED/ACTION lifecycle) + test; utils.ts buildInboxViewedProperties + new utils.test.ts; inboxFilterStore exports DEFAULT_STATUS_FILTER; inboxStore lastVisibleReportIds/previousOpenedReportId; DismissReportSheet onDismissed(DismissReportResult); TinderView trackReportAction dismiss/create_pr; (tabs)/inbox.tsx INBOX_VIEWED per focusVersion; inbox/[...id].tsx engagement tracker wiring + onScroll; task/[id].tsx useActiveTaskAnalyticsContext; tasks/types.ts signal_report field. All 14 files byte-identical to upstream blobs except 2 deliberate comment-path drift fixes: analytics.ts:6 "apps/code/src/shared/types/analytics.ts"→"packages/shared/src/analytics-events.ts" (event names verified matching at packages/shared/src/analytics-events.ts:771-775), utils.ts:103 renderer InboxSignalsTab path→packages/ui/src/features/inbox/components/InboxSignalsTab.tsx. @posthog/core import in analytics.ts = npm PostHog SDK core 1.20.0 (hoisted root node_modules, posthog-react-native dep), not workspace packages/core — resolves correctly since apps/mobile doesn't declare the workspace pkg. Validation: vitest analytics/utils/useInboxEngagementTracker tests 15/15 ✓; biome lint 14 touched files ✓; mobile tsc --noEmit zero errors in touched files (45 pre-existing baseline in untouched .test.tsx/setup.ts). |
| 25 | 6f783e1ee | 2026-06-03 | #2418 | additional directories UI button | port | 0/6/3 | replayed | Migrations transcribed verbatim (workspace-server 0008_snapshot byte-identical to upstream, prevId chain intact): new packages/workspace-server/src/db/migrations/0009_bake_default_directories.sql + meta/0009_snapshot.json, _journal.json idx 9. Backend: agent.ts (workspace-server) dropped resolveAdditionalDirectories + DefaultAdditionalDirectoryRepository injection, getOrCreateSession now reads workspaceRepository.getAdditionalDirectories directly; agent.test.ts mock/ctor arg removed. UI: new packages/ui/src/features/folder-picker/AdditionalDirectoriesButton.tsx (upstream verbatim, repointed to useHostTRPCClient + useService(ROOT_LOGGER) + ui useFolders per FolderPicker idiom); TaskInput.tsx renders it for workspaceMode!=="cloud"; useTaskCreation.ts adds listDefaults useQuery (useHostTRPC) + override state + reset-on-success + return fields. Saga step relocated per architecture: shared TaskCreationInput += additionalDirectories; core taskInput prepareTaskInput strips it for cloud; core taskCreationSaga gains additional_directories step with rollback via new ITaskCreationHost.addAdditionalDirectory/removeAdditionalDirectory (ui TrpcTaskCreationHost forwards to hostClient().additionalDirectories.addForTask/removeForTask — upstream trpcClient calls re-homed behind the host seam); saga test mockHost extended. Validation: shared dist rebuilt; typecheck shared/core/ui/workspace-server all clean; biome lint 11 touched files + packages/core clean; vitest taskCreationSaga.test 7/7, agent.test 18/18. |
| 26 | 4ea2cacea | 2026-06-04 | #2194 | inline banner on cloud stream disconnect | port | 0/6/0 | replayed | All 6 files relocated; hunks re-applied at new homes. AgentSession.errorRetryable?: boolean → packages/shared/src/sessions.ts:59 (upstream sessionStore.ts type moved to shared; dist rebuilt). View-state derivation errorRetryable: session?.errorRetryable → packages/core/src/sessions/sessionViewState.ts (SessionViewState field + deriveSessionViewState return; upstream useSessionViewState hook split into core derive + ui hook spreading ...derived, so ui hook needed no edit). SessionView.tsx (packages/ui/sessions/components): CloudStreamDisconnectedBanner component after DEFAULT_ERROR_MESSAGE (transcribed verbatim — Flex/Warning 14 duotone/red title+gray message/soft red Retry), errorRetryable prop + = false default, showInlineBanner = hasError && errorRetryable && events.length > 0 after handoffInProgress, banner rendered after DropZoneOverlay, full-screen overlay gated hasError && !showInlineBanner. Consumers CommandCenterSessionView.tsx + TaskLogsPanel.tsx (packages/ui): destructure errorRetryable + pass prop. Service hunks → packages/core/src/sessions/sessionService.ts retryCloudTaskWatch (errorRetryable: update.retryable (CloudTaskErrorPayload.retryable pre-exists at core/cloud-task/cloud-task-types.ts:38). Validation: shared build+typecheck ✓, core typecheck ✓, ui typecheck ✓, biome lint 6 touched files ✓. |
| 27 | c36eb21d1 | 2026-06-03 | #2477 | fix "Manage in PostHog Web" link | port | 0/1/0 | replayed | Single-hunk URL fix; upstream apps/code SlackSettings.tsx moved to packages/ui/src/features/settings/sections/SlackSettings.tsx:22 — changed /project/${projectId}/settings/environment-posthog-code#integration-posthog-code-slack → /project/${projectId}/settings/project-integrations#setting=integration-slack. Validation: pnpm --filter @posthog/ui typecheck ✓, biome lint SlackSettings.tsx ✓. Note: #28 (e8574bb6a) later changes the anchor to #integration-slack. |
| 28 | e8574bb6a | 2026-06-04 | #2479 | Deep-link Slack settings to correct anchor | port | 0/1/0 | replayed | Single hunk; file relocated to packages/ui/src/features/settings/sections/SlackSettings.tsx (apps path gone). Pre-image matched upstream parent exactly; changed slackSettingsUrl fragment #setting=integration-slack → #integration-slack at :22. Brief's "already environment-posthog-code anchor" claim was stale — tree had the old anchor. Validation: pnpm --filter @posthog/ui typecheck ✓, biome lint touched file ✓. |
| 29 | cb0e8b4c7 | 2026-06-04 | #2459 | mcp apps for posthog's mcp | port | 0/9/2 | replayed | Split across refactor homes. schemas hunk (BUILTIN_POSTHOG_SERVER_NAME/EXEC_TOOL_NAME/POSTHOG_EXEC_TOOL_KEY/LEGACY_RESOURCE_URI_META_KEY/resolveResultResourceUri/getUiResourceByUriInput) was ALREADY present at HEAD: packages/core/src/mcp-apps/schemas.ts:80-82,91,99-108,162 (covers every shared/types/mcp-apps.ts hunk) — added the upstream shared/types/mcp-apps.test.ts as packages/core/src/mcp-apps/schemas.test.ts (import from ./schemas). Core service packages/core/src/mcp-apps/mcp-apps.ts: added summarizeResult() free fn, discoverServerUiTools listed-tools log.info + exec-tool definition caching, client name Twig→posthog-code, getUiResourceForTool now delegates to new fetchUiResourceByUri(serverName,uri), new public getUiResourceByUri (ui:// guard) + private doFetchUiResource that RETHROWS transient connect/read errors (boot race) instead of caching null, notifyToolResult spreads summarizeResult; used this.log (injected RootLogger), not module log. New packages/core/src/mcp-apps/mcp-apps.test.ts adapted from upstream service.test.ts (constructor (urlLauncher, rootLogger) fake, no module-logger mock). host-router packages/host-router/src/routers/mcp-apps.router.ts: added getUiResourceByUri publicProcedure (getUiResourceByUriInput, mcpUiResourceSchema.nullable output) one-line forward. ws-server auth-adapter.ts:107 +{name:"x-posthog-mcp-consumer",value:"posthog-code"} (comment dropped per repo style) + test case; mcp-proxy.ts:171/191/231 added forwardRequest debug log + method/requestBody on auth-failure warn + forward-error log (uses this.log + existing truncateRequestBody). ui: useAppBridge HOST_INFO.name Twig→posthog-code; McpAppHost.tsx exec detection (isExec/execResourceUri from toolCall.rawOutput), conditional getUiResourceByUri vs getUiResource query (enabled gate), sentResultForCallRef + sendResultOnce dedupe, onToolResult exec-scoped delivery, exec replay useEffect, render log.debug→info+fields; McpToolBlock.tsx exec detection, hasUiByTool (enabled !isExec) + hasUi=isExec?!!execResourceUri:hasUiByTool, onDiscoveryComplete enabled gate + exec→getUiResourceByUri.pathFilter invalidation branch; schema imports from @posthog/core/mcp-apps/schemas. Validation: biome check 10 files clean; scoped typecheck core/ui/host-router/ws-server — zero errors in any touched mcp-apps/mcp-proxy/auth-adapter line; only exogenous baseline reds (api-client PermissionMode; stale @posthog/agent dist driving agent.ts + auth-adapter.ts:3-4 import errors, pre-existing). vitest: core mcp-apps.test+schemas.test 7/7 ✓, ws-server auth-adapter.test 6/6 ✓ (incl. new x-posthog-mcp-consumer case). |
| 30 | 4feabd560 | 2026-06-04 | #2481 | inbox: edit suggested reviewers in detail pane | port | 0/6/2 | replayed | Split across refactored homes. Types: packages/shared/src/domain-types.ts:408 SuggestedReviewerWriteEntry (github_login?/user_uuid?/github_name?); analytics-events.ts:509 added add_suggested_reviewer/remove_suggested_reviewer to InboxReportActionType + :614 suggested_reviewer_login?/suggested_reviewer_uuid? on InboxReportActionProperties (JSDoc dropped per repo style). api-client: posthog-client.ts:2180 updateSignalReportArtefact(reportId, artefactId, content) PUT + normalizeSignalReportArtefact guard, import SuggestedReviewerWriteEntry; posthog-client.test.ts appended updateSignalReportArtefact suite (it.each + 2 throw cases) using the api.fetcher.fetch makeClient shape. ui hook: packages/ui/src/features/inbox/hooks/useInboxReports.ts +useUpdateSuggestedReviewers (optimistic patch/rollback via useAuthenticatedMutation+useQueryClient+sonner toast, relative imports). NEW packages/ui/.../components/detail/SuggestedReviewersEditor.tsx (popover add/remove, core utils buildSuggestedReviewerFilterOptions/getSuggestedReviewerDisplayName, Badge primitive, useCurrentUser/useOptionalAuthenticatedClient/useInboxAvailableSuggestedReviewers). NEW useInboxReports.test.tsx (2 tests; mocks repointed to @posthog/ui/features/auth/authClient + sonner, dropped upstream's @renderer/trpc + @utils/logger mocks). ReportDetailPane.tsx: swapped suggestedReviewers useMemo→reviewerArtefact (SuggestedReviewersArtefact find), removed isSuggestedReviewerRowMe + inline section → <SuggestedReviewersEditor reportId/artefact/meUuid/fireAction={fireDetailAction}>; dropped now-unused imports (Badge primitive, ArrowSquareOutIcon/EyeIcon/InfoIcon, selectSuggestedReviewers, SuggestedReviewer type); DetailActionExtra auto-covers new analytics fields via Omit. Validation: shared dist rebuilt; biome check 8 files clean (1 import-order autofix); api-client typecheck 1 pre-existing unrelated err (@posthog/agent/execution-mode PermissionMode), ui typecheck only exogenous errs (workspace-server/agent dist staleness + pre-existing QuestionPermission), grep confirms 0 errors in touched files; vitest posthog-client.test.ts 20/20, useInboxReports.test.tsx 2/2. |
| 31 | 078c98cb5 | 2026-06-04 | #2472 | paste rich text as Markdown in composer | port | 2/1/3 | replayed | Ported to packages/ui. New utils/htmlToMarkdown.ts + .test.ts (turndown + @joplin/turndown-plugin-gfm singleton); new src/types/joplin-turndown-plugin-gfm.d.ts ambient decl. Wired handlePaste in tiptap/useTiptapEditor.ts: html→htmlToMarkdown(html, clipboardText)→effectiveText feeds shouldAutoConvertLongText + pasteTextAsFile (HEAD uses shouldAutoConvertLongText helper, not upstream inline length check; adapted), plus inline markdown insert before the >200 hint. Added deps to packages/ui/package.json: turndown ^7.2.4, @joplin/turndown-plugin-gfm ^1.0.67, @types/turndown ^5.0.6 (pnpm install updated lock, resolves). Validation: vitest htmlToMarkdown.test.ts 6/6 pass; biome check --write 5 files clean; pnpm --filter @posthog/ui typecheck = only exogenous baseline-red (@posthog/agent stale dist: api-client/workspace-server/permissions), zero errors in my touched paths. POST-COMMIT FIX: ambient joplin d.ts in ui/src/types was invisible to apps/web+code (they compile ui from source, sibling .d.ts not auto-included); ui-only typecheck during replay missed it. Added /// <reference path to htmlToMarkdown.ts (FileIcon.tsx idiom); full pnpm typecheck 22/22 green. |
| 32 | af00a58ab | 2026-06-04 | #2471 | recover pending permission prompts on reconnect | port | 3/2/0 | replayed | Split per refactor homes. Notification constants added in BOTH copies: packages/agent/src/acp-extensions.ts (PERMISSION_REQUEST/PERMISSION_RESOLVED after PERMISSION_RESPONSE, per-key comments matching idiom) and packages/core/src/sessions/acpNotifications.ts (bare keys, no per-key comments matching that file). Agent-side persistence transcribed verbatim into packages/agent/src/server/agent-server.ts: toolCallId? added to pendingPermissions map value type; relayPermissionToClient captures toolCall?.toolCallId, calls persistPermissionLifecycle(PERMISSION_REQUEST,…) and stores toolCallId in pendingPermissions.set; new persistPermissionLifecycle() appends {jsonrpc,method,params} via session.logWriter.appendRawLine (guards if(!this.session)return); resolvePermission emits PERMISSION_RESOLVED before pending.resolve. Renderer service.ts hunks → packages/core/src/sessions/sessionService.ts (SessionService moved there): module-level export function derivePendingPermissionRequests(entries) added before the class (uses already-imported isNotification/POSTHOG_NOTIFICATIONS/StoredLogEntry/CloudTaskPermissionRequestUpdate); handleCloudPermissionRequest param retyped to DerivedPermissionRequest; new private surfacePersistedPendingPermissions(); snapshot guard if(update.kind==="snapshot" && !isTerminalStatus(update.status)) inserted before the auto-flush NOTE block (log-append already above per upstream ordering). Tests: renderer service.test.ts describe block → new packages/core/src/sessions/derivePendingPermissionRequests.test.ts (3 tests, imports fn from ./sessionService, StoredLogEntry from @posthog/shared); agent question-relay.test.ts new "permission lifecycle persisted to log" describe appended before "relayAgentResponse duplicate suppression". Validation: biome check 6 files ✓ (no fixes); pnpm --filter @posthog/agent typecheck ✓; pnpm --filter @posthog/core typecheck ✓; vitest derivePendingPermissionRequests.test.ts 3/3 ✓; vitest question-relay.test.ts 43/43 ✓ (incl. new test). No timeout binary on host — used Bash tool timeout=150000 guard instead. |
| 33 | 5acc1e1a1 | 2026-06-04 | #2469 | migrate renderer to TanStack Router | decide | 5/53/29 | replayed | DECISION: file-based routing, MIRROR UPSTREAM. Generator (@tanstack/router-generator, standalone node) owned by packages/ui -> routeTree.gen.ts committed in packages/ui/src/router, biome-ignored + linguist-generated; both apps consume it; apps/code gets @tanstack/router-plugin for dev HMR+codesplitting. Route subsystem under packages/ui/src/router/. Content mirrored 1:1, only import specifiers adapted to @posthog/ui/*. In progress. STAGE 0 done (router deps in catalog+packages/ui, generator script, biome-ignore, .gitattributes, apps/code vite plugin). Install side-fixes (committed-tree was latent-red, turbo-cache-masked): pinned zod 4.3.6 via root pnpm.overrides (router install bumped it to 4.4.3); FIXED phantom zod dep -> declared zod ^4.1.12 in @posthog/shared (it imported zod undeclared -> duplicate nested copy -> SomeType brand mismatch breaking ws-server/core z.record). Full typecheck 22/22 green. PROGRESS: router subsystem BUILT + @posthog/ui typechecks 0 errors. Done: router/{routerRef,router,navigationBridge,RoutePending,useAppView,useOpenTask}.ts, all 13 route files under router/routes/, routeTree.gen.ts (generated, biome-ignored), settings split (components/SettingsPanel.tsx + thin SettingsDialog.tsx imperative wrapper + hooks/useOpenSettings.ts + stores/settingsPageStore.ts+test + types.ts), task-detail/stores/taskInputPrefillStore.ts, tasks/queries.ts (taskDetailQuery+getCachedTask via IMPERATIVE_QUERY_CLIENT), __root.tsx (= old MainLayout + Outlet + settings branch), App.tsx mounts RouterProvider. openTask preserves NavigationTaskBinder DI. REMAINING: sweep ~19 navigationStore + ~18 settingsDialogStore consumers (both stores still present so tree green mid-sweep), then DELETE navigation/store.ts+test + settingsDialogStore.ts+test + shell/MainLayout.tsx, then full typecheck. Apps consumers too: web-auth-side-effects, task-deletion, desktop-services, auth-side-effects, mobile _layout. COMPLETE (code-level): all consumers swept (ui 4 agent-batches + 9 relative-import stragglers + apps: task-deletion/desktop-services/auth-side-effects(code+web)); deleted navigation/store.ts(+test), settingsDialogStore.ts(+test), shell/MainLayout.tsx. Full pnpm typecheck 22/22 green, @posthog/ui 611/611 tests pass, biome clean, host-boundaries OK. REMAINING VALIDATION: live Electron smoke (navigation/routing correctness can't be headlessly tested) — the only unverified piece, flagged from the start. |
| 34 | 9dc170e06 | 2026-06-04 | #2176 | inbox: filter reports by priority | port | 0/8/0 | replayed | Split across refactor homes: query param priority? -> @posthog/shared/domain-types SignalReportsQueryParams (+root re-export of existing SignalReportPriority type); searchParams set -> api-client posthog-client.ts reports query; buildPriorityFilterParam + it.each test -> @posthog/core/inbox/reportFilters(.test) (filter builders live in CORE not a ui util); priorityFilter state/togglePriority/setPriorityFilter/reset/persist + tests -> ui inboxSignalsFilterStore(.test); InboxSignalsTab wires priority into query memo+deps+hasActiveFilters; FilterSortMenu PRIORITY_OPTIONS + Priority section before Status. Validation: shared dist rebuilt; full typecheck 22/22; core reportFilters 20/20, ui store 16/16; biome clean. |
| 35 | 444d9ce49 | 2026-06-04 | #2485 | router devtools dismissable via Devtools shell | port | 3/1/0 | replayed | Devtools shell: __root.tsx (packages/ui/src/router/routes) TanStackRouterDevtools -> unified TanStackDevtools shell (lazy Promise.all of @tanstack/react-devtools + @tanstack/react-router-devtools, hideUntilHover config + router plugin), both DEV-gated usages swapped. Deps: @tanstack/react-devtools (catalog, ui dep), @tanstack/devtools-vite (apps/code devDep) + catalog/exclude entries (+devtools-core). apps/code vite.renderer.config: devtools() source-inspector plugin, mode===development only. Validation: install green, full typecheck 22/22, biome clean. Dev-only (runtime = dev server, user-run). |
| 36 | 73fd6add6 | 2026-06-04 | #2486 | cloud-agent: git_signed_rewrite tool | mech | 6/0/2 | replayed | packages/agent + packages/git untouched by refactor -> git apply of the full commit was CLEAN (prior #7/#14 edits to signed-commit.ts don't overlap #36's hunks). New: signed-git-tool.ts + signed-rewrite.ts (git_signed_rewrite local tool). Modified signed-commit.ts/signed-commit-shared.ts/local-tools index/agent-server byte-identical to upstream 73fd6add6 blobs (full convergence). Validation: git+agent typecheck 0 errors, git signed-commit.test 8/8, biome clean, full typecheck 22/22. |
| 37 | d45115636 | 2026-06-04 | #2466 | packaging: .deb and .rpm | mech | 5/0/0 | replayed | Packaging/CI (apps/code untouched-config). git apply of non-lock files CLEAN: forge.config.ts gains MakerDeb/MakerRpm (hunk applied on our diverged base, so not byte-identical to upstream full file but intent landed), build-linux-docker.sh + code-release.yml byte-identical to upstream; package.json += @electron-forge/maker-deb + maker-rpm ^7.11.1; lockfile regenerated via pnpm install. Validation: install green, apps/code typecheck 0, full typecheck 22/22. Runtime = electron-forge make (CI/user-run, can't headless). |
| 38 | 1e35e640e | 2026-06-04 | #2473 | folder-picker loading state | port | 0/1/1 | replayed | FolderPicker loading state ported to packages/ui/src/features/folder-picker/FolderPicker.tsx (flat, not components/): isOpening useState + CircleNotch spinner + Opening... text + disabled/aria-busy on the no-recent-folders buttons; intent mirrored, specifiers are ours (useHostTRPCClient/useService(ROOT_LOGGER)/useFolders). New FolderPicker.test.tsx with mocks repointed to @posthog/host-router/react + @posthog/ui/features/folders/useFolders + @posthog/di/react. Validation: ui typecheck 0, test 2/2, biome clean, full typecheck 22/22. |
| 39 | e38d72482 | 2026-06-04 | #2362 | Fix sidebar task scroll layout | port | 0/2/1 | replayed | Sidebar scroll layout (3 files, agent-ported mirroring upstream at our specifiers): NEW packages/ui/src/features/sidebar/components/TasksHeader.tsx (TasksHeader + TaskSearchButton + TaskFilterMenu moved out of TaskListView; useMeQuery@auth/useMeQuery, useCommandMenuStore@shell, useSidebarStore@sidebar/sidebarStore); SidebarMenu.tsx drops ScrollArea wrapper -> flex min-h-0 col + sticky nav/separator/TasksHeader + scrollable task div; TaskListView.tsx strips the moved helpers + simplifies SectionLabel. Validation: full typecheck 22/22, sidebar tests 26/26, biome clean. |
| 40 | 3f1cc9f9c | 2026-06-04 | #2422 | PR badge in sidebar task list | port | 0/3/2 | replayed | PR badge in sidebar (agent-ported, 5 files + dep). NEW packages/ui/src/primitives/NestedButton.tsx(+test) verbatim (span role=button, a11y biome-ignores kept). TaskIcon/TaskItem: inline role=button spans -> NestedButton; PrBadge (GitPullRequest + parseGithubUrl from @posthog/git/utils SUBPATH (biome bans only bare @posthog/, subpath OK) + openExternalUrl, NOT upstream openUrlInBrowser); prUrl prop threaded; cloudPrUrl already on core TaskData. TaskListView passes task.cloudPrUrl. Added @posthog/git workspace: to ui deps (NOTE: ui->git dep; subpath is pure parser, web typecheck green; could relocate parseGithubUrl to shared later for stricter purity). Validation: full typecheck 22/22, NestedButton+sidebar tests 30/30, biome clean. |
| 41 | 86889386e | 2026-06-05 | #2482 | mobile: edit suggested reviewers (port of #2481) | mech | 6/3/2 | replayed | Mobile-only (apps/mobile untouched by refactor) -> git apply CLEAN. 9/11 files byte-identical to upstream 86889386e; utils.ts + lib/analytics.ts DIFF only because earlier mobile replays (#24) touched them, hunks merged. New: EditReviewersSheet/ReviewerOptionRow + useInboxReports edit-mutation + utils. Validation: mobile typecheck 0 errors (fully green, not baseline), inbox utils.test 11/11, full typecheck 22/22. |
| 42 | 5a638ea41 | 2026-06-04 | #2476 | show PostHog products used below each turn | port | 9/3/5 | replayed | PostHog products bar. Agent side (untouched) git apply CLEAN: posthog-products.ts(+test, product catalog + PostHogProductId), RESOURCES_USED in acp-extensions, claude-agent/hooks/options/types. NEW agent subpath export ./posthog-products (tsup entry + package.json + dist built) so ui imports the type via allowed subpath (bare @posthog/agent banned for ui). UI side (agent-ported, 6 files -> packages/ui/.../sessions/components): NEW accumulateSessionResources(.ts/.test), SessionResourcesBar.tsx (PostHogProductId@agent/posthog-products, isNotification/POSTHOG_NOTIFICATIONS@agent/acp-extensions matching existing buildConversationItems, AcpMessage@shared, openUrlInBrowser@ui/utils/browser, CHAT_CONTENT_MAX_WIDTH@ui/sessions/constants), buildConversationItems comment+test, SessionView renders . Validation: full typecheck 22/22, agent 79 tests, ui 16 tests, biome clean. |
| 43 | a11534062 | 2026-06-05 | #2332 | select task title text entering rename mode | port | 0/2/0 | replayed | Trivial: input.setSelectionRange(len,len) -> input.select() in packages/ui/src/features/sidebar/components/items/TaskItem.tsx:240 + packages/ui/src/features/task-detail/HeaderTitleEditor.tsx:22 (flat, not components/). ui typecheck 0. |
| 44 | fa8df3a0f | 2026-06-04 | #2495 | Restore "Back to app" exit, rename spend banner | port | 0/3/0 | replayed | 3 files at our paths: navigationBridge (router/) += canGoBackInHistory (history.canGoBack()); useOpenSettings.closeSettings -> if !onSettingsRoute return; canGoBack? back : navigateToCode (Back-to-app fallback); TokenSpendAnalysisBanner (billing/, flat) 'PostHog LLM analytics'->'PostHog AI Observability' x2. Validation: full typecheck 22/22, biome clean. |
| 45 | e0ddd01e4 | 2026-06-04 | #2339 | MCP permission dialog: server name + exec context | mech | 2/0/0 | replayed | packages/agent (untouched) git apply CLEAN, byte-identical: claude/permissions/permission-handlers.ts(+test) show server name + exec context in MCP permission dialog. agent typecheck 0, test 16/16. |
| 46 | 5f1f254c7 | 2026-06-04 | #2494 | Validate external URL schemes before opening | port | 1/2/2 | replayed | Validated once in shared. NEW packages/shared/src/url.ts(+test) isSafeExternalUrl (http/https/mailto only) + index export (biome re-sorted). Wired at OUR homes: ws-server os/schemas.ts openExternalInput url.refine(isSafeExternalUrl) (router uses the shared schema, not inline like upstream); ui/utils/browser.ts openUrlInBrowser guards if(!isSafeExternalUrl)return (uses openExternalUrl port, not trpcClient). shared dist rebuilt. Validation: url.test 16/16, full typecheck 22/22, biome clean. |
| 47 | 3ff2b739d | 2026-06-04 | #2340 | human-readable worktree branch names | mech | 1/0/2 | replayed | packages/git (untouched) git apply CLEAN, byte-identical: NEW worktree-name.ts(+test) human-readable worktree branch names + worktree.ts uses it. git build+typecheck 0, git tests 52/52, full typecheck 22/22. |
| 48 | c7d19fceb | 2026-06-05 | #2443 | lock composer top edge (suggestions jump) | port | 0/3/0 | replayed | 3 task-detail components at same relative path (packages/ui/.../task-detail/components): path-translated git apply CLEAN. CSS/framer-motion only: SuggestedTaskCard drops index prop + scale anim, SuggestedTasksPanel inline page variants + nested AnimatePresence, TaskInput composer pinned to vertical center with absolute mode-row + suggestions below. Hunks merged onto our diverged base. ui typecheck 0, full typecheck 22/22, biome clean. |
| 49 | faf2d3de3 | 2026-06-05 | #2475 | incremental conversation parsing + memoize UserMessage | port | 0/3/3 | replayed | Incremental conversation parsing (agent-ported, 6 sessions files, perf). buildConversationItems.ts split into reusable processEvent/finalizeBuilder/readLastTurnInfo/createItemBuilder/markThoughtCompletion + types (public fn unchanged; #42 resources_used comment preserved). NEW incrementalConversationItems.ts(+equivalence test) + hooks/useConversationItems.ts (ref-cached). ConversationView uses the hook; UserMessage wrapped in memo. AcpMessage@shared. Validation: equivalence+regression 37/37, ui typecheck 0, full typecheck 22/22, ui suite 648/648. |
| 50 | f30a60871 | 2026-06-05 | #2499 | fix(code): stop false "No internet connection" from a single failed probe | port | 0/2/? | replayed | Connectivity service moved to packages/workspace-server/src/services/connectivity (service.ts+test). Manual (our service inits in ctor, not init()): CHECK_URL->CHECK_URLS[google,cloudflare] + OFFLINE_CONFIRM_THRESHOLD=2 + consecutiveFailures + probe()/Promise.any; checkConnectivity confirms offline only after 2 consecutive fails. Test rewritten for new behavior + multi-endpoint, adapted to new ConnectivityService(). ws-server typecheck 0, tests 16/16, full typecheck 22/22. |
| 51 | a7937a893 | 2026-06-05 | #2487 | feat(signals): add option for default team channel for signals notifications | port | 0/10/? | replayed | Signals default team channel (agent-ported, 10 files). shared SignalTeamConfig += default_slack_notification_channel; api-client updateSignalTeamConfig widened to Partial; ui settings: NEW SlackChannelCombobox + SignalDefaultChannelSettings + SlackInboxNotificationsSettings, SignalSlackNotifications slimmed, SignalSources +showSlackNotifications, SlackSettings swap; inbox useSignalSourceManager += handleUpdateTeamSlackChannel. KEY: reused our @posthog/core/settings/slackNotificationTarget helpers (refactor already factored them) instead of upstream locals; api via useAuthenticatedClient not trpcClient. shared dist rebuilt. Validation: full typecheck 22/22, ui settings/inbox 18, core settings 46, biome clean. |
| 52 | cee190ec6 | 2026-06-05 | #2484 | fix(onboarding): make folder picker dialog reliably open on top | port | 1/1/? | replayed | Electron adapter stays in apps/code (architecture). git apply CLEAN, byte-identical: electron-dialog.ts resolveDialogParent() (focused window -> visible fallback + focus, parents native dialogs on top) + NEW electron-dialog.test.ts. code typecheck 0, test 5/5. |
| 53 | 3ce204e99 | 2026-06-05 | #2501 | chore(code): add flag to discovery run | port | 1/2/? | replayed | Discovery flag. Our tree moved the discovery/enricher branching into core SetupRunService.maybeStart (vs upstream's inline hook). Applied intent there: maybeStart(dir, discoveryEnabled) always startEnricherForRepo, gate startDiscovery on flag + !anyDiscoveryStarted; removed startSetup. shared/flags.ts += DISCOVERY_RUN_FLAG; hook reads useFeatureFlag + passes it. shared dist rebuilt. core+ui typecheck 0, setup test 6/6, full typecheck 22/22. |
| 54 | ed362597e | 2026-06-05 | #2502 | chore(code): bump Pro tier usage banners from 20x to 40x | port | 0/3/? | replayed | PRO_USAGE_MULTIPLIER=40 added to @posthog/core/billing/usageDisplay (formatResetTime home in our tree, not a ui billing/utils.ts); UsageLimitModal '20x more'->${PRO_USAGE_MULTIPLIER}× more, PlanUsageSettings badge + charge-description templated. core from src (no rebuild). Full typecheck 22/22, biome clean. |
| 55 | 636bb6b2e | 2026-06-06 | #2506 | feat(agent): forward task title as $ai_generation property | mech | 4/0/? | replayed | packages/agent (untouched) git apply CLEAN, byte-identical: gateway.ts forwards task title as $ai_generation property (+test), agent-server wiring (+configure-environment test). agent typecheck 0, tests 30/30. |
| 56 | a2582f56a | 2026-06-06 | #2505 | feat(signals): add Scouts as a signal source in the inbox | port | 0/6/? | replayed | Scouts signal source (6 files). api-client SignalSourceConfig source_product += signals_scout, source_type += cross_source_issue; ui (3 path-translated): SignalCard scout source-line, FilterSortMenu CompassIcon option, source-product-icons SOURCE_PRODUCT_META; inboxSignalsFilterStore (flat) SourceProduct += signals_scout; the Exclude<SourceProduct,...> SOURCE_TYPE_MAP lives in @posthog/core/inbox/signalSourceService (refactor moved it from the ui hook) -> added signals_scout there x2. Full typecheck 22/22, inbox tests 44/44. |
| 57 | 7a4f19a33 | 2026-06-06 | #2508 | fix(agent): detect feature flags product across tool-name variants | mech | 0/2/? | replayed | packages/agent/src/posthog-products.ts(+test) (the #42 file) git apply CLEAN, byte-identical: detect feature-flags product across tool-name variants. agent dist rebuilt (ui consumes ./posthog-products subpath). agent test 59/59, ui typecheck 0. |
| 58 | df832cdb7 | 2026-06-08 | #2520 | chore(ci): add react doctor github action | mech | 0/2/? | replayed | 2 NEW CI files (.github/scripts/react-doctor-comment.mjs + workflows/react-doctor.yml) git apply CLEAN, byte-identical. CI-only, no typecheck impact; biome clean. |
| 59 | 336f30382 | 2026-06-08 | #2500 | fix(sessions): keep conversation pinned to bottom incl. footer | port | 0/1/? | replayed | VirtualizedList footer-as-paddingEnd rewrite (packages/ui/.../sessions/components/VirtualizedList.tsx). Path-translated git apply CLEAN + byte-identical (our #13 tanstack-virtual rewrite matched upstream base): footer reserved as paddingEnd (not fake virtual row) so followOnAppend works; re-pin keyed off totalSize; scroll hysteresis (FAR_DRIFT_THRESHOLD). ui typecheck 0, full typecheck 22/22. |
| 60 | 3870c79d0 | 2026-06-08 | #2525 | fix(ci): harden react-doctor workflow and comment renderer | mech | 0/2/? | replayed | Hardens the #58 CI files (react-doctor-comment.mjs + react-doctor.yml). git apply CLEAN, byte-identical. CI-only, biome clean. |
| 61 | 2436b3742 | 2026-06-08 | #2523 | feat(tasks): show upgrade prompt for over-limit cloud task creation | port | 0/8/? | replayed | Over-limit upgrade prompt (agent-ported, 10 files, architecture-sensitive). Routed cloud-usage preflight through core->host port (NOT upstream's direct trpc in renderer service, since our TaskService is in core): ITaskCreationHost += assertCloudUsageAvailable; core taskService isUsageLimitResult + usage_limit failedStep + CLOUD_USAGE_LIMIT_ERROR_MESSAGE from api-client; ui preflightCloudUsage.ts(+test) via HOST_TRPC_CLIENT + usageLimitStore + track; taskCreationHostImpl delegates; useTaskCreation preflight+suppress; inbox hooks adapted to our SignalReportTaskService status-union divergence. api-client CloudUsageLimitError/withCloudUsageLimitCheck; shared analytics CLOUD_TASK_USAGE_BLOCKED. Validation: full typecheck 22/22, preflight 5/5, core task-detail 25/25, api-client 20/20, biome clean. |
| 62 | 91f5bc510 | 2026-06-08 | #2528 | fix(ci): match linux maker bin to executableName | port | 1/0/? | replayed | 1-line forge.config.ts (apps/code, same path; touched in #37): sharedLinuxOptions.bin 'posthog-code'->'PostHog Code' (+comment) to match packagerConfig.executableName for deb/rpm maker bin lookup. code typecheck 0. Packaging change (runtime=make, CI). |
| 63 | 9151bc2b9 | 2026-06-08 | #2317 | fix(inbox): break signal summary sections onto separate lines | port | 0/3/? | replayed | NEW packages/ui/src/features/inbox/utils/formatSignalReportSummaryMarkdown.ts(+test) verbatim (pure regex formatter, breaks section: headers onto own lines); SignalReportSummaryMarkdown.tsx imports it, raw=format(rawContent), listMarkdown uses rawContent. ui typecheck 0, test 4/4, full typecheck 22/22. |
| 64 | ff99183ab | 2026-06-08 | #2480 | feat(inbox): configurable base branch for inbox auto-PRs | port | 0/6/? | replayed | Configurable base branch for inbox auto-PRs (agent-ported, 6 files +2 core). shared SignalTeamConfig += autostart_base_branches; api-client updateSignalTeamConfig partial widened; ui NEW AutostartBaseBranchesSettings (GitHubRepoPicker+BranchSelector), SignalSources wires it, useSignalSourceManager handleUpdateAutostartBaseBranches, useCreatePrReport computes baseBranch. NECESSARY DIVERGENCE: our TaskCreationInput built in core SignalReportTaskService, so baseBranch threaded through core signalReportTaskService.ts + reportTaskCreation.ts (branch: baseBranch ?? null) or override would be inert. shared dist rebuilt. Validation: full typecheck 22/22, ui settings/inbox 18, core inbox 65. |
| 65 | c419790b4 | 2026-06-08 | #2503 | feat(code): add claude code import page to onboarding | port | 1/8/? | replayed | Claude-config import onboarding (agent-ported, ARCH split). Upstream main fs-router -> NEW ws-server onboarding-import service (schemas/identifiers/module/test, reads ~/.claude.json + settings.json, reuses skills skill-discovery + FOLDERS_SERVICE) + host-router onboarding-import.router (registered in router.ts + container.ts load) + ui ImportConfigStep.tsx/.css + useHasImportableConfig via useHostTRPC (@posthog/host-router/react). DIVERGENCE: our onboarding step logic in core, so import-config step threaded through core steps.ts computeActiveSteps(hasCodeAccess, hasImportableConfig) + test. shared OnboardingStepId += import-config. Validation: 5 pkgs typecheck 0, ws-server import test 3/3, core steps 6/6, host-boundaries clean, full typecheck 22/22. |
| 66 | 1a83b8b34 | 2026-06-08 | #2229 | fix(code): show user skills in / popup and drop the autofill | port | 0/9/? | replayed | User skills in / popup + drop autofill (agent-ported, 9 files). getSuggestions returns AvailableCommand[] |
| 67 | 88cbbedae | 2026-06-08 | #2534 | Add "why" context and Slack thread link to agent-created PRs | mech | 2/0/? | replayed | packages/agent (untouched) git apply CLEAN, byte-identical: agent-server.ts adds why-context + Slack thread link to agent-created PRs (+test). agent typecheck 0, test 54/54. |
| 68 | fb0bd9d0e | 2026-06-08 | #2529 | fix(code): make PR diff source consistent with PR badge | port | 0/1/? | replayed | 1 file (packages/ui/.../code-review/hooks/useEffectiveDiffSource.ts): swap useLinkedBranchPrUrl -> useTaskPrUrl(taskId, workspace?.mode===cloud) so diff source matches PR badge. useTaskPrUrl flat in our git-interaction. ui typecheck 0. |
| 69 | d36064a57 | 2026-06-08 | #2537 | feat(code): auto-run commands during onboarding | port | 0/2/? | replayed | Auto-run onboarding commands (agent-ported, 2 files). InstallCliStep.tsx += RunnableCommand (embedded auto-running Terminal + exit-code + analytics); specifiers: Terminal/terminalManager from @posthog/ui/features/terminal (flat, singleton export), isMac from @posthog/ui/utils/platform; shell.destroy via useHostTRPCClient() imperative seam (useHostTRPC is query-proxy, no .mutate). shared analytics ONBOARDING_CLI_RUN_COMPLETED. shared dist rebuilt. Validation: ui typecheck 0, terminal test 1/1, full typecheck 22/22. |
| 70 | 053465407 | 2026-06-08 | #2532 | chore(code): add prompt sent event to cloud tasks | port | 0/1/? | replayed | PROMPT_SENT event on cloud-task start. Saga moved to core (taskCreationSaga.ts); upstream's renderer track() = host concern, so added track:(event,props)=>void to TaskCreationDeps (mirrors sessionService deps), called after startTaskRun if transport with {task_id,is_initial:true,execution_type:cloud,prompt_length_chars}. TaskService injects ANALYTICS_SERVICE (IAnalytics, like cloud-task.ts) + passes track to both saga deps; saga test mocks += track vi.fn() x7. Validation: core typecheck 0, saga test 7/7, full typecheck 22/22. |
| 71 | a279eafa4 | 2026-06-08 | #2530 | feat(code): add warning dialog for archiving running tasks | port | 0/3/? | replayed | apps/code/scripts/download-binaries.mjs(+test) (build scripts, unchanged path) git apply CLEAN, byte-identical: retry binary downloads on transient HTTP errors. biome clean, vitest 6/6. |
| 72 | 1123df10a | 2026-06-08 | #2509 | fix(ci): Retry binary downloads on transient HTTP errors | port | 1/1/? | replayed | SignalCard.tsx (the #56 file) path-translated git apply CLEAN (merged on our base): prettifyScoutName(skill_name) + signal.extra.skill_name -> 'Scout · ' on signal cards. ui typecheck 0. |
| 73 | f1bbd22e0 | 2026-06-09 | #2538 | feat(code): show scout name on signal cards | port | 0/1/? | replayed | Archive-running-task warning (3 files). NEW ui sidebar/components/ArchiveRunningTaskDialog.tsx (pure, verbatim); SidebarMenu.tsx (manual, imports diverged): isTaskActivelyRunning + archiveConfirm state + handleTaskArchive->useCallback(guard running) + handleConfirmArchive + onArchive in ctx-menu opts + dialog render; useTaskContextMenu.ts (features/tasks/) +onArchive option used in archive case. ui typecheck 0, sidebar tests pass, full typecheck 22/22. |
| 74 | 59a93d859 | 2026-06-09 | #2524 | refactor(rename): use "AI observability" for renamed LLM analytics product | port | 3/7/? | replayed | 'LLM analytics' -> 'AI observability' label/URL rename (10 files). mobile (FilterSheet/SignalCard) + agent posthog-products.ts byte-identical git apply (untouched subtrees); 7 renderer files at our homes (TokenSpendAnalysisBanner flat ui, spendAnalysisPrompt -> core/billing, inbox components) applied via direct string sub (context diverged): docs/llm-analytics->ai-observability, 'LLM [Aa]nalytics'->'AI observability', 'PostHog AI Observability'->lowercase. llm_analytics IDENTIFIER/value untouched. agent dist rebuilt (consumed subpath). Validation: full typecheck 22/22, core spendAnalysis 21/21, biome clean. |
| 75 | 19b6e12bc | 2026-06-09 | #2539 | fix(ci): pre-create release so parallel publishers don't race | mech | 1/0/? | replayed | .github/workflows/code-release.yml (CI, unchanged path) git apply CLEAN, byte-identical: pre-create release so parallel publishers don't race. CI-only, no typecheck impact. |
| 76 | 0d1b0faef | 2026-06-09 | #2540 | feat(agent): move Slack thread link to PR footer | mech | 2/0/? | replayed | 2 ui files path-translated git apply CLEAN: command/keyboard-shortcuts.ts (prompt-history prev/next shift+up/down -> up/down) + message-editor/tiptap/useTiptapEditor.ts (arrow-key history nav only when input empty + !shiftKey; dropped isAtStart/isAtEnd/forceNavigate). full typecheck 22/22. |
| 77 | d069600f3 | 2026-06-09 | #2542 | fix(message-editor): only navigate prompt history when input is empty | port | 0/2/? | replayed | packages/agent (untouched) git apply CLEAN, byte-identical: agent-server.ts moves Slack thread link to PR footer (+test). agent typecheck 0, test 55/55. |
| 78 | f2f2609be | 2026-06-09 | #2474 | feat: Home Tab | big | 4/10/48 | replayed | Decomposed pass; upstream main-process plumbing COLLAPSED per architecture (both upstream services are thin authenticated clients over the PostHog cloud API — placement rule sends cloud API to core+api-client, so no main services, no tRPC routers, no MAIN_TOKENS, no renderer subscriptions). Wire schemas → core: home-snapshot.ts→core/home/schemas.ts + pr-snapshot.ts→core/home/prSnapshot.ts + workflow.ts→core/workflow/schemas.ts (HomeEvent/WorkflowEvent emitter types dropped — no emitters remain), workflow-validate(.test).ts→core/workflow/workflowValidate(.test).ts 9/9 ✓. api-client posthog-client.ts += getHomeSnapshot/refreshHomeSnapshot/getCodeWorkflow/saveCodeWorkflow (409/422 pass the structured body)/resetCodeWorkflow via project-scoped fetcher idiom (covers upstream authService.authenticatedProjectFetch hunk). HomeService 120s poll+dedupe → ui hooks/useHomeSnapshot.ts (useAuthenticatedQuery + zod parse + EMPTY fallback + refetchInterval 120s; snapshot's only consumer is HomeView — upstream SidebarMenu renders HomeItem without attentionCount, verified); WorkflowEvent.Changed → useSaveWorkflowMutation/useResetWorkflowMutation onSuccess setQueryData(homeKeys.workflow) — replaces subscriptions.ts + App.tsx registerHomeSubscriptions (DROPPED); home.refresh kept as api-client method (zero UI consumers upstream too). ui feature agent-ported: components/ ×9 + config/ ×7 (ConfigMap trpc save/reset → the mutation hooks; divergence: our useConnectivity lacks isChecking/check(), Retry=refetch only) + useWorkstreamPresentation + stores/utils (+27 tests ✓; homeUiStore electronStorage→ui/shell/rendererStorage). useRunWorkstreamAction re-seamed: get(RENDERER_TOKENS.TaskService)→useService(TASK_SERVICE), inbox resolveDefaultModel→useService(REPORT_MODEL_RESOLVER), pendingTaskPromptStoreApi@ui/shell, navigateToTaskPending@ui/router; useSkillsForPicker wraps existing useSkills host seam; useBoundActions verbatim. Sidebar: combined HomeItem.tsx split per upstream (HomeItem rewritten + NEW InboxItem/NewTaskItem/SidebarCountBadge), SidebarMenu flag-gated HomeItem + navigateToHome + NewTaskItem variant prop dropped, useSidebarData += isHomeViewActive + ViewState "home" (core sidebarData.types.ts SidebarData += isHomeViewActive); upstream's toTaskData extraction ALREADY-PRESENT as core deriveTaskData (buildSidebarData.ts; upstream toTaskData had zero external consumers). Router: NEW routes/code/home.tsx, __root.tsx HOME_TAB_FLAG + flags-loaded redirect (onFeatureFlagsLoaded@ui/shell/posthogAnalyticsImpl), useAppView "home", navigationBridge.navigateToHome, routeTree.gen.ts regenerated via generate-routes (+21 = upstream stat). shared flags.ts += HOME_TAB_FLAG, analytics TaskCreatedFrom += "home-quick-action"; .gitignore tsup hunk; docs ×3 transcribed (implementation-path sections updated to our homes, historical design bullets verbatim). Upstream main service tests' wire-contract intent → NEW core/home/schemas.test.ts 12/12 ✓ (poll/emit mechanics have no target). Validation: full pnpm typecheck 22/22 ✓, ui home+sidebar+inbox 55/55 ✓, biome ✓, host-boundaries no new violations ✓. ENV BASELINE (Node 26.0.0 on this machine): 63 ui test failures in 4 UNTOUCHED zustand-persist test files (panelLayoutStore/terminalStore/inboxSignalsFilterStore/useSeedSuggestedReviewerFilter — Node 26's experimental localStorage stub shadows jsdom's; all 10 involved files verified byte-identical to HEAD) — fixed via test-setup shim; better-sqlite3 rebuilt for NODE_MODULE_VERSION 147. |
| 79 | adf5bf5f9 | 2026-06-09 | #2548 | fix(agent-server): remove debug build-marker log on start | mech | 1/0/0 | replayed | packages/agent (untouched) git apply CLEAN: agent-server.ts start() drops the 🐷 build-marker debug log. agent typecheck 0. |
| 80 | add02dc55 | 2026-06-09 | #2546 | feat(agent): exclude Code from "PostHog resources used" bar | port | 5/1/0 | replayed | Agent part (claude-agent.ts, hooks.ts+test, session/options.ts, posthog-products.ts) git apply CLEAN — drops code product detection + catalog entry; agent dist rebuilt (ui consumes ./posthog-products subpath). UI hunk path-translated to packages/ui/src/features/sessions/components/SessionResourcesBar.tsx (the #42 file): CodeIcon import + PRODUCT_ICON.code + PRODUCT_DOC_URL.code removed, sed-rewrite git apply CLEAN. Validation: agent typecheck ✓, hooks/refresh/models tests 63/63 ✓ (batch), ui typecheck ✓, biome ✓. |
| 81 | dea0a5aa9 | 2026-06-09 | #2533 | feat(inbox): remove scale-gated rollout for signals inbox | port | 3/5/0 | replayed | Mobile part (utils.ts/test, lib/analytics.ts 1-line deletions) git apply CLEAN. Renderer/shared at our homes: InboxEmptyStates.tsx (packages/ui inbox) drops GatedDueToScalePane + now-dead imports (CheckCircleIcon/ANALYTICS_EVENTS/builderHog/track/useState); InboxView.tsx rewritten to upstream post-state (gating flag + gated INBOX_VIEWED effect removed); InboxSignalsTab.tsx drops is_gated_due_to_scale payload field; packages/shared/src/flags.ts drops INBOX_GATED_DUE_TO_SCALE_FLAG (upstream constants.ts); analytics-events.ts drops is_gated_due_to_scale field + INBOX_INTEREST_REGISTERED event + EventPropertyMap entry; shared dist rebuilt. rg confirms zero scale-gate refs remain. Validation: ui typecheck ✓, biome ✓. |
| 82 | b4f0bd5d4 | 2026-06-09 | #2549 | fix(agent): preserve in-process MCP server across session refresh | mech | 2/0/0 | replayed | packages/agent (untouched) git apply CLEAN: claude-agent.ts keeps local-tools in-process MCP server across refreshSession (+refresh test). agent typecheck 0, claude-agent.refresh.test 63/63 batch ✓. |
| 83 | d4931fa42 | 2026-06-09 | #2554 | feat(agent): add claude-fable-5 model support | mech | 3/0/0 | replayed | packages/agent session/models.ts(+test) + apps/mobile composer options.ts (untouched subtrees) git apply CLEAN. agent typecheck 0, models.test 20/20 ✓. |
| 84 | 5d4a221d2 | 2026-06-10 | #2496 | feat(mobile): show PR badge on task list rows (port #2422) | mech | 1/0/1 | replayed | apps/mobile (untouched) git apply CLEAN: TaskItem.tsx PR badge + new TaskItem.test.tsx, byte-identical to upstream blobs. vitest 86/86 mobile batch ✓, biome ✓, tsc baseline-only errors (45, all in untouched automation .test.tsx/setup.ts). |
| 85 | 79cf8bfa1 | 2026-06-09 | #2559 | feat(mobile): configurable font size with larger iOS default | mech | 4/0/0 | replayed | apps/mobile (untouched) git apply CLEAN: settings/index.tsx, preferencesStore.ts(+test), textDefaults.ts byte-identical. preferencesStore tests in 86/86 batch ✓. |
| 86 | 88edb0a5e | 2026-06-10 | #2551 | docs(code): add troubleshooting note for missing Plan & usage tab | mech | 1/0/0 | replayed | apps/code/README.md (unchanged path) git apply CLEAN, byte-identical. Docs-only. |
| 87 | b22b40b4f | 2026-06-10 | #2497 | feat(mobile): filter inbox reports by priority (port #2176) | mech | 7/0/2 | replayed | apps/mobile (untouched) git apply CLEAN: inboxFilterStore.ts(+new test), types.ts, utils.ts(+test) + FilterSheet/SignalCard/inbox screens, byte-identical. inboxFilterStore + utils tests in 86/86 batch ✓. |
| 88 | e1a617112 | 2026-06-10 | #2498 | fix(mobile): validate external URL schemes before opening (port #2494) | mech | 9/0/2 | replayed | apps/mobile (untouched) git apply CLEAN: new lib/openExternalUrl.ts(+test) http/https/mailto allowlist, raw Linking.openURL call sites swapped (McpAppHost, PrStatusBadge + 7 more), byte-identical. openExternalUrl.test in 86/86 batch ✓. |
| 89 | ba359b97e | 2026-06-10 | #2543 | fix(mobile): break signal report summary sections onto separate lines (port #2317) | mech | 4/0/0 | replayed | apps/mobile (untouched) git apply CLEAN: utils.ts formatSignalReportSummaryMarkdown port + TinderView/[...id].tsx wiring (+test cases), byte-identical. utils.test in 86/86 batch ✓. |
| 90 | 315b68def | 2026-06-09 | #2558 | fix(mobile): persist selected execution mode across prompts | mech | 1/0/0 | replayed | apps/mobile/src/app/task/index.tsx (untouched) git apply CLEAN, byte-identical. |
| 91 | 63b9e2b14 | 2026-06-10 | #2544 | feat(mobile): warn before archiving a running task (port #2530) | mech | 1/0/2 | replayed | apps/mobile (untouched) git apply CLEAN: new tasks/utils/archiveGuard.ts(+test) + SwipeableTaskItem confirm wiring, byte-identical. archiveGuard.test in 86/86 batch ✓. |
| 92 | a3c4c1f02 | 2026-06-10 | #2526 | fix(ci): url-encode file paths in react-doctor comment links | mech | 1/0/0 | replayed | .github/scripts/react-doctor-comment.mjs (the #58/#60 file, unchanged path) git apply CLEAN, byte-identical. biome ✓. |
| 93 | c2539cb66 | 2026-06-10 | #2521 | feat(mobile): add Scout as an inbox signal source (port #2505) | mech | 4/0/0 | replayed | apps/mobile (untouched) git apply CLEAN: FilterSheet/SignalCard scout entries + inboxFilterStore(+test), byte-identical. Tests in 86/86 batch ✓. |
| 94 | 9e84213c7 | 2026-06-10 | #2449 | feat(mobile): highlight and surface current user in suggested reviewers (port #2435) | mech | 3/0/0 | replayed | apps/mobile (untouched) git apply CLEAN: SuggestedReviewers.tsx + utils.ts sort-me-first (+test cases), byte-identical. Tests in 86/86 batch ✓. apps/mobile now byte-identical to origin/main except the two deliberate #24 comment-path fixes (verified per-file vs upstream blobs). |
| 95 | 24a59287c | 2026-06-10 | #2560 | fix(git): skip PR revalidation when worktree directory is missing | port | 0/1/1 | replayed | Upstream apps/code git service hunks land in packages/workspace-server/src/services/git/task-pr-status.ts (TaskPrStatusService, the #22 home): computeWorktreeHasDiff gains !fs.existsSync(workspace.worktreePath) guard after linkedBranch check; computeTaskPrStatus gains repoPath && !fs.existsSync(repoPath) early return after isCloud; import fs from "node:fs" added; upstream comments dropped per repo style. NEW task-pr-status.test.ts adapted from upstream's GitService describe to our (gitService, workspaceRepo, workspaceService) ctor — fs.existsSync spy false, drains revalidation, asserts {prState:null,hasDiff:false} + getDiffStats never called. Validation: ws-server typecheck ✓, test 1/1 ✓ (suite 387/387), biome ✓. |
| 96 | 4552b1072 | 2026-06-10 | #2561 | fix(workspace): don't delete task workspace association on a transient missing path | port | 0/5/2 | replayed | Two intents at our homes. (1) workspace.ts (packages/workspace-server) verifyWorkspaceExists made read-only: 3 removeTaskAssociation calls dropped + log messages shortened per upstream (removal stays deleteWorkspace-only). (2) Upstream worktree-helpers.ts heuristic→disk-probe rewrite lands in services/worktree-path/worktree-path.ts: deriveWorktreePath now sync-probes new <base>/<name>/<repo> then legacy <base>/<repo>/<name> then defaults new (name heuristic was wrong since #47 slug names); now-redundant async resolveWorktreePathByProbe DELETED, its 3 consumers (suspension/archive/shell private wrappers) migrated to the sync fn via deriveWorktreePathFromBase alias (await-of-string call sites unchanged). Tests: worktree-path.test.ts rewritten for probe semantics (upstream's 3 it.each cases + both-layouts + basename, real tmpdir instead of upstream settingsStore mock — base path is a param in our signature); NEW workspace.verify.test.ts ports upstream service.verify.test.ts onto our ctor-injection harness (workspace.test.ts mocks + per-test tmpdir worktree base). Validation: ws-server typecheck ✓, full ws-server suite 387/387 ✓ (incl. 5 sqlite repo tests after pnpm --filter @posthog/workspace-server rebuild better-sqlite3 — NODE_MODULE_VERSION 145→147 env fix, pre-existing), biome ✓ (3 wrapper signatures reformatted). |
| 97 | 007e90ef5 | 2026-06-09 | #2541 | feat(inbox): add feedback dropdown to Create PR button | port | 0/5/0 | replayed | Split per refactor homes (prompt builder lives in CORE, not ui utils). core/inbox/reportPrompts.ts buildCreatePrReportPrompt gains feedback?: trimmed append of "Additional feedback from the user…" block (upstream verbatim); signalReportTaskService.ts CreateSignalReportTaskInput += feedback?, create-pr branch passes it; buildCreatePrReportPrompt.test.ts appends upstream's 2 new describes (9/9 ✓). shared analytics-events.ts InboxReportActionProperties += has_feedback/feedback_text (comments kept per file idiom); dist rebuilt. ui useCreatePrReport.ts createPrReport(feedback?) threads it into the service input (JSDoc updated per upstream). ReportDetailPane.tsx: prFeedback/prFeedbackOpen state, handleCreateImplementationTask(feedback?) fires create_pr with has_feedback/feedback_text(≤500) + closes popover, handleCreatePrSubmit, Create PR button → split-button (rounded-r-none + CaretDownIcon trigger) + Popover TextArea form w/ ⌘↵ submit — transcribed verbatim (all imports pre-existed). Validation: core+ui typecheck ✓, biome ✓. |
| 98 | 4ee1d12ff | 2026-06-09 | #2562 | chore(ci): Temporarily disable scheduled code releases | mech | 1/0/0 | replayed | .github/workflows/code-tag.yml (CI, unchanged path) git apply CLEAN, byte-identical: cron schedule commented out. CI-only. |
| 99 | dbf6b5120 | 2026-06-09 | #2552 | fix(agent): run native Claude executable directly | mech | 1/0/1 | replayed | packages/agent (untouched) git apply CLEAN: session/options.ts runs native claude executable directly (+options.test.ts cases), byte-identical. options.test 10/10 ✓, agent typecheck ✓ (batch), biome ✓. |
| 100 | 210549233 | 2026-06-10 | #2565 | fix(auth): retry org fetch so a transient blip can't reset the project | port | 0/2/0 | replayed | Upstream apps/code main AuthService hunks land in packages/core/src/auth/auth.ts (core AuthService home). fetchOrgWithProjects split into a retry loop (ORG_FETCH_MAX_ATTEMPTS=3, sleepWithBackoff on retryable) + fetchOrgWithProjectsOnce returning {ok:true,data} |
pending → in_progress → one of:
replayed— intent applied at new homes, scoped typecheck + lint green.already-present— proven redundant with file:line evidence in notes.blocked— concrete named blocker in notes; revisit, do not abandon.
Validation evidence goes in the row notes (commands run, files touched). No replay commits — the tree stays uncommitted until the whole replay is reviewed.