feat(design): Linear-quality design system + custom resizer#2
Merged
Conversation
explore 스캔으로 발견된 BROKEN 3파일 정리: - packages/app/README.md: 삭제된 test/phase-a/ 증거·체크리스트 경로 2행 제거(상세는 CHANGELOG.md 참조로 대체), test:ime-checklist·test:runtime-terminal shim 행을 test:integration 통합 행으로 교체 - .nexus/context/stack.md: 동일 shim 행 2개를 test:integration 통합 행으로 교체 - packages/app/scripts/runtime/terminal-zombie-checklist.ts: 제거된 test:runtime-terminal 참조를 bun test ./test/e2-terminal-runtime.test.ts로 교체 CHANGELOG.md의 release-evidence/ 복원 안내는 의도된 git 히스토리 참조이므로 유지.
정체성: Linear급 품질의 개발자 워크벤치. VS Code계 레이아웃 관용구 차용, AI 터미널·E3 영역만 Warp 감성 국소 차용, Cursor·VS Code blue·보라 회피. ## 디자인 문서 - .nexus/context/design.md 신설 (12.6KB, 6섹션): 정체성·토큰·타이포·레이아웃·금지시각언어·E3국소차별화 ## 토큰 시스템 - styles.css Tailwind v4 CSS-first(@import + @theme) 마이그레이션 - tailwind.config.ts 삭제, @source 지시자로 content 이관 - shadcn semantic 토큰 전체 수용 + sidebar·status-{running,idle,error} 확장 - 프리미티브 zinc, Accent oklch(0.70 0.10 195) Terminal Teal - destructive oklch(0.55 0.18 25) (WCAG AA 4.83:1 보정) - radius 0.5rem, text/leading 3단 스케일 ## 타이포그래피 - packages/app/assets/fonts: Inter Variable(344KB) + Pretendard Variable KR subset(451KB) + JetBrains Mono Variable(111KB) woff2 번들 (OFL 1.1) - UI sans: Inter + Pretendard, UI mono: JetBrains Mono, xterm은 기존 D2Coding+Noto Sans KR 유지 - base 13px, 행높이 1.45, 리가처 OFF, Inter cv11+ss01 ## 컴포넌트 - components.json(shadcn baseColor zinc + cssVariables) 신설 - shadcn primitive 재생성 9종: button/tabs/input/sheet/dialog/tooltip/command/separator/scroll-area + resizable - lucide-react stroke 1.75 아이콘 라이브러리 도입 - ActivityBar.tsx 분리(텍스트 Wo/Se/Gi → 아이콘 5개 + Tooltip) - App.tsx: 4열 grid → ResizablePanelGroup(Workspace 17rem+12-28 collapse, Shared 20rem+16-32 collapse), localStorage 지속 - WorkspaceSidebar/TerminalPane: slate/sky/emerald 하드코딩 0건, 시맨틱 토큰, lucide 아이콘, ScrollArea, 거대 헤더 제거 ## 상호작용 - keyboard-registry.ts(Zustand): 단일 레지스트리 + 충돌 감지 - CommandPalette.tsx(cmdk): Cmd+Shift+P 열림, 10개 MVP 명령 등록 - 11개 단축키 바인딩: Cmd+O/1/2/3/W/T/Shift+[]/B/J/P/Shift+P, Ctrl+`, Esc - workspace-switching-commands 레지스트리 통합 ## Empty state (AI 슬롭 회피) - EmptyState.tsx 통일: 24px 아이콘 + 제목(명사) + 설명 + 조건부 액션 - 7패널 적용: Workspace/Terminal/FileTree/Tool/Session/Diff/Preview - 일러스트·'Coming soon'·장식 컬러·2px 강조 border 모두 금지 ## 검증 - test:unit 44 files 156 pass / test:integration 2 files / shared / sidecar 모두 PASS - bun run build 성공 - WCAG AA 대비 재측정 전 쌍 PASS (foreground 18.10, primary 7.80, destructive 4.83, ring 7.80, status 4.12~9.35) - grep 감사: slate/sky/emerald 0건, coming soon 0건, border-2 0건, SVG illustration 0건
## 원인 commit 848855e 실행 시 3개 런타임 에러로 검은 화면: 1. 'The result of getSnapshot should be cached to avoid an infinite loop' — Zustand useSyncExternalStore에서 selector가 매 호출마다 새 배열 반환 시 발생 2. 'Unknown event handler property onCollapse/onExpand' — react-resizable-panels v4 API 불일치로 인한 DOM 누수 3. 'Maximum update depth exceeded' — 위 1번의 연쇄 결과 ## 수정 ### CommandPalette.tsx - selector가 state.getCommands() 직접 호출 → 매번 새 배열(Object.values + filter) → useSyncExternalStore 무한 loop - 수정: selector는 state.commands(stable record ref)만 구독 + useMemo로 filter 수행 ### App.tsx (ResizablePanel prop) - panelRef → ref (react-resizable-panels v4 API) - onCollapse/onExpand 제거 (v4에서 DOM 누수 원인) - onResize(size)에서 size===0으로 collapse 판정하는 단일 패턴으로 통합 ### components/ui/resizable.tsx - ResizablePanel을 React.forwardRef로 래핑 - 외부 ref를 내부 ResizablePrimitive.Panel의 panelRef prop으로 연결 - Props 타입에서 panelRef 제외(ref로 대체) ## 검증 - bun run test:unit: PASS (78 tests) - bun run build: PASS - bun run dev 스모크: renderer dev server 기동, Electron 진입까지 정상, getSnapshot/Unknown event handler/Maximum update depth 경고·에러 0건
## 증상 commit 9a2be79 실행 시 workspace/shared panel이 얇게 collapsed 상태로 고정, 드래그 불가. 화면 최대화해도 복원 안 됨. ## 근본 원인 이전 commit 848855e(검은 화면 hotfix 전)에서 broken onCollapse/onExpand 경로가 동작하는 동안 localStorage에 '{collapsed: true, ...}' state가 저장됨. hotfix 9a2be79의 defaultSize={collapsed ? 0 : size} 로직이 이를 충실히 복원하여 두 패널이 collapsed로 시작. shadcn 기본 w-px handle 과소 affordance로 드래그 타겟 발견 불가가 증폭. ## 수정 ### App.tsx - StoredPanelState에서 collapsed 필드 제거, {size: number}만 유지 - readStoredPanelState가 minSize/maxSize 범위 검증 후 유효 size만 복원 - 이전 {collapsed: true, ...} JSON은 collapsed 필드가 무시되어 자동 마이그레이션 - ResizablePanel defaultSize={state.size}로 collapsed 분기 제거 → 항상 expanded 시작 - onResize에서 size < minSize 때 persist 건너뜀 → collapse snap state 저장 안 됨 - Cmd+B/Cmd+J runtime 토글은 ref.collapse()/expand()로 유지 ### components/ui/resizable.tsx - ResizableHandle 본체: w-px → w-1.5 (6px) - cursor-col-resize 명시 (horizontal) - hover:bg-accent 및 data-[resize-handle-state=drag]:bg-accent 피드백 - GripVerticalIcon 크기 증가 (드래그 타겟 식별성 향상) ## 검증 - bun run test:unit PASS (78) - bun run test:integration PASS (8) - bun run build PASS - bun run dev 20초 스모크: getSnapshot/Unknown handler/Maximum depth 경고 0건 - grep 감사: StoredPanelState 내 collapsed 필드 부재, w-px 부재, cursor/hover 클래스 존재
…ounce ## 배경 commit 9f863a1 이후에도 사용자가 리사이저 드래그 불가 보고. researcher 외부 조사(축 1~8) + explore 코드 점검 결과 Electron -webkit-app-region: drag 가설은 0건 확인으로 배제. 남은 가능성은 shadcn wrapper hit-target (#532), withHandle inner div의 pointer event 가로채기, onResize 드래그 중 setState 재진입(#456 유사). ## 수정 ### components/ui/resizable.tsx - ResizableHandle 본체 폭 w-1.5 → w-2 (8px hit area) - horizontal variant h-2 대응 - withHandle inner grip div에 pointer-events-none 추가 → PanelResizeHandle 루트가 pointerdown target 보장, 자식 div가 이벤트를 먼저 먹어 delta 계산을 교란하는 경로 차단 - icon size-2.5 → size-3 시각 강화(기존 hotfix 유지) ### App.tsx - onResize persist를 requestAnimationFrame debounce로 교체 · pendingResizeRef: 대기 중 rAF id · latestSizeRef: 마지막 size 값 · 드래그 중 매 tick setState/localStorage write → rAF 1회로 축소 · minSize 가드 유지 (size < minSize persist 건너뜀) · workspace·shared 각각 독립 ref 쌍 - aria-valuenow는 즉시 반영(접근성 유지) - unmount 시 useEffect cleanup으로 cancelAnimationFrame ## 배제된 가설 - Electron -webkit-app-region: drag → 전역 0건 확인 - Chromium 134 PointerEvent 회귀 → release notes 미발견 - Tailwind v4 data 셀렉터 간섭 → 공식 자료 없음 - react-resizable-panels 4.10.0 자체 pointer capture 버그 → 4.7.4·4.5.8 fix 포함 ## 검증 - shared bun test: PASS (3) - app test:unit: PASS (78) - app test:integration: PASS (8) - sidecar go test: PASS (no tests) - app build: PASS - app lint:renderer: PASS - app dev 20초 스모크: 경고 0건(getSnapshot / Unknown handler / Maximum depth) - grep 감사: resizable.tsx w-2·pointer-events-none 존재, App.tsx requestAnimationFrame 존재 ## Fallback 경로 (본 패치 무효 시) - 사용자 DevTools F12 → Elements → data-panel-resize-handle-* attr·pointerdown 도달 여부 캡처 - react-resizable-panels 4.2.0 다운그레이드 실험(#594) - shadcn wrapper 제거하고 PanelResizeHandle 직접 사용
## 증상 재정의 사용자 재현: '드래그는 되지만 펼치는 방향으로는 몇 픽셀만 반응하고 접는 방향은 정상'. 이전 3회 hotfix는 drag 반응 자체가 없다는 가정이라 부분적으로 빗겨남. ## 근본 원인 onResize 콜백이 rAF debounce 안에서도 setWorkspacePanelState/setSharedPanelState를 호출 → 16ms 간격으로 App 전체 re-render 발생 → ResizablePanel 자식 (ScrollArea·WorkspaceSidebar·EmptyState·TerminalPane·Tabs 등)의 reconcile이 pointer move 처리 tick을 밀어냄 → 확장 방향 drag delta가 library state에 반영되기 전 새 re-render가 덮어씀 → '몇 픽셀만 반응' 증상. 축소 방향은 collapsible snap 때문에 적은 delta에서도 동작처럼 보여 정상 동작으로 착시. researcher 조사에서 언급된 react-resizable-panels #456 'drag 중 state 업데이트 빈번으로 인한 회귀'와 같은 범주. ## 수정 (packages/app/src/renderer/App.tsx) - persistWorkspacePanelState·persistSharedPanelState useCallback 제거 - handleWorkspacePanelResize·handleSharedPanelResize rAF callback 내부에서 persistPanelState(localStorage, ...)만 호출 — setState 유발 완전 제거 - useState destructuring에서 setter 제거: const [state] = useState(...) - workspacePanelState·sharedPanelState는 mount 시 1회 복원용으로만 유지 (defaultSize·aria-valuenow 초기값 공급) ## 트레이드오프 - aria-valuenow가 drag 후에도 초기값으로 고정 → 스크린리더가 현재 크기를 정확히 못 읽음. drag 복구 우선 판단. 후속 과제로 ResizeObserver 기반 별도 update 가능 - 드래그 종료 후 localStorage에만 저장되므로 다음 세션에서 복원 - React state 없이도 ref 기반 Cmd+B/J 토글·ArrowLeft/Right 키 조작은 유지 ## 검증 - shared bun test: PASS (3) - app test:unit: PASS (78) - app test:integration: PASS (8) - sidecar go test: PASS - app build: PASS - app lint:renderer: clean - app dev 20초 스모크: 경고 0건 - grep 감사: · setWorkspacePanelState|setSharedPanelState 호출 0건 · persistWorkspacePanelState|persistSharedPanelState 정의 0건 · persistPanelState(STORAGE_KEY, ...) 호출 rAF 콜백 내부 각 1건 · const [state] = useState(...) setter 제외 destructure 확인 ## Fallback (본 수정 무효 시) - react-resizable-panels 4.10.0 → 4.2.0 다운그레이드 (#594 workaround) - shadcn Resizable wrapper 제거하고 PanelResizeHandle 직접 사용
## 순차 진단 Step 1 WORKSPACE_PANEL_MAX_SIZE 28 → 50 SHARED_PANEL_MAX_SIZE 32 → 50 '확장 제한' 증상이 (A) maxSize 상한 정상 동작의 체감인지 (B) library bug인지 구분하기 위한 저비용 실험. A면 풀림, B면 여전함. ## 검증 - test:unit: PASS (78) - build: PASS ## Rollback 전제 본 수정은 진단용. 원인 규명 후 maxSize 값은 재조정 예정.
## DevTools 실측으로 확정된 원인
사용자 DevTools 덤프(window 725x772):
- workspace panel: flex 0 1 0px, width 0px → collapsed 상태
- center panel: flex 97.579 1 0px, width 645px
- shared panel: flex 2.421 1 0px, width 16px → minSize 16% 훨씬 아래
- data-panel-size / data-panel-id null
- localStorage: {collapsed:false, size:17} / {collapsed:false, size:20} (복원값은 정상)
원인: collapsible={true} + collapsedSize={0} 조합이 drag halfway point
(minSize/2)에서 auto-collapse 동작. workspace halfway = 6% (725px 기준 44px),
shared halfway = 8%. drag가 halfway 아래로 내려가면 snap to 0, 위로 올라오면
snap back. 사용자의 '펼치는 방향 drag 몇 픽셀만 반응' 증상은 halfway 근방
snap-back 진동이었음.
이전 3회 hotfix(shadcn wrapper, pointer-events, onResize setState,
maxSize 증대) 모두 원인 밖의 오진이었음.
## 수정 (packages/app/src/renderer/App.tsx)
### drag auto-collapse 차단
- ResizablePanel workspace/shared에서 collapsible={true} 제거
- collapsedSize={0} 제거
- drag 하한이 minSize에 고정되어 snap 동작 자체가 없어짐
### Cmd+B/J 동작 전환
- togglePanel(ref) 함수 제거(collapsible 없으면 동작 안 함)
- workspaceVisible / sharedVisible useState 추가(기본 true)
- toggleWorkspacePanel / toggleSharedPanel useCallback
- registerAppCommands 시그니처: panelRef props → toggle 콜백
- view.toggleSidebar / view.toggleSharedPanel가 state flag toggle
- JSX Fragment conditional render — false 시 Panel/Handle DOM 자체 unmount
### maxSize 원상
- Step 1 실험값(50/50) → 원래 설계값(28/32)
### 부수 정리
- unused import RefObject 제거
## 트레이드오프
- Cmd+B/J가 이전처럼 animate shrink → animate expand가 아니라 즉시 hide/show.
Linear 류 즉시성 정체성에는 더 부합
- Panel unmount 후 remount 시 defaultSize는 localStorage 복원값으로 재적용
(workspacePanelState는 초기값 고정이므로 첫 mount 시 값 유지)
- workspacePanelRef / sharedPanelRef는 ArrowLeft/Right 키 resize용으로 유지.
Panel mount 상태에서만 ref 살아있음 — hidden 상태에서 화살표키 resize는 무시됨.
기대한 동작
## 검증
- shared bun test: PASS (3)
- app test:unit: PASS (78)
- app test:integration: PASS (8)
- sidecar go test: PASS
- app build: PASS
- app lint:renderer: clean
- app dev 20초 스모크: 경고 0건
## 사용자 조치
앱 재기동 전 DevTools Console에서:
localStorage.clear(); location.reload();
기존 오염된 localStorage 제거. 이후 드래그는 minSize~maxSize 사이에서 자유롭게
동작, Cmd+B/J는 패널 전체를 hide/show.
…n layout ## 배경 4회 hotfix(9f863a1·46377aa·ba2fdf8·9efd366·6f0b61e)에도 드래그 확장 불가 증상 잔존. DevTools 실측에서 Panel flex 0 1 0px·data-panel-size null 확인. collapsible 제거 후에도 workspace/shared 최소 크기 고정. Lead 가설 반복 실패로 engineer에게 전권 위임. ## 엔지니어 판단 react-resizable-panels v4.10.0은 percentage 기반 layout solver를 사용. React 19 + Tailwind v4 + Electron 35 + shadcn forwardRef wrapper + 조건부 렌더링 조합에서 solver가 예상과 다른 수렴점을 가져 확장 drag delta가 반영 안 됨. library 자체 교체/다운그레이드 대신 **bypass** 선택. ## 수정 (packages/app/src/renderer/App.tsx) react-resizable-panels 완전 제거 → 커스텀 pixel-based flex layout으로 교체: ### Layout - 4열 flex row 구조 유지(Activity 48px · Workspace · Center · Shared) - 패널 폭은 pixel 단위로 직접 관리: · Workspace: default 272px, min 192px, max 448px · Shared: default 320px, min 256px, max 512px - Center: flex-1 min-w-0 — 남은 공간 자동 차지 ### Resize handle - 순수 pointer event(onPointerDown/Move/Up) 기반 drag - handle 시각 유지: w-2 · cursor-col-resize · hover:bg-accent · grip 아이콘 - 드래그 중 document에 listener 등록 → pointerup 시 해제 - pixel delta 직접 계산 → min/max clamp → setState ### State - workspaceWidth / sharedWidth useState (pixel) - localStorage {size: number} 스키마 유지(pixel 저장) - Cmd+B/J conditional render 유지(plan #12 구조) - ArrowLeft/Right 키 resize 유지 ## 검증 - shared bun test: PASS (3) - app test:unit: PASS (78) - app test:integration: PASS (8) - sidecar go test: PASS - app build: PASS - app lint:renderer: clean - app dev 20초 스모크: 경고 0건 - bundle size: 1701 → 1648 KB (-53 KB) ## 후속 과제 (별도 사이클) - components/ui/resizable.tsx 파일 제거 (현재 import되지 않음) - package.json의 react-resizable-panels dependency 제거 - 위 두 가지는 체감 PASS 확인 후 정리
## 정리 (commit 24ebee1 후속) 24ebee1에서 App.tsx가 react-resizable-panels 대신 custom pointer-driven layout을 사용하도록 전환. 이제 관련 죽은 코드 정리. ### 제거 - packages/app/src/renderer/components/ui/resizable.tsx (shadcn Resizable wrapper, import 0건) - packages/app/package.json 의존성 react-resizable-panels (1 package removed) ### Memory 기록 (.nexus/memory/) - external-react-resizable-panels.md — 5회 hotfix 실패 이력과 추정 원인 - pattern-library-bypass-decision.md — 반복 library 실패 시 bypass 의사결정 - pattern-zustand-selector-stability.md — CommandPalette selector 무한 loop 경험(commit 9a2be79 시점) ## 검증 - bun install: 1 package removed - test:unit: PASS (78) - build: PASS (bundle 1648KB 유지) - lint:renderer: clean
moreih29
added a commit
that referenced
this pull request
May 7, 2026
A — warm word-highlight 토큰 복원 (Card #2 from Plan #22) - biome.json L69 가 configuration-service-override 차단 (workspace-singleton 결합 우려). 따라서 updateUserConfiguration 경로 폐기 → registerExtension + 동적 theme JSON spread 채택. base "2026-dark" colors 를 spread 하고 word-highlight 3 토큰만 warm rgba 로 override 한 customTheme 을 URL.createObjectURL(new Blob(...)) 로 등록. EDITOR_THEME_NAME = "Dark 2026 Warm" 으로 변경. B — Stage 2 IFileService overlay (preacquire workaround 제거) - lsp-result-preacquire.ts 자체 주석에 명시된 Stage 2 본질 실현. initialize() 에 getFilesServiceOverride + getModelServiceOverride spread 추가, RegisteredFileSystemProvider singleton + registerFileSystemOverlay 로 cross-file LSP 결과 URI 를 model service 가 자동 lifecycle 관리하도록 전환. preAcquireLocationModels + scheduleRelease 패턴 폐기, 모듈 삭제. - lsp-providers.ts 의 provideDefinition / provideReferences 콜백이 기존 fs/readExternal IPC 재사용 (신규 IPC 신설 0) → registerLocationModel helper 로 overlay 등록. - model-cache.ts 의 createModel → createModelReference 마이그레이션은 16 callsite / 8+ 파일 영향이라 별도 cycle 로 분리 (Issue 2 결정). - lsp-providers.ts 의 monaco.languages.register*Provider 6개 호출은 그대로 유지. vscode.languages.* 이전은 본 cycle 제외 (Issue 3 결정). 테스트 / bundle: - 1219 pass → 1291 pass / 3 skip / 0 fail (+83 신규, -11 preacquire 삭제, net +72). 신규 unit test 2개 (theme-customization 27 + lsp-overlay 56). - bundle 47MB renderer / 49MB out — 변화 0 (service-override 패키지가 이미 transitive dep 으로 포함됨). R1 visual gate (peek widget cross-file preview / warm word-highlight 색상 visible) 은 autonomous mode 로 deferred — 사용자 dev 재개 시 manual 확인. empirical-codex-self-pass.md R1 에 따라 silent self-PASS 회피, deferred 명시. 본 cycle 은 R1-R3 룰의 첫 실전 검증 — T1 진입 시 engineer 가 R3 룰대로 self-stop + 보고 (configuration-service-override biome 차단 발견), Issue 1 reopen + Pattern B (registerExtension) 로 재결정 후 진행. 룰이 의도대로 작동 확인. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
moreih29
added a commit
that referenced
this pull request
May 8, 2026
audit Plan #23 issue #2 / task T2. Tester audit found SaveResult 7-way union had only read-only and not-dirty covered. Added 3 scenarios for the previously-uncovered branches: - conflict: mocks IPC return {kind:"conflict"} → verifies SaveResult forwards actual mtime payload AND markSaved is NOT called (so caller can decide reload vs force). - superseded: 3 concurrent saveModel calls; first holds gate, third displaces second from sequentializer queue. Verifies displaced caller receives {kind:"superseded"} via SaveSupersededError catch (line 114). - race (dirty=false re-check): getDirtyEntry returns isDirty=true at outer check, isDirty=false at inner re-check inside gate. Verifies saveModel short-circuits to {kind:"not-dirty"} without IPC. Tests: 5 pass / 0 fail. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
moreih29
added a commit
that referenced
this pull request
May 8, 2026
audit Plan #24 issue #2 / task T15 — F3.3 follow-up. components/lsp/palette/ mixed generic palette infrastructure with LSP-specific consumers. Architect noted "lsp/ is a domain not a UI area name" inconsistency. Resolution: - src/renderer/components/ui/palette/ (6 files, generic) — command-palette, command-palette-frame, controller, types, utils, index. Reusable for any palette-style UI. - src/renderer/components/lsp/workspace-symbol/ (3 files, LSP-specific) — workspace-symbol-palette, workspace-symbol-palette- state, workspace-symbol-source. - lsp/palette/ folder removed. components/lsp/outline/ kept — outline IS LSP-specific UI. Test folders split in parallel: - tests/unit/renderer/components/ui/palette/ (3 generic tests) - tests/unit/renderer/components/lsp/workspace-symbol/ (1 LSP test) Consumer updates: global-roots.tsx, palette-commands.ts, palette-command-keybinding.test.ts. Validation: bun test 1125/0, typecheck clean, madge 0. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
moreih29
added a commit
that referenced
this pull request
Jun 2, 2026
Follow-up to the idle watchdog (e528ccd). Review surfaced six issues across correctness, scope, and recovery; this addresses all of them. #1 Monotonic clock: lastInbound was stored as wall-clock UnixNano and compared via time.Since on a time.Unix value, which silently falls back to wall-clock arithmetic. A laptop waking from sleep (local agent) or an NTP step (remote) made elapsed jump past the limit and reap a live session. Now anchored to a monotonic startMono via stampInbound/ idleElapsed. #2 Scope: the watchdog ran for local agents too, where parent death already arrives as stdin EOF (plus Pdeathsig on Linux) — pure downside. Now gated on a new --idle-watchdog flag the SSH launch sets and the local launch omits. #3 Threshold: 60s limit with 3-ping margin was tight enough that a stalled Electron main thread (ping is event-loop bound; ssh ServerAlive is not) could trip it. Widened to 90s limit / 15s ping (6 slots), with the check interval decoupled to limit/6 so the kill window stays tight. #4 Contract: client ping was gated on heartbeat advertisement, the agent watchdog on nothing — drift-prone. The agent now advertises idleWatchdogMs in the Ready frame; the client pings iff positive, at idleWatchdogMs/6. #5 Orphans: drainAndExit reaches os.Exit, which skips the `defer pty.Close()`. Linux survived via Pdeathsig; a darwin remote (supported, shipped) had only SIGHUP-on-fd-close, so SIGHUP-ignoring children orphaned. PTY cleanup is now a shutdown hook that SIGKILLs each process group on every OS. #6 Recovery: the watchdog exited 0, which the client's handleClose treats as a clean terminal exit (no reconnect). On a false positive (client alive but stalled) the session died permanently. Now exits 75 (EX_TEMPFAIL) so the client reconnects. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Linear 품질의 개발자 워크벤치 디자인 시스템 구축. VS Code계 4열 레이아웃 차용, Warp 감성 AI 터미널 국소 적용, WCAG AA 준수. 리사이저는 react-resizable-panels 반복 실패 후 custom pointer-driven 구현으로 전환.
주요 변경
디자인 시스템 (commit 848855e)
UI 리페인팅 (commit 848855e)
Hotfix 이력 (commits 9a2be79 → 2c010fa)
리사이저 최종 구현
Memory 기록 (`.nexus/memory/`)
검증
사용자 체감 확인 (완료)
리스크
기타