claude-settings-sync 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/i18n.ts","../src/utils/terminal.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { userConfigPath } from './paths.js';\n\ntype Lang = 'ko' | 'en';\n\nconst messages = {\n // ── General ───────────────────────────────\n 'app.name': { ko: 'claudesync', en: 'claudesync' },\n 'app.description': {\n ko: 'Claude Code 설정을 GitHub Gist로 동기화합니다',\n en: 'Sync Claude Code settings via GitHub Gist',\n },\n\n // ── Auth ──────────────────────────────────\n 'auth.no_token': {\n ko: '인증 정보가 없습니다. `claudesync init`을 먼저 실행하세요.',\n en: 'No auth found. Run `claudesync init` first.',\n },\n 'auth.token_saved': {\n ko: '토큰이 저장되었습니다.',\n en: 'Token saved.',\n },\n 'auth.device_prompt': {\n ko: '아래 URL을 브라우저에서 열고 코드를 입력하세요:',\n en: 'Open the following URL and enter the code:',\n },\n 'auth.waiting': {\n ko: '인증 대기 중...',\n en: 'Waiting for authorization...',\n },\n 'auth.success': {\n ko: '인증 성공!',\n en: 'Authentication successful!',\n },\n 'auth.enter_token': {\n ko: 'GitHub Personal Access Token (gist 스코프 필요): ',\n en: 'GitHub Personal Access Token (gist scope required): ',\n },\n\n // ── Push ──────────────────────────────────\n 'push.scanning': {\n ko: '설정 파일을 스캔 중...',\n en: 'Scanning settings files...',\n },\n 'push.no_files': {\n ko: '동기화할 파일이 없습니다.',\n en: 'No files to sync.',\n },\n 'push.summary': {\n ko: '변경 요약:',\n en: 'Change summary:',\n },\n 'push.confirm': {\n ko: '위 변경사항을 Gist에 업로드하시겠습니까?',\n en: 'Upload these changes to Gist?',\n },\n 'push.success': {\n ko: 'Gist에 동기화 완료!',\n en: 'Synced to Gist!',\n },\n 'push.cancelled': {\n ko: '업로드가 취소되었습니다.',\n en: 'Upload cancelled.',\n },\n 'push.creating_gist': {\n ko: '새 Gist를 생성 중...',\n en: 'Creating new Gist...',\n },\n\n // ── Pull ──────────────────────────────────\n 'pull.fetching': {\n ko: 'Gist에서 설정을 가져오는 중...',\n en: 'Fetching settings from Gist...',\n },\n 'pull.no_changes': {\n ko: '변경사항이 없습니다. 로컬과 원격이 동일합니다.',\n en: 'No changes. Local and remote are identical.',\n },\n 'pull.confirm': {\n ko: '위 변경사항을 로컬에 적용하시겠습니까?',\n en: 'Apply these changes locally?',\n },\n 'pull.success': {\n ko: '로컬 설정이 업데이트되었습니다!',\n en: 'Local settings updated!',\n },\n 'pull.cancelled': {\n ko: '복원이 취소되었습니다.',\n en: 'Restore cancelled.',\n },\n\n // ── Diff ──────────────────────────────────\n 'diff.no_diff': {\n ko: '차이가 없습니다.',\n en: 'No differences found.',\n },\n\n // ── Status ────────────────────────────────\n 'status.authenticated': {\n ko: '인증됨',\n en: 'Authenticated',\n },\n 'status.not_authenticated': {\n ko: '인증 안됨',\n en: 'Not authenticated',\n },\n 'status.gist_linked': {\n ko: 'Gist 연결됨',\n en: 'Gist linked',\n },\n 'status.no_gist': {\n ko: 'Gist 연결 안됨',\n en: 'No Gist linked',\n },\n\n // ── History ───────────────────────────────\n 'history.title': {\n ko: '동기화 히스토리',\n en: 'Sync history',\n },\n 'history.empty': {\n ko: '히스토리가 없습니다.',\n en: 'No history found.',\n },\n\n // ── Conflict ──────────────────────────────\n 'conflict.detected': {\n ko: '충돌이 감지되었습니다:',\n en: 'Conflicts detected:',\n },\n 'conflict.options': {\n ko: '로컬 유지 / 원격 적용 / diff 보기 / 건너뛰기',\n en: 'Keep local / Use remote / Show diff / Skip',\n },\n\n // ── Errors ────────────────────────────────\n 'error.gist_not_found': {\n ko: 'Gist를 찾을 수 없습니다. ID를 확인하세요.',\n en: 'Gist not found. Check the ID.',\n },\n 'error.api_failed': {\n ko: 'GitHub API 요청 실패:',\n en: 'GitHub API request failed:',\n },\n 'error.path_unsafe': {\n ko: '안전하지 않은 경로가 감지되었습니다:',\n en: 'Unsafe path detected:',\n },\n\n // ── Auto Sync ────────────────────────────────\n 'auto.title': {\n ko: '자동 동기화 설정',\n en: 'Auto Sync Setup',\n },\n 'auto.select_direction': {\n ko: 'push / pull 중 선택하세요:',\n en: 'Select push or pull:',\n },\n 'auto.direction_push': {\n ko: 'Push — 이 디바이스의 설정을 Gist에 자동 업로드',\n en: 'Push — auto-upload this device settings to Gist',\n },\n 'auto.direction_pull': {\n ko: 'Pull — Gist의 설정을 이 디바이스에 자동 다운로드',\n en: 'Pull — auto-download Gist settings to this device',\n },\n 'auto.primary_warning': {\n ko: '현재 Primary 디바이스: {machine} ({hostname}). 이 디바이스로 변경하면 기존 디바이스의 auto push는 무시됩니다.',\n en: 'Current primary device: {machine} ({hostname}). Changing to this device will ignore the previous auto push.',\n },\n 'auto.select_conflict_policy': {\n ko: '로컬 파일이 변경된 경우 처리 방식:',\n en: 'How to handle locally modified files:',\n },\n 'auto.policy_overwrite': {\n ko: 'Overwrite — 원격으로 덮어쓰기',\n en: 'Overwrite — replace with remote',\n },\n 'auto.policy_skip': {\n ko: 'Skip — 로컬 변경 파일은 건너뛰기',\n en: 'Skip — skip locally modified files',\n },\n 'auto.policy_backup': {\n ko: 'Backup — .bak 백업 후 덮어쓰기',\n en: 'Backup — backup to .bak then overwrite',\n },\n 'auto.select_interval': {\n ko: '동기화 주기를 입력하세요 (예: 5m, 1h, 30s, 1d):',\n en: 'Enter sync interval (e.g., 5m, 1h, 30s, 1d):',\n },\n 'auto.interval_too_short': {\n ko: '최소 주기는 1분(60초)입니다.',\n en: 'Minimum interval is 1 minute (60 seconds).',\n },\n 'auto.interval_invalid': {\n ko: '올바른 형식: 숫자 + s/m/h/d (예: 5m, 1h)',\n en: 'Valid format: number + s/m/h/d (e.g., 5m, 1h)',\n },\n 'auto.select_categories': {\n ko: '동기화할 카테고리를 선택하세요 (쉼표로 구분, 빈 입력=전체):',\n en: 'Select categories to sync (comma-separated, empty=all):',\n },\n 'auto.select_encrypt': {\n ko: '암호화를 활성화하시겠습니까?',\n en: 'Enable encryption?',\n },\n 'auto.enabled': {\n ko: '자동 동기화가 활성화되었습니다!',\n en: 'Auto sync enabled!',\n },\n 'auto.disabled': {\n ko: '자동 동기화가 비활성화되었습니다.',\n en: 'Auto sync disabled.',\n },\n 'auto.not_configured': {\n ko: '자동 동기화가 설정되지 않았습니다. `claudesync auto`를 실행하세요.',\n en: 'Auto sync not configured. Run `claudesync auto`.',\n },\n 'auto.status_title': {\n ko: '자동 동기화 상태',\n en: 'Auto Sync Status',\n },\n 'auto.confirm_primary_change': {\n ko: 'Primary 디바이스를 이 머신으로 변경하시겠습니까?',\n en: 'Change primary device to this machine?',\n },\n 'auto.lock_held': {\n ko: '동기화가 진행 중입니다. 잠시 후 다시 시도하세요.',\n en: 'Sync in progress. Try again later.',\n },\n\n // ── Config ───────────────────────────────────\n 'config.not_set': {\n ko: '(설정 안됨)',\n en: '(not set)',\n },\n 'config.invalid_lang': {\n ko: '지원하는 언어: ko, en',\n en: 'Supported languages: ko, en',\n },\n 'config.lang_saved': {\n ko: '언어 설정이 저장되었습니다.',\n en: 'Language setting saved.',\n },\n 'config.unknown_key': {\n ko: '알 수 없는 설정 키입니다. 사용 가능: lang',\n en: 'Unknown config key. Available: lang',\n },\n\n // ── Help ─────────────────────────────────────\n 'help.usage': {\n ko: '사용법: claudesync <command> [options]',\n en: 'Usage: claudesync <command> [options]',\n },\n 'help.commands': {\n ko: '명령어:',\n en: 'Commands:',\n },\n 'help.options': {\n ko: '옵션:',\n en: 'Options:',\n },\n 'help.init': {\n ko: '인증 설정 (OAuth Device Flow)',\n en: 'Set up authentication (OAuth Device Flow)',\n },\n 'help.init_token': {\n ko: 'PAT 수동 입력',\n en: 'Manual PAT input',\n },\n 'help.link': {\n ko: '기존 Gist 연결',\n en: 'Link existing Gist',\n },\n 'help.push': {\n ko: '로컬 → Gist 업로드',\n en: 'Upload local → Gist',\n },\n 'help.pull': {\n ko: 'Gist → 로컬 복원',\n en: 'Restore Gist → local',\n },\n 'help.diff': {\n ko: '로컬 vs 원격 비교',\n en: 'Compare local vs remote',\n },\n 'help.status': {\n ko: '인증/동기화 상태 확인',\n en: 'Check auth/sync status',\n },\n 'help.list': {\n ko: '동기화 대상 로컬 파일 목록',\n en: 'List local files to sync',\n },\n 'help.history': {\n ko: 'Gist revision 히스토리',\n en: 'Gist revision history',\n },\n 'help.rollback': {\n ko: '특정 버전으로 복원',\n en: 'Restore to specific version',\n },\n 'help.auto': {\n ko: '자동 동기화 설정 (인터랙티브)',\n en: 'Set up auto sync (interactive)',\n },\n 'help.auto_disable': {\n ko: '자동 동기화 해제',\n en: 'Disable auto sync',\n },\n 'help.auto_status': {\n ko: '자동 동기화 상태 확인',\n en: 'Check auto sync status',\n },\n 'help.config': {\n ko: '설정 관리',\n en: 'Manage configuration',\n },\n 'help.opt_message': {\n ko: 'push 시 메시지 기록 (history에서 표시)',\n en: 'Record message on push (shown in history)',\n },\n 'help.opt_only': {\n ko: '카테고리 필터 (settings|instructions|hooks|skills|plugins|teams|ui)',\n en: 'Category filter (settings|instructions|hooks|skills|plugins|teams|ui)',\n },\n 'help.opt_force': {\n ko: '확인 없이 실행',\n en: 'Run without confirmation',\n },\n 'help.opt_encrypt': {\n ko: '암호화 활성화',\n en: 'Enable encryption',\n },\n 'help.opt_lang': {\n ko: '언어 설정',\n en: 'Set language',\n },\n 'help.opt_help': {\n ko: '도움말',\n en: 'Help',\n },\n 'help.opt_version': {\n ko: '버전 정보',\n en: 'Version info',\n },\n\n // ── CLI ──────────────────────────────────────\n 'cli.link_usage': {\n ko: 'Usage: claudesync link <gist-id>',\n en: 'Usage: claudesync link <gist-id>',\n },\n 'cli.rollback_usage': {\n ko: 'Usage: claudesync rollback <version>',\n en: 'Usage: claudesync rollback <version>',\n },\n 'cli.list_empty': {\n ko: '동기화 대상 파일 없음',\n en: 'No files to sync',\n },\n 'cli.list_total': {\n ko: '총 {count}개 파일',\n en: '{count} files total',\n },\n 'cli.unknown_command': {\n ko: '알 수 없는 명령어: {command}',\n en: 'Unknown command: {command}',\n },\n\n // ── Terminal ─────────────────────────────────\n 'terminal.select_prompt': {\n ko: '선택 (1-{max}):',\n en: 'Choose (1-{max}):',\n },\n\n // ── Init ─────────────────────────────────────\n 'init.no_token_input': {\n ko: '토큰이 입력되지 않았습니다.',\n en: 'No token entered.',\n },\n 'init.gist_linked': {\n ko: 'Gist {id}에 연결되었습니다.',\n en: 'Linked to Gist {id}.',\n },\n 'init.validating': {\n ko: '토큰 검증 중...',\n en: 'Validating token...',\n },\n 'init.token_invalid': {\n ko: '토큰이 유효하지 않습니다. gist 스코프가 있는지 확인하세요.',\n en: 'Token is invalid. Make sure it has the gist scope.',\n },\n 'init.searching_gist': {\n ko: '기존 claudesync Gist 검색 중...',\n en: 'Searching for existing claudesync Gist...',\n },\n 'init.gist_found': {\n ko: '기존 Gist를 찾았습니다: {id}',\n en: 'Found existing Gist: {id}',\n },\n 'init.no_gist': {\n ko: '기존 Gist가 없습니다. `claudesync push`로 새로 생성하세요.',\n en: 'No existing Gist found. Run `claudesync push` to create one.',\n },\n\n // ── Push (additional) ────────────────────────\n 'push.secret_found': {\n ko: '{path}: {count}개 의심 항목 발견',\n en: '{path}: {count} suspicious item(s) found',\n },\n 'push.no_changes': {\n ko: '변경사항 없음. 로컬과 원격이 동일합니다.',\n en: 'No changes. Local and remote are identical.',\n },\n 'push.gist_not_found_creating': {\n ko: 'Gist를 찾을 수 없습니다. 새로 생성합니다.',\n en: 'Gist not found. Creating a new one.',\n },\n 'push.uploading_new': {\n ko: '{count}개 파일을 새 Gist에 업로드합니다:',\n en: 'Uploading {count} file(s) to new Gist:',\n },\n\n // ── Pull (additional) ────────────────────────\n 'pull.no_gist': {\n ko: 'Gist가 연결되지 않았습니다. `claudesync push` 또는 `claudesync link <id>`를 먼저 실행하세요.',\n en: 'No Gist linked. Run `claudesync push` or `claudesync link <id>` first.',\n },\n 'pull.changes_heading': {\n ko: '변경사항:',\n en: 'Changes:',\n },\n 'pull.icon_added': {\n ko: '+ 추가',\n en: '+ Add',\n },\n 'pull.icon_modified': {\n ko: '~ 수정',\n en: '~ Mod',\n },\n 'pull.icon_deleted': {\n ko: '- 삭제',\n en: '- Del',\n },\n 'pull.diff_truncated': {\n ko: '({count}줄 변경 — claudesync diff로 전체 확인)',\n en: '({count} lines changed — run claudesync diff to see full diff)',\n },\n 'pull.skip_deleted': {\n ko: '스킵: {path} (원격에서 삭제됨, 로컬은 유지)',\n en: 'Skipped: {path} (deleted on remote, kept locally)',\n },\n 'pull.decrypt_failed': {\n ko: '복호화 실패: {path}',\n en: 'Decryption failed: {path}',\n },\n 'pull.applied': {\n ko: '{count}개 파일 적용',\n en: '{count} file(s) applied',\n },\n\n // ── Diff (additional) ────────────────────────\n 'diff.no_gist': {\n ko: 'Gist가 연결되지 않았습니다.',\n en: 'No Gist linked.',\n },\n 'diff.fetching': {\n ko: '원격 설정을 가져오는 중...',\n en: 'Fetching remote settings...',\n },\n 'diff.total': {\n ko: '총 {count}개 파일에 차이가 있습니다.',\n en: '{count} file(s) have differences.',\n },\n\n // ── Status (additional) ──────────────────────\n 'status.title': {\n ko: 'claudesync 상태',\n en: 'claudesync status',\n },\n 'status.auth_label': {\n ko: '인증',\n en: 'Auth',\n },\n 'status.gist_label': {\n ko: 'Gist',\n en: 'Gist',\n },\n 'status.last_sync': {\n ko: '마지막 동기화:',\n en: 'Last sync:',\n },\n 'status.machine': {\n ko: '머신',\n en: 'Machine',\n },\n 'status.host': {\n ko: '호스트',\n en: 'Host',\n },\n 'status.platform': {\n ko: '플랫폼',\n en: 'Platform',\n },\n 'status.time': {\n ko: '시간',\n en: 'Time',\n },\n 'status.file_count': {\n ko: '파일 수',\n en: 'Files',\n },\n 'status.remote_files': {\n ko: '원격 파일: {count}개',\n en: 'Remote files: {count}',\n },\n 'status.gist_fetch_failed': {\n ko: 'Gist 조회 실패 — 네트워크를 확인하세요',\n en: 'Failed to fetch Gist — check your network',\n },\n 'status.current_machine': {\n ko: '현재 머신',\n en: 'Current machine',\n },\n\n // ── History (additional) ─────────────────────\n 'history.no_gist': {\n ko: 'Gist가 연결되지 않았습니다.',\n en: 'No Gist linked.',\n },\n 'history.loading': {\n ko: '최근 {count}개 리비전의 메시지를 불러오는 중...',\n en: 'Loading messages for {count} recent revision(s)...',\n },\n 'history.more': {\n ko: '... 외 {count}개',\n en: '... and {count} more',\n },\n 'history.total': {\n ko: '총 {count}개 리비전',\n en: '{count} revision(s) total',\n },\n 'history.rollback_hint': {\n ko: '복원: claudesync rollback <version>',\n en: 'Restore: claudesync rollback <version>',\n },\n\n // ── Rollback ─────────────────────────────────\n 'rollback.no_gist': {\n ko: 'Gist가 연결되지 않았습니다.',\n en: 'No Gist linked.',\n },\n 'rollback.not_found': {\n ko: \"리비전 '{version}'을 찾을 수 없습니다. `claudesync history`로 확인하세요.\",\n en: \"Revision '{version}' not found. Run `claudesync history` to check.\",\n },\n 'rollback.restoring': {\n ko: '리비전 {sha} ({date})을 복원합니다.',\n en: 'Restoring revision {sha} ({date}).',\n },\n 'rollback.target_heading': {\n ko: '복원 대상:',\n en: 'Restore targets:',\n },\n 'rollback.new_file': {\n ko: '(새 파일)',\n en: '(new file)',\n },\n 'rollback.decrypt_failed': {\n ko: '복호화 실패: {path}',\n en: 'Decryption failed: {path}',\n },\n 'rollback.no_changes': {\n ko: '현재 상태와 동일합니다.',\n en: 'Already at this state.',\n },\n 'rollback.files_changed': {\n ko: '{count}개 파일이 변경됩니다.',\n en: '{count} file(s) will be changed.',\n },\n 'rollback.confirm': {\n ko: '복원하시겠습니까?',\n en: 'Restore?',\n },\n 'rollback.cancelled': {\n ko: '복원이 취소되었습니다.',\n en: 'Restore cancelled.',\n },\n 'rollback.success': {\n ko: '리비전 {sha}로 복원 완료!',\n en: 'Restored to revision {sha}!',\n },\n\n // ── Auto (additional) ────────────────────────\n 'auto.no_gist': {\n ko: 'Gist가 연결되지 않았습니다. `claudesync push` 또는 `claudesync link <id>`를 먼저 실행하세요.',\n en: 'No Gist linked. Run `claudesync push` or `claudesync link <id>` first.',\n },\n 'auto.setup_cancelled': {\n ko: '설정이 취소되었습니다.',\n en: 'Setup cancelled.',\n },\n 'auto.invalid_categories': {\n ko: '유효한 카테고리가 없습니다. 전체 카테고리로 설정합니다.',\n en: 'No valid categories. Using all categories.',\n },\n 'auto.scheduler_failed': {\n ko: '스케줄러 등록 실패: {error}',\n en: 'Scheduler registration failed: {error}',\n },\n 'auto.primary_register_failed': {\n ko: 'Primary 디바이스 정보를 Gist에 등록하지 못했습니다. 다음 auto push 시 등록됩니다.',\n en: 'Failed to register primary device to Gist. It will be registered on next auto push.',\n },\n 'auto.summary_direction': {\n ko: '방향',\n en: 'Direction',\n },\n 'auto.summary_interval': {\n ko: '주기',\n en: 'Interval',\n },\n 'auto.summary_categories': {\n ko: '카테고리',\n en: 'Categories',\n },\n 'auto.summary_encrypt': {\n ko: '암호화',\n en: 'Encrypt',\n },\n 'auto.summary_conflict': {\n ko: '충돌 정책',\n en: 'Conflict',\n },\n 'auto.yes': {\n ko: '예',\n en: 'Yes',\n },\n 'auto.no': {\n ko: '아니오',\n en: 'No',\n },\n\n // ── Auto Status (additional) ─────────────────\n 'auto.status_enabled': {\n ko: '활성',\n en: 'Enabled',\n },\n 'auto.status_disabled': {\n ko: '비활성',\n en: 'Disabled',\n },\n 'auto.interval_seconds': {\n ko: '{n}초',\n en: '{n}s',\n },\n 'auto.interval_minutes': {\n ko: '{n}분',\n en: '{n}m',\n },\n 'auto.interval_hours': {\n ko: '{n}시간',\n en: '{n}h',\n },\n 'auto.interval_days': {\n ko: '{n}일',\n en: '{n}d',\n },\n 'auto.status_label': {\n ko: '상태',\n en: 'Status',\n },\n 'auto.created_label': {\n ko: '생성일',\n en: 'Created',\n },\n 'auto.primary_device_label': {\n ko: 'Primary 디바이스',\n en: 'Primary Device',\n },\n 'auto.this_machine': {\n ko: '(이 머신)',\n en: '(this machine)',\n },\n 'auto.since_label': {\n ko: '등록일',\n en: 'Since',\n },\n 'auto.recent_logs_label': {\n ko: '최근 로그',\n en: 'Recent Logs',\n },\n\n // ── Core errors ──────────────────────────────\n 'error.cli_not_found': {\n ko: 'claudesync CLI 경로를 찾을 수 없습니다. 글로벌 설치를 권장합니다: npm install -g claudesync',\n en: 'claudesync CLI path not found. Global install recommended: npm install -g claudesync',\n },\n 'auth.device_url': {\n ko: ' URL: {url}',\n en: ' URL: {url}',\n },\n 'auth.device_code': {\n ko: ' 코드: {code}',\n en: ' Code: {code}',\n },\n 'auth.oauth_error': {\n ko: 'OAuth 오류: {error}',\n en: 'OAuth error: {error}',\n },\n 'auth.device_flow_timeout': {\n ko: 'Device flow 시간 초과',\n en: 'Device flow timed out',\n },\n 'error.unsupported_platform': {\n ko: '지원하지 않는 플랫폼: {platform}',\n en: 'Unsupported platform: {platform}',\n },\n\n // ── Auto Run ─────────────────────────────────\n 'auto_run.failed': {\n ko: '자동 {direction} 실패: {message}',\n en: 'Auto {direction} failed: {message}',\n },\n 'auto_run.push_synced': {\n ko: '{count}개 파일 동기화됨',\n en: '{count} files synced',\n },\n 'auto_run.pull_applied': {\n ko: '{applied}개 파일 적용',\n en: '{applied} files applied',\n },\n 'auto_run.pull_applied_skipped': {\n ko: '{applied}개 파일 적용, {skipped}개 건너뜀',\n en: '{applied} files applied, {skipped} skipped',\n },\n} as const;\n\ntype MessageKey = keyof typeof messages;\n\nlet currentLang: Lang = 'en';\n\nexport function setLang(lang: Lang): void {\n currentLang = lang;\n}\n\nexport function getLang(): Lang {\n return currentLang;\n}\n\nexport function t(key: MessageKey): string {\n return messages[key]?.[currentLang] ?? key;\n}\n\nexport function detectLang(): Lang {\n const env = process.env.LANG || process.env.LANGUAGE || process.env.LC_ALL || '';\n if (env.startsWith('ko')) return 'ko';\n return 'en';\n}\n\n/** Load lang from ~/.claudesync/config.json */\nexport function loadLangConfig(): Lang | null {\n const path = userConfigPath();\n if (!existsSync(path)) return null;\n try {\n const data = JSON.parse(readFileSync(path, 'utf-8'));\n if (data.lang === 'ko' || data.lang === 'en') return data.lang;\n return null;\n } catch {\n return null;\n }\n}\n\n/** Save lang to ~/.claudesync/config.json */\nexport function saveLangConfig(lang: Lang): void {\n const path = userConfigPath();\n let data: Record<string, unknown> = {};\n if (existsSync(path)) {\n try {\n data = JSON.parse(readFileSync(path, 'utf-8'));\n } catch {\n data = {};\n }\n }\n data.lang = lang;\n writeFileSync(path, JSON.stringify(data, null, 2), 'utf-8');\n}\n","import { createInterface } from 'node:readline';\nimport { t } from './i18n.js';\n\n// ── ANSI Colors ─────────────────────────────────────────────\nconst esc = (code: string) => `\\x1b[${code}m`;\nconst reset = esc('0');\n\nexport const c = {\n bold: (s: string) => `${esc('1')}${s}${reset}`,\n dim: (s: string) => `${esc('2')}${s}${reset}`,\n red: (s: string) => `${esc('31')}${s}${reset}`,\n green: (s: string) => `${esc('32')}${s}${reset}`,\n yellow: (s: string) => `${esc('33')}${s}${reset}`,\n blue: (s: string) => `${esc('34')}${s}${reset}`,\n cyan: (s: string) => `${esc('36')}${s}${reset}`,\n gray: (s: string) => `${esc('90')}${s}${reset}`,\n};\n\n// ── Output helpers ──────────────────────────────────────────\nexport function info(msg: string): void {\n console.log(`${c.blue('ℹ')} ${msg}`);\n}\n\nexport function success(msg: string): void {\n console.log(`${c.green('✔')} ${msg}`);\n}\n\nexport function warn(msg: string): void {\n console.log(`${c.yellow('⚠')} ${msg}`);\n}\n\nexport function error(msg: string): void {\n console.error(`${c.red('✖')} ${msg}`);\n}\n\nexport function heading(msg: string): void {\n console.log(`\\n${c.bold(msg)}`);\n}\n\n// ── Diff display ────────────────────────────────────────────\nexport function printDiff(filename: string, lines: string[]): void {\n console.log(`\\n${c.bold(filename)}`);\n console.log(c.dim('─'.repeat(60)));\n for (const line of lines) {\n if (line.startsWith('+')) console.log(c.green(line));\n else if (line.startsWith('-')) console.log(c.red(line));\n else if (line.startsWith('@')) console.log(c.cyan(line));\n else console.log(line);\n }\n}\n\n// ── Prompts ─────────────────────────────────────────────────\nexport async function confirm(message: string, defaultYes = true): Promise<boolean> {\n const hint = defaultYes ? '[Y/n]' : '[y/N]';\n const answer = await ask(`${message} ${c.dim(hint)} `);\n if (answer.trim() === '') return defaultYes;\n return answer.trim().toLowerCase().startsWith('y');\n}\n\nexport async function ask(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport async function askHidden(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n process.stdout.write(question);\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n if (stdin.isTTY) stdin.setRawMode(true);\n\n let input = '';\n const onData = (ch: Buffer) => {\n const char = ch.toString('utf8');\n if (char === '\\n' || char === '\\r') {\n if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);\n stdin.removeListener('data', onData);\n process.stdout.write('\\n');\n rl.close();\n resolve(input);\n } else if (char === '\\u0003') {\n // Ctrl+C\n rl.close();\n process.exit(1);\n } else if (char === '\\u007f') {\n // Backspace\n input = input.slice(0, -1);\n } else {\n input += char;\n }\n };\n stdin.on('data', onData);\n });\n}\n\nexport async function select(message: string, options: string[]): Promise<number> {\n console.log(`\\n${message}`);\n options.forEach((opt, i) => {\n console.log(` ${c.bold(`${i + 1}.`)} ${opt}`);\n });\n const answer = await ask(`${c.dim(t('terminal.select_prompt').replace('{max}', String(options.length)))} `);\n const idx = parseInt(answer.trim(), 10) - 1;\n if (idx >= 0 && idx < options.length) return idx;\n return 0;\n}\n"],"mappings":"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","names":[]}