Commit Graph

188 Commits (1b09030b80401c944d4cfcc60c3b2a7da9bf1536)

Author SHA1 Message Date
RyuJongJin d1081f337e W JjChip: 고르기 칩 21곳을 JjChip 하나로 + 여럿 고르기 목록은 withPicked 하나로 + 모니터 캡처 흔들림 고정
- lib/ui/jj_chip.dart: 아이콘 없는 칩은 Material 처음 꼴 (고르면 앞에 ✓), 아이콘 칩은 고르면 그 자리에 ✓ 만 (62ba78d 규칙 -
  예전에는 화면 · 색 보정 비율 칩 한 곳만 손으로). multi 면 FilterChip. 화면 · 색 보정 · 압축 · 찾기 · 일정 · 저장 공간 · 보기 ·
  정리 · 받기 설정 · 즐겨찾기 · 자막 찾기 · 복사 방식 · 원본 정리 등 21곳이 부르기만 한다. 탐색기 왼쪽 / 오른쪽 창 고르기 칩은
  고르기가 아니라 탭이라 그대로
- lib/core/picked_list.dart withPicked: 여럿 고르기 목록 켜고 끄기 (설정 3곳에 같은 코드가 있던 것)
- 시험: jj_chip_contract_test (아이콘 ✓ 바꾸기 · 처음 꼴 · multi · 못 누름 · withPicked)
- 앞 · 뒤 캡처 9 묶음 132장 각 두 번: 앞 · 뒤 0px (보이는 것은 그대로)
- 시험 쪽: monitor_shot 도 고정 폴더 · shotServices (CPU · 메모리 · 디스크 · 대상 디스크)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:06:21 +09:00
RyuJongJin 4985887a5b P2 재생 화면 조절 줄 좁을 때 두 줄 · 재생 목록 모듈 (소리 파일은 소리끼리) 을 새 구조로 옮김 (82a87da, after_1020)
- lib/ui/row_fit.dart: fitRow (판단만 - 82a87da 그대로) + FitButtonRows (그 판단대로 한 줄 / 두 줄로 그림, 단추 크기 그대로,
  소리 막대만 남는 폭 최대 100). 재생 화면은 부르기만 한다 (player_page 580 → 576줄)
- 재생 목록 모듈 (core/playlist.dart): isPlayableFile · samePlayKind · folderPlaylist. buildPlaylist 의 형제는 고른 파일과 같은 종류만,
  폴더 [재생] 은 동영상이 없으면 소리 파일 (안내 글 "이 폴더에 재생할 동영상 · 소리 파일이 없습니다." - en · ja · zh 사전 함께).
  컨트롤러 (playback_prep) · 탐색기 (explorer_buttons · open_flow) 는 부르기만
- 시험: row_fit_contract_test (새) · player_test 약속 줄 · full_player_test 실제 mpv 장면 (82a87da 에서 옮김).
  explorer_flows_contract_test 의 알림 글을 새 글로 (틀 것이 없으면 알림은 그대로)
- full_player_test: 앞 판은 mp3 목록이 [ep1.mkv, Other - Track 2.mp3] 로 실패 (결함 재현), 뒤 판은 목록은 통과하나
  "audio 재생 시작" 에서 멈춤 - 이 PC 는 소리 출력 장치가 모두 꺼져 있음 (AudioEndpoint 모두 Unknown). 조절 줄 장면은 기기 (노트 10+) 확인 몫

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 04:31:13 +09:00
RyuJongJin 21e1d90f82 W JjTitleBar 1: 쪽 위 막대 (AppBar) 17곳을 jjTitleBar 하나로 + 캡처 흔들림 wifi · vault 고정
- lib/ui/jj_title_bar.dart: 제목은 늘 한 줄 (넘치면 "…", 경로는 TailText 로 끝이 보이게) · 넓은 단추를 가진 쪽은 좁으면
  단추들을 제목 아래 둘째 줄로 (거기도 넘치면 그 줄만 줄임, 숨기지 않음). 휴지통 · 보관함 · 저장 공간 · 압축 · 글 보기 ·
  찾기 결과 · DLNA (경로) · AI 비교 · 앱 안 폴더 고르기 등 17곳이 부르기만 한다
- 바뀐 동작: AI 올리기 비교 · 앱 안 폴더 고르기는 좁은 폭에서 단추가 제목 아래 줄로 (예전에는 412 ja 폴더 고르기가 넘쳤음)
- 주입: WifiSharePage.random (접속 코드 난수, 처음 값 안전한 난수) · Vault.add(added) (넣은 때, 처음 값 지금)
- 시험: jj_title_bar_contract_test · titlebar_places_shot_test. wifi (폴더 · 코드 · 스크롤 막대) · vault (폴더 · 넣은 날) 고정

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 00:39:36 +09:00
RyuJongJin e93b0b0be6 SecretGate.passIf: "비밀 값이 있으면 문을 지나야 함" 을 한 곳에서 (관리자 10/24)
- SecretGate.passIf(hasSecret, force): 비밀 값이 없으면 묻지 않고 지나감, 있으면 pass 의 답
- 모은 곳 (같은 꼴의 복사 9곳): 원격 등록 requireSecretGate · 플레이어 (WebDAV 머리) · 그림 AI (API 키) ·
  WebDAV · FTP · SFTP · SMB 설정 · AI 서비스 설정 (저장된 비밀 값이 있는 것을 고치기 전). 오류 종류 · 닫기는 그대로
- 그대로 둔 것 (같은 꼴 아님): 사용자가 직접 누른 일 앞에서 다시 묻는 8곳 (탐색기 · 폴더 고르기 · 다시 시도 · 보관함 · 자막 찾기 등),
  OpenSubtitles (비밀 값 조건 없이 늘 문 - 따로 보고)
- 약속 시험 한 줄 (remote_registry_contract: 묻는지 · 답 · force)

사용자가 보게 될 동작: 바뀌는 것 없음

확인: analyze 0 · 단위 1498 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:35:07 +09:00
RyuJongJin c27eb9b59e modular_sync #6 F11 나머지: 원격 등록 4벌 · 마스터 문 4벌을 RemoteRegistry · requireSecretGate 하나로
- lib/core/remote_registry.dart: RemoteRegistry<S, C> (configure · servers · server · client · closeAll, onDrop) - 서버마다 다른 것은
  비밀 값 목록 · "설정 없음" 오류 · 만들기뿐. DavRegistry · SftpRegistry · SmbRegistry · FtpRegistry 는 같은 이름 그대로 이것을 부름
- 다시 접속하는 바뀜은 예전과 같게 (관리자 조건 ①): 지움 · 비밀이 아닌 칸 (toJson: 주소 · 포트 · 사용자 · 루트 · 보안 · 지문 · 공유 · 도메인 · insecure) ·
  비밀 값 (WebDAV · SMB · FTP = 비밀번호, SFTP = 비밀번호 · 개인 키 · 키 암호). 접속에 쓰는 칸은 모두 이 둘 안 - 주소 · 사용자가 바뀌었는데
  예전 클라이언트를 쓰는 경우는 예전에도 없음. SMB: 버린 연결의 서명 기록 지우기 · 서명 필수가 바뀌면 모두 닫기 그대로
- 문 (관리자 조건 ②, 보안): SecretGate.pass 를 부르는 곳은 requireSecretGate 하나 - 비밀 값이 있으면 연결 전에 마스터 확인
- 약속 시험 remote_registry_contract (7): 4종 등록 규칙 · SMB 서명 필수 · 4종 문 (거절이면 연결 전 DavLockedException, SFTP 는 키만 있어도) ·
  비밀 값이 없으면 묻지 않음. 바꾸기 전 판 (fe8e5b7) 에서도 7개 모두 같게 통과 (동작 그대로임을 확인)

사용자가 보게 될 동작: 바뀌는 것 없음 (구조만)

확인: analyze 0 · 단위 1497 ×2 · 통합 6/6 ×2 · base10 214장 0px · ftp_shot · sshkey_shot · remote_idle_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 14:59:15 +09:00
RyuJongJin ecb2b9f7b1 modular_sync #6 RemoteFs (F11): 원격 4종의 mkdirs 를 한 규칙으로 (remoteMkdirs) - 같은 이름의 파일이면 모두 RemoteNameIsFile
- remote_fs.dart: remoteMkdirs(client, rel, mkdirOne) - 없는 위 폴더까지 · 이미 폴더면 그대로 · 같은 이름의 파일이면 RemoteNameIsFile (파일은 그대로).
  서버마다 다른 것은 한 칸 만들기뿐 (FTP MKD · SFTP mkdir (그 사이 다른 곳이 만들었으면 그대로) · SMB 채널 · WebDAV MKCOL).
  위 폴더 계산 remoteParent 하나 (FTP · SFTP · SMB 의 _parent 복사 3벌 지움)
- 고치기 전 판 (bdea662) 에서 FTP 는 같은 이름의 파일 위 mkdirs 가 오류 없이 넘어감을 확인 (r6_before.log) - 뒤의 쓰기가 엉뚱한 오류로 끝났다.
  WebDAV 는 서버 오류 글, SFTP · SMB 는 서버마다 다른 예외였다
