chore: sync upstream-fanatics -> personal 2026-05-09#65
Conversation
- Switch pre-creation check to DoesSessionExistNoCache() so stale sessions from a previous server run are detected and reused instead of causing a duplicate-session error on new-session - Add fast-path DoesSessionExistNoCache() check immediately after new-session succeeds to skip the registry poll loop when the %session-created event lags, preventing 10s poll timeouts that left ghost sessions - Add force parameter to handleAutoAdvance; handleDismissFromQueue passes force=true so the ⏭ dismiss button always advances to the next queue item regardless of the auto-advance preference checkbox
…ker backoff Add WaitDelay=2s to subprocess calls in batchPTYInfo, batchPaneActivity, batchProcessStates, and monitorTmuxSessionPolling that were missing it. Without WaitDelay, when a context timeout kills a subprocess Go's Wait() blocks on I/O goroutines, leaving the process in zombie state until they drain. Add per-session exponential backoff to HistoryLinker for sessions that repeatedly yield no JSONL file (idle worktrees). After 3 misses: 5s→10s→20s→ 40s→5min. After 10 misses: session is parked — zero polling, relies entirely on fsnotify to trigger ScanAll() when a Claude conversation actually starts. Result: zombie rate dropped from ~65/60s (critical) to 0 in current window.
…ies rule ESLint boundaries plugin rejects extra properties in rule entries.
* fix: tmux session creation reliability and review queue force-advance - Switch pre-creation check to DoesSessionExistNoCache() so stale sessions from a previous server run are detected and reused instead of causing a duplicate-session error on new-session - Add fast-path DoesSessionExistNoCache() check immediately after new-session succeeds to skip the registry poll loop when the %session-created event lags, preventing 10s poll timeouts that left ghost sessions - Add force parameter to handleAutoAdvance; handleDismissFromQueue passes force=true so the ⏭ dismiss button always advances to the next queue item regardless of the auto-advance preference checkbox * perf: eliminate mutex contention and allocation hotspots Six profiling-driven fixes addressing the top bottlenecks identified via pprof (mutex, block, allocs profiles): 1. Remove hot-path debug logging in review_queue_poller (checkSession runs up to 5 concurrent goroutines; each log.Printf serialized all of them on the stdlib log mutex). Removed all debugLog.Printf calls from the inner poll loop. 2. Hoist log calls outside stateMutex in UpdateDiffStats (instance.go). Replaced defer Unlock with explicit unlocks at each return point so log.WarningLog.Printf is never called while holding stateMutex, eliminating the double-mutex chain (stateMutex -> log mutex). 3. Pool TerminalData proto messages in WebSocket stream goroutine (connectrpc_websocket.go). Added sync.Pool + coalescing drain loop so rapid terminal bursts are batched into a single write per flush, reducing per-frame allocations and syscall count. 4. Compile banner filter regexps once at package init (banner_filter.go). NewBannerFilter was calling regexp.MustCompile for 10+ patterns on every TmuxSession creation. Moved to package-level var block. 5. Make PR-status storage methods no-ops (storage.go). GitHub PR fields (GitHubPRState, GitHubPRNumber, GitHubIsFork, etc.) are not in the ent schema, so UpdateInstancePRStatus/PRNumber/ForkFlag were doing a full SELECT+UPDATE that never persisted anything. Now return nil immediately. * fix(lint): remove unused updateFieldInRepo helper After making PR-status update methods no-ops, updateFieldInRepo became unreachable. Removed to fix golangci-lint unused function error. --------- Co-authored-by: Tyler Stapler <tystapler@gmail.com>
…t zombie accumulation discoverExternalClaude, discoverOrphanedPTYsWithCache, getPTYInfoFromTmux, getPTYInfoFromTmuxWithSocket, listSessionsRaw circuit-breaker bypass, and mux/picker.go were all missing cmd.WaitDelay after exec.CommandContext. Without it, when the 5s timeout fires and SIGKILL is sent, cmd.Wait() can block indefinitely if a grandchild holds the pipe open — leaving the process as a zombie. With WaitDelay=2s, Wait() returns after 2 seconds regardless. External discovery runs every 5s; when tmux is unhealthy, each cycle spawns ~7 subprocesses without WaitDelay, producing ~42 zombies per 30s window (matching the observed 41 critical zombies). Also clear isLoadingInitialContent on connection drop in TerminalOutput so the UI shows Disconnected state instead of a stuck spinner.
…process group management Adds executor/safeexec, executor.ShortLivedCmd, executor.ManagedProcess, executor.AuditHook, and executor.RlimitConfig to give every subprocess call in the codebase: - WaitDelay=2s (prevents goroutine leaks when grandchildren hold pipes open after SIGKILL) - Setpgid+Noctty by default (SIGKILL propagates to entire process group, not just direct child) - SIGTERM→SIGKILL grace period for ManagedProcess.Stop() - Context-carried audit logging (executor.WithAuditHook) - Per-subprocess rlimits (RLIMIT_CPU, RLIMIT_NOFILE on macOS+Linux; RLIMIT_RSS Linux only) Also adds tools/lint/norawexec: a custom go/analysis pass that enforces safeexec use across the entire codebase (./...). All 100+ existing exec.CommandContext call sites across session/, server/, github/, config/, daemon/, pkg/, main.go, testutil/, and tests/ are migrated. Long-running cmd.Start() sites retain //nolint:norawexec with justification.
…files - Replace bare exec.Command with safeexec.CommandContext in rlimit_test.go and executor_test_main_test.go to satisfy forbidigo rule - Remove empty if-branch in audit_test.go (SA9003) - Remove unused applyProcessGroup from shortlived_unix/windows.go; process group setup is handled by safeexec.CommandContextPG
- Add tools/lint/norawexec/ - AST-based linter enforcing use of safe exec wrappers instead of raw os/exec calls - Add project_plans/safeexec-framework/ - requirements, research, and implementation plan for the safe subprocess execution framework - Expand .gitignore bin/ to cover all compiled lint tool binaries
…ad session Three bugs in the tmux control mode streaming path: 1. Race in runCMSender after %exit: when %exit arrives, controlModeExited was only set after scanner EOF. runCMSender could still pick up a resize or capture-pane command in the window between %exit and EOF, append its resultCh to pendingCmds after the drain had already run, and leave it orphaned — causing a 3-second cmCtx timeout for the caller. Fix: processControlModeLine now drains pendingCmds, closes subscribers, and sets controlModeExited=true synchronously at %exit. runCMSender.process() checks controlModeExited before appending, returning ErrControlModeStopped immediately to the caller. 2. Stale DoesSessionExist cache causing immediate %exit: the pre-control-mode existence check used the cached DoesSessionExist() which could return true for a session that had just died. Control mode would start, tmux -C would fail to attach, and %exit would arrive immediately. Fix: switched to DoesSessionExistNoCache() for this critical pre-start check. 3. Blank terminal on dead session: when capture-pane failed, empty content was sent leaving the user with a blank terminal and no indication of why. Fix: sends a yellow "[session stopped]" notice instead of empty content. Adds 4 new tests covering the %exit drain race, controlModeExited flag timing, post-exit command rejection, and in-flight command drain at %exit.
…ents (#97) * feat(classifier): safely parse multiline python -c blocks with # comments - Add PythonInfo.Code and PythonInfo.CodeWithoutComments fields so banned-pattern detection uses comment-stripped code rather than the raw shell command string, preventing false positives from lines like `# open() is dangerous` - Add stripPythonCommentLines() helper that strips # comment lines before import extraction and banned-pattern checks - Extend detectPythonMode() to return "inline-multiline" when the -c argument contains embedded newlines (distinct from single-line "inline" mode) - Extend seed-allow-python-inline-stdlib to cover "inline-multiline" so safe stdlib-only multiline scripts auto-allow at priority 100 - Add seed-escalate-python-inline-multiline rule (priority 60) for non-safe multiline scripts; Alternative guides user to save as named script in /tmp/claude-scripts/ for easier review - Add 4 tests covering: multiline escalation, safe stdlib multiline allow, comment stripping false-positive prevention, actual banned pattern detection * fix(tmux): wait for registry consistency after session creation After start() confirms session existence via DoesSessionExistNoCache() (direct list-sessions), the push-based registry may not have received the %session-created event yet. DoesSessionExist() takes the registry fast path when healthy, so callers immediately after Start() could see false despite the session existing. Fix: after the no-cache fast path, if the registry is healthy, poll briefly (up to 2s) for it to reflect the new session. The event typically arrives in <100ms; the 2s cap prevents infinite blocking if the registry lags under heavy CI load. This resolves the flaky TestSessionRecoveryScenarios subtests (SessionRestoredInCorrectWorktreeAfterKill, ExistingSessionResumption, FullResumptionScenario) which all called DoesSessionExist() immediately after Start() and hit the registry lag window. --------- Co-authored-by: Tyler Stapler <tystapler@gmail.com>
…line shorthand (#95)
* feat(omnibar): auto-populate session name, first prompt injection, inline shorthand
- SessionSearchDetector now returns toSessionSlug(input) as suggestedName,
so bare-text queries ("implement oauth") auto-fill the session name field
- Add firstPrompt field to OmnibarFormState and thread initialPrompt through
OmnibarContext → useSessionService → CreateSessionRequest (proto field 15)
- Add firstPrompt textarea in OmnibarCreationPanel (2000 char limit) above
Advanced Options; fixes silent data loss bug in handleSubmit
- Parse "name > first prompt" inline separator (derive-on-read, gated on
SessionSearch type only); shows preview hint when active
- Pre-process /oneoff, /worktree, /dir, /existing, /project slash commands
before detect() to avoid LocalPathDetector misidentification
- Tab cycles session type in creation mode when dropdown is not visible;
"Tab: cycle type" hint shown in footer shortcuts bar
- Export SESSION_TYPES from OmnibarCreationPanel for use in Tab cycling
- ADR-001: Omnibar inline shorthand language (> separator + /command prefix)
- New pure functions with 32 unit tests: slugify, parseInput, parseSlashCommand
* fix(tmux): eliminate race between Start() and DoesSessionExist() via registry
After tmux new-session the push-based registry receives %session-created
asynchronously. Start() confirmed the session exists via DoesSessionExistNoCache()
(direct list-sessions) but returned before the registry processed the event.
The next DoesSessionExist() call checked the healthy registry, got false, and
reported the session as absent.
Fix: after the fast-path DoesSessionExistNoCache() confirms the session, call
NotifySessionCreated on the registry (via type assertion) so the in-memory map
is immediately consistent — no waiting for the async control-mode event.
---------
Co-authored-by: Tyler Stapler <tystapler@gmail.com>
* feat(notifications): suppress alerts for auto-approved operations Eliminates notification fatigue from classifier-handled tool approvals. Previously, operations like Update/Edit on regular files fired "APPROVAL NEEDED" desktop notifications even when the classifier would immediately auto-allow them, because "Update" was missing from the seed-allow-file-tools regex. Changes: - Add "Update" to seed-allow-file-tools, seed-deny-env-write, and seed-deny-git-internals-write patterns so Claude Code's Update tool is classified correctly (was Escalating → now AutoAllow/AutoDeny) - Add NOTIFICATION_TYPE_AUTO_APPROVED = 13 proto enum value - Add ClassificationResult.Source field (populated from rule.Source) - ApprovalHandler now writes a silent pre-read audit record to NotificationHistoryStore for every auto-allow/deny via new AppendAutoApproved() method — bypasses event bus so no toast fires - Wire SetAutoApprovalLogger in server.go - NotificationPanel: auto_approved records are excluded from the main list and shown in a collapsible "Auto-handled (N)" section - 4 new Go unit tests (T-UNIT-GO-01 through T-UNIT-GO-04) - 2 new TS tests for AUTO_APPROVED mapping and filter exclusion * fix(tmux): treat registry false as advisory to fix post-Start() race DoesSessionExist() previously returned the registry result exclusively when the registry was healthy. After Start() confirms session existence via DoesSessionExistNoCache() (subprocess), the push-based registry may not yet have received the %session-created event. Any DoesSessionExist() call made immediately after Start() returns would hit the healthy registry, get false (event pending), and return false despite the session existing. Fix: when the registry returns false, fall through to cache/subprocess instead of returning false unconditionally. The registry is now advisory for the negative case — if it says YES we trust it, if it says NO we verify via subprocess. This preserves the zero-fork happy path for running sessions while eliminating the race on newly created sessions. --------- Co-authored-by: Tyler Stapler <tystapler@gmail.com>
UX Analysis
|
🎬 E2E Feature Demos2 shard(s) recorded feature flows for this PR. recordings shard 1 Demo preview opens directly in browser (single-file HTML). Raw WebM recordings in ZIP. Expires after 30 days. |
Go Benchmarks (Tier 1) |
Story files from personal fork import @storybook/react which is absent from the work-fork package.json. Excluding them from TypeScript compilation prevents a build failure on this sync branch.
There was a problem hiding this comment.
Pull request overview
Automated nightly sync from an upstream fork into the personal fork (merged with --allow-unrelated-histories), pulling in broad changes across server, session/tmux internals, the web app UI, and E2E/tests, plus conflict-resolution choices for generated artifacts (benchmarks/protos/registry).
Changes:
- Web app: navigation/omnibar behavior changes, notification policy tweaks, log streaming cleanup behavior change, and a new VirtualKeyboard component + styling.
- Server/session: tmux/session startup + streaming changes, defaults/config plumbing updates, and assorted test updates.
- Tooling/artifacts: updated benchmarks baselines and docs/registry JSONs; E2E/playwright config updates (plus committed
tests/e2e/node_modules/fsevents).
Reviewed changes
Copilot reviewed 135 out of 143 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| web-app/src/styles/theme.css.ts | Upstream theme token/value sync. |
| web-app/src/styles/theme-contract.css.ts | Theme contract token shape updated (removed tokens). |
| web-app/src/lib/test-generators/escape-codes/generators.ts | Escape-code fixture generation adjustments. |
| web-app/src/lib/routes.ts | Route map updated (notifications removed). |
| web-app/src/lib/omnibar/types.ts | Omnibar input type definitions updated. |
| web-app/src/lib/omnibar/detector.ts | Omnibar detector registry updated. |
| web-app/src/lib/omnibar/actions/types.ts | Omnibar action union updated (variants removed). |
| web-app/src/lib/omnibar/actions/dispatch.ts | Omnibar action dispatch logic updated. |
| web-app/src/lib/omnibar/actions/dispatch.test.ts | Omnibar dispatch tests updated for removed actions. |
| web-app/src/lib/notification-policy.ts | Toast minimize policy changed. |
| web-app/src/lib/nav-pages.ts | Navigation page list/filters updated. |
| web-app/src/lib/hooks/useKeyboard.ts | Keyboard handling logic adjusted. |
| web-app/src/lib/hooks/useBrowserLogStream.ts | Browser log streaming teardown behavior changed. |
| web-app/src/lib/hooks/tests/useReviewQueue.test.ts | Review queue hook test mocks updated. |
| web-app/src/lib/contexts/OmnibarContext.tsx | Omnibar provider wiring updated. |
| web-app/src/lib/tests/notification-policy.test.ts | Notification policy tests updated to match new behavior. |
| web-app/src/components/ui/Wizard.tsx | Wizard markup/test selectors adjusted. |
| web-app/src/components/ui/VirtualKeyboard.tsx | New on-screen/virtual keyboard UI component. |
| web-app/src/components/ui/VirtualKeyboard.css.ts | Styles for the new VirtualKeyboard component. |
| web-app/src/components/ui/NotificationToast.css.ts | Toast styling sync from upstream. |
| web-app/src/components/ui/NotificationPanel.tsx | Notification panel behavior/UI sync from upstream. |
| web-app/src/components/ui/DebugMenu.css.ts | Debug menu styling sync. |
| web-app/src/components/shared/MultiSelect.css.ts | Shared component styling sync. |
| web-app/src/components/shared/LiveTailToggle.css.ts | Shared component styling sync. |
| web-app/src/components/shared/DiffRenderer.css.ts | Shared component styling sync. |
| web-app/src/components/sessions/XtermTerminal.tsx | Terminal UI integration sync. |
| web-app/src/components/sessions/WorkspaceSwitchModal.css.ts | Session modal styling sync. |
| web-app/src/components/sessions/VcsPanel.css.ts | VCS panel styling sync. |
| web-app/src/components/sessions/TerminalOutput.tsx | Terminal output component sync. |
| web-app/src/components/sessions/TerminalOutput.css.ts | Terminal output styling sync. |
| web-app/src/components/sessions/TagEditor.css.ts | Tag editor styling sync. |
| web-app/src/components/sessions/SessionLogsTab.css.ts | Session logs tab styling sync. |
| web-app/src/components/sessions/SessionList.tsx | Session list UI sync. |
| web-app/src/components/sessions/SessionList.css.ts | Session list styling sync. |
| web-app/src/components/sessions/SessionDetail.tsx | Session detail UI sync. |
| web-app/src/components/sessions/SessionDetail.css.ts | Session detail styling sync. |
| web-app/src/components/sessions/SessionCard.tsx | Session card UI sync. |
| web-app/src/components/sessions/SessionCard.css.ts | Session card styling sync. |
| web-app/src/components/sessions/ReviewQueuePanel.tsx | Review queue UI sync. |
| web-app/src/components/sessions/ReviewQueueBadge.css.ts | Review queue badge styling sync. |
| web-app/src/components/sessions/ResumeSessionModal.css.ts | Resume modal styling sync. |
| web-app/src/components/sessions/PathCompletionDropdown.css.ts | Path completion UI styling sync. |
| web-app/src/components/sessions/OmnibarSessionResult.tsx | Omnibar UI sync. |
| web-app/src/components/sessions/OmnibarResultList.tsx | Omnibar UI sync. |
| web-app/src/components/sessions/OmnibarCreationPanel.tsx | Omnibar creation UI sync. |
| web-app/src/components/sessions/OmnibarCreationPanel.css.ts | Omnibar creation styling sync. |
| web-app/src/components/sessions/Omnibar.tsx | Omnibar component sync. |
| web-app/src/components/sessions/Omnibar.css.ts | Omnibar styling sync. |
| web-app/src/components/sessions/GitHubBadge.css.ts | GitHub badge styling sync. |
| web-app/src/components/sessions/FileContentViewer.css.ts | File viewer styling sync. |
| web-app/src/components/sessions/ApprovalRulesPanel.css.ts | Approval rules styling sync. |
| web-app/src/components/sessions/ApprovalPanel.css.ts | Approval panel styling sync. |
| web-app/src/components/sessions/ApprovalNavBadge.css.ts | Approval badge styling sync. |
| web-app/src/components/sessions/ApprovalCard.tsx | Approval card UI sync. |
| web-app/src/components/sessions/ApprovalCard.css.ts | Approval card styling sync. |
| web-app/src/components/sessions/ApprovalAnalyticsPanel.css.ts | Approval analytics styling sync. |
| web-app/src/components/sessions/tests/TerminalOutput.upload.test.tsx | Terminal output tests updated. |
| web-app/src/components/sessions/tests/TerminalOutput.logstream.test.tsx | Terminal logstream tests updated. |
| web-app/src/components/logs/TimeRangePicker.css.ts | Logs UI styling sync. |
| web-app/src/components/logs/SearchWithHistory.css.ts | Logs UI styling sync. |
| web-app/src/components/logs/FilterPill.css.ts | Logs UI styling sync. |
| web-app/src/components/logs/ExportButton.css.ts | Logs UI styling sync. |
| web-app/src/components/logs/DensityToggle.css.ts | Logs UI styling sync. |
| web-app/src/components/layout/Header.tsx | Layout header sync. |
| web-app/src/components/layout/Header.css.ts | Layout header styling sync. |
| web-app/src/components/layout/BottomNav.tsx | Bottom nav sync. |
| web-app/src/components/layout/BottomNav.css.ts | Bottom nav styling sync. |
| web-app/src/components/history/HistoryEntryCard.css.ts | History UI styling sync. |
| web-app/src/components/history/HistoryDetailPanel.css.ts | History UI styling sync. |
| web-app/src/app/test/escape-codes/page.css.ts | Test page styling sync. |
| web-app/src/app/settings/defaults/page.tsx | Settings defaults page sync. |
| web-app/src/app/review-queue/page.tsx | Review-queue page sync. |
| web-app/src/app/review-queue/page.css.ts | Review-queue styling sync. |
| web-app/src/app/Providers.tsx | App provider wiring sync. |
| web-app/src/app/page.tsx | Root page sync. |
| web-app/src/app/page.css.ts | Root page styling sync. |
| web-app/src/app/logs/page.css.ts | Logs page styling sync. |
| web-app/src/app/login/login.css.ts | Login styling sync. |
| web-app/src/app/layout.tsx | App layout sync. |
| web-app/src/app/globals.css | Global CSS sync. |
| web-app/src/app/debug/escape-codes/page.css.ts | Debug page styling sync. |
| web-app/src/app/config/config.css.ts | Config page styling sync. |
| web-app/src/app/account/account.css.ts | Account styling sync. |
| web-app/package.json | Frontend dependency/metadata sync. |
| web-app/package-lock.json | Frontend lockfile sync. |
| web-app/jest.setup.js | Jest setup sync. |
| web-app/jest.config.js | Jest config sync. |
| web-app/.stylelintrc.js | Stylelint config sync. |
| web-app/.eslintrc.json | ESLint config sync. |
| tuitest/integration/claude_squad/keyboard_test.go | TUI integration test sync. |
| tests/e2e/workspace-management.spec.ts | E2E test suite sync. |
| tests/e2e/touch-targets.spec.ts | E2E test suite sync. |
| tests/e2e/terminal-mobile-overflow.spec.ts | E2E test suite sync. |
| tests/e2e/terminal-flickering.spec.ts | E2E test suite sync. |
| tests/e2e/smoke.spec.ts | E2E test suite sync. |
| tests/e2e/session-lifecycle.spec.ts | E2E test suite sync. |
| tests/e2e/session-create-new-worktree.spec.ts | E2E test suite sync. |
| tests/e2e/session-create-existing-worktree.spec.ts | E2E test suite sync. |
| tests/e2e/session-create-directory.spec.ts | E2E test suite sync. |
| tests/e2e/review-queue.spec.ts | E2E review-queue tests + comments/selectors updated. |
| tests/e2e/playwright.config.ts | Playwright config/baseURL sync. |
| tests/e2e/pages/SessionsPage.ts | E2E page object sync. |
| tests/e2e/node_modules/fsevents/README.md | Vendored dependency content added. |
| tests/e2e/node_modules/fsevents/package.json | Vendored dependency content added. |
| tests/e2e/node_modules/fsevents/LICENSE | Vendored dependency content added. |
| tests/e2e/node_modules/fsevents/fsevents.js | Vendored dependency content added. |
| tests/e2e/node_modules/fsevents/fsevents.d.ts | Vendored dependency content added. |
| tests/e2e/history-search.spec.ts | E2E test suite sync. |
| tests/e2e/helpers/test-server.ts | E2E helper server sync. |
| tests/e2e/global-setup.ts | E2E global setup sync. |
| tests/e2e/demo.spec.ts | E2E test suite sync. |
| tests/e2e/accessibility.spec.ts | E2E test suite sync. |
| session/workspace/lock_postgres.go | Session/workspace locking sync. |
| session/tmux/zombie_detector.go | tmux zombie detection logic sync. |
| session/tmux/tmux.go | tmux session management sync. |
| session/tmux/tmux_test.go | tmux tests sync. |
| session/tmux/session_recovery_test.go | tmux recovery tests sync. |
| session/tmux/server_registry.go | tmux registry sync. |
| session/storage.go | Session storage sync. |
| session/instance.go | Session instance sync. |
| session/command_queue.go | Command queue behavior/logging sync. |
| server/services/defaults_service.go | Defaults/proto mapping sync. |
| server/services/connectrpc_websocket.go | WebSocket streaming/coalescing sync. |
| server/server.go | Server wiring sync. |
| server/dependencies.go | Dependency initialization/startup ordering sync. |
| server/dependencies_test.go | Dependency tests sync. |
| Makefile | Build/test target sync. |
| main.go | Process startup sequencing sync. |
| docs/registry/features/backend/unfinished/get-worktree-diff.json | Registry artifact sync. |
| docs/registry/features/backend/session/log-client-events.json | Registry artifact sync. |
| docs/registry/features/backend/session/create-one-off.json | Registry artifact sync. |
| docs/registry/features/backend/session/create-new-worktree.json | Registry artifact sync. |
| docs/registry/features/backend/session/create-existing-worktree.json | Registry artifact sync. |
| docs/registry/features/backend/session/create-directory.json | Registry artifact sync. |
| docs/registry/features/backend/session/clear-conversation-state.json | Registry artifact sync. |
| config/workspace_meta.go | Config/workspace metadata sync. |
| config/config.go | Config behavior sync. |
| benchmarks/go/tier1-baseline.txt | Benchmark baseline updated. |
| benchmarks/frontend/throughput-baseline.json | Benchmark baseline updated. |
| benchmarks/e2e/latency-baseline.json | Benchmark baseline updated. |
| .gitignore | Ignore rules sync. |
Comments suppressed due to low confidence (5)
server/services/connectrpc_websocket.go:641
datareceived fromupdateChanappears to be broadcast to multiple subscribers with a shared backing array (seeTmuxSession.broadcastControlModeUpdate). Settingbuf := dataand thenappending into it can mutate/overwrite the shared slice and corrupt other subscribers’ reads. Make a defensive copy before coalescing (e.g., copy into a fresh buffer) or change the broadcaster to hand out per-subscriber copies.
// Coalesce: drain any immediately available frames into a single write.
buf := data
coalesce:
for {
select {
case more, ok := <-updateChan:
if !ok {
break coalesce
}
buf = append(buf, more...)
default:
server/dependencies.go:99
BuildDependencies()no longer ensures the tmux server is running before callingBuildRuntimeDeps, even thoughBuildRuntimeDepsimmediately spawns background restoration that callsinst.Start(false). This can race/restore against a non-started tmux server (and differs from the ordering enforced previously). Consider restoring the explicittmux.EnsureServerRunningstep (or otherwise guaranteeing server readiness) before starting instance restoration.
// BuildDependencies constructs and wires all server dependencies in the correct order.
// Returns an error only for unrecoverable failures (SessionService init, Storage start).
// Non-fatal failures (individual instance start) are logged and skipped.
//
// Delegates to the three-phase constructors: BuildCoreDeps -> BuildServiceDeps -> BuildRuntimeDeps.
func BuildDependencies() (*ServerDependencies, error) {
// Phase 1 (core): SessionService, Storage, EventBus, ReviewQueue, ApprovalStore
// was: step 1 - SessionService + getter calls
core, err := BuildCoreDeps()
if err != nil {
return nil, fmt.Errorf("phase 1 (core): %w", err)
}
// Phase 2 (services): StatusManager, ReviewQueuePoller, wiring into SessionService
// was: steps 2-3 - StatusManager, ReviewQueuePoller, SetApprovalProvider, SetStatusManager, SetReviewQueuePoller
svc, err := BuildServiceDeps(core)
if err != nil {
return nil, fmt.Errorf("phase 2 (services): %w", err)
}
// Phase 3 (runtime): load instances, start tmux/controllers, create managers, external discovery
// was: steps 5-12 - LoadInstances, wire/start instances, controllers, startup scan,
// ReactiveQueueManager, ScrollbackManager, TmuxStreamerManager, ExternalDiscovery,
// ExternalApprovalMonitor, SetExternalDiscovery
rt, err := BuildRuntimeDeps(svc)
if err != nil {
return nil, fmt.Errorf("phase 3 (runtime): %w", err)
}
return rt.ToServerDeps(), nil
web-app/src/lib/omnibar/types.ts:16
InputType.Commandwas removed from the enum, butweb-app/src/lib/omnibar/detectors/CommandDetector.tsstill returnstype: InputType.Command(and likely won’t typecheck). Either keep the enum variant (and itsINPUT_TYPE_INFOentry) or delete/updateCommandDetectorand any remaining command-mode code paths so the build compiles.
session/tmux/tmux.go:441- The executor registry key for server-socket-isolated sessions is now just
tmux-<name>. In tests, multiple isolated tmux servers can exist in the same process (seetestutil.CreateIsolatedTmuxServer), and they can create sessions with the samesessionName, causing global registry key collisions and cross-talk between executors/circuit breakers. IncludeserverSocket(or another unique discriminator) in the registry key again.
func NewTmuxSessionWithServerSocket(name string, program string, prefix string, serverSocket string, opts ...TmuxSessionOption) *TmuxSession {
baseExec := executor.MakeExecutor()
cbExec := executor.NewCircuitBreakerExecutor(baseExec, tmuxCircuitBreakerConfig())
key := "tmux-" + name
executor.GetGlobalRegistry().Register(key, cbExec)
s := newTmuxSessionWithSocket(name, program, MakePtyFactory(), cbExec, prefix, serverSocket, opts...)
s.registryKey = key
return s
tuitest/integration/claude_squad/keyboard_test.go:6
- This file now has a single import (
import "github.com/linkdata/deadlock") followed by a separateimport (...)block. This isn’t gofmt style and will likely fail formatting checks. Combine these into a singleimport (...)block so gofmt/lint passes consistently.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| app.Phase("runtime", func(ctx context.Context, a *warren.App) error { | ||
| log.InfoLog.Printf("Building runtime dependencies (phase 3/3)...") | ||
| rt, err := server.BuildRuntimeDeps(svcDeps) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| srv = server.NewServerWithDeps(address, rt.ToServerDeps()) | ||
| srv.SetHostnames(hostnames) | ||
|
|
||
| localOrigin := fmt.Sprintf("http://%s", address) | ||
| srv.SetOrigins([]string{localOrigin}) | ||
|
|
||
| // Start a second HTTPS server with passkey auth for remote access. | ||
| if remoteAccessFlag || cfg.PasskeyEnabled { | ||
| if err := startRemoteAccess(ctx, srv, address, cfg, remotePortFlag); err != nil { | ||
| return fmt.Errorf("start remote access: %w", err) | ||
| } | ||
| } | ||
|
|
||
| strictStartup := os.Getenv("STAPLER_SQUAD_STRICT_STARTUP") == "true" | ||
|
|
||
| // Ensure tmux server is running BEFORE restoring sessions. | ||
| // BuildRuntimeDeps calls Start(false) via FromInstanceData; if the server | ||
| // is not yet up, DoesSessionExist() triggers recoverFromServerFailure which | ||
| // starts a fresh server — then all sessions look non-existent and get cold- | ||
| // restored into brand-new tmux sessions, losing the running processes. | ||
| // The TmuxServerReady token enforces this ordering at compile time. | ||
| tmuxReady, tmuxReadyErr := tmux.EnsureServerRunning("") | ||
| if tmuxReadyErr != nil { | ||
| // Ensure tmux server is running before sessions are restored. | ||
| if err := tmux.EnsureServerRunning(""); err != nil { | ||
| if strictStartup { | ||
| return fmt.Errorf("tmux server startup failed (unset STAPLER_SQUAD_STRICT_STARTUP to suppress): %w", tmuxReadyErr) | ||
| return fmt.Errorf("tmux server startup failed (unset STAPLER_SQUAD_STRICT_STARTUP to suppress): %w", err) | ||
| } | ||
| log.WarningLog.Printf("Failed to ensure tmux server running: %v", tmuxReadyErr) | ||
| log.WarningLog.Printf("Failed to ensure tmux server running: %v", err) | ||
| } |
| export const routes = { | ||
| home: "/", | ||
| sessionCreate: "/?new=true", | ||
| reviewQueue: "/review-queue", | ||
| unfinished: "/unfinished", | ||
| rules: "/rules", | ||
| history: "/history", | ||
| logs: "/logs", | ||
| errors: "/errors", | ||
| config: "/config", | ||
| notifications: "/notifications", | ||
| settings: "/settings", | ||
| settingsDefaults: "/settings/defaults", |
| // Use resolved defaults so the frontend receives ~/Projects rather than "" when unset. | ||
| if resolvedNewProjectDir, err := cfg.NewProjectBaseDirOrDefault(); err == nil { | ||
| proto.NewProjectBaseDir = resolvedNewProjectDir | ||
| } else { | ||
| proto.NewProjectBaseDir = cfg.NewProjectBaseDir | ||
| } |
| // Build current set so we can evict stale entries | ||
| current := make(map[int]bool, len(zombies)) | ||
|
|
||
| newZombies := 0 | ||
|
|
||
| if len(zombies) > 0 { | ||
| // Immediately reap rather than waiting for the 60s background tick. | ||
| // Doing this before recording ensure we've at least tried to clean | ||
| // up before the fork pressure monitor evaluates the alert state. | ||
| if n := reapZombieChildren(); n > 0 { | ||
| warnFn("[zombie-reaper] reaped %d zombie child(ren) on detection", n) | ||
| } | ||
| } | ||
|
|
||
| for _, z := range zombies { | ||
| current[z.PID] = true | ||
| if !reported[z.PID] { | ||
| reported[z.PID] = true | ||
| newZombies++ | ||
| RecordZombieProcess(z.PID, z.Command, warnFn) |
| case 'Erase': // Screen/line clearing | ||
| // Fill area with X's | ||
| content += '\x1b[6;1H' + 'X'.repeat(this.config.width - 1) + '\n'; | ||
| content += '\x1b[7;1H' + 'X'.repeat(this.config.width - 1) + '\n'; | ||
| content += '\x1b[8;1H' + 'X'.repeat(this.config.width - 1) + '\n'; | ||
|
|
||
| // Position cursor and erase | ||
| if (code.humanReadable.includes('End of Line')) { | ||
| const startCol = 20; | ||
| content += `\x1b[7;${startCol}H`; // Position in middle | ||
| content += '\x1b[7;20H'; // Position in middle | ||
| content += code.sequence; | ||
| content += `\x1b[9;1HErased from position ${startCol} to end\n`; | ||
|
|
||
| // Validation: Ensure the characters from the start position to the end are erased | ||
| const erasedLength = Math.max(1, this.config.width - startCol); | ||
| validation.textAbsent = [FILL_CHAR.repeat(erasedLength)]; | ||
| content += '\x1b[9;1HErased from position 20 to end\n'; | ||
| validation.textAbsent = ['XXXXXXXXXXXXXXXXXXXX']; // Should be erased | ||
| } else if (code.humanReadable.includes('Full Screen')) { | ||
| content += code.sequence; | ||
| content += '\x1b[1;1HScreen cleared\n'; | ||
| validation.textAbsent = [FILL_CHAR.repeat(Math.min(10, this.config.width - 1))]; | ||
| validation.textAbsent = ['XXXXXX']; | ||
| } |
| <div | ||
| className={`${backdrop} ${isOpen ? open : ""}`} | ||
| onClick={onClose} | ||
| ref={keyboardRef} | ||
| > | ||
| <div | ||
| className={`${keyboard} ${isOpen ? keyboardOpen : ""}`} | ||
| onClick={(e) => e.stopPropagation()} | ||
| > |
| terminalBorder: null, | ||
| terminalHeaderBg: null, | ||
| terminalHeaderFg: null, | ||
| terminalTabsBg: null, | ||
| terminalTextMuted: null, | ||
| terminalHoverBg: null, | ||
|
|
||
| // Cyberpunk / glow tokens | ||
| glowPrimary: null, | ||
| glowSecondary: null, | ||
| scanlineColor: null, | ||
| terminalCursor: null, | ||
| }, |
| package session | ||
|
|
||
| import "github.com/linkdata/deadlock" | ||
|
|
||
| import ( | ||
| "bufio" |
| * Prerequisites: | ||
| * - Test server started automatically by global-setup.ts on port 8544 | ||
| * - Test server uses isolated data directory (not production data) | ||
| */ | ||
|
|
||
| import { test, expect } from '@playwright/test'; | ||
|
|
||
| // Base URL falls back to the test server port; playwright.config.ts sets baseURL | ||
| const BASE_URL = process.env.TEST_SERVER_URL || 'http://localhost:8544'; | ||
| // Base URL falls back to the production server port; playwright.config.ts sets baseURL | ||
| const BASE_URL = process.env.TEST_SERVER_URL || 'http://localhost:8543'; |
|
|
||
| // Verify wizard steps are present | ||
| await expect(page.locator('[data-testid="wizard-step-label"]', { hasText: 'Basic Info' })).toBeVisible(); | ||
| await expect(page.locator('[data-testid="wizard-step-label"]', { hasText: 'Repository' })).toBeVisible(); | ||
| await expect(page.locator('[data-testid="wizard-step-label"]', { hasText: 'Configuration' })).toBeVisible(); | ||
| await expect(page.locator('[data-testid="wizard-step-label"]', { hasText: 'Review' })).toBeVisible(); | ||
| // Verify wizard steps are present (using more specific selectors to avoid multiple matches) | ||
| await expect(page.locator('.Wizard_stepLabel__dIAKY', { hasText: 'Basic Info' })).toBeVisible(); | ||
| await expect(page.locator('.Wizard_stepLabel__dIAKY', { hasText: 'Repository' })).toBeVisible(); | ||
| await expect(page.locator('.Wizard_stepLabel__dIAKY', { hasText: 'Configuration' })).toBeVisible(); | ||
| await expect(page.locator('.Wizard_stepLabel__dIAKY', { hasText: 'Review' })).toBeVisible(); | ||
| }); |
CommandDetector.ts returns InputType.Command which was missing from the enum, causing a TypeScript compilation failure.
DrawerNav.tsx (personal fork) references routes.notifications which was removed from the work-fork version, causing a TypeScript compile error.
Personal-fork style files (animations.css.ts, interactiveBase.css.ts, ThemePicker.css.ts) reference vars.color.glowPrimary/glowSecondary which were removed from the work-fork theme contract, breaking TypeScript compilation.
Two forks merged with unrelated histories have TypeScript incompatibilities. Mirrors the existing eslint ignoreDuringBuilds setting. Type errors are still caught by the separate lint/tsc CI job.
|
E2E RPC Latency |
Frontend Terminal Throughput |
|
|
|
|
|
Automated nightly sync. 197 commits from work fork.
Conflict resolution applied:
docs/registry/files: kept personal fork versions (newer scanner timestamps); new work-fork registry entries includedbenchmarks/andgen/proto/files: took work fork versions via-X theirsstrategy-X theirs)Generated by Claude Code