Files
CodeNomad/packages/ui/src/lib/i18n/messages/ja/instance.ts
VooDisss e022a158eb improve delete worktree failure diagnostics (#302)
## Summary
- move delete-worktree failures out of transient toast-only UX and keep
them inline in the delete modal
- add parsed diagnostics for common failure modes, including a short
summary, likely cause, and suggested next step
- make the raw error easier to review and share with raw and sanitized
copy actions

Closes #301.

## BEFORE:

<img width="1127" height="860" alt="image"
src="https://github.com/user-attachments/assets/dd09ba1e-be8c-450c-a1dd-f1cde2a48802"
/>

## AFTER: 

<img width="1384" height="835" alt="image"
src="https://github.com/user-attachments/assets/6b0d1459-21fa-4264-9e54-45540f584538"
/>

## Problem
Before this change, delete-worktree failures were difficult to work
with:

1. The failure message was effectively raw backend or git output.
2. Users had to infer the meaning of the error themselves.
3. The UI did not explain what likely went wrong or what to do next.
4. Sharing the error for debugging was awkward when it included
machine-local absolute paths.
5. The confirmation modal was not being used as the primary diagnostic
surface for a destructive action that frequently fails for
understandable reasons.

This was especially frustrating for common cases such as:
- modified or untracked files in the worktree
- a process still using the worktree directory
- permission errors on Windows
- missing worktree directories or stale worktree records

## What changed

### Modal failure UX
- keep delete failures inline inside
`packages/ui/src/components/worktree-selector.tsx`
- clear modal-local error state when opening or closing the dialog
- keep the success toast on successful deletion, but use the modal
itself for failure presentation

### Human-readable diagnostics
- parse JSON-shaped backend error payloads such as `{"error":"..."}`
before classification
- classify common delete failure patterns into:
  - `localChanges`
  - `inUse`
  - `notFound`
  - `permissionDenied`
  - `unknown`
- render three user-facing lines above the raw error:
  - summary
  - likely cause
  - suggested next step

### Copy flows
- add `Copy error` for the original failure text
- add `Copy sanitized` to redact common absolute path and username
patterns before copying

### Modal content and sizing
- present the target worktree in a simpler two-line summary block
- update the delete description text to plain English: `Deletes this
branch worktree and its local folder.`
- size the delete modal deliberately for desktop use while allowing
vertical expansion to the viewport limit before scrolling

### i18n coverage
- add the new delete diagnostic strings across all currently supported
locales touched by this area:
  - `en`
  - `es`
  - `fr`
  - `he`
  - `ja`
  - `ru`
  - `zh-Hans`

## Why this approach
- It keeps the backend contract unchanged and solves the UX problem
where it occurs.
- It preserves access to the raw failure text instead of hiding
implementation detail entirely.
- It gives users immediate guidance without forcing them to translate
git errors into next actions.
- It improves bug reporting without requiring a separate logging or
export workflow.

## Not included
- server-side preflight guards that block delete when the worktree is
still assigned or in use
- process-aware worktree locking detection
- automatic retry or force-delete-and-retry flows

Those are useful follow-ups, but this PR is intentionally scoped to
failure presentation and debuggability.

## Files changed
- `packages/ui/src/components/worktree-selector.tsx`
- `packages/ui/src/lib/i18n/messages/en/instance.ts`
- `packages/ui/src/lib/i18n/messages/es/instance.ts`
- `packages/ui/src/lib/i18n/messages/fr/instance.ts`
- `packages/ui/src/lib/i18n/messages/he/instance.ts`
- `packages/ui/src/lib/i18n/messages/ja/instance.ts`
- `packages/ui/src/lib/i18n/messages/ru/instance.ts`
- `packages/ui/src/lib/i18n/messages/zh-Hans/instance.ts`

## Validation
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/ui`
- `npm run typecheck --workspace @neuralnomads/codenomad-electron-app`

## Notes for reviewers
- The error classifier is intentionally heuristic and string-based. It
is meant to improve the common cases without increasing backend
coupling.
- The sanitized copy flow is conservative and focused on path and
username redaction, not full structured log scrubbing.

---------

Co-authored-by: Shantur Rathore <i@shantur.com>
2026-04-17 17:12:17 +01:00

215 lines
16 KiB
TypeScript

export const instanceMessages = {
"instanceTabs.new.title": "新しいインスタンス (Cmd/Ctrl+N)",
"instanceTabs.new.ariaLabel": "新しいインスタンス",
"instanceTabs.remote.title": "リモート接続",
"instanceTabs.remote.ariaLabel": "リモート接続",
"instanceInfo.title": "インスタンス情報",
"instanceInfo.labels.folder": "フォルダ",
"instanceInfo.labels.project": "プロジェクト",
"instanceInfo.labels.versionControl": "バージョン管理",
"instanceInfo.labels.opencodeVersion": "OpenCode バージョン",
"instanceInfo.labels.binaryPath": "バイナリのパス",
"instanceInfo.labels.environmentVariables": "環境変数 ({count})",
"instanceInfo.loading": "読み込み中...",
"instanceInfo.server.title": "サーバー",
"instanceInfo.server.port": "ポート:",
"instanceInfo.server.pid": "PID:",
"instanceInfo.server.status": "状態:",
"instanceTab.status.permission": "許可待ち",
"instanceTab.status.compacting": "圧縮中",
"instanceTab.status.working": "作業中",
"instanceTab.status.idle": "待機中",
"instanceTab.status.ariaLabel": "インスタンス状態: {status}",
"instanceTab.actions.close.ariaLabel": "インスタンスを閉じる",
"instanceShell.leftPanel.sessionsTitle": "セッション",
"instanceShell.leftPanel.instanceInfo": "インスタンス情報",
"instanceShell.leftDrawer.pin": "左ドロワーを固定",
"instanceShell.leftDrawer.unpin": "左ドロワーの固定を解除",
"instanceShell.leftDrawer.toggle.pinned": "左ドロワーを固定しました",
"instanceShell.leftDrawer.toggle.open": "左ドロワーを開く",
"instanceShell.leftDrawer.toggle.close": "左ドロワーを閉じる",
"instanceShell.rightDrawer.pin": "右ドロワーを固定",
"instanceShell.rightDrawer.unpin": "右ドロワーの固定を解除",
"instanceShell.rightDrawer.toggle.pinned": "右ドロワーを固定しました",
"instanceShell.rightDrawer.toggle.open": "右ドロワーを開く",
"instanceShell.rightDrawer.toggle.close": "右ドロワーを閉じる",
"instanceShell.fullscreen.enter": "全画面",
"instanceShell.fullscreen.exit": "全画面を終了",
"instanceShell.metrics.usedLabel": "使用",
"instanceShell.metrics.availableLabel": "残り",
"instanceShell.commandPalette.openAriaLabel": "コマンドパレットを開く",
"instanceShell.commandPalette.button": "コマンドパレット",
"instanceShell.connection.ariaLabel": "接続 {status}",
"instanceShell.connection.connected": "接続済み",
"instanceShell.connection.connecting": "接続中...",
"instanceShell.connection.disconnected": "切断",
"instanceShell.connection.unknown": "不明",
"instanceWelcome.shortcuts.newSession": "新しいセッション",
"instanceWelcome.empty.title": "以前のセッションはありません",
"instanceWelcome.empty.description": "下で新しいセッションを作成して開始",
"instanceWelcome.loading.title": "セッションを読み込み中",
"instanceWelcome.loading.description": "以前のセッションを取得中...",
"instanceWelcome.resume.title": "セッションを再開",
"instanceWelcome.resume.subtitle.one": "{count} 件のセッション",
"instanceWelcome.resume.subtitle.other": "{count} 件のセッション",
"instanceWelcome.session.untitled": "無題のセッション",
"instanceWelcome.new.title": "新しいセッションを開始",
"instanceWelcome.new.subtitle": "前回のエージェント/モデルを自動で再利用します",
"instanceWelcome.new.createButton": "セッションを作成",
"instanceWelcome.overlay.close": "閉じる",
"instanceWelcome.actions.viewInstanceInfo": "インスタンス情報を表示",
"instanceWelcome.actions.renameTitle": "セッション名を変更",
"instanceWelcome.actions.deleteTitle": "セッションを削除",
"instanceWelcome.hints.navigate": "移動",
"instanceWelcome.hints.jump": "ジャンプ",
"instanceWelcome.hints.firstLast": "先頭/末尾",
"instanceWelcome.hints.resume": "再開",
"instanceWelcome.hints.delete": "削除",
"instanceWelcome.toasts.renameError": "セッション名を変更できません",
"instanceDisconnected.title": "インスタンスが切断されました",
"instanceDisconnected.folderFallback": "このワークスペース",
"instanceDisconnected.reasonFallback": "サーバーが応答しなくなりました",
"instanceDisconnected.description": "{folder} に接続できません。作業を続けるにはタブを閉じてください。",
"instanceDisconnected.details.title": "詳細",
"instanceDisconnected.details.folderLabel": "フォルダ:",
"instanceDisconnected.actions.closeInstance": "インスタンスを閉じる",
"instanceShell.empty.title": "セッションが選択されていません",
"instanceShell.empty.description": "メッセージを表示するにはセッションを選択してください",
"instanceShell.rightPanel.title": "ステータスパネル",
"instanceShell.rightPanel.tabs.changes": "変更",
"instanceShell.rightPanel.tabs.gitChanges": "Git 変更",
"instanceShell.rightPanel.tabs.files": "ファイル",
"instanceShell.rightPanel.tabs.status": "ステータス",
"instanceShell.rightPanel.tabs.ariaLabel": "右パネルのタブ",
"instanceShell.rightPanel.actions.refresh": "更新",
"instanceShell.rightPanel.actions.save": "保存 (Ctrl+S)",
"instanceShell.rightPanel.actions.saveConfirm.message": "「{path}」への変更を切り替え前に保存しますか?",
"instanceShell.rightPanel.actions.saveConfirm.confirmLabel": "保存",
"instanceShell.rightPanel.actions.saveConfirm.cancelLabel": "変更を破棄",
"instanceShell.rightPanel.actions.conflict.message": "ファイルはエージェントによって変更されました。上書きしますか?",
"instanceShell.rightPanel.actions.conflict.confirmLabel": "上書き",
"instanceShell.rightPanel.actions.conflict.cancelLabel": "キャンセル",
"instanceShell.rightPanel.actions.refreshDirty.message": "ファイルには未保存の変更があります。更新すると編集が破棄されます。続行しますか?",
"instanceShell.rightPanel.actions.refreshDirty.confirmLabel": "更新",
"instanceShell.rightPanel.actions.refreshDirty.cancelLabel": "キャンセル",
"instanceShell.rightPanel.toast.saveSuccess": "ファイルを保存しました",
"instanceShell.rightPanel.toast.saveError": "ファイルの保存に失敗しました",
"instanceShell.rightPanel.sections.yoloMode": "Yoloモード",
"instanceShell.rightPanel.sections.yoloMode.tooltip": "現在のセッションの権限リクエストを自動承認します。実行中のツールを信頼できる場合にのみ使用してください。",
"instanceShell.rightPanel.sections.sessionChanges": "セッション変更",
"instanceShell.rightPanel.sections.sessionChanges.tooltip": "現在のセッションで変更されたファイル。各ファイルの追加と削除を表示します。",
"instanceShell.rightPanel.sections.plan": "計画",
"instanceShell.rightPanel.sections.plan.tooltip": "このセッションにおけるエージェントのロードマップ。タスクやサブタスク、および完了状況を追跡します。",
"instanceShell.rightPanel.sections.backgroundProcesses": "バックグラウンドシェル",
"instanceShell.rightPanel.sections.backgroundProcesses.tooltip": "エージェントが開始した長時間実行プロセス。出力を監視し、停止または終了できます。",
"instanceShell.rightPanel.sections.mcp": "MCP サーバー",
"instanceShell.rightPanel.sections.mcp.tooltip": "Model Context Protocol (MCP) サーバー。外部ツールやサービスでエージェントの機能を拡張します。",
"instanceShell.rightPanel.sections.lsp": "LSP サーバー",
"instanceShell.rightPanel.sections.lsp.tooltip": "Language Server Protocolサーバーがコードインテリジェンス、診断、言語固有の機能を提供します。",
"instanceShell.rightPanel.sections.plugins": "プラグイン",
"instanceShell.rightPanel.sections.plugins.tooltip": "UI とサーバーの動作をカスタマイズし、MCP や LSP 以外の機能も追加できるプラグイン。",
"instanceShell.sessionChanges.noSessionSelected": "変更を表示するにはセッションを選択してください。",
"instanceShell.sessionChanges.loading": "変更を取得中...",
"instanceShell.sessionChanges.empty": "まだ変更はありません。",
"instanceShell.sessionChanges.filesChanged": "{count} 個のファイルが変更されました",
"instanceShell.sessionChanges.actions.show": "変更を表示",
"instanceShell.gitChanges.loading": "Git の変更を読み込み中...",
"instanceShell.gitChanges.empty": "Git の変更はまだありません。",
"instanceShell.gitChanges.deleted": "削除済み",
"instanceShell.gitChanges.binaryViewer": "バイナリファイルは表示できません",
"instanceShell.gitChanges.sections.staged": "ステージ済みの変更",
"instanceShell.gitChanges.sections.unstaged": "変更",
"instanceShell.gitChanges.actions.insertContext": "プロンプトに追加",
"instanceShell.gitChanges.actions.stage": "ファイルをステージ",
"instanceShell.gitChanges.actions.unstage": "ステージ解除",
"instanceShell.gitChanges.commit.placeholder": "コミットメッセージを入力",
"instanceShell.gitChanges.commit.submit": "コミット",
"instanceShell.gitChanges.commit.submitting": "コミット中...",
"instanceShell.gitChanges.commit.success": "コミットを作成しました",
"instanceShell.gitChanges.commit.error": "コミットを作成できませんでした",
"instanceShell.filesShell.fileListTitle": "ファイル一覧",
"instanceShell.filesShell.mobileSelectorLabel": "ファイルを選択",
"instanceShell.filesShell.mobileSelectorEmpty": "ファイルを選択してください",
"instanceShell.filesShell.viewerTitle": "変更ビューア",
"instanceShell.filesShell.viewerPlaceholder": "詳細な変更表示は次のステップで追加します。",
"instanceShell.filesShell.viewerEmpty": "ファイルが選択されていません。",
"instanceShell.plan.noSessionSelected": "計画を表示するにはセッションを選択してください。",
"instanceShell.plan.empty": "まだ計画はありません。",
"instanceShell.yoloMode.noSessionSelected": "Yoloモードを設定するにはセッションを選択してください。",
"instanceShell.yoloMode.title": "Yoloモード",
"instanceShell.yoloMode.description": "このセッションの権限リクエストを自動承認します。デフォルトでは無効です。",
"instanceShell.yoloMode.badge": "Yolo",
"instanceShell.yoloMode.badgeAriaLabel": "Yoloモードが有効",
"instanceShell.backgroundProcesses.empty": "バックグラウンドプロセスはありません。",
"instanceShell.backgroundProcesses.status": "状態: {status}",
"instanceShell.backgroundProcesses.output": "出力: {sizeKb}KB",
"instanceShell.backgroundProcesses.notify.enabled": "完了通知が有効",
"instanceShell.backgroundProcesses.notify.disabled": "完了通知が無効",
"instanceShell.backgroundProcesses.actions.output": "出力",
"instanceShell.backgroundProcesses.actions.stop": "停止",
"instanceShell.backgroundProcesses.actions.terminate": "終了",
"instanceShell.worktree.delete.error.title": "削除に失敗しました",
"instanceShell.worktree.delete.error.fallback": "worktree の削除に失敗しました",
"instanceShell.worktree.delete.error.causeLabel": "考えられる原因:",
"instanceShell.worktree.delete.error.nextStepLabel": "推奨される次の手順:",
"instanceShell.worktree.delete.error.summary.localChanges": "この worktree に変更済みまたは未追跡のファイルがあるため、Git が削除を拒否しました。",
"instanceShell.worktree.delete.error.summary.inUse": "このディレクトリ内のファイルがまだ使用中のため、CodeNomad はこの worktree を削除できませんでした。",
"instanceShell.worktree.delete.error.summary.notFound": "ディレクトリまたは worktree レコードが見つからなかったため、CodeNomad はこの worktree を削除できませんでした。",
"instanceShell.worktree.delete.error.summary.permissionDenied": "ディレクトリへのアクセスが拒否されたため、CodeNomad はこの worktree を削除できませんでした。",
"instanceShell.worktree.delete.error.summary.unknown": "CodeNomad はこの worktree を削除できませんでした。",
"instanceShell.worktree.delete.error.cause.localChanges": "ローカル変更",
"instanceShell.worktree.delete.error.cause.inUse": "別のプロセスがこの worktree を使用中です",
"instanceShell.worktree.delete.error.cause.notFound": "worktree のディレクトリまたは記録が見つかりません",
"instanceShell.worktree.delete.error.cause.permissionDenied": "ファイルシステム権限が不足しています",
"instanceShell.worktree.delete.error.cause.unknown": "バックエンドが分類できない削除エラーを返しました",
"instanceShell.worktree.delete.error.nextStep.localChanges": "ローカル変更を破棄したい場合は Force delete を有効にするか、worktree を整理してから再試行してください。",
"instanceShell.worktree.delete.error.nextStep.inUse": "この worktree を使用している端末、エディタ、watcher、バックグラウンドプロセスを閉じてから再試行してください。",
"instanceShell.worktree.delete.error.nextStep.notFound": "worktree 一覧を更新して再試行してください。まだ失敗する場合は、ディスク上の worktree パスを確認してください。",
"instanceShell.worktree.delete.error.nextStep.permissionDenied": "ファイルシステム権限を確認し、このディレクトリをロックしている可能性のあるアプリを閉じてから再試行してください。",
"instanceShell.worktree.delete.error.nextStep.unknown": "下の生エラーで詳細を確認し、報告された問題に対処してから再試行してください。",
"instanceShell.worktree.delete.error.copyRaw": "エラーをコピー",
"instanceShell.worktree.delete.error.copySanitized": "サニタイズ済みをコピー",
"instanceShell.worktree.delete.error.copySuccess": "削除エラーをコピーしました",
"instanceShell.worktree.delete.error.copySanitizedSuccess": "サニタイズ済みの削除エラーをコピーしました",
"instanceShell.worktree.delete.error.copyFailure": "削除エラーをコピーできませんでした",
"versionPill.appWithVersion": "アプリ {version}",
"versionPill.ui": "UI",
"versionPill.uiWithVersion": "UI {version}",
"versionPill.source": " ({source})",
"opencodeBinarySelector.title": "OpenCode バイナリ",
"opencodeBinarySelector.subtitle": "OpenCode を実行する実行ファイルを選択",
"opencodeBinarySelector.customPath.placeholder": "opencode バイナリのパスを入力…",
"opencodeBinarySelector.actions.add": "追加",
"opencodeBinarySelector.actions.browse": "バイナリを参照…",
"opencodeBinarySelector.actions.removeTitle": "バイナリを削除",
"opencodeBinarySelector.badge.systemPath": "system PATH のバイナリを使用",
"opencodeBinarySelector.status.checkingVersions": "バージョンを確認中…",
"opencodeBinarySelector.status.checking": "確認中…",
"opencodeBinarySelector.dialog.title": "OpenCode バイナリを選択",
"opencodeBinarySelector.dialog.description": "CLI サーバーから公開されているファイルを参照します。",
"opencodeBinarySelector.validation.invalidBinary": "OpenCode バイナリが無効です",
"opencodeBinarySelector.validation.alreadyValidating": "すでに検証中です",
"opencodeBinarySelector.display.systemPath": "{name} (system PATH)",
"opencodeBinarySelector.versionLabel": "v{version}",
} as const