- 약속 시험: 실제 시험 서버 WebDAV (TestDavServer) · FTP (pyftpdlib) · SFTP (asyncssh). SMB 는 Android 에서만 (기기 확인)

사용자가 보게 될 동작: 원격으로 복사 · 맞출 때 받는 쪽에 같은 이름의 파일이 있으면 서버와 상관없이 "같은 이름의 파일이 있어 폴더를 만들 수 없습니다"

확인: analyze 0 · 단위 1489 ×2 · 통합 6/6 ×2 · base10 214장 0px · windows_ftp_shot · windows_sshkey_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:27:13 +09:00
RyuJongJin bdea662daa modular_sync #3 OptionText: "rsync 옵션이 있나" 를 popt 규칙 하나로 (rsyncHasOption) - 거르기 값의 u 를 -u 로 오인하던 것 (데이터)
- rsync_options.dart rsyncHasOption(words, short, long): 짧은 묶음은 한 글자씩, 값 자리 (값을 받는 글자 B e f M T @ 의 뒤 ·
  값을 받는 긴 옵션의 다음 낱말) 는 옵션으로 보지 않음. rsyncShortWithArg 는 거르기 해석 (rsync_filter) 과 함께 씀
- "-u 가 있나" 세 곳 (transfer_job._update · withUpdateOption · optionsUpdate) 이 이것을 부름. 예전에는 "-로 시작하는 낱말에 u 가 있으면"
  이라 -f'- build/' · -f "- run/" 를 -u 로 읽었다: 미리 보기는 "받는 쪽이 더 새것은 건너뜀", 실제 rsync 는 덮어씀 · 앱이 맞출 때도 건너뜀
- 고치기 전 판 (512d290) 에서 같은 시험이 틀리게 나옴을 먼저 확인: 판단 [true, true, true] (기대 [true, false, false]) ·
  실제 rsync 는 -avf'- build/' 에서 build.txt 를 보내는데 앱은 -u 로 봄 (c3_before.log). 고친 판에서는 2회 통과
- 약속 시험: 판단 표 + 실제 rsync (받는 쪽이 더 새 파일, 옵션 5가지) - 앱의 -u 판단 = rsync 가 보내는지

사용자가 보게 될 동작: rsync 옵션의 거르기 값에 u 가 들어 있어도 "받는 쪽이 더 새것은 건너뜀" 으로 잘못 보거나 앱이 맞출 때 건너뛰지 않음 (실제 rsync 와 같게)

확인: analyze 0 · 단위 1486 ×2 · 통합 6/6 ×2 · base10 214장 0px · rsync_page ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 12:39:19 +09:00
RyuJongJin 512d2904d2 modular_sync #4 CopyPolicy: "받는 쪽이 더 새것이면 건너뛰기" 판단을 SameFile.keepNewer 하나로
- SameFile.keepNewer(skipNewer, targetModified, modified): 설정 (229) 이 켜져 있고 받는 쪽이 2초 넘게 새것일 때만 그대로 둠, 시각을 모르면 덮음
- 부르는 곳: 폴더 합치기 (로컬 isNewerThere · 원격 anyCopy) · 압축 풀기 덮어쓰기 (archive_ops). 같은 이름 창의 "더 새것" 표시 (name_clash) 도
  SameFile.targetNewer - 2초 규칙을 따로 계산하던 곳이 없어짐 (robocopy 는 /XO, rsync 는 -u 로 같은 일)
- 동작은 그대로 (판단 모으기만). 약속 시험 한 줄 더함

확인: analyze 0 · 단위 1484 ×2 (c4_unit1 · c4_unit3) · 통합 6/6 ×2 · base10 214장 0px · move_left_shot · check_shot ×2
(c4_unit2 에서 ftp_test 1 · l10n_check 1 이 같은 때 실패 - 따로 3회 · 전체 다시 1회 모두 통과, 부하 때의 흔들림으로 보이며 따로 보고)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 11:58:58 +09:00
RyuJongJin 81a2c169ff modular_sync F1: 맞추기는 로컬 · 원격 모두 같은 구현 하나 (anyMirror) - 로컬도 거르기 · 같은 이름 폴더 충돌을 따름
- FileOps.mirror 가 늘 anyMirror 를 부름. localMirror (거르기를 무시 · 같은 이름 폴더 충돌 (M1) 을 모름) 를 지움
- anyMirror 의 같은 파일 판단: SameFile.forAppSync(remote: 경로에 원격이 있는지, move: strict) - "받는 쪽이 더 새것도 같음" 은 원격일 때만
  (로컬끼리는 크기 + ±2초 그대로)
- 약속 시험: mirror_one_impl (실제 폴더 - 거르기: 거른 것은 보내지 않고 받는 쪽의 거른 것은 지우지 않음 · 나머지는 --delete, 미리 보기와 같음 /
  같은 이름 폴더: 지우기 없으면 건너뛰고 알림 · 있으면 파일로). same_file 의 원격 경우는 실제 WebDAV 시험 서버로

사용자가 보게 될 동작: 로컬끼리 맞추기 (현재 방식 · 실시간 동기화) 가 rsync 옵션의 거르기를 따름 - 미리 보기에서 빠진 것은 실제로도 보내지 않고
받는 쪽의 거른 것은 지우지 않음 (예전에는 미리 보기와 달리 다 보내고 다 지웠다). 받는 쪽의 같은 이름 폴더는 지우기 포함일 때만 바꿈

확인: analyze 0 · 단위 1484 ×2 · 통합 6/6 ×2 · base10 214장 0px · rsync_page · copy_sync_shot · lsync_p0_shot · live_excl_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 11:02:48 +09:00
RyuJongJin 9d1883311f modular_sync F5: 화면에 보이는 실행 옵션 글 = 실제 실행 인수 (runOptionsText 하나)
- core/sync_preview.dart runOptionsText: 실행 인수 (rsyncArgs · robocopyRuns) 와 같은 규칙 - 원본 지우기 옵션은 빼고 이동일 때만 그 방법의 것,
  robocopy 는 앱이 붙이는 것 (이동의 /MOVE /IS /IT /IM · 링크 /XJ · 더 새것 건너뛰기 /XO) 까지
- 부르는 곳: 모니터링 "실제 실행" · 실행 전 미리 보기 (effectiveRunText) · 탐색기 복사 · 이동 확인 창 · 실시간 동기화 [최종 정리] 창
- 고친 어긋남 (15 검토 F5): 탐색기 확인 창이 robocopy 이동을 /MOVE 로만 보였다 · [최종 정리] 창이 모니터링에서 고친 옵션이 있어도 늘 -avHPOg 로 보였다
- 약속 시험: 보이는 글 = 실제 인수 (robocopy 4 · rsync 4 · 현재 방식)

사용자가 보게 될 동작: 탐색기의 robocopy 이동 확인 창에 실제 옵션이 모두 보임 · [최종 정리] 창에 실제로 실행할 옵션이 보임

확인: analyze 0 · 단위 1482 ×2 · 통합 6/6 ×2 · base10 214장 0px · lsync_p0_shot ×2 · rsync_page ×2
(rsync_page 1회는 시작 3초 만에 시험 앱이 끝남 - media_kit 디버그 기록 파일의 PID 겹침, 이 고침과 무관 · 따로 보고)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:15:30 +09:00
RyuJongJin 88f0701d23 modular_sync F2: "같은 파일" 판단을 SameFile 하나로 - 실행 전 미리 보기 = 실제 맞추기
- lib/core/files/same_file.dart: 크기 + 바뀐 때 ±2초, 받는 쪽 시각이 올린 때인 곳 (원격이 낀 앱 맞추기, 이동 아님) 은 받는 쪽이 더 새것도 같음.
  SameFile.forAppSync(remote, move) · targetNewer
- 부르는 곳: 로컬 맞추기 (local_transfer) · 원격 맞추기 (any_transfer) · 미리 보기 (sync_preview) · 실시간 동기화 기다림 (sync_diff) ·
  -u 건너뛰기 · 폴더 합칠 때 더 새것 지키기
- 고친 어긋남 (15 검토 F2): 원격으로 앱이 직접 맞출 때 받는 쪽이 같은 크기에 더 새 파일이면 미리 보기에 "바뀜" 으로 나왔는데 실제로는
  보내지 않았다. 이제 미리 보기도 실제와 같은 판단 (rsync_runner viaDav · sync_preview_view direct 가 SameFile.forAppSync 를 넘김)
- 약속 시험: 판단 표 + 실제 파일로 미리 보기와 실제 맞추기 (anyMirror · localMirror) 가 같은지 - 원격 규칙 · 이동 · 로컬

사용자가 보게 될 동작: 원격으로 앱이 직접 맞출 때 받는 쪽의 같은 크기 · 더 새 파일이 미리 보기에서 빠짐 (실제로도 보내지 않던 것). 로컬 · rsync · 이동은 그대로

확인: analyze 0 · 단위 1479 ×2 · 통합 6/6 ×2 · base10 214장 0px · rsync_page · copy_sync_shot · lsync_p0_shot · live_excl_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:27:39 +09:00
RyuJongJin eaaa096ea1 (가) 10곳: 시험이 앱 동작을 바꾸던 길을 주입 · 모듈로 (lib 의 @visibleForTesting 은 들여다보기 4곳만 남음)
- Tor: debugRunning · executable 없앰 → 떠난 뒤 잠시 켜 두기를 IdleStop 모듈로 (schedule · cancel · stopNow).
  환경 설정 > Tor 는 IdleStop 을 받음 (처음 값 = 앱의 Tor), [지금 끄기] = stopNow
- Wi-Fi 공유: debugLoopbackOnly · debugAddresses · loopbackOnly 인자 없앰 → WifiShareNet 주입 (열 주소 · 설정 열기).
  WifiSharePage(net:) 가 debugLaunch 를 대신함. debugFail 없앰 - 시험이 실제 다른 루프백 주소 (127.0.0.x) 에서 틀린 코드를 보냄
- 관리자 권한: Elevation.debugElevated 없앰 → PlatformInfo.elevated (조립 주입), CefView(elevated:)
- CEF 시작 시간: 바꿀 수 없게 (const) - 시험은 가짜 시간을 넘김
- 단일 실행: debugStopListening 없앰 - 시험이 instance.json 을 아무도 듣지 않는 포트로 (받는 곳이 죽은 첫 창)
- SMB 찾기: 전역 debugFindSmbServers 없앰 → PlatformServices.findLanSmb 주입
- 남은 @visibleForTesting (들여다보기만): browser_page · tor_page debugNav, secret_store dpapiAt, reader_page dropMissingFiles

확인: analyze 0 · 단위 1473 ×2 · 통합 6/6 ×2 · base10 214장 0px · windows_wifi_shot ×2 · windows_smbfind_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 01:06:00 +09:00
RyuJongJin beb8107d81 M2-a: LocalFs (목록 · 저장 장치 · 드라이브) 주입 + 빈 목록 경합 고침
- lib/app/local_fs.dart: LocalFs 약속 (list · volumes · probe), RealLocalFs = 이 기기 그대로
- ExplorerDevice.listVolumes/probeDrive → ExplorerDevice.fs (LocalFs)
- ExplorerController(fs:) → loadDir(list:) (처음 값 listEntries)
- 빈 목록 경합: reloadOpen 이 끝날 때, 시작할 때 읽어 둔 것 중 닫힌 것만 잊음
  (예전: 시작할 때 찍은 열린 목록으로 지워, 다시 읽는 동안 펼친 폴더가 비어 보였다)
- 결정적 시험 explorer_reload_race_test: 다시 읽기를 붙잡는 느린 LocalFs 를 생성자로 넘김
  (실제 폴더 · 실제 목록). 예전 판에서는 실패 (펼친 폴더 [] ), 고친 판에서는 통과

확인: analyze 0 · 단위 1471 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 21:43:25 +09:00
RyuJongJin 3434ad4937 M1-2: lib 의 …ForTest 이름 정리 (실제 기능 · 주입으로)
- SuRoot.resetForTest → forgetGrant (이번 실행의 su 허락 잊기)
- ComGuard.releaseForTest → release (ensure 와 짝인 CoUninitialize)
- debugUpscalerForTest 전역 → PlatformServices.createUpscaler 주입
- 원격 썸네일 reset…ForTest 3개 → forgetRemoteThumbHub · forgetRemoteRangeSupport · forgetRemoteThumbNet
- vaultIterationsForTest 전역 → VaultPage(iterations:) (처음 값 VaultCrypto.defaultIterations)
- 남은 recycleBinForTest 는 M2 (TrashBackend) 에서 정리

확인: analyze 0 · 단위 1470 ×2 · 통합 6/6 ×2 · base10 214장 0px · com_guard_test · windows_vault_shot_test ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 20:45:32 +09:00
RyuJongJin 2199d7c15f M1-1: "Android 인 척" 스위치 · 실패 흉내 플래그를 주입으로 (PlatformInfo · WebViewProxyTarget)
- MemorySecretStore.failRead/failWrite 를 없앰 → 시험 쪽 test/support/flaky_secret_store.dart
- WebProxy.debugAndroid/debugSetProxy 를 없앰 → WebViewProxyTarget 주입 (Android=ProxyController, 그 밖=없음)
- ExitGuard.forceAndroid 를 없앰 → PlatformServices.platform (PlatformInfo)
- JJ_NLLB_LOW_MEMORY 환경 변수를 없앰 → NllbTranslator(lowMemory:), 처음 값은 PlatformInfo.host
- archive_ops · rsync_launch · file_error 의 기본값을 PlatformInfo.host 로 모음
- 이름 바꿈: WebProxy.shownForTest → shown, debugReset → reset
- 보안: 남은 Tor 웹 뷰가 있는 동안에도 removeImplicitRules (localhost 까지 Tor 로)
- 약속 시험 platform_info_contract_test 3개

확인: analyze 0 · 단위 1470 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 20:05:31 +09:00
RyuJongJin 6f9d8f6284 목록에서 두 번 누르면 도로 나오던 것 고침 · TC Enter = 열기
- 원인 (실제 앱): 목록 줄 (TC · '폴더 + 파일 목록') 의 폴더 · '..' 는 한 번에 열려, 두 번 누르면 두 번째 누르기가 같은 자리의 '..' 에
  맞아 도로 나왔다
- TC 모양: 폴더 · '..' 도 한 번 = 고르기, 두 번 = 열기 (ClickPolicy doubleOpens - Total Commander 와 같게)
- TC 모양: Enter = 열기 (폴더는 들어가기, 파일은 열기) - 바꿀 수 있는 키 동작 'open', 처음 키는 TC 모양일 때만 Enter
- '폴더 + 파일 목록': 한 번 열기는 그대로, 연 직후 두 번 누르기 시간 (300ms) 안의 다음 누르기는 버림 (마지막 틀 시각으로 잼)
- 약속 시험: 누르기 표 (TC) · TC 한 번 / Enter / '..' 두 번 · 목록 배치 곧바로 두 번째 누르기 · 시간 지난 '..' 한 번
- 점검 시험: TC 를 두 번 누르기 · Enter 로 되돌림 (실제 시간에서 들어가기 · 나오기 됨), 목록 배치 단계 더함 - 214장 2회 같음 (base10)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:48:45 +09:00
RyuJongJin afe15620bd E6 보충 (관리자 결정 10/23): 지운 뒤 초점 · 좁은 TC 줄의 확장자 · TC 전용 점검 단계
- 지운 뒤 초점: 지운 줄의 다음 줄로, 마지막이었으면 앞 줄로 (TC · X-plore 같음) - focus_after_delete (순수 함수, 약속 시험 4) +
  지우기 흐름이 부름. 실제 화면 시험: TC 목록에서 F8 단추로 지우면 다음 줄이 지금 줄
- TC: 확장자 칸이 없으면 (좁은 줄 · 좁아 숨긴 열) 이름에 확장자를 붙인다 ('notes.txt') - 정보를 숨기지 않게.
  기존 큰 글자 시험 3곳의 TC 기대를 'a' → 'a.txt' 로 (이 결정에 따른 것, 주석에 적음)
- 탐색기 점검 시험: TC 전용 단계 (Backspace 로 맨 위 · 메뉴 [열기] 로 들어가기 · Backspace 로 나오기 · F5 · F6 · F8 · 지운 뒤 초점,
  단계마다 폴더 시각 다시 고정 + Ctrl+R). 두 번 누르기는 이 실제 시간 시험에서 열기로 잡히지 않아 단위 약속 시험이 본다
- 확인: 단위 1461 ×2 · 통합 6/6 ×2 · 캡처 201장 2회 0px 같음 (base9) · X-plore 는 '삭제 확인' 3장만 바뀜 (초점)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:30:21 +09:00
RyuJongJin 343ef533cd 나누기 core D: sync_tools (656) 를 lib/core/sync/ 모듈 3개로 (→ 정면 sync_tools)
- rsync_options (옵션 글 고치기 · 나누기 · 문제 찾기 · 고칠 방법 · 목록 파일 값)
- copy_commands (복사 방법 · rsync 인수 · MSYS 경로 · robocopy 묶음 · 성공 코드 · MSYS2 rsync 패키지)
- copy_output (rsync · robocopy 출력 읽기)
- sync_tools.dart 는 export 만 (부르는 쪽은 바꾸지 않음). 임시 이름 제외는 files/path_rules 를 부름
- 약속 시험: test/sync_modules_contract_test.dart

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:56:14 +09:00
RyuJongJin 5a897344c6 나누기 core C: sftp (612) 를 lib/core/sftp/ 모듈 2개로 (→ 정면 sftp)
- sftp_server (설정 · 실패 종류 · 오류 · 개인 키 읽기 · 호스트 키 지문 · 연결 꼴)
- sftp_remote (SftpRemote 원격 저장소 · 연결 · 소켓 다리 · SftpRegistry)
- sftp.dart 는 export 만 (부르는 쪽은 바꾸지 않음)
- 약속 시험: test/sftp_modules_contract_test.dart (실제 paramiko 서버 · 시험 폴더)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:48:27 +09:00
RyuJongJin 8c3b9b7c55 나누기 core B: ftp (691) 를 lib/core/ftp/ 모듈 3개로 (→ 정면 ftp)
- ftp_server (설정 · 실패 종류 · 오류 · 인증서 지문 · 이름 풀기 꼴)
- ftp_session (명령 채널 하나: 연결 · TLS · 로그인 · 명령 · 자료 채널 - 예전 _Session 을 FtpSession 으로)
- ftp_remote (FtpRemote 원격 저장소 · FtpRegistry)
- ftp.dart 는 export 만 (debugFtpLog 포함, 부르는 쪽은 바꾸지 않음)
- 약속 시험: test/ftp_modules_contract_test.dart (실제 pyftpdlib 서버 · 시험 폴더)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:48:24 +09:00
RyuJongJin 197072b482 나누기 core A: file_ops (1,081) 를 lib/core/files/ 모듈 8개로 (→ 정면 file_ops)
- file_listing (항목 · 정렬 · 폴더 읽기 · 찾기 · 크기 글) · windows_drives (드라이브 · 종류 · UNC 맨 위)
- path_rules (같은 경로 · 안에 있음 · 바깥 것만 · 전송 전 확인 · 임시 이름) · name_ops (이름 규칙 · 이름 바꾸기 · 새 폴더)
- transfer_guard (취소 · 원본을 읽을 수 없음 · 지우기 전 원본 확인 · 빈 폴더 정리)
- transfer_control (취소 · 속도 제한 · 알림 · 같은 이름 처리 - FileOps 가 이것을 이음)
- local_transfer (로컬끼리 복사 · 이동 · 맞추기 · 지우기) · any_transfer (원격이 섞인 복사 · 이동 · 맞추기)
- file_ops.dart 는 FileOps (고르기만) 와 예전 이름 그대로 export - 부르는 쪽은 바꾸지 않음
- 약속 시험: test/file_ops_modules_contract_test.dart (실제 시험 폴더)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:25:46 +09:00
RyuJongJin 067746223b E5c: 압축 보기 · 여는 길 · 목록에서 숨기기 · Rsync 실행을 모듈로 + 점검 통합 시험
관리자 승인 E5 계획 (E5a~E5e). 동작은 바꾸지 않음
- lib/app/archive_browse.dart ArchiveBrowser: 압축을 폴더처럼 (읽기 · 바뀌면 다시 읽고 잊음 알림 · 안의 목록 · 하나 꺼내기),
  archive_ops 를 부르기만, 7-Zip 실행 파일은 부르는 쪽이 줌
- lib/app/file_opener.dart openRouteFor: 열 때 어느 길 (플레이어 · 압축 풀기 · 그림 · PDF · ZIP · HWP · 문서 · 바깥 앱) - 순수
- lib/core/app_hidden.dart HiddenList: 목록에서 숨긴 경로 (대소문자 · 옮기면 따라감 · 실제로 없어진 것만 뺌)
- lib/app/rsync_runner.dart RsyncRun: Rsync 화면 실행 (막는 조건 · 작업 · 옵션 (⇄ 의 ← 는 지우지 않음 · -u) · 미리 보기 ·
  차례로 실행) - sync_preview · sync_tools · rsync_filter · CopyCenter 를 부르기만 (modular_sync 는 rc2 그대로라 겹침 없음,
  15 의 RsyncPlan · RsyncLaunch 가 생기면 그것을 부르게 맞춤)
- lib/ui/explorer/rsync_run_dialog.dart: Rsync 확인 창 위젯 (RsyncRun 만 부름)
- integration_test/explorer_use_check_test.dart: 탐색기 점검 통합 시험 (관리자 승인) - 시험 폴더 이름 · 파일 시각 고정
  (픽셀 비교 기준), 시험 폴더만 씀
- explorer_page 6,267 → 5,922

확인: analyze 0 · 전체 단위 2회 통과 1,329 · 건너뜀 18 · 실패 0 (E5b 에서 고친 explorer_test
"X-plore e: Android 앱 휴지통 - 지우기 = 휴지통으로 · [되돌리기] · [휴지통] 화면에서 되살리기" 도 이 2회 통과) ·
점검 통합 시험 (1920 · 960 · 412) 2회 통과.
캡처 픽셀 비교 (고정 기준 = E5a 를 두 번 찍은 것, 기준끼리 87장 같음): 90장 중 87 · 88장 픽셀까지 같음,
다른 2 · 3장은 기준끼리도 다른 움직이는 장면 (이동 확인 · 선택 끝)
약속 시험 (실제 시험 폴더 · 실제 ZIP · 실제 폴더 비교): test/explorer_modules_e5c_contract_test.dart 5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 09:51:34 +09:00
RyuJongJin 0300d51092 E5b: 지우기 · 되돌리기 · 복사 계획 · 담기를 모듈로 (explorer_page 는 확인 창 · 알림만)
관리자 승인 E5 계획 (E5a~E5e). 동작은 바꾸지 않음
- lib/app/delete_ops.dart deletePaths · deleteForever · undoTrash · undoRecycle · DeleteReport: 휴지통은 recycle_bin
  (Windows) · app_trash (Android) 를 부르기만. 하나가 실패해도 나머지는 계속, 휴지통으로 못 보낸 것은 몰래 영구 삭제하지
  않고 보고에 (앱 휴지통 밖 · 긴 경로) - 영구 삭제는 부르는 쪽이 물은 뒤
- lib/app/transfer_plan.dart planTransfer · findClashes · namesOf: 복사 · 이동 전 계획 (바깥 것만 · 같은 폴더 135 ·
  막는 문제), 같은 이름 (크기 · 바뀐 날)
- lib/core/file_clipboard.dart FileClipboard: 담기 (빈 것은 담지 않음, 이동은 붙여넣은 뒤 비움, 복사는 남김)
- 다시 쓰는 곳: 탐색기 · 다운로드 화면 지우기 · 보관함 · 정리 · 끌어 놓기 · 붙여넣기 · 찾기 결과 복사
- explorer_page 6,357 → 6,267
- test/explorer_test.dart "X-plore e: Android 앱 휴지통" 시험: [되살리기] 를 화면 넘김이 끝나 눌릴 수 있을 때 누르게
  (넘기는 중에 누르면 다른 화면을 눌러 한 번 실패 - TrashPage 는 바꾸지 않음, 기대값 그대로, 줄 수 그대로 2,009)

확인: analyze 0 · 전체 단위 2회 통과 1,324 · 건너뜀 18 (새 실제 휴지통 시험 1) · 실패 0 ·
실제 Windows 휴지통 시험 (JJ_TEST_REAL_RECYCLE=1: delete_ops · recycle_bin · explorer_conflict 28개) 2회 통과, 흔적 없음 ·
점검 통합 시험 (1920 · 960 · 412) 2회 통과.
캡처 픽셀 비교 (시험 폴더 이름 · 파일 시각 고정, E5a dab9db5 를 두 번 찍은 것이 기준 - 기준끼리 87장 같음): 90장 중
87 · 88장 픽셀까지 같음, 다른 2 · 3장은 기준끼리도 다른 움직이는 장면 (이동 확인 · 선택 끝)
약속 시험 (실제 시험 폴더 · 실제 앱 휴지통 · 열려 있어 못 지우는 실제 파일): delete_ops 3 · transfer_plan + file_clipboard 5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 09:20:50 +09:00
RyuJongJin dab9db5d4d E5a: 탐색기 창 상태 · 내역 · 줄 목록 · 폴더 읽기 · 저장 장치를 모듈로 (explorer_page 는 부르기만)
사용자 지시 (10/22): 나누기는 곧 모듈화 - 모듈 재사용 · 600줄. 관리자 승인 E5 계획 (E5a~E5e)
- lib/core/nav_history.dart NavHistory: 가 본 폴더 내역 (visit · take → arrive → finish, 상한 50, 움직이는 중 겹침 막기)
- lib/core/explorer/pane_state.dart PaneState: 창 하나의 상태 (화면 부품 없음). 탐색기의 _Pane 은 스크롤 · 필터 칸만 더함
- lib/core/explorer/tree_rows.dart buildTreeRows · TreeRow · passesFilter · quickFilterMatch · globToRegExp:
  펼친 트리 → 줄 목록 (빠른 필터 · 숨김 · 맨 위 장치 · 즐겨찾기 · 압축 안)
- lib/core/explorer/dir_loader.dart loadDir: 폴더 하나 읽기 - file_ops listEntries 를 부르기만, 오류는 이유를 남김
  (빈 목록으로 숨기지 않음), 보던 폴더가 지워지면 갈 상위 폴더를 알림
- lib/app/volumes.dart localVolumes · volumeOf · reachable · reachableAsync · DriveStatus: 저장 장치 · 드라이브 상태
- 모듈마다 첫머리에 약속 (입력 · 출력 · 오류). 다시 쓰는 곳: Rsync 화면 · 보관함 · 찾기 결과 창 (뒤 단계)
- 동작은 바꾸지 않음. explorer_page 6,590 → 6,357

확인: analyze 0 · 전체 단위 2회 통과 1,317 · 건너뜀 17 · 실패 0 · 점검 통합 시험 (1920 · 960 · 412) 2회 통과.
캡처 픽셀 비교 (E4 8335a3e 두 번 찍은 것을 흔들림 기준): 90장 중 84 · 85장 흔들림 안, 벗어난 5 · 6장은 모두 확인 창 -
창 안의 무작위 임시 경로 길이가 달라 창이 몇 px 밀린 것 (눈으로 같음 확인)
약속 시험 (실제 시험 폴더 · 실제 드라이브): nav_history 3 · explorer_rows (pane_state · dir_loader · tree_rows) 5 · volumes 3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 08:27:49 +09:00
RyuJongJin 8335a3eac7 E4: 탐색기 불편 고침 - 공용 알림 showNotice (13곳) · 공용 확인 창 confirmDialog · 두 창 처음 폴더 · 다른 창 표시 안내 · 지금 줄 강조 · 폰 두 창 넘침
점검 (wiki 파일 탐색기 사용 점검 10-22) U1 · U2 · U4 · U5 · U7 · U8, 관리자 승인 10/22
- U2: lib/ui/notice.dart showNotice - 단추가 있는 알림은 앱 전체 한 값 noticeDuration (10초) 뒤 저절로 닫힘, 모두 ✕.
  단추 있는 SnackBar 13곳을 모두 옮김. 사용자가 닫을 때까지 두는 것은 248 DNS · 198 감지한 언어, 부르는 쪽이 닫는 것은
  AI 시작 전 [취소] · 다운로드 준비 (untilClosed)
- U7: lib/ui/confirm_dialog.dart confirmDialog - [확인] 만 true · Enter = 첫 초점, 되돌릴 수 없는 일 (영구 삭제 · 늘 덮어쓰기)
  은 첫 초점 [취소] (관리자 결정). 탐색기 지우기 · 영구 삭제 2곳 · 복사 · 이동 · 같은 폴더를 옮김 (나머지는 W)
- U4: 복사 · 이동 · 지우기 확인 창에 "다른 창에 N개 표시됨 (이번 대상 아님)" - 다른 창 표시는 그대로 (관리자 결정)
- U1: 저장된 경로가 없을 때만 오른쪽 창은 두 번째 저장 장치
- U5: 지금 줄은 진한 바탕 + 왼쪽 강조 막대
- U8: rc2 e785ba9 (TailText) 로 이미 됨 - 412 캡처로 확인
- 폰 세로 두 창 (E3 규칙 7) 넘침 2곳: 아래 표시 줄은 공용 lib/ui/adaptive_row.dart AdaptiveRow (좁으면 두 줄),
  진행 패널 이름 칸은 min(300, 폭 45%). 넓은 화면은 그대로
- explorer_page 는 시각을 생성자로 받음 (clock, 처음 값 DateTime.now) - 폴더 두 번 누르기 판단을 시험이 정한 시각으로
- 600줄 규칙: NameClash · clashCompareText · fileDateText 를 lib/core/name_clash.dart 로 (explorer_page 6,605 → 6,590),
  시험 도우미 testNow · refreshKey 를 test/support/explorer_clock_keys.dart 로 (explorer_test 2,011 → 2,009)

기대값을 바꾼 시험 (근거):
- browser_test 실행 취소 알림 5초 → noticeDuration: 5초는 정해진 값이 아님. 10/5 967b729 (HANDOFF 12) 가 정한 것은
  "버튼 달린 알림은 저절로 사라짐" 이고 앱은 시간을 정하지 않아 Flutter 기본 4초였다. 성질은 지키고 시간은 관리자가
  승인한 앱 전체 한 값 (U2)
- explorer_test "두 창: …" 다시 눌러도 접지 않음 (189) → 다시 누르면 접힘: 선택 규칙 노트 규칙 3 "폴더 한 번 누르기 =
  펼치기 · 접기" (노트 머리: 관리자 판단과 다르면 이 노트를 따름) · E3 승인. E3 에서는 두 번째 누르기가 600ms 안에
  들어와 우연히 통과했었음 → 시각 주입 (testNow) 으로 고침

확인: analyze 0 · 전체 단위 2회 통과 1,306 · 건너뜀 17 (E4 실패 0) · 점검 통합 시험 (1920 · 960 · 412) 2회 통과,
넘침 0, 두 회 파일 결과 같음. 약속 시험 notice 4 · confirm 3 (지문 notice.dart 29b3c951 · confirm_dialog.dart ff964f5f)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 07:53:09 +09:00
RyuJongJin 797126b297 E2: 탐색기 화면은 Selection · ClickPolicy 만 부름 + X-plore 식 폴더 표시 설정 뺌 (결정 5)
- explorer_page: 누르기 (한 번 · 두 번 · 길게 · 오른쪽) 는 ClickPolicy.decide 로만, 표시 (고르기 · 범위 · 뒤집기 ·
  이름 바꾸기 · 지우기 따라가기 · Rsync 폴더 하나) 는 _Pane.sel (Selection) 로만. 화면 안의 규칙 코드 (_normalizeMarks ·
  _toggleMark 의 나누기 · _pick 의 하나만) 를 지움
- Selection 에 rename · removeWhere · has, ClickPolicy 에 사용자 설정 옵션 tapOpens (바로 열기) · retapCollapses
  (다시 누르면 접기) - 처음 값은 E3 에서 규칙대로
- 관리자 결정 5 (10/22): explorerFolderMarkRule ('xplore' 1 · 2 · 3번) 설정 · 설정 화면 항목 · 번역 4개 · 시험 1개를 뺌.
  사용자가 요청하지 않고 넣은 것이라 규칙 6 하나로 합침. 저장된 값은 읽지 않음
- test/explorer_test.dart "선택 모드: 파일 누르기…" 기대값을 바꿈: 하나를 뺀 폴더를 다시 누르면 예전 "전체 다시 고름" →
  관리자 결정 2 (10/22) "그 폴더와 안의 것 전체 취소" (규칙 6). 앱 동작이 결정대로 바뀐 것
- 약속 시험 25개 (지문 selection.dart d438fac0 · 시험 007d2a59) 같은 판 2회 통과
- 전체 단위 1,298 통과 · 건너뜀 17 · 실패 0 (third_party 연결 뒤), 점검 통합 시험 (1920 · 960 · 412) 2회 파일 결과가 1b31609 와 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 03:04:53 +09:00
RyuJongJin 88790819be E1: 탐색기 누르기 · 고르기 모듈 Selection · ClickPolicy (lib/core/selection.dart) + 약속 시험 한 장
- 기준: wiki "10 wiki/규칙/파일 탐색기 선택 규칙 (사용자 지시 모음)" 규칙 2~6 · 8
- ClickPolicy.decide: 누르기 (한 번 · 두 번 · 길게 · 오른쪽) · 종류 · 선택 모드 · 펼침 · 목록 · 다시 → 할 일 하나
- Selection: 파일 고름/취소 · 폴더 = 자기 + 안 전체 · 안의 하나만 빼기 · Rsync 폴더 하나
- 관리자 결정 2 (10/22): 하나를 뺀 폴더를 다시 누르면 그 폴더와 안의 것 전체 취소
- 목록을 읽지 못하면 표시를 바꾸지 않고 던짐 (반쯤 바뀐 상태 없음)
- 약속 시험 test/selection_contract_test.dart 23개 (규칙 표 16 + 실제 폴더 7), analyze 0 뒤 같은 판 2회 통과
- 지문 (git blob): selection.dart feb2d80a · 시험 ceb4e16e
- 화면은 아직 이 모듈을 부르지 않음 (E2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 02:28:21 +09:00
RyuJongJin 06a6b1e8aa rc2: 보관함에 넣은 파일의 썸네일 캐시 지우기 · 내용 파일이 빠진 항목 안내 · [목록에서 빼기] (28 지적, 관리자 지시 10/21)
- 썸네일 캐시: 넣을 때마다 그 원본 (경로 · 크기 · 바뀐 때) 의 캐시를 지움 - 탐색기 동영상 썸네일 (jj_thumbs) · 빠른 보기 큰 것 (|640) ·
  원격 썸네일 (jj_rthumbs), 이름은 같은 키의 md5 (lib/core/thumb_cache.dart). 메모리 기억 (탐색기 · 원격) 도 그 경로만 잊고,
  다 넣은 뒤 화면 그림 기억 (Flutter imageCache) 도 비움. [원본 지우기 (이동)] 은 같은 파일이라 넣을 때 이미 지워짐
- 내용 파일이 없거나 (예전 목록으로 되돌림 등 - 전에는 PathNotFoundException) 짝이 맞지 않으면: "보관함 파일이 바뀌었거나 빠졌습니다 -
  이 항목은 꺼낼 수 없습니다 (보관함 폴더를 다른 곳에서 바꿨는지 확인하세요)", 원문은 [자세히], [목록에서 빼기] (확인 창 - 남은 내용 파일도 지움).
  꺼내기 · 보기 (그림 · 동영상) 모두. 받는 쪽 폴더 오류 등 그 밖은 예전처럼 알림
- 시험: thumb_cache_test (그 파일 것만 3개 지움 · 다른 파일 것 그대로 · 원격 키 꼴이 같음 · 메모리 잊음),
  vault_page_test (내용 파일 지운 항목 → 안내 · [자세히] · 남은 파일 없음 · [목록에서 빼기] 로 비움). 관련 35개 통과

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:07:33 +09:00
RyuJongJin aa67171a5e rc2: 원격 썸네일 - Range 를 모르는 서버의 동영상은 받지 않음 · 썸네일 하나에 받는 양 상한 (28 지적, 관리자 지시 10/21)
- 틈: WebDAV 서버가 Range 를 모르면 (200) 처음부터 받으며 건너뛰어, 큰 동영상의 뒤쪽 한 장면 썸네일에 파일 전체를 받을 수 있었다
- WebDAV: 동영상 썸네일 전에 한 바이트 (bytes=0-0) 를 물어 206 이 아니면 만들지 않고 기본 아이콘 (몸은 받지 않고 끊음).
  서버마다 이번 실행 동안 기억 (앱을 다시 켜면 한 번 다시 봄), 물어보다 실패하면 기억하지 않음
- 시스템 폴더 · 루트 (shz://): 읽기가 늘 파일 전체 복사라 동영상 썸네일을 만들지 않음 (d3 판단). SFTP · SMB · FTP 는 그 자리부터 읽어 그대로
- 스트리밍 다리에 썸네일 주소마다 보낼 양의 상한 (동영상 8MB · 그림 30MB) - 넘으면 끊음. 플레이어 주소는 상한 없음 (그대로)
- 그림은 지금처럼 30MB 아래만
- 시험: 200 서버 동영상 → FFmpeg 를 부르지 않음 · 한 번만 물음 (같은 서버 다시 안 물음), 206 서버 → 지금처럼 다리로, shz:// 동영상 안 함, 상한 (100 바이트 상한 → 100 에서 끊고 다시 와도 0, 플레이어 주소는 1000 그대로)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:03:12 +09:00
RyuJongJin 0f5ed3517e rc2: 보관함 형식 3 - 목록 항목 ↔ 내용 파일 짝 (id · 크기) · 꺼내기 .jjvtmp 기록 (28 지적, 관리자 지시 10/21, 데이터)
- 틈: 내용 파일 (blob) 열쇠를 그 파일 머리의 id 로 만들고 목록 항목에는 id 가 없어, B 의 내용 파일을 A 의 것으로 덮거나 같은 항목의
  예전 내용 파일로 되돌려도 오류 없이 다른 내용을 B 이름으로 꺼냈다
- 고침: 목록 항목에 내용 파일 id (16B, 16진) - 꺼내기 · 메모리로 풀기 (그림 보기) 에서 머리 id 가 목록과 다르거나 (모르면) 풀린 크기가
  목록 크기와 다르면 VaultAuthException, 결과 · .jjvtmp 는 남기지 않음. 머리 (id 포함) 는 이미 조각마다 AAD 라 내용 쪽은 id 에 묶여 있음
- 형식 번호 3: 1 · 2 는 비밀번호 (열쇠) 가 맞은 뒤 목록에 지금 내용 파일의 id 를 채워 다시 쓰고 3 으로 (아직 어느 판에도 나가지 않아 지금 것을 믿음)
- 꺼내기의 "이름.jjvtmp" (받는 폴더의 평문): 쓰기 시작할 때 앱 전용 폴더의 기록 (jj_vault_exporting.txt) 에 적고 끝나면 (성공 · 실패) 지움.
  앱을 켤 때 기록에 남은 .jjvtmp 만 지움 (사용자 폴더를 뒤지지 않음, .jjvtmp 가 아닌 줄은 지우지 않음)
- 시험: 다른 항목 내용 파일로 덮기 · 같은 원본의 다른 내용 파일로 되돌리기 · 목록 크기 다름 → 셋 다 실패 · 남은 파일 0,
  형식 2 → 3 (id 채움 뒤 꺼내기 됨), 꺼내기 기록 (끝나면 지움 · 끊긴 뒤 켤 때 기록의 .jjvtmp 만 지움). vault 22개 통과

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:00:02 +09:00
RyuJongJin a907b3d25e rc2: after_1020 f67e1e3 (15) + xplore_p3b 4ebc4f2 (d3) - 10.20_001 다음 정식 판 후보 (시험판 · 태그 없음, 관리자 지시 10/21)
둘 다 1b31609 (v2026.10.20_001) 바탕. 충돌:
- assets/l10n en · ja · zh-Hans: 열쇠별 3방향 합치기 (양쪽이 같은 열쇠를 다르게 바꾼 것 0)
- lib/ui/home_page.dart 자막 줄: after_1020 의 새 배치 (좁으면 두 줄) 를 따르고, xplore_p3b 의 JjColors (테마 색) 쪽 const 빼기를 다시 적용
- lib/ui/settings_page.dart 설명 글: after_1020 의 테마 글자색 (bodyMedium · onSurfaceVariant - 밝은 화면에서도 맞음)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 17:47:59 +09:00
RyuJongJin ab735396ac WIP X-plore 비교 5-2 루트 폴더 보기 (su · 읽기 전용) (검토 대기)
관리자 지시 10/21: Shizuku 와 같은 틀 - 처음 끔 · 경고 두 번 (켤 때 · 앱을 켠 뒤 처음 열 때) · 주황 띠 · 고정 명령 셋 · 쓰기 길 없음.
- su 를 Dart 에서 바로 (Kotlin 없음), 경로는 shz://root/… - 시스템 폴더와 같은 읽기 전용 막기 (탐색기 · 클라이언트 둘 다)
- su 가 없거나 거절하면 안내만 (들어가지 않음). 있는지 볼 때는 허락 창을 띄우지 않고, 탭을 누를 때 su 앱의 허락 창
- 처음 여는 곳 "/" (관리자 3a 결정: 다른 앱의 개인 자료가 있는 /data 를 고르기 전에 펼치지 않음), 경고 창에 "다른 앱의 개인 자료도 보일 수 있습니다"
- 셸 경로는 절대 경로만 · 줄바꿈 · \0 거절 · 작은따옴표로 감쌈
- 설정의 켜기 경고 창을 시스템 폴더 · 루트가 같이 씀 (confirmReadOnlyView)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:34:21 +09:00
RyuJongJin 5a5ecacb31 WIP 보관함 형식 번호 2 (2단계 폴더) - 1단계 보관함은 열 때 번호만 올림 (검토 대기)
관리자 3a 지시 (10/21): 1단계 형식만 아는 판이 2단계 보관함을 열면 '새 판으로' 를 알리게. 열쇠가 맞은 뒤에만 vault.json 의 format 만 바꾼다 (솔트 · 감싼 열쇠는 그대로).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:20:31 +09:00
RyuJongJin 8fa270a62e WIP X-plore 비교 5-2 보관함 2단계: 폴더째 넣기 · 원격 파일 · 보관함 안 폴더 (검토 대기)
관리자 지시 10/21 (보관함 2단계):
- 폴더째 넣기: 안의 구조 · 빈 폴더 그대로, 폴더 이름도 암호화한 목록에만 (바깥 보관함 폴더에는 무작위 이름 파일뿐)
- 원격 (WebDAV · SFTP · SMB · FTP · 시스템 폴더) 파일: 앱 전용 폴더 (jj_vault_view_in_…) 에 받아 넣고 받은 것은 바로 지움
- 보관함 안 새 폴더 · 파일 · 폴더 옮기기 · 폴더 이름 바꾸기 · 폴더째 꺼내기 · 폴더째 지우기 (확인 창에 파일 수), ← 는 위 폴더로
- [원본 지우기 (이동)] 는 다 들어간 것만 (폴더는 안의 것이 모두 들어갔을 때만, 읽지 못한 폴더는 반만 넣지 않음)
- 보관함 비밀번호 바꾸기는 1단계에 있음 (열쇠만 다시 감쌈)
- 버그 수정: 이름 묻는 창이 닫히는 중에 글자 칸을 버려 오류 → 창과 함께 버림
- 내 판단: 폴더 정보는 1단계 판과 맞게 - 맨 위 파일은 목록 모양 그대로, 빈 폴더 목록은 따로 (folders.jjd, 1단계의 정리가 지우지 않음).
  1단계 판으로 되돌려 쓰면 파일은 다 보이지만 폴더 구조는 그 판이 목록을 다시 쓸 때 풀린다 (내용은 잃지 않음)
- 내 판단: 넣는 폴더 이름이 지금 폴더에 있으면 합치지 않고 " (2)"
- 내 판단: 같은 폴더에 같은 이름 파일을 넣으면 " (2)" (전에는 겹친 이름이 그대로 둘)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:39 +09:00
RyuJongJin 8f6fcdd9ed WIP X-plore 비교 5-2 시스템 폴더 보기 (Shizuku · 읽기 전용) (검토 대기)
관리자 결정 10/21: 1단계는 Shizuku 만 · 읽기 전용 · 처음 끔 · 경고 두 번 (켤 때 · 앱을 켠 뒤 처음 열 때).
- Shizuku API 13.1.5 (MIT - 3a 지시의 "Apache-2.0" 이 아니라 실제 라이선스는 MIT, 고지에 MIT 원문)
- shz://sys/<기기 경로>: 목록 · 정보 · 내용 읽기 (임시로 받아 읽고 지움) 만, 쓰기 · 지우기 · 옮기기 · 새 폴더는 막음
- 셸 명령은 고정된 셋 (목록 · stat · cat), 경로는 절대 경로만 · 따옴표 처리
- 탐색기 탭 [시스템 (읽기 전용)] → Android 폴더, 주황 띠, 꺼짐 · 허락 없음 안내
- 내 판단: Shizuku API 13 의 newProcess 는 숨겨져 있어 반사로 부름 (널리 쓰는 방법, 버전이 바뀌면 다시 확인)
- 내 판단: 시스템 폴더 오류 띠에는 [서버 설정 고치기] 를 두지 않음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 12:50:23 +09:00
RyuJongJin dc4bae5329 WIP 암호 보관함: 평문이 남을 수 있는 두 곳 (관리자 지시 10/21) - ① 넣기의 [원본 지우기 (이동)]: "원본은 휴지통으로 갑니다 - 휴지통에 평문이 남습니다" 를 보이고 [휴지통으로 (처음 값)] / [영구 삭제] 를 고름, 영구 삭제는 탐색기의 영구 삭제 길 (Shift+Delete 와 같은 확인 창을 한 번 더) ② [보기]: 그림은 메모리에서 바로 (파일로 풀지 않음, ReaderSource 를 MemoryImage 로), 동영상 · 음악만 앱 전용 폴더 (Android getCacheDir · Windows 앱 데이터의 temp) 아래 jj_vault_view_… 에 잠깐 - 닫으면 지움, 자동 잠금 · [잠그기] 때 열린 보기를 닫고 지움, 앱이 강제로 꺼져 남은 것은 다음에 켤 때 지움 (jj_hwp_ 정리처럼), Windows 에서 막 쓴 파일을 다른 프로그램이 잠깐 잡아 지우기가 실패하는 것은 몇 번 더 시도 · 시험: 영구 삭제 고르기 · 그림은 파일 0 · 동영상 보기 뒤 0 · 잠그면 보기 닫힘 · 남은 것 0 · 켤 때 정리 (시험의 보기 폴더는 파일마다 임시로 - flutter_test_config) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 12:10:00 +09:00
RyuJongJin 9c72320737 WIP 암호 보관함: PBKDF2 처음 60만 번 (관리자 결정 10/21 - OWASP 권장, 반복 수는 vault.json 에 있어 기기 확인 뒤 다시 정할 수 있음) · 시험: 같은 원본을 다시 넣어도 · 목록을 다시 쓸 때마다 새 무작위 파일 id (조각 nonce 가 (파일 열쇠, 조각 번호) 이므로 같은 id 를 다시 쓰지 않음을 보임) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:22:49 +09:00
RyuJongJin b51a17a82b WIP 암호 보관함 1단계-1 암호 · 폴더 (관리자 결정 10/21, 설계안 위키 프로젝트/암호 보관함 · 루트 설계안 (10-21)): 화면 없이 바탕만 - 비밀번호 → PBKDF2-SHA256 (반복 수는 vault.json 에, 처음 30만 번 - d3 판단: 설계안의 60만은 이 PC 에서 10만 = 0.3초라 폰에서 수 초, 반복 수를 파일에 두어 나중에 올릴 수 있음, Isolate 에서) → AES-256-GCM 으로 무작위 보관함 열쇠를 감쌈 (비밀번호를 바꿔도 파일은 다시 암호화 안 함). 파일마다 무작위 id → 파일 열쇠 HMAC-SHA256, 1MB 조각마다 AES-256-GCM (nonce = 조각 번호, AAD = 머리 + 조각 번호 + 마지막 표시 - 바꾸기 · 바꿔 끼우기 · 끝 자르기 · 덧붙이기를 알아챔). 이름 · 크기 · 넣은 날은 암호화한 index.jjv 에만, 바깥 이름은 무작위. 쓰기는 .tmp → 이름 바꾸기, 목록이 기준 (넣기: 내용 → 목록, 지우기: 목록 → 내용), 다음에 열 때 끊긴 것 정리. 꺼내기는 다 풀고 인증이 맞은 뒤에만 그 이름으로. vault.json 형식 번호 - 모르는 새 형식은 열지 않음. pointycastle (MIT) 직접 의존 (dartssh2 를 통해 있던 4.0.0 그대로), 고지에 "보관함 암호화에도 씀" · 시험 10개 (AES-GCM · PBKDF2 알려진 벡터 · 틀린 비밀번호 · 변조 6가지 · 왕복 크기 · 끊긴 쓰기 4가지 · 형식) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:21:43 +09:00
RyuJongJin fffb9d7dbc WIP X-plore 비교 5-2 앱 관리자 (사용자 결정 10/21, 관리자 판단, Android): 가운데 버튼 [앱 관리자] (Android 만, 버튼 끝에 - 좁으면 [더 보기]) - 모든 앱 목록 권한 (QUERY_ALL_PACKAGES) 없이 매니페스트 queries 의 LAUNCHER 로 실행할 수 있는 앱만, 화면 위에 "보이는 앱만 나옵니다 (모든 앱 목록 권한은 쓰지 않음)". 이름 · 판 · 크기 · 설치일, 이름 · 크기 · 설치일 정렬 · 찾기, [APK 백업] (Download/JJ_MKVMaker/apk, 이름_판.apk · 겹치면 (2), 나눠진 앱은 알림) · [앱 정보] (시스템 화면) · [지우기] (시스템 지우기 창, 시스템 앱은 없음). 아이콘은 그때그때 PNG 로 · 시험 (지도 읽기 · 백업 이름 · 화면 · 버튼은 Android 만) · APK 빌드로 Kotlin 확인 (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:15:28 +09:00
RyuJongJin 9f6c5c0bd5 SFTP SSH 키 파일 로그인: 키 형식 · 키 암호 · 서버 거부를 따로 알림 · 고를 때 바로 꼴을 봄 · 키 종류마다 실제 서버 시험 (사용자 승인 10/21, 관리자 지시)
- 이미 있던 것 (그대로): 서버 설정 [개인 키 파일 고르기] · 키 암호 칸, 키 내용은 안전 저장소 (sftp.key.<id> · sftp.kp.<id>) 에 두고
  파일 경로는 저장하지 않음, 설정 파일 · .bak · 보관본에는 평문 없음 (redactSecrets). "개인 키 붙여넣기" 는 없어 합칠 것 없음. 셸은 넣지 않음
- 더한 것: SftpFailure 에 keyFormat · keyPassphrase · keyRejected
  · checkPrivateKey: OpenSSH · PEM RSA · PEM EC (dartssh2 4.1.0 이 읽는 꼴) 인지, 암호가 걸렸는지. PuTTY (.ppk) 는 PuTTYgen 으로 바꾸는 법,
    PKCS#8 · 공개 키 (.pub) · 다른 파일은 고를 꼴을 알림 - [개인 키 파일 고르기] 에서 바로 (암호가 걸린 키면 "아래에 키 암호를 넣으세요")
  · parsePrivateKey: 암호가 걸렸는데 비었으면 "키 암호를 넣으세요", 못 풀면 "암호가 맞지 않습니다" (PEM 의 다른 오류도), 그 밖은 꼴
  · 키만으로 들어가다 SSHAuthError 면 "서버가 이 키를 받지 않습니다 (authorized_keys · 아이디)", 비밀번호도 있으면 "모두 거부"
- 시험 (실제 paramiko 서버 · Windows ssh-keygen): ed25519 OpenSSH (암호 · 없음) · rsa OpenSSH 암호 · rsa PEM · ecdsa OpenSSH 암호 ·
  ecdsa PEM 6종으로 로그인, 짝이 없는 키 = keyRejected, 암호 없음 = keyPassphrase, PuTTY · PKCS#8 · 공개 키 · 다른 파일 = keyFormat.
  틀린 키 암호 시험은 kind 를 keyPassphrase 로. sftp · sftp_stream 14개 통과, l10n 빠진 것 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:53:44 +09:00
RyuJongJin 59f417552a WIP X-plore 비교 5-2 DLNA 보기만 (사용자 결정 10/21, 관리자 지시): 파일 탐색기 [미디어 서버 (DLNA)] (넓은 화면은 창 위 아이콘, 좁은 화면은 ⋮) - 같은 망의 미디어 서버를 찾아 (SSDP) 폴더 · 동영상 · 음악 · 사진 목록 · 200 개씩 [더 보기], 동영상 · 음악은 내장 플레이어로 (같은 폴더 차례대로), 사진은 임시로 받아 보기 화면. 서버 (내보내기) · 올리기 · 지우기 없음. 새 패키지 없음 (xml 은 이미 씀). 찾기는 Wi-Fi · 유선의 사설 주소에서만 (모바일 데이터 · VPN · 가상 어댑터로 보내지 않음 - SMB 찾기와 같은 localPrivateIPv4), 서버가 알려 준 주소 (설명 · 제어 · 미디어) 는 사설망 · 이 기기만 따름 (바깥 주소 항목은 "열 수 없음"), 받는 XML 은 4MB · 정한 시간까지 · 시험 (SSDP · 설명 · DIDL · 주소 제한 · 가짜 서버 Browse · 화면) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:52:38 +09:00
RyuJongJin 7dfbc400d1 WIP X-plore 비교 5-1 ⑤ 저장 공간 분석에서 그 자리 작업 (관리자 지시 10/21): 큰 폴더 · 큰 파일 줄의 ⋮ (길게 누르기 · 오른쪽 단추도) [그 자리로] · [지우기 (확인 · 휴지통)] · [이동 (붙여넣기로)] - 지우기는 예전 관리자 판단대로 탐색기의 지우기 (같은 확인 창 · 휴지통) 를 부르고, 실제로 지워진 것만 다시 훑지 않고 결과에서 뺌 (위 폴더들의 크기 · 파일 수도 덜어 냄), 취소면 그대로. 이동은 탐색기의 [이동 (붙여넣기로)] 에 담고 안내 · 시험 (결과에서 빼기 · 화면 취소 / 확인 / 담기) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 03:21:19 +09:00
RyuJongJin dcc805c4b8 WIP X-plore 비교 5-1 ④ SQLite 보기 (읽기 전용, 관리자 지시 10/21): 파일 탐색기 길게 누르기 [SQLite 보기 (읽기 전용)] (.db · .sqlite · .sqlite3 · .db3, 원격은 임시로 받아서) - 테이블 고르기 · 행 수 · 200 행씩 [더 보기] · 칸을 누르면 전체 값 (BLOB 은 16진 앞 256 바이트) · NULL 흐리게. 새 패키지 · 네이티브 라이브러리 없이 파일 형식을 직접 읽음 (머리 · sqlite_schema · 테이블 b-tree · 넘친 페이지 · 레코드, UTF-8 · UTF-16) - 파일은 읽기 전용으로만 염. 못 하는 것: WITHOUT ROWID 테이블 (안내) · -wal 에만 있는 바뀐 것 · 시험 파일은 진짜 SQLite 로 만든 것 (tool/fixtures/make_sqlite_fixtures.py → test/fixtures/sqlite, 2000 행 · 넘친 페이지 · 한글 · 64비트 정수 · 잘린 파일) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 03:09:23 +09:00
RyuJongJin 3444d84f35 WIP X-plore 비교 5-1 ③ 일괄 이름 바꾸기 - 음악 태그 · 글자 범위 (관리자 지시 10/21): 이름 틀에 [Artist] · [Title] · [Album] · [Track] (두 자리) · [Year] (창의 ♪ 메뉴로 넣기) - 이 기기의 MP3 (ID3v2.2 · 2.3 · 2.4, 없으면 ID3v1) · FLAC (Vorbis comment) · M4A (MP4 ilst) 의 앞부분만 읽는 작은 읽개 (새 패키지 없음 - 📜 걱정 없음), 원격 · 못 읽으면 빈칸, 이름에 못 쓰는 글자는 _. [N2-5] = 원래 이름의 2~5 번째 글자, [N3-] = 3 번째부터 (유니코드 한 글자씩) · 412 큰 글자에서 넘치지 않게 ♪ 는 작은 아이콘 · 시험 (태그 형식 4가지 · 한글 · 일본어 · 잘린 머리 · 범위 · 창) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 03:03:42 +09:00
RyuJongJin f92f801e7a WIP X-plore 비교 5-1 ② 원격 썸네일 (관리자 지시 10/21): WebDAV · SFTP · SMB · FTP 의 그림 (30MB 아래) · 동영상을 X-plore 모양 목록에서 작은 그림으로 - 환경 설정 > 파일 탐색기 "원격 썸네일" (Wi-Fi 에서만 (처음 값) · 늘 · 받지 않음) · 캐시 상한 (처음 200MB, 넘으면 오래 쓰지 않은 것부터) · [캐시 지우기]. 동시에 2개, 화면에서 사라진 줄은 시작하지 않음, 같은 것은 한 번. FFmpeg 가 이 기기 안 스트리밍 다리 (127.0.0.1, Range) 에서 일부만 읽음 - WebDAV 도 Range 로 (모르는 서버는 받으며 건너뜀), 비밀번호는 명령 줄에 넣지 않음. "Wi-Fi 에서만" = Android 의 데이터 요금제 판단 (isActiveNetworkMetered) - 내 판단: VPN 은 그 아래 망을 따름 (집 Wi-Fi 위의 Tailscale 은 받음, 모바일 데이터 위는 받지 않음), PC 는 늘 받음 · 시험 (동시 수 · 보이는 줄 · 상한 · 망 · Range 206/200 · 실제 FFmpeg 썸네일) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 02:51:45 +09:00
RyuJongJin 1f0c094656 WIP X-plore 맞추기 (관리자 지시 10/20): 보기 화면 사진 정보 (Exif) - 위 막대 [사진 정보 (Exif)] (폴더의 그림만): 파일 · 크기 (픽셀 · 바이트) · 찍은 날 · 기기 · 위치 - 위치는 [위치 보기] 를 눌러야 보이고 지도 · 인터넷으로 보내지 않음 (링크 없음) · Exif 없으면 안내 · image 패키지 (MIT, 이미 씀) 로 읽어 새 의존 없음 · 시험 (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:35:34 +09:00
RyuJongJin ae4e29620e next11: rc_next 44c69af + hwp2 (7bc452e: Android HWP · HWPX 보기 1 · 2단계 · 고침) - 시험판 988
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:34:50 +09:00
RyuJongJin 7bc452e54c WIP HWP 고침 (관리자 지시 10/20, 28 검토): ① 앱 시작의 HWP 작업 폴더 정리를 기다리지 않음 (queue_test 가 가짜 시간 안에서 10분 걸리던 회귀) ② 시간 제한은 바꾸기가 실제로 시작된 때부터 · 멈춤은 요청마다 (QueuedHwpDoc 로 줄 세우기 · 시간 · 멈춤을 FFI 에서 떼어 시험할 수 있게), Rust ABI 3: export 에 요청 번호 · jj_rhwp_cancel(번호) · jj_rhwp_cancel_all (시작할 때 깃발을 지우지 않음), 닫으면 줄에 선 것은 시작하지 않음 · check_apk 필요 함수 8개 ③ 진행 창 close 는 그 창이 맨 위일 때만 · 시험: 줄 세우기 3개 · ABI 판 3 (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:11:11 +09:00
RyuJongJin 9e40b485a9 rc 회귀 고침: 네트워크 공유 (UNC) 목록 · 기록 파일은 \\ 그대로 · 받는 쪽 UNC 도 \\ · 막히면 모니터링 [▶ 실행] 도 끔 · 표준 입력 (-) 문구 (검토 대기)
관리자 지시 (10/20, 28 이 f43f067 에서 확인 - 지운 것은 없음):
1. 회귀: ed459a0 이 목록 · 기록 · 배치 파일의 \\localhost\C$\… 를 //localhost/C$/… 로 바꿔 넘겨 rsync 가 "failed to open exclude
   file" (exit 11) 로 멈췄다 (985 는 \\ 그대로라 됨). 15 가 앱이 실제로 띄우는 방식 (응답 파일 · MSYS=noglob, rsync 3.5.1) 으로 자리마다
   확인 - 28 의 측정과 같음: 원본 = // 만 됨 (\\ 는 exit 23), 받는 쪽 = \\ 만 됨 (// 는 change_dir 실패 exit 3), 목록 · 기록 파일 =
   \\ 만 됨 (// 는 exit 11 · 기록이 안 생김).
   - rsyncFileOptionArgs: UNC 는 \\ 로 (//서버 로 적은 것도 \\ 로 바꿈), 드라이브는 /cygdrive/… 그대로.
   - 받는 쪽: 새 rsyncDestPath - UNC 면 \\서버\… (rsyncArgs 의 대상 · 실시간 동기화 rsyncArgsFor 의 받는 쪽). 원본은 toCygwinPath (//) 그대로.
     ed459a0 전부터 Windows 네트워크 공유가 받는 쪽인 rsync 는 실패했다 (관리자 판단: 데이터 문제는 아니지만 사용자가 겪는 실패라 rc 에).
2. 모니터링 복사 · rsync 카드: 옵션이 막혀 빨간 안내가 보이면 [▶ 실행] 도 끈다 (확인 창과 같게 - 누르면 실패로 끝났다).
3. --files-from=- · --exclude-from=- (표준 입력) 은 따로 된 문구 "표준 입력 (-) 은 쓸 수 없습니다" · 끝 문구 "목록 파일의 전체 경로를
   적어 주세요" (예전에는 "적어 주세요: - - C:\ …" 로 하이픈이 겹침).
시험: rsync_msys_args_test (실제 rsync - 관리 공유 \\localhost\C$ 로 원본 · 받는 쪽 UNC 와 목록 파일 \\ · // 를 복사 작업으로, 받는 쪽 UNC
실시간 동기화 쌍 · 바꿔 넘기기 단위 · 표준 입력 문구) · monitor_test (막히면 [실행] 꺼짐 · 고치면 켜짐).
전체 시험 1142 통과 · 1 실패 (explorer_test "여러 개 표시 → 삭제 · 새 폴더 · 이름 변경" - 이번 고침과 상관없음, 혼자 두 번 통과 ·
ed459a0 의 전체 시험에서도 통과 - 부하 흔들림) · analyze 문제 없음 · l10n 빠진 번역 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:29:47 +09:00
RyuJongJin 0d2b14ce68 WIP HWP: 닫을 때 다 연 PDF 묶음은 닫기를 기다림 (Windows 는 연 파일을 잡아 임시 폴더를 못 지웠음 - 통합 시험이 잡음), 만드는 중인 것만 기다리지 않음 · hwp_pdf_ffi 줄 끝 CRLF (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:04:45 +09:00