dsh-git-worktree 0.7.5 → 0.9.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.
Files changed (150) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.en.md +11 -5
  3. package/README.md +11 -5
  4. package/docs/i18n.md +63 -0
  5. package/lib/adapters/files.d.ts +0 -7
  6. package/lib/adapters/files.js +4 -3
  7. package/lib/adapters/files.js.map +1 -1
  8. package/lib/adapters/git.d.ts +0 -10
  9. package/lib/adapters/git.js +92 -18
  10. package/lib/adapters/git.js.map +1 -1
  11. package/lib/adapters/initial-commit.d.ts +16 -0
  12. package/lib/adapters/initial-commit.js +112 -0
  13. package/lib/adapters/initial-commit.js.map +1 -0
  14. package/lib/adapters/lookup.js +21 -0
  15. package/lib/adapters/lookup.js.map +1 -1
  16. package/lib/adapters/registry.d.ts +0 -7
  17. package/lib/adapters/registry.js +2 -1
  18. package/lib/adapters/registry.js.map +1 -1
  19. package/lib/adapters/safe-file.d.ts +0 -7
  20. package/lib/adapters/safe-file.js +5 -4
  21. package/lib/adapters/safe-file.js.map +1 -1
  22. package/lib/client/WorktreeCreateRow.js +5 -2
  23. package/lib/client/WorktreeCreateRow.js.map +1 -1
  24. package/lib/client/WorktreeReviewRow.d.ts +1 -1
  25. package/lib/client/WorktreeReviewRow.js +11 -9
  26. package/lib/client/WorktreeReviewRow.js.map +1 -1
  27. package/lib/client/actions.d.ts +4 -7
  28. package/lib/client/actions.js +17 -13
  29. package/lib/client/actions.js.map +1 -1
  30. package/lib/client/console-remote/adapter.d.ts +2 -1
  31. package/lib/client/console-remote/adapter.js +37 -32
  32. package/lib/client/console-remote/adapter.js.map +1 -1
  33. package/lib/client/console-remote/index.js +6 -2
  34. package/lib/client/console-remote/index.js.map +1 -1
  35. package/lib/client/i18n.d.ts +25 -0
  36. package/lib/client/i18n.js +43 -0
  37. package/lib/client/i18n.js.map +1 -0
  38. package/lib/client/index.d.ts +1 -1
  39. package/lib/client/index.js +17 -4
  40. package/lib/client/index.js.map +1 -1
  41. package/lib/client/model.d.ts +3 -2
  42. package/lib/client/model.js +8 -8
  43. package/lib/client/model.js.map +1 -1
  44. package/lib/client/pre-session/PreSessionWorktreeToggle.d.ts +2 -2
  45. package/lib/client/pre-session/PreSessionWorktreeToggle.js +95 -80
  46. package/lib/client/pre-session/PreSessionWorktreeToggle.js.map +1 -1
  47. package/lib/client/pre-session/controller.d.ts +3 -0
  48. package/lib/client/pre-session/controller.js +27 -13
  49. package/lib/client/pre-session/controller.js.map +1 -1
  50. package/lib/client/pre-session/harness-input.d.ts +13 -0
  51. package/lib/client/pre-session/harness-input.js +18 -0
  52. package/lib/client/pre-session/harness-input.js.map +1 -0
  53. package/lib/client/pre-session/index.d.ts +13 -2
  54. package/lib/client/pre-session/index.js +11 -2
  55. package/lib/client/pre-session/index.js.map +1 -1
  56. package/lib/client/review-console/DeliveryProof.js +15 -12
  57. package/lib/client/review-console/DeliveryProof.js.map +1 -1
  58. package/lib/client/review-console/PreflightStatus.js +15 -8
  59. package/lib/client/review-console/PreflightStatus.js.map +1 -1
  60. package/lib/client/review-console/ReviewActions.d.ts +4 -1
  61. package/lib/client/review-console/ReviewActions.js +139 -114
  62. package/lib/client/review-console/ReviewActions.js.map +1 -1
  63. package/lib/client/review-console/ReviewDetailsModal.d.ts +12 -0
  64. package/lib/client/review-console/ReviewDetailsModal.js +56 -0
  65. package/lib/client/review-console/ReviewDetailsModal.js.map +1 -0
  66. package/lib/client/review-console/ReviewIcon.d.ts +35 -0
  67. package/lib/client/review-console/ReviewIcon.js +14 -0
  68. package/lib/client/review-console/ReviewIcon.js.map +1 -0
  69. package/lib/client/review-console/WorktreeReviewPanel.d.ts +3 -7
  70. package/lib/client/review-console/WorktreeReviewPanel.js +20 -82
  71. package/lib/client/review-console/WorktreeReviewPanel.js.map +1 -1
  72. package/lib/client/review-console/recovery-continuation.d.ts +2 -1
  73. package/lib/client/review-console/recovery-continuation.js +12 -8
  74. package/lib/client/review-console/recovery-continuation.js.map +1 -1
  75. package/lib/client/review-console/review-console.styles.js +101 -23
  76. package/lib/client/review-console/review-console.styles.js.map +1 -1
  77. package/lib/client/styles.js +13 -10
  78. package/lib/client/styles.js.map +1 -1
  79. package/lib/client/target-console/TargetStatusAction.js +87 -65
  80. package/lib/client/target-console/TargetStatusAction.js.map +1 -1
  81. package/lib/client/target-console/WorktreeConsoleView.d.ts +2 -1
  82. package/lib/client/target-console/WorktreeConsoleView.js +42 -37
  83. package/lib/client/target-console/WorktreeConsoleView.js.map +1 -1
  84. package/lib/client/target-console/WorktreeManagerModal.js +3 -1
  85. package/lib/client/target-console/WorktreeManagerModal.js.map +1 -1
  86. package/lib/client/target-console/WorktreeReviewStatus.js +45 -88
  87. package/lib/client/target-console/WorktreeReviewStatus.js.map +1 -1
  88. package/lib/client/target-console/current-polling.d.ts +11 -0
  89. package/lib/client/target-console/current-polling.js +104 -0
  90. package/lib/client/target-console/current-polling.js.map +1 -0
  91. package/lib/client/target-console/target-console.styles.js +8 -0
  92. package/lib/client/target-console/target-console.styles.js.map +1 -1
  93. package/lib/client/workspace-sidebar/index.js +8 -3
  94. package/lib/client/workspace-sidebar/index.js.map +1 -1
  95. package/lib/client/workspace-sidebar/model.d.ts +5 -1
  96. package/lib/client/workspace-sidebar/model.js +97 -23
  97. package/lib/client/workspace-sidebar/model.js.map +1 -1
  98. package/lib/client.js +12228 -8928
  99. package/lib/commands.js +32 -35
  100. package/lib/commands.js.map +1 -1
  101. package/lib/console-contract.d.ts +20 -0
  102. package/lib/console-contract.js.map +1 -1
  103. package/lib/console-host/control-plane.d.ts +3 -1
  104. package/lib/console-host/control-plane.js +186 -95
  105. package/lib/console-host/control-plane.js.map +1 -1
  106. package/lib/console-host/errors.js +2 -1
  107. package/lib/console-host/errors.js.map +1 -1
  108. package/lib/console-host/projection.js +3 -1
  109. package/lib/console-host/projection.js.map +1 -1
  110. package/lib/console-host/review-diff.js +6 -5
  111. package/lib/console-host/review-diff.js.map +1 -1
  112. package/lib/console-host/service.d.ts +27 -23
  113. package/lib/console-host/service.js +66 -51
  114. package/lib/console-host/service.js.map +1 -1
  115. package/lib/console-remote/descriptors.js +4 -2
  116. package/lib/console-remote/descriptors.js.map +1 -1
  117. package/lib/console-remote/remote.d.ts +25 -22
  118. package/lib/console-remote/remote.js.map +1 -1
  119. package/lib/console-remote/schemas.d.ts +14 -2
  120. package/lib/console-remote/schemas.js +8 -0
  121. package/lib/console-remote/schemas.js.map +1 -1
  122. package/lib/i18n/client-messages.d.ts +1671 -0
  123. package/lib/i18n/client-messages.js +1468 -0
  124. package/lib/i18n/client-messages.js.map +1 -0
  125. package/lib/i18n/core.d.ts +12 -0
  126. package/lib/i18n/core.js +10 -0
  127. package/lib/i18n/core.js.map +1 -0
  128. package/lib/i18n/host-messages.d.ts +1495 -0
  129. package/lib/i18n/host-messages.js +1485 -0
  130. package/lib/i18n/host-messages.js.map +1 -0
  131. package/lib/i18n/host.d.ts +9 -0
  132. package/lib/i18n/host.js +34 -0
  133. package/lib/i18n/host.js.map +1 -0
  134. package/lib/i18n/transport-messages.d.ts +10 -0
  135. package/lib/i18n/transport-messages.js +11 -0
  136. package/lib/i18n/transport-messages.js.map +1 -0
  137. package/lib/ports.d.ts +15 -0
  138. package/lib/session-checkout-apply.js +93 -92
  139. package/lib/session-checkout-apply.js.map +1 -1
  140. package/lib/session-checkout-module.js +234 -229
  141. package/lib/session-checkout-module.js.map +1 -1
  142. package/lib/session-target-context.js +2 -1
  143. package/lib/session-target-context.js.map +1 -1
  144. package/lib/tools.d.ts +0 -8
  145. package/lib/tools.js +108 -96
  146. package/lib/tools.js.map +1 -1
  147. package/package.json +3 -1
  148. package/scripts/check-publish.mjs +1 -1
  149. package/scripts/dev-dsh-lib.mjs +1 -1
  150. package/scripts/workspace-sidebar-upstream.mjs +1 -1
@@ -1,3 +1,5 @@
1
+ import { hostMessages, hostPersistedCleanupMessage } from './i18n/host-messages.js';
2
+ import { hostMessage } from './i18n/host.js';
1
3
  import { createHash } from 'node:crypto';
2
4
  import { realpathSync } from 'node:fs';
3
5
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
@@ -8,8 +10,8 @@ const UNVERSIONED_OID = 'unversioned';
8
10
  const UNVERSIONED_REF = 'WORKING_TREE';
9
11
  const RETENTION_24H_MS = 24 * 60 * 60 * 1000;
10
12
  const RETENTION_3D_MS = 3 * RETENTION_24H_MS;
11
- const CLEANUP_IDENTITY_CHANGED_MESSAGE = 'Worktree 的 Git 身份或路径已变化,未执行清理。';
12
- const CLEANUP_RESIDUE_MESSAGE = 'Git Worktree 已解除注册,仅剩物理目录残余;可重试清理环境。';
13
+ const CLEANUP_IDENTITY_CHANGED_MESSAGE = hostMessages.cleanupIdentityChanged.zh;
14
+ const CLEANUP_RESIDUE_MESSAGE = hostMessages.cleanupResidue.zh;
13
15
  const TRANSIENT_CLEANUP_RETRY_DELAYS_MS = [100, 300, 800];
14
16
  /**
15
17
  * 单个 checkout 清理/维护操作的启动收敛超时。
@@ -24,7 +26,7 @@ async function withCleanupTimeout(checkoutId, operation) {
24
26
  operation(),
25
27
  new Promise((resolve) => {
26
28
  timeoutHandle = setTimeout(() => {
27
- console.warn(`[session-checkout] ${checkoutId.slice(0, 8)} 清理超时(${CHECKOUT_CLEANUP_TIMEOUT_MS}ms),已跳过本次收敛`);
29
+ console.warn(hostMessage('cleanupTimeout', { p0: checkoutId.slice(0, 8), p1: CHECKOUT_CLEANUP_TIMEOUT_MS }));
28
30
  resolve(null);
29
31
  }, CHECKOUT_CLEANUP_TIMEOUT_MS);
30
32
  }),
@@ -103,18 +105,18 @@ export function createSessionCheckoutModule(dependencies) {
103
105
  function requireSession(sessionId) {
104
106
  const session = dependencies.lookup.getSession(sessionId);
105
107
  if (!session)
106
- throw new SessionCheckoutError('session_not_found', `会话不存在: ${sessionId}`);
108
+ throw new SessionCheckoutError('session_not_found', hostMessage('sessionNotFound', { p0: sessionId }));
107
109
  return session;
108
110
  }
109
111
  async function resolveSessionProject(sessionId) {
110
112
  const session = requireSession(sessionId);
111
113
  if (!session.projectId)
112
- throw new SessionCheckoutError('project_not_found', '会话尚未关联项目');
114
+ throw new SessionCheckoutError('project_not_found', hostMessage('theSessionIsNotAssociatedWithAProject'));
113
115
  const project = dependencies.lookup.getProject(session.projectId);
114
116
  if (!project)
115
- throw new SessionCheckoutError('project_not_found', `项目不存在: ${session.projectId}`);
117
+ throw new SessionCheckoutError('project_not_found', hostMessage('projectNotFound', { p0: session.projectId }));
116
118
  if (!dependencies.files.exists(project.root)) {
117
- throw new SessionCheckoutError('project_root_missing', `项目根目录不存在: ${project.name}`);
119
+ throw new SessionCheckoutError('project_root_missing', hostMessage('projectRootDirectoryNotFound', { p0: project.name }));
118
120
  }
119
121
  return { session, project };
120
122
  }
@@ -132,7 +134,7 @@ export function createSessionCheckoutModule(dependencies) {
132
134
  checkout: {
133
135
  id: `local:${binding.projectId}`,
134
136
  kind: 'local',
135
- label: 'Local Checkout',
137
+ label: hostMessage('localCheckout'),
136
138
  phase: 'ready',
137
139
  },
138
140
  source: { ref: binding.sourceRef, oid: binding.sourceOid },
@@ -202,7 +204,7 @@ export function createSessionCheckoutModule(dependencies) {
202
204
  commitOid: delivery.commitOid,
203
205
  ...(projectProof(delivery.proof) ? { proof: projectProof(delivery.proof) } : {}),
204
206
  cleanup: delivery.cleanup,
205
- ...(delivery.cleanupMessage ? { cleanupMessage: delivery.cleanupMessage } : {}),
207
+ ...(delivery.cleanupMessage ? { cleanupMessage: hostPersistedCleanupMessage(delivery.cleanupMessage, hostMessage) } : {}),
206
208
  };
207
209
  }
208
210
  if (delivery.state === 'retained') {
@@ -215,7 +217,7 @@ export function createSessionCheckoutModule(dependencies) {
215
217
  retainedAt: delivery.retainedAt,
216
218
  expiresAt: delivery.expiresAt,
217
219
  cleanup: delivery.cleanup,
218
- ...(delivery.cleanupMessage ? { cleanupMessage: delivery.cleanupMessage } : {}),
220
+ ...(delivery.cleanupMessage ? { cleanupMessage: hostPersistedCleanupMessage(delivery.cleanupMessage, hostMessage) } : {}),
219
221
  };
220
222
  }
221
223
  if (delivery.state === 'delivered') {
@@ -252,7 +254,7 @@ export function createSessionCheckoutModule(dependencies) {
252
254
  checkout: {
253
255
  id: record?.checkoutId ?? (binding.target.kind === 'isolated' ? binding.target.checkoutId : `local:${binding.projectId}`),
254
256
  kind: binding.target.kind === 'isolated' ? 'isolated' : 'local',
255
- label: binding.target.kind === 'isolated' ? 'Isolated Checkout' : 'Local Checkout',
257
+ label: binding.target.kind === 'isolated' ? hostMessage('isolatedCheckout') : hostMessage('localCheckout'),
256
258
  phase,
257
259
  },
258
260
  source: { ref: binding.sourceRef, oid: binding.sourceOid },
@@ -315,7 +317,7 @@ export function createSessionCheckoutModule(dependencies) {
315
317
  checkout: {
316
318
  id: record.checkoutId,
317
319
  kind: 'isolated',
318
- label: 'Isolated Checkout',
320
+ label: hostMessage('isolatedCheckout'),
319
321
  // Commit 已是权威交付事实;残余环境异常只能影响 cleanup,不能降级整个会话。
320
322
  phase: delivery.state === 'retained' ? 'retained' : delivery.state === 'delivered' ? 'discarded' : 'finalized',
321
323
  },
@@ -557,7 +559,7 @@ export function createSessionCheckoutModule(dependencies) {
557
559
  checkout: {
558
560
  id: record.checkoutId,
559
561
  kind: 'isolated',
560
- label: 'Isolated Checkout',
562
+ label: hostMessage('isolatedCheckout'),
561
563
  phase: 'discarded',
562
564
  },
563
565
  };
@@ -624,7 +626,7 @@ export function createSessionCheckoutModule(dependencies) {
624
626
  checkout: {
625
627
  id: record.checkoutId,
626
628
  kind: 'isolated',
627
- label: 'Isolated Checkout',
629
+ label: hostMessage('isolatedCheckout'),
628
630
  phase: record.phase,
629
631
  },
630
632
  source: { ref: record.sourceRef, oid: record.baseOid },
@@ -759,12 +761,12 @@ export function createSessionCheckoutModule(dependencies) {
759
761
  }
760
762
  }
761
763
  if (!isolatedWorkspaceMatches) {
762
- throw new SessionCheckoutError('project_mismatch', '会话当前 Workspace 与已绑定 Session Target 不一致,已停止访问 checkout');
764
+ throw new SessionCheckoutError('project_mismatch', hostMessage('theSessionWorkspaceNoLongerMatchesItsBoundSession'));
763
765
  }
764
766
  }
765
767
  return persisted;
766
768
  }
767
- throw new SessionCheckoutError('target_unselected', '会话尚未选择 Session Target');
769
+ throw new SessionCheckoutError('target_unselected', hostMessage('theSessionHasNotSelectedASessionTarget'));
768
770
  }
769
771
  let bindingQueue = Promise.resolve();
770
772
  let activeBindingOperation = null;
@@ -948,7 +950,7 @@ export function createSessionCheckoutModule(dependencies) {
948
950
  await dependencies.git.releaseInternalArtifacts(current.localRoot, current.checkoutId, `checkpoints/${journal.checkpointId}`);
949
951
  }
950
952
  catch {
951
- console.warn('[session-checkout] 清理未生效 Checkpoint ref 失败,已保守保留不可见引用');
953
+ console.warn(hostMessage('checkpointRefCleanupFailed'));
952
954
  }
953
955
  record = { ...current, phase: 'ready', journal: null, revision: current.revision + 1 };
954
956
  }
@@ -1110,22 +1112,22 @@ export function createSessionCheckoutModule(dependencies) {
1110
1112
  async function markReadyForReviewTarget(sessionId, input) {
1111
1113
  const binding = await resolveBinding(sessionId);
1112
1114
  if (binding.ownerSessionId !== sessionId || binding.target.kind !== 'isolated') {
1113
- throw new SessionCheckoutError('not_owner', '只有 owner Isolated 会话可以准备验收');
1115
+ throw new SessionCheckoutError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanPrepareAReview'));
1114
1116
  }
1115
1117
  const summary = input.summary.trim();
1116
1118
  const suggestedCommitMessage = input.suggestedCommitMessage.trim();
1117
1119
  if (!summary || !suggestedCommitMessage || input.tests.length > 20) {
1118
- throw new SessionCheckoutError('invalid_input', '验收摘要、提交信息或验证项目无效');
1120
+ throw new SessionCheckoutError('invalid_input', hostMessage('theReviewSummaryCommitMessageOrValidationItemsAre'));
1119
1121
  }
1120
1122
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1121
1123
  if (!record)
1122
- throw new SessionCheckoutError('checkout_missing', 'Isolated Checkout 记录不存在');
1124
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1123
1125
  if (record.phase !== 'ready' || record.delivery.state === 'preview_active' || record.delivery.state === 'preview_detached') {
1124
- throw new SessionCheckoutError('operation_not_allowed', `当前 ${record.phase}/${record.delivery.state} 状态不能准备验收`);
1126
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('cannotPrepareAReviewInTheCurrentState', { p0: record.phase, p1: record.delivery.state }));
1125
1127
  }
1126
1128
  const inspected = await inspectIsolated(binding);
1127
1129
  if (inspected.checkout.phase !== 'ready') {
1128
- throw new SessionCheckoutError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复');
1130
+ throw new SessionCheckoutError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'));
1129
1131
  }
1130
1132
  const snapshot = await dependencies.applyEngine.inspectReview({
1131
1133
  baseOid: record.applyBaseOid ?? record.baseOid,
@@ -1175,7 +1177,7 @@ export function createSessionCheckoutModule(dependencies) {
1175
1177
  }
1176
1178
  async function operateCheckpoint(input, binding) {
1177
1179
  if (binding.ownerSessionId !== input.sessionId || binding.target.kind !== 'isolated') {
1178
- return operationError('not_owner', '只有 owner Isolated 会话可以保存阶段');
1180
+ return operationError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanSaveACheckpoint'));
1179
1181
  }
1180
1182
  const commitMessage = input.commitMessage.trim();
1181
1183
  if (!commitMessage
@@ -1185,10 +1187,10 @@ export function createSessionCheckoutModule(dependencies) {
1185
1187
  || !input.requestId.trim()
1186
1188
  || input.requestId.length > 200
1187
1189
  || /[\0\r\n]/u.test(input.requestId))
1188
- return operationError('invalid_input', 'Checkpoint 请求或 Commit Message 无效');
1190
+ return operationError('invalid_input', hostMessage('theCheckpointRequestOrCommitMessageIsInvalid'));
1189
1191
  let record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1190
1192
  if (!record)
1191
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
1193
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1192
1194
  const previousRequest = record.checkpoints?.find(checkpoint => checkpoint.requestId === input.requestId);
1193
1195
  if (previousRequest) {
1194
1196
  const exactReplay = record.delivery.state === 'working'
@@ -1198,7 +1200,7 @@ export function createSessionCheckoutModule(dependencies) {
1198
1200
  && previousRequest.generation === input.expectedGeneration
1199
1201
  && previousRequest.commitMessage === commitMessage;
1200
1202
  if (!exactReplay)
1201
- return operationError('stale_target', 'Checkpoint requestId 已被其他状态使用,请刷新');
1203
+ return operationError('stale_target', hostMessage('theCheckpointRequestIdIsAlreadyUsedByAnotherState'));
1202
1204
  return {
1203
1205
  status: 'checkpointed',
1204
1206
  target: await inspectIsolated(binding),
@@ -1207,21 +1209,21 @@ export function createSessionCheckoutModule(dependencies) {
1207
1209
  };
1208
1210
  }
1209
1211
  if (record.revision !== input.expectedRevision) {
1210
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
1212
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
1211
1213
  }
1212
1214
  if (record.phase !== 'ready' || (record.delivery.state !== 'ready_for_review' && record.delivery.state !== 'preview_active')) {
1213
- return operationError('operation_not_allowed', `当前 ${record.phase}/${record.delivery.state} 状态不能保存阶段`, await inspectIsolated(binding));
1215
+ return operationError('operation_not_allowed', hostMessage('cannotSaveACheckpointInTheCurrentState', { p0: record.phase, p1: record.delivery.state }), await inspectIsolated(binding));
1214
1216
  }
1215
1217
  if (record.delivery.review.reviewId !== input.expectedReviewId || checkpointGenerationForRecord(record) !== input.expectedGeneration) {
1216
- return operationError('stale_target', 'Checkpoint Review 或 generation 已变化,请刷新后重试', await inspectIsolated(binding));
1218
+ return operationError('stale_target', hostMessage('theCheckpointReviewOrGenerationHasChangedRefreshAnd'), await inspectIsolated(binding));
1217
1219
  }
1218
1220
  const holder = findProjectAcceptanceHolder(record);
1219
1221
  if (holder) {
1220
- return operationError('project_acceptance_busy', '另一个任务正在占用该项目的 Local 验收槽位', await inspectIsolated(binding));
1222
+ return operationError('project_acceptance_busy', hostMessage('anotherTaskIsOccupyingThisProjectSLocalAcceptance'), await inspectIsolated(binding));
1221
1223
  }
1222
1224
  const inspected = await inspectIsolated(binding);
1223
1225
  if (inspected.checkout.phase !== 'ready') {
1224
- return operationError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复', inspected);
1226
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'), inspected);
1225
1227
  }
1226
1228
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
1227
1229
  if (!record
@@ -1230,7 +1232,7 @@ export function createSessionCheckoutModule(dependencies) {
1230
1232
  || (record.delivery.state !== 'ready_for_review' && record.delivery.state !== 'preview_active')
1231
1233
  || record.delivery.review.reviewId !== input.expectedReviewId
1232
1234
  || checkpointGenerationForRecord(record) !== input.expectedGeneration)
1233
- return operationError('stale_target', 'Checkpoint 状态在 Host CAS 前发生变化,请刷新后重试');
1235
+ return operationError('stale_target', hostMessage('theCheckpointStateChangedBeforeTheHostCASRefresh'));
1234
1236
  if (record.delivery.state === 'preview_active') {
1235
1237
  const { preview, review } = record.delivery;
1236
1238
  const rollbackOperationId = dependencies.createCheckoutId();
@@ -1283,12 +1285,12 @@ export function createSessionCheckoutModule(dependencies) {
1283
1285
  revision: current.revision + 1,
1284
1286
  }));
1285
1287
  if (!restored)
1286
- return operationError('checkout_missing', 'Preview 已撤回,但 Checkout 记录丢失');
1288
+ return operationError('checkout_missing', hostMessage('previewWasRolledBackButTheCheckoutRecordIs'));
1287
1289
  await releasePreviewArtifactsBestEffort(record, preview.previewId);
1288
1290
  record = restored;
1289
1291
  }
1290
1292
  if (record.delivery.state !== 'ready_for_review') {
1291
- return operationError('operation_not_allowed', '当前没有可保存的验收阶段', await inspectIsolated(binding));
1293
+ return operationError('operation_not_allowed', hostMessage('thereIsNoReviewCheckpointToSave'), await inspectIsolated(binding));
1292
1294
  }
1293
1295
  const review = record.delivery.review;
1294
1296
  const checkpointId = dependencies.createCheckoutId();
@@ -1316,7 +1318,7 @@ export function createSessionCheckoutModule(dependencies) {
1316
1318
  revision: current.revision + 1,
1317
1319
  }));
1318
1320
  if (!mutating)
1319
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
1321
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1320
1322
  const result = await dependencies.applyEngine.checkpoint({
1321
1323
  isolatedPath: mutating.managedRoot,
1322
1324
  expectedFingerprint: review.isolatedFingerprint,
@@ -1338,7 +1340,7 @@ export function createSessionCheckoutModule(dependencies) {
1338
1340
  revision: current.revision + 1,
1339
1341
  }));
1340
1342
  if (!journaled?.journal || journaled.journal.operation !== 'checkpoint' || journaled.journal.commitOid !== prepared.commitOid) {
1341
- throw new SessionCheckoutError('stale_target', 'Checkpoint journal 在保留内部 ref 前发生变化');
1343
+ throw new SessionCheckoutError('stale_target', hostMessage('theCheckpointJournalChangedBeforeRetainingTheInternalRef'));
1342
1344
  }
1343
1345
  await dependencies.git.retainInternalArtifact(mutating.localRoot, mutating.checkoutId, `checkpoints/${checkpointId}`, prepared.commitOid);
1344
1346
  },
@@ -1392,7 +1394,7 @@ export function createSessionCheckoutModule(dependencies) {
1392
1394
  };
1393
1395
  });
1394
1396
  if (!completed)
1395
- return operationError('checkout_missing', 'Checkpoint 已创建,但 Checkout 记录丢失');
1397
+ return operationError('checkout_missing', hostMessage('checkpointWasCreatedButTheCheckoutRecordIsMissing'));
1396
1398
  return {
1397
1399
  status: 'checkpointed',
1398
1400
  target: await inspectIsolated(binding),
@@ -1403,23 +1405,23 @@ export function createSessionCheckoutModule(dependencies) {
1403
1405
  async function resumeRevisionTarget(sessionId, expectedRevision, expectedReviewId, recovery) {
1404
1406
  const binding = await resolveBinding(sessionId);
1405
1407
  if (binding.ownerSessionId !== sessionId || binding.target.kind !== 'isolated') {
1406
- throw new SessionCheckoutError('not_owner', '只有 owner Isolated 会话可以恢复编辑');
1408
+ throw new SessionCheckoutError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanResumeEditing'));
1407
1409
  }
1408
1410
  let record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1409
1411
  if (!record)
1410
- throw new SessionCheckoutError('checkout_missing', 'Isolated Checkout 记录不存在');
1412
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1411
1413
  if (record.revision !== expectedRevision) {
1412
- throw new SessionCheckoutError('stale_target', 'Session Target 已变化,请刷新后重试');
1414
+ throw new SessionCheckoutError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'));
1413
1415
  }
1414
1416
  if (record.phase !== 'ready' || record.delivery.state !== 'ready_for_review') {
1415
- throw new SessionCheckoutError('operation_not_allowed', '当前 Worktree 没有可恢复编辑的未同步验收稿');
1417
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('theCurrentWorktreeHasNoUnsyncedReviewToResume'));
1416
1418
  }
1417
1419
  if (record.delivery.review.reviewId !== expectedReviewId) {
1418
- throw new SessionCheckoutError('stale_target', '该验收卡已不是当前 Review,请刷新后重试');
1420
+ throw new SessionCheckoutError('stale_target', hostMessage('thisReviewCardIsNoLongerTheCurrentReview'));
1419
1421
  }
1420
1422
  const inspected = await inspectIsolated(binding);
1421
1423
  if (inspected.checkout.phase !== 'ready') {
1422
- throw new SessionCheckoutError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复');
1424
+ throw new SessionCheckoutError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'));
1423
1425
  }
1424
1426
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
1425
1427
  if (!record
@@ -1427,7 +1429,7 @@ export function createSessionCheckoutModule(dependencies) {
1427
1429
  || record.phase !== 'ready'
1428
1430
  || record.delivery.state !== 'ready_for_review'
1429
1431
  || record.delivery.review.reviewId !== expectedReviewId) {
1430
- throw new SessionCheckoutError('stale_target', '验收状态在恢复编辑前发生变化,请刷新后重试');
1432
+ throw new SessionCheckoutError('stale_target', hostMessage('theAcceptanceStateChangedBeforeResumingEditingRefreshAnd'));
1431
1433
  }
1432
1434
  if (recovery) {
1433
1435
  const preflight = await preflightTarget(sessionId, expectedRevision);
@@ -1440,13 +1442,13 @@ export function createSessionCheckoutModule(dependencies) {
1440
1442
  || preflight.status !== 'conflict'
1441
1443
  || preflight.localHeadOid !== recovery.localHeadOid
1442
1444
  || !sameFiles)
1443
- throw new SessionCheckoutError('stale_target', '冲突恢复身份在 Host CAS 前已变化,请重新预检');
1445
+ throw new SessionCheckoutError('stale_target', hostMessage('theConflictRecoveryIdentityChangedBeforeHostCASRun'));
1444
1446
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
1445
1447
  if (!record
1446
1448
  || record.revision !== expectedRevision
1447
1449
  || record.delivery.state !== 'ready_for_review'
1448
1450
  || record.delivery.review.reviewId !== expectedReviewId)
1449
- throw new SessionCheckoutError('stale_target', '验收状态在冲突恢复前发生变化,请刷新后重试');
1451
+ throw new SessionCheckoutError('stale_target', hostMessage('theAcceptanceStateChangedBeforeConflictRecoveryRefreshAnd'));
1450
1452
  }
1451
1453
  const reviewBeforeResume = record.delivery.review;
1452
1454
  const iteration = reviewBeforeResume.iteration;
@@ -1467,7 +1469,7 @@ export function createSessionCheckoutModule(dependencies) {
1467
1469
  async function prepareReviewRegenerationTarget(sessionId, expectedRevision, expectedReviewId, requestId) {
1468
1470
  const binding = await resolveBinding(sessionId);
1469
1471
  if (binding.ownerSessionId !== sessionId || binding.target.kind !== 'isolated') {
1470
- throw new SessionCheckoutError('not_owner', '只有 owner Isolated 会话可以请求重新生成验收结果');
1472
+ throw new SessionCheckoutError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanRequestReviewRegeneration'));
1471
1473
  }
1472
1474
  const preflight = await preflightTarget(sessionId, expectedRevision);
1473
1475
  if (preflight.status !== 'blocked'
@@ -1475,7 +1477,7 @@ export function createSessionCheckoutModule(dependencies) {
1475
1477
  || preflight.checkoutId !== binding.target.checkoutId
1476
1478
  || preflight.reviewId !== expectedReviewId
1477
1479
  || preflight.revision !== expectedRevision)
1478
- throw new SessionCheckoutError('stale_target', '只读验收再生成身份在 Host 授权前已变化');
1480
+ throw new SessionCheckoutError('stale_target', hostMessage('theReadOnlyReviewRegenerationIdentityChangedBeforeHost'));
1479
1481
  const continuation = {
1480
1482
  kind: 'worktree_review_regeneration', requestId, reviewId: expectedReviewId, revision: expectedRevision,
1481
1483
  };
@@ -1483,17 +1485,17 @@ export function createSessionCheckoutModule(dependencies) {
1483
1485
  if (current.revision !== expectedRevision
1484
1486
  || current.delivery.state !== 'ready_for_review'
1485
1487
  || current.delivery.review.reviewId !== expectedReviewId)
1486
- throw new SessionCheckoutError('stale_target', 'Ready Review 在只读授权前发生变化');
1488
+ throw new SessionCheckoutError('stale_target', hostMessage('theReadyReviewChangedBeforeReadOnlyAuthorization'));
1487
1489
  return { ...current, recoveryContinuation: continuation };
1488
1490
  });
1489
1491
  if (!updated)
1490
- throw new SessionCheckoutError('checkout_missing', 'Isolated Checkout 记录不存在');
1492
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1491
1493
  return continuation;
1492
1494
  }
1493
1495
  async function preparePreviewRecoveryAnalysisTarget(sessionId, proof, requestId) {
1494
1496
  const recovery = await preflightPreviewRecoveryTarget(sessionId, proof.revision, proof.reviewId, proof.previewId);
1495
1497
  if (recovery.status !== 'assessed' || !recoveryProofMatches(proof, recovery.proof)) {
1496
- throw new SessionCheckoutError('stale_target', 'Detached Preview Recovery proof 已变化,请重新检查');
1498
+ throw new SessionCheckoutError('stale_target', hostMessage('theDetachedPreviewRecoveryProofHasChangedCheckAgain'));
1497
1499
  }
1498
1500
  const continuation = {
1499
1501
  kind: 'worktree_preview_recovery_analysis',
@@ -1509,31 +1511,31 @@ export function createSessionCheckoutModule(dependencies) {
1509
1511
  || current.delivery.state !== 'preview_detached'
1510
1512
  || current.delivery.review.reviewId !== proof.reviewId
1511
1513
  || current.delivery.preview.previewId !== proof.previewId)
1512
- throw new SessionCheckoutError('stale_target', 'Detached Preview 在分析授权前发生变化');
1514
+ throw new SessionCheckoutError('stale_target', hostMessage('theDetachedPreviewChangedBeforeAnalysisAuthorization'));
1513
1515
  return { ...current, recoveryContinuation: continuation };
1514
1516
  });
1515
1517
  if (!updated)
1516
- throw new SessionCheckoutError('checkout_missing', 'Isolated Checkout 记录不存在');
1518
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1517
1519
  return continuation;
1518
1520
  }
1519
1521
  async function createPreviewRecoveryHandoffTarget(sessionId, proof, targetSessionId, requestId) {
1520
1522
  if (!targetSessionId || targetSessionId === sessionId) {
1521
- throw new SessionCheckoutError('invalid_input', 'Recovery handoff 必须使用新的预分配 Session ID');
1523
+ throw new SessionCheckoutError('invalid_input', hostMessage('recoveryHandoffRequiresANewPreallocatedSessionID'));
1522
1524
  }
1523
1525
  if (dependencies.lookup.getSession(targetSessionId) || getPersistedBinding(targetSessionId)) {
1524
- throw new SessionCheckoutError('target_already_bound', 'Recovery handoff Session ID 已被占用');
1526
+ throw new SessionCheckoutError('target_already_bound', hostMessage('theRecoveryHandoffSessionIDIsAlreadyInUse'));
1525
1527
  }
1526
1528
  const recovery = await preflightPreviewRecoveryTarget(sessionId, proof.revision, proof.reviewId, proof.previewId);
1527
1529
  if (recovery.status !== 'assessed' || !recoveryProofMatches(proof, recovery.proof)) {
1528
- throw new SessionCheckoutError('stale_target', 'Detached Preview Recovery proof 已变化,请重新检查');
1530
+ throw new SessionCheckoutError('stale_target', hostMessage('theDetachedPreviewRecoveryProofHasChangedCheckAgain'));
1529
1531
  }
1530
1532
  const source = dependencies.registry.read().managedCheckouts[proof.checkoutId];
1531
1533
  if (!source || source.ownerSessionId !== sessionId || source.delivery.state !== 'preview_detached') {
1532
- throw new SessionCheckoutError('stale_target', '旧 Detached Preview 身份已变化');
1534
+ throw new SessionCheckoutError('stale_target', hostMessage('thePreviousDetachedPreviewIdentityHasChanged'));
1533
1535
  }
1534
1536
  const originSessionId = source.sourceSessionId ?? source.ownerSessionId;
1535
1537
  if (!dependencies.lookup.getSession(originSessionId)) {
1536
- throw new SessionCheckoutError('session_not_found', '原始 source Session 不可用,未创建 handoff Worktree');
1538
+ throw new SessionCheckoutError('session_not_found', hostMessage('theOriginalSourceSessionIsUnavailableNoHandoffWorktree'));
1537
1539
  }
1538
1540
  const target = await bindTarget(targetSessionId, { kind: 'isolated' }, 0, Date.now(), originSessionId);
1539
1541
  const binding = getPersistedBinding(targetSessionId);
@@ -1541,7 +1543,7 @@ export function createSessionCheckoutModule(dependencies) {
1541
1543
  ? dependencies.registry.read().managedCheckouts[binding.target.checkoutId]
1542
1544
  : undefined;
1543
1545
  if (!created)
1544
- throw new SessionCheckoutError('checkout_missing', 'Recovery handoff Worktree 创建后记录缺失');
1546
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theRecoveryHandoffWorktreeRecordIsMissingAfterCreation'));
1545
1547
  const continuation = {
1546
1548
  kind: 'worktree_preview_recovery_handoff',
1547
1549
  requestId,
@@ -1556,31 +1558,31 @@ export function createSessionCheckoutModule(dependencies) {
1556
1558
  }
1557
1559
  async function operateApply(input, binding) {
1558
1560
  if (binding.ownerSessionId !== input.sessionId) {
1559
- return operationError('not_owner', '继承 Session Target 的会话不能执行 Apply');
1561
+ return operationError('not_owner', hostMessage('aSessionThatInheritedItsSessionTargetCannotPerform'));
1560
1562
  }
1561
1563
  if (binding.target.kind !== 'isolated') {
1562
- return operationError('operation_not_allowed', 'Local Checkout 不支持 Apply');
1564
+ return operationError('operation_not_allowed', hostMessage('localCheckoutDoesNotSupportApply'));
1563
1565
  }
1564
1566
  let record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1565
1567
  if (!record)
1566
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
1568
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1567
1569
  if (record.revision !== input.expectedRevision) {
1568
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
1570
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
1569
1571
  }
1570
1572
  if (record.phase !== 'ready') {
1571
- return operationError('operation_not_allowed', `当前 ${record.phase}/${record.delivery.state} 状态不能 Apply`, await inspectIsolated(binding));
1573
+ return operationError('operation_not_allowed', hostMessage('cannotApplyInTheCurrentState', { p0: record.phase, p1: record.delivery.state }), await inspectIsolated(binding));
1572
1574
  }
1573
1575
  const holder = findProjectAcceptanceHolder(record);
1574
1576
  if (holder) {
1575
- return operationError('project_acceptance_busy', `同一项目已有验收任务正在占用 Local:${holder.projectName}`, await inspectIsolated(binding));
1577
+ return operationError('project_acceptance_busy', hostMessage('anotherAcceptanceTaskInTheSameProjectIsOccupying', { p0: holder.projectName }), await inspectIsolated(binding));
1576
1578
  }
1577
1579
  const inspected = await inspectIsolated(binding);
1578
1580
  if (inspected.checkout.phase !== 'ready') {
1579
- return operationError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复', inspected);
1581
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'), inspected);
1580
1582
  }
1581
1583
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
1582
1584
  if (!record || record.phase !== 'ready') {
1583
- return operationError('recovery_required', 'Isolated Checkout 状态已变化,需要恢复');
1585
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutStateHasChangedRecoveryIsRequired'));
1584
1586
  }
1585
1587
  const startedAt = Date.now();
1586
1588
  const operationId = dependencies.createCheckoutId();
@@ -1592,7 +1594,7 @@ export function createSessionCheckoutModule(dependencies) {
1592
1594
  revision: current.revision + 1,
1593
1595
  }));
1594
1596
  if (!applying)
1595
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
1597
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1596
1598
  const planResult = await dependencies.applyEngine.plan({
1597
1599
  baseOid: applyBaseOid,
1598
1600
  isolatedPath: applying.managedRoot,
@@ -1626,7 +1628,7 @@ export function createSessionCheckoutModule(dependencies) {
1626
1628
  journal: null,
1627
1629
  revision: current.revision + 1,
1628
1630
  }));
1629
- return operationError('stale_isolated', 'Worktree 在标记可验收后又发生变化,请重新准备验收', await inspectIsolated(binding));
1631
+ return operationError('stale_isolated', hostMessage('worktreeChangedAfterBeingMarkedReadyForReviewPrepare'), await inspectIsolated(binding));
1630
1632
  }
1631
1633
  if (planResult.plan.changedFiles.length === 0) {
1632
1634
  updateManagedCheckout(applying.checkoutId, (current) => ({ ...current, phase: 'ready', journal: null, revision: current.revision + 1 }));
@@ -1643,11 +1645,11 @@ export function createSessionCheckoutModule(dependencies) {
1643
1645
  reviewId: operationId,
1644
1646
  iteration,
1645
1647
  preparedAt: startedAt,
1646
- summary: 'Worktree 修改已通过 ApplyWorktree 写入 Local Preview',
1648
+ summary: hostMessage('worktreeChangesWereWrittenToLocalPreviewThroughApplyWorktree'),
1647
1649
  validationStatus: 'not_run',
1648
1650
  tests: [],
1649
1651
  changedFiles: [...planResult.plan.changedFiles],
1650
- suggestedCommitMessage: 'chore: 提交 Worktree 修改',
1652
+ suggestedCommitMessage: hostMessage('choreCommitWorktreeChanges'),
1651
1653
  isolatedFingerprint: planResult.plan.isolatedFingerprint,
1652
1654
  isolatedHeadOid: planResult.plan.isolatedHeadOid,
1653
1655
  };
@@ -1715,7 +1717,7 @@ export function createSessionCheckoutModule(dependencies) {
1715
1717
  await dependencies.git.releaseInternalArtifacts(record.localRoot, record.checkoutId, `previews/${previewId}`);
1716
1718
  }
1717
1719
  catch {
1718
- console.warn('[session-checkout] 清理 Preview refs 失败,已保守保留不可见引用');
1720
+ console.warn(hostMessage('previewRefsCleanupFailed'));
1719
1721
  }
1720
1722
  }
1721
1723
  async function previewArtifactsMatch(record, receipt) {
@@ -1766,28 +1768,28 @@ export function createSessionCheckoutModule(dependencies) {
1766
1768
  async function preflightPreviewRecoveryTarget(sessionId, expectedRevision, expectedReviewId, expectedPreviewId) {
1767
1769
  const binding = await resolveBinding(sessionId);
1768
1770
  if (binding.ownerSessionId !== sessionId || binding.target.kind !== 'isolated') {
1769
- return blockedPreviewRecovery(undefined, 'not_owner', '只有 owner Isolated 会话可以检查 Preview 恢复');
1771
+ return blockedPreviewRecovery(undefined, 'not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanCheckPreviewRecovery'));
1770
1772
  }
1771
1773
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1772
1774
  if (!record)
1773
- return blockedPreviewRecovery(undefined, 'checkout_unavailable', 'Isolated Checkout 记录不存在');
1775
+ return blockedPreviewRecovery(undefined, 'checkout_unavailable', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1774
1776
  if (record.revision !== expectedRevision) {
1775
- return blockedPreviewRecovery(record, 'stale_target', 'Session Target 已变化,请刷新后重新检查');
1777
+ return blockedPreviewRecovery(record, 'stale_target', hostMessage('theSessionTargetHasChangedRefreshBeforeCheckingAgain'));
1776
1778
  }
1777
1779
  if (record.phase !== 'ready'
1778
1780
  || record.delivery.state !== 'preview_detached'
1779
1781
  || record.delivery.review.reviewId !== expectedReviewId
1780
1782
  || record.delivery.preview.previewId !== expectedPreviewId) {
1781
- return blockedPreviewRecovery(record, 'not_preview_detached', '当前并非指定的 detached Preview 恢复状态');
1783
+ return blockedPreviewRecovery(record, 'not_preview_detached', hostMessage('theCurrentStateIsNotTheSpecifiedDetachedPreview'));
1782
1784
  }
1783
1785
  const validated = await validateManagedCheckoutDetailed(binding, record, false);
1784
1786
  if (validated.status !== 'valid') {
1785
- return blockedPreviewRecovery(record, 'checkout_unavailable', 'Worktree 身份、路径或 Git 状态暂时无法确认');
1787
+ return blockedPreviewRecovery(record, 'checkout_unavailable', hostMessage('theWorktreeIdentityPathOrGitStateCannotCurrently'));
1786
1788
  }
1787
1789
  const { review, preview } = record.delivery;
1788
1790
  try {
1789
1791
  if (!await previewArtifactsMatch(record, preview)) {
1790
- return blockedPreviewRecovery(record, 'artifacts_missing', 'Preview retained artifacts 缺失或与 receipt 不一致');
1792
+ return blockedPreviewRecovery(record, 'artifacts_missing', hostMessage('previewRetainedArtifactsAreMissingOrDoNotMatch'));
1791
1793
  }
1792
1794
  const assessment = await dependencies.applyEngine.assessPreviewRecovery({
1793
1795
  localPath: record.localRoot,
@@ -1801,10 +1803,10 @@ export function createSessionCheckoutModule(dependencies) {
1801
1803
  ? { checkoutId: holder.checkoutId, ownerSessionId: holder.ownerSessionId, revision: holder.revision, state: holder.delivery.state }
1802
1804
  : undefined;
1803
1805
  const rollback = holder
1804
- ? { status: 'blocked', code: 'project_acceptance_busy', message: '另一个任务正在占用该项目的 Local 验收槽位' }
1806
+ ? { status: 'blocked', code: 'project_acceptance_busy', message: hostMessage('anotherTaskIsOccupyingThisProjectSLocalAcceptance') }
1805
1807
  : assessment.rollback;
1806
1808
  const finalize = holder
1807
- ? { status: 'blocked', code: 'project_acceptance_busy', message: '另一个任务正在占用该项目的 Local 验收槽位' }
1809
+ ? { status: 'blocked', code: 'project_acceptance_busy', message: hostMessage('anotherTaskIsOccupyingThisProjectSLocalAcceptance') }
1808
1810
  : assessment.finalize;
1809
1811
  const facts = {
1810
1812
  sessionId,
@@ -1830,16 +1832,16 @@ export function createSessionCheckoutModule(dependencies) {
1830
1832
  || current.delivery.state !== 'preview_detached'
1831
1833
  || current.delivery.review.reviewId !== review.reviewId
1832
1834
  || current.delivery.preview.previewId !== preview.previewId) {
1833
- return blockedPreviewRecovery(current, 'stale_target', 'Preview 恢复状态在检查期间发生变化');
1835
+ return blockedPreviewRecovery(current, 'stale_target', hostMessage('thePreviewRecoveryStateChangedDuringTheCheck'));
1834
1836
  }
1835
1837
  if (!await previewArtifactsMatch(current, current.delivery.preview)) {
1836
- return blockedPreviewRecovery(current, 'artifacts_missing', 'Preview retained artifacts 在检查期间发生变化');
1838
+ return blockedPreviewRecovery(current, 'artifacts_missing', hostMessage('previewRetainedArtifactsChangedDuringTheCheck'));
1837
1839
  }
1838
1840
  const proof = { ...facts, generation: recoveryGeneration(facts) };
1839
1841
  return { status: 'assessed', localModified: false, proof };
1840
1842
  }
1841
1843
  catch (error) {
1842
- const message = error instanceof Error ? error.message : 'Preview 恢复检查失败';
1844
+ const message = error instanceof Error ? error.message : hostMessage('previewRecoveryCheckFailed');
1843
1845
  return blockedPreviewRecovery(record, 'git_error', message);
1844
1846
  }
1845
1847
  }
@@ -1871,24 +1873,24 @@ export function createSessionCheckoutModule(dependencies) {
1871
1873
  async function preflightTarget(sessionId, expectedRevision) {
1872
1874
  const binding = await resolveBinding(sessionId);
1873
1875
  if (binding.ownerSessionId !== sessionId || binding.target.kind !== 'isolated') {
1874
- return blockedPreflight(undefined, 'not_owner', '只有 owner Isolated 会话可以执行同步预检');
1876
+ return blockedPreflight(undefined, 'not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanRunSyncPreflight'));
1875
1877
  }
1876
1878
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1877
1879
  if (!record)
1878
- return blockedPreflight(undefined, 'checkout_unavailable', 'Isolated Checkout 记录不存在');
1880
+ return blockedPreflight(undefined, 'checkout_unavailable', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1879
1881
  if (record.revision !== expectedRevision) {
1880
- return blockedPreflight(record, 'stale_target', 'Session Target 已变化,请刷新后重新预检');
1882
+ return blockedPreflight(record, 'stale_target', hostMessage('theSessionTargetHasChangedRefreshBeforeRunningPreflight'));
1881
1883
  }
1882
1884
  if (record.phase !== 'ready' || record.delivery.state !== 'ready_for_review') {
1883
- return blockedPreflight(record, 'not_ready_for_review', '当前 Worktree 尚未处于可验收状态');
1885
+ return blockedPreflight(record, 'not_ready_for_review', hostMessage('theCurrentWorktreeIsNotReadyForReview'));
1884
1886
  }
1885
1887
  const holder = findProjectAcceptanceHolder(record);
1886
1888
  if (holder) {
1887
- return blockedPreflight(record, 'project_acceptance_busy', '另一个任务正在占用该项目的 Local 验收槽位', holder);
1889
+ return blockedPreflight(record, 'project_acceptance_busy', hostMessage('anotherTaskIsOccupyingThisProjectSLocalAcceptance'), holder);
1888
1890
  }
1889
1891
  const validated = await validateManagedCheckoutDetailed(binding, record, false);
1890
1892
  if (validated.status !== 'valid') {
1891
- return blockedPreflight(record, 'checkout_unavailable', 'Worktree 身份、路径或 Git 状态暂时无法确认');
1893
+ return blockedPreflight(record, 'checkout_unavailable', hostMessage('theWorktreeIdentityPathOrGitStateCannotCurrently'));
1892
1894
  }
1893
1895
  const review = record.delivery.review;
1894
1896
  const result = await dependencies.applyEngine.preflight({
@@ -1901,7 +1903,7 @@ export function createSessionCheckoutModule(dependencies) {
1901
1903
  || current.revision !== expectedRevision
1902
1904
  || current.delivery.state !== 'ready_for_review'
1903
1905
  || current.delivery.review.reviewId !== review.reviewId)
1904
- return blockedPreflight(current, 'stale_target', 'Session Target 在预检期间发生变化,请刷新后重试');
1906
+ return blockedPreflight(current, 'stale_target', hostMessage('theSessionTargetChangedDuringPreflightRefreshAndRetry'));
1905
1907
  if (result.status === 'error') {
1906
1908
  const reason = result.error.code === 'stale_isolated'
1907
1909
  ? 'stale_isolated'
@@ -1914,7 +1916,7 @@ export function createSessionCheckoutModule(dependencies) {
1914
1916
  ? result.plan.isolatedFingerprint
1915
1917
  : result.isolatedFingerprint;
1916
1918
  if (isolatedFingerprint !== review.isolatedFingerprint) {
1917
- return blockedPreflight(current, 'stale_isolated', 'Worktree 在准备验收后发生变化,请重新生成验收结果');
1919
+ return blockedPreflight(current, 'stale_isolated', hostMessage('worktreeChangedAfterTheReviewWasPreparedRegenerateThe'));
1918
1920
  }
1919
1921
  const localBranch = result.status === 'ready' && result.plan.localHeadRef?.startsWith('refs/heads/')
1920
1922
  ? result.plan.localHeadRef.slice('refs/heads/'.length)
@@ -1944,28 +1946,28 @@ export function createSessionCheckoutModule(dependencies) {
1944
1946
  }
1945
1947
  async function operatePreview(input, binding) {
1946
1948
  if (binding.ownerSessionId !== input.sessionId || binding.target.kind !== 'isolated') {
1947
- return operationError('not_owner', '只有 owner Isolated 会话可以同步验收');
1949
+ return operationError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanSyncAReview'));
1948
1950
  }
1949
1951
  let record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
1950
1952
  if (!record)
1951
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
1953
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1952
1954
  if (record.revision !== input.expectedRevision) {
1953
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
1955
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
1954
1956
  }
1955
1957
  if (record.phase !== 'ready' || record.delivery.state !== 'ready_for_review') {
1956
- return operationError('operation_not_allowed', '当前 Worktree 尚未处于可验收状态', await inspectIsolated(binding));
1958
+ return operationError('operation_not_allowed', hostMessage('theCurrentWorktreeIsNotReadyForReview'), await inspectIsolated(binding));
1957
1959
  }
1958
1960
  const holder = findProjectAcceptanceHolder(record);
1959
1961
  if (holder) {
1960
- return operationError('project_acceptance_busy', `同一项目已有验收任务正在占用 Local:${holder.projectName}`, await inspectIsolated(binding));
1962
+ return operationError('project_acceptance_busy', hostMessage('anotherAcceptanceTaskInTheSameProjectIsOccupying', { p0: holder.projectName }), await inspectIsolated(binding));
1961
1963
  }
1962
1964
  const inspected = await inspectIsolated(binding);
1963
1965
  if (inspected.checkout.phase !== 'ready') {
1964
- return operationError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复', inspected);
1966
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'), inspected);
1965
1967
  }
1966
1968
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
1967
1969
  if (!record || record.delivery.state !== 'ready_for_review') {
1968
- return operationError('stale_target', '验收状态已变化,请刷新后重试');
1970
+ return operationError('stale_target', hostMessage('theAcceptanceStateHasChangedRefreshAndRetry'));
1969
1971
  }
1970
1972
  const review = record.delivery.review;
1971
1973
  const operationId = dependencies.createCheckoutId();
@@ -1987,7 +1989,7 @@ export function createSessionCheckoutModule(dependencies) {
1987
1989
  revision: current.revision + 1,
1988
1990
  }));
1989
1991
  if (!mutating)
1990
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
1992
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
1991
1993
  const planResult = await dependencies.applyEngine.plan({
1992
1994
  baseOid: applyBaseOid,
1993
1995
  isolatedPath: mutating.managedRoot,
@@ -2020,7 +2022,7 @@ export function createSessionCheckoutModule(dependencies) {
2020
2022
  journal: null,
2021
2023
  revision: current.revision + 1,
2022
2024
  }));
2023
- return operationError('stale_isolated', 'Worktree 在标记可验收后又发生变化,请重新准备验收', await inspectIsolated(binding));
2025
+ return operationError('stale_isolated', hostMessage('worktreeChangedAfterBeingMarkedReadyForReviewPrepare'), await inspectIsolated(binding));
2024
2026
  }
2025
2027
  updateManagedCheckout(mutating.checkoutId, (current) => ({
2026
2028
  ...current,
@@ -2085,7 +2087,7 @@ export function createSessionCheckoutModule(dependencies) {
2085
2087
  }
2086
2088
  async function detachPreviewAfterLocalDrift(record, binding, reason, attemptedAction) {
2087
2089
  if (record.delivery.state !== 'preview_active') {
2088
- return operationError('preview_not_active', '当前没有可解除的 Local Preview', await inspectIsolated(binding));
2090
+ return operationError('preview_not_active', hostMessage('thereIsNoLocalPreviewToRelease'), await inspectIsolated(binding));
2089
2091
  }
2090
2092
  const { review, preview } = record.delivery;
2091
2093
  const detached = updateManagedCheckout(record.checkoutId, (current) => {
@@ -2107,7 +2109,7 @@ export function createSessionCheckoutModule(dependencies) {
2107
2109
  };
2108
2110
  });
2109
2111
  if (!detached || detached.delivery.state !== 'preview_detached') {
2110
- return operationError('stale_target', 'Preview 状态已变化,请刷新后重试', await inspectIsolated(binding));
2112
+ return operationError('stale_target', hostMessage('thePreviewStateHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2111
2113
  }
2112
2114
  return {
2113
2115
  status: 'preview_detached',
@@ -2119,20 +2121,20 @@ export function createSessionCheckoutModule(dependencies) {
2119
2121
  }
2120
2122
  async function operateRollbackPreview(input, binding) {
2121
2123
  if (binding.ownerSessionId !== input.sessionId || binding.target.kind !== 'isolated') {
2122
- return operationError('not_owner', '只有 owner Isolated 会话可以撤回验收');
2124
+ return operationError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanRollBackAcceptance'));
2123
2125
  }
2124
2126
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
2125
2127
  if (!record)
2126
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2128
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2127
2129
  if (record.revision !== input.expectedRevision) {
2128
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
2130
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2129
2131
  }
2130
2132
  const retryingRecovery = record.phase === 'recovery_required'
2131
2133
  && record.delivery.state === 'preview_active'
2132
2134
  && record.journal?.operation === 'rollback_preview';
2133
2135
  if ((record.phase !== 'ready' && !retryingRecovery)
2134
2136
  || (record.delivery.state !== 'preview_active' && record.delivery.state !== 'preview_detached')) {
2135
- return operationError('preview_not_active', '当前没有可撤回的 Local Preview', await inspectIsolated(binding));
2137
+ return operationError('preview_not_active', hostMessage('thereIsNoLocalPreviewToRollBack'), await inspectIsolated(binding));
2136
2138
  }
2137
2139
  const retryingDetached = record.delivery.state === 'preview_detached';
2138
2140
  if (retryingDetached) {
@@ -2141,7 +2143,7 @@ export function createSessionCheckoutModule(dependencies) {
2141
2143
  return operationError('stale_target', recovery.message, await inspectIsolated(binding));
2142
2144
  }
2143
2145
  if (!recoveryProofMatches(input.recoveryProof, recovery.proof)) {
2144
- return operationError('stale_target', 'Preview Recovery proof 已过期或不匹配,请重新检查', await inspectIsolated(binding));
2146
+ return operationError('stale_target', hostMessage('thePreviewRecoveryProofHasExpiredOrDoesNot'), await inspectIsolated(binding));
2145
2147
  }
2146
2148
  if (recovery.proof.rollback.status !== 'safe') {
2147
2149
  return operationError(recovery.proof.rollback.code, recovery.proof.rollback.message, await inspectIsolated(binding));
@@ -2262,10 +2264,10 @@ export function createSessionCheckoutModule(dependencies) {
2262
2264
  }
2263
2265
  return current;
2264
2266
  });
2265
- return { cleaned: false, message, reason };
2267
+ return { cleaned: false, message: hostPersistedCleanupMessage(message, hostMessage), reason };
2266
2268
  };
2267
2269
  if (record.delivery.state !== 'finalized' && record.delivery.state !== 'retained') {
2268
- return block('Worktree 交付状态不完整,未执行清理。');
2270
+ return block(hostMessages.cleanupIncompleteDelivery.zh);
2269
2271
  }
2270
2272
  if ((record.delivery.state === 'finalized' || record.delivery.state === 'retained')
2271
2273
  && record.delivery.cleanup === 'blocked'
@@ -2305,7 +2307,7 @@ export function createSessionCheckoutModule(dependencies) {
2305
2307
  const quarantineAndRemove = async (currentRecord, residue) => {
2306
2308
  const journal = currentRecord.journal?.operation === 'cleanup' ? currentRecord.journal : undefined;
2307
2309
  if (!journal?.managedDirectoryIdentity)
2308
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree cleanup receipt 不完整');
2310
+ throw new SessionCheckoutError('checkout_mismatch', hostMessages.cleanupIncompleteReceipt.zh);
2309
2311
  const quarantinePath = journal.cleanupQuarantinePath ?? join(dirname(currentRecord.managedGitRoot), `.dsh-wt-cleanup--${currentRecord.checkoutId.replace(/[^a-zA-Z0-9]/g, '').slice(0, 8)}--${journal.operationId}`);
2310
2312
  const quarantining = journal.cleanupQuarantinePath
2311
2313
  ? currentRecord
@@ -2317,13 +2319,13 @@ export function createSessionCheckoutModule(dependencies) {
2317
2319
  revision: current.revision + 1,
2318
2320
  }));
2319
2321
  if (!quarantining)
2320
- throw new SessionCheckoutError('checkout_missing', 'Worktree 记录在 quarantine 前丢失');
2322
+ throw new SessionCheckoutError('checkout_missing', hostMessages.cleanupMissingBeforeQuarantine.zh);
2321
2323
  if (!dependencies.files.exists(quarantinePath)) {
2322
2324
  await retryTransientCleanup(() => dependencies.files.quarantineDirectoryTree(residue.canonicalManagedGitRoot, residue.directoryIdentity, quarantinePath));
2323
2325
  }
2324
2326
  const validatedQuarantine = await validateCleanupQuarantine(quarantining);
2325
2327
  if (!validatedQuarantine)
2326
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree quarantine 身份无法验证');
2328
+ throw new SessionCheckoutError('checkout_mismatch', hostMessages.cleanupQuarantineIdentity.zh);
2327
2329
  await retryTransientCleanup(() => dependencies.files.removeDirectoryTree(validatedQuarantine));
2328
2330
  };
2329
2331
  try {
@@ -2345,14 +2347,14 @@ export function createSessionCheckoutModule(dependencies) {
2345
2347
  localPath: record.localRoot,
2346
2348
  });
2347
2349
  if (snapshot.status !== 'ready' || snapshot.isolatedFingerprint !== record.delivery.isolatedFingerprint) {
2348
- return block('Worktree 在提交后出现了新修改,未执行清理。');
2350
+ return block(hostMessages.cleanupNewChanges.zh);
2349
2351
  }
2350
2352
  const directoryIdentity = await dependencies.files.inspectDirectoryIdentity(validated.canonicalManagedGitRoot);
2351
2353
  if (!directoryIdentity)
2352
2354
  return block(CLEANUP_IDENTITY_CHANGED_MESSAGE);
2353
2355
  const removing = beginRemoval(record, directoryIdentity);
2354
2356
  if (!removing)
2355
- return block('Worktree 记录在清理前丢失,未执行清理。');
2357
+ return block(hostMessages.cleanupMissingBeforeRemoval.zh);
2356
2358
  await retryTransientCleanup(() => dependencies.git.removeWorktree(removing.localRoot, removing.managedGitRoot));
2357
2359
  if (dependencies.files.exists(removing.managedGitRoot)) {
2358
2360
  const residue = await validateDetachedCleanupResidue(removing);
@@ -2367,7 +2369,7 @@ export function createSessionCheckoutModule(dependencies) {
2367
2369
  return block(CLEANUP_IDENTITY_CHANGED_MESSAGE);
2368
2370
  const removing = beginRemoval(record, residue.directoryIdentity);
2369
2371
  if (!removing)
2370
- return block('Worktree 记录在清理前丢失,未执行清理。');
2372
+ return block(hostMessages.cleanupMissingBeforeRemoval.zh);
2371
2373
  const revalidatedResidue = await validateDetachedCleanupResidue(removing);
2372
2374
  if (!revalidatedResidue)
2373
2375
  return block(CLEANUP_IDENTITY_CHANGED_MESSAGE);
@@ -2400,8 +2402,8 @@ export function createSessionCheckoutModule(dependencies) {
2400
2402
  const quarantineBusy = failureRecord.journal?.operation === 'cleanup' && Boolean(failureRecord.journal.cleanupQuarantinePath);
2401
2403
  const reason = quarantineBusy ? 'quarantine_busy' : 'directory_busy';
2402
2404
  const message = quarantineBusy
2403
- ? 'Worktree 已安全移入 quarantine,但目录仍被进程占用;dsh-git-worktree 会在同一清理授权内有限重试。'
2404
- : 'Worktree 目录仍被进程占用或 Windows 暂时拒绝删除;dsh-git-worktree 已完成有限重试,可稍后重试清理。';
2405
+ ? hostMessages.cleanupQuarantineBusy.zh
2406
+ : hostMessages.cleanupDirectoryBusy.zh;
2405
2407
  updateManagedCheckout(record.checkoutId, (current) => {
2406
2408
  const journal = current.journal?.operation === 'cleanup' ? current.journal : null;
2407
2409
  if (current.delivery.state === 'finalized') {
@@ -2417,17 +2419,17 @@ export function createSessionCheckoutModule(dependencies) {
2417
2419
  }
2418
2420
  async function operateFinalizePreview(input, binding) {
2419
2421
  if (binding.ownerSessionId !== input.sessionId || binding.target.kind !== 'isolated') {
2420
- return operationError('not_owner', '只有 owner Isolated 会话可以完成验收提交');
2422
+ return operationError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanFinalizeTheAcceptance'));
2421
2423
  }
2422
2424
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
2423
2425
  if (!record)
2424
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2426
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2425
2427
  if (record.revision !== input.expectedRevision) {
2426
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
2428
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2427
2429
  }
2428
2430
  if (record.phase !== 'ready'
2429
2431
  || (record.delivery.state !== 'preview_active' && record.delivery.state !== 'preview_detached')) {
2430
- return operationError('preview_not_active', '当前没有等待验收的 Local Preview', await inspectIsolated(binding));
2432
+ return operationError('preview_not_active', hostMessage('thereIsNoLocalPreviewAwaitingAcceptance'), await inspectIsolated(binding));
2431
2433
  }
2432
2434
  const retryingDetached = record.delivery.state === 'preview_detached';
2433
2435
  if (retryingDetached) {
@@ -2436,7 +2438,7 @@ export function createSessionCheckoutModule(dependencies) {
2436
2438
  return operationError('stale_target', recovery.message, await inspectIsolated(binding));
2437
2439
  }
2438
2440
  if (!recoveryProofMatches(input.recoveryProof, recovery.proof)) {
2439
- return operationError('stale_target', 'Preview Recovery proof 已过期或不匹配,请重新检查', await inspectIsolated(binding));
2441
+ return operationError('stale_target', hostMessage('thePreviewRecoveryProofHasExpiredOrDoesNot'), await inspectIsolated(binding));
2440
2442
  }
2441
2443
  if (recovery.proof.finalize.status !== 'safe') {
2442
2444
  return operationError(recovery.proof.finalize.code, recovery.proof.finalize.message, await inspectIsolated(binding));
@@ -2522,12 +2524,12 @@ export function createSessionCheckoutModule(dependencies) {
2522
2524
  revision: current.revision + 1,
2523
2525
  }));
2524
2526
  if (!finalized)
2525
- return operationError('checkout_missing', '提交已创建,但 Checkout 记录丢失');
2527
+ return operationError('checkout_missing', hostMessage('theCommitWasCreatedButTheCheckoutRecordIs'));
2526
2528
  const retention = input.retention ?? 'cleanup';
2527
2529
  if (retention !== 'cleanup') {
2528
2530
  const retained = retainFinalized(finalized, retention);
2529
2531
  if (!retained)
2530
- return operationError('checkout_missing', '提交已创建,但保留 Worktree 状态写入失败');
2532
+ return operationError('checkout_missing', hostMessage('theCommitWasCreatedButSavingTheRetainedWorktree'));
2531
2533
  return {
2532
2534
  status: 'finished',
2533
2535
  target: await inspectIsolated(binding),
@@ -2549,16 +2551,16 @@ export function createSessionCheckoutModule(dependencies) {
2549
2551
  }
2550
2552
  async function operateRetryCleanup(input, binding) {
2551
2553
  if (binding.ownerSessionId !== input.sessionId || binding.target.kind !== 'isolated') {
2552
- return operationError('not_owner', '只有 owner Isolated 会话可以重试清理');
2554
+ return operationError('not_owner', hostMessage('onlyTheOwnerIsolatedSessionCanRetryCleanup'));
2553
2555
  }
2554
2556
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
2555
2557
  if (!record)
2556
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2558
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2557
2559
  if (record.revision !== input.expectedRevision) {
2558
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
2560
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2559
2561
  }
2560
2562
  if (record.delivery.state !== 'finalized' && record.delivery.state !== 'retained') {
2561
- return operationError('operation_not_allowed', '当前没有待重试的 Worktree 清理', await inspectIsolated(binding));
2563
+ return operationError('operation_not_allowed', hostMessage('thereIsNoWorktreeCleanupToRetry'), await inspectIsolated(binding));
2562
2564
  }
2563
2565
  const cleanup = await cleanupFinalized(record, { allowLegacyResidue: true });
2564
2566
  return {
@@ -2573,38 +2575,38 @@ export function createSessionCheckoutModule(dependencies) {
2573
2575
  }
2574
2576
  async function operateFinish(input, binding) {
2575
2577
  if (binding.ownerSessionId !== input.sessionId) {
2576
- return operationError('not_owner', '继承 Session Target 的会话不能执行 Finish');
2578
+ return operationError('not_owner', hostMessage('aSessionThatInheritedItsSessionTargetCannotPerform162'));
2577
2579
  }
2578
2580
  if (binding.target.kind !== 'isolated') {
2579
- return operationError('operation_not_allowed', 'Local Checkout 不支持 Finish');
2581
+ return operationError('operation_not_allowed', hostMessage('localCheckoutDoesNotSupportFinish'));
2580
2582
  }
2581
2583
  let record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
2582
2584
  if (!record)
2583
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2585
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2584
2586
  if (record.revision !== input.expectedRevision) {
2585
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
2587
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2586
2588
  }
2587
2589
  if (input.expectedReviewId !== undefined && (record.delivery.state !== 'ready_for_review'
2588
2590
  || record.delivery.review.reviewId !== input.expectedReviewId)) {
2589
- return operationError('stale_target', '该验收卡已不是当前 Review,请刷新并确认最新交付', await inspectIsolated(binding));
2591
+ return operationError('stale_target', hostMessage('thisReviewCardIsNoLongerTheCurrentReview166'), await inspectIsolated(binding));
2590
2592
  }
2591
2593
  if (record.applyBaseOid && (record.delivery.state === 'working' || record.delivery.state === 'ready_for_review')) {
2592
- return operationError('operation_not_allowed', '该历史 Worktree 已通过旧版 Apply 写入 Local;为避免遗漏或重复提交,已禁止自动 Finish,请先人工核对 Local 后再清理记录。', await inspectIsolated(binding));
2594
+ return operationError('operation_not_allowed', hostMessage('thisLegacyWorktreeWasWrittenToLocalThroughAn'), await inspectIsolated(binding));
2593
2595
  }
2594
2596
  if (record.phase !== 'ready' || record.delivery.state === 'preview_active' || record.delivery.state === 'preview_detached') {
2595
- return operationError('operation_not_allowed', `当前 ${record.phase}/${record.delivery.state} 状态不能直接 Finish`, await inspectIsolated(binding));
2597
+ return operationError('operation_not_allowed', hostMessage('cannotFinishDirectlyInTheCurrentState', { p0: record.phase, p1: record.delivery.state }), await inspectIsolated(binding));
2596
2598
  }
2597
2599
  const holder = findProjectAcceptanceHolder(record);
2598
2600
  if (holder) {
2599
- return operationError('project_acceptance_busy', `同一项目已有验收任务正在占用 Local:${holder.projectName}`, await inspectIsolated(binding));
2601
+ return operationError('project_acceptance_busy', hostMessage('anotherAcceptanceTaskInTheSameProjectIsOccupying', { p0: holder.projectName }), await inspectIsolated(binding));
2600
2602
  }
2601
2603
  const inspected = await inspectIsolated(binding);
2602
2604
  if (inspected.checkout.phase !== 'ready') {
2603
- return operationError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复', inspected);
2605
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'), inspected);
2604
2606
  }
2605
2607
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
2606
2608
  if (!record || record.phase !== 'ready') {
2607
- return operationError('recovery_required', 'Isolated Checkout 状态已变化,需要恢复');
2609
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutStateHasChangedRecoveryIsRequired'));
2608
2610
  }
2609
2611
  const startedAt = Date.now();
2610
2612
  const operationId = dependencies.createCheckoutId();
@@ -2622,7 +2624,7 @@ export function createSessionCheckoutModule(dependencies) {
2622
2624
  revision: current.revision + 1,
2623
2625
  }));
2624
2626
  if (!applying)
2625
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2627
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2626
2628
  const planResult = await dependencies.applyEngine.plan({
2627
2629
  baseOid: applyBaseOid,
2628
2630
  isolatedPath: applying.managedRoot,
@@ -2670,7 +2672,7 @@ export function createSessionCheckoutModule(dependencies) {
2670
2672
  journal: null,
2671
2673
  revision: current.revision + 1,
2672
2674
  }));
2673
- return operationError('stale_isolated', 'Worktree 在验收后又发生变化,请重新准备验收', await inspectIsolated(binding));
2675
+ return operationError('stale_isolated', hostMessage('worktreeChangedAfterReviewPrepareTheReviewAgain'), await inspectIsolated(binding));
2674
2676
  }
2675
2677
  const iteration = applying.delivery.state === 'working'
2676
2678
  ? applying.delivery.iteration
@@ -2683,7 +2685,7 @@ export function createSessionCheckoutModule(dependencies) {
2683
2685
  reviewId: operationId,
2684
2686
  iteration,
2685
2687
  preparedAt: startedAt,
2686
- summary: '跳过 Local 验收并直接提交',
2688
+ summary: hostMessage('skipLocalAcceptanceAndCommitDirectly'),
2687
2689
  validationStatus: 'not_run',
2688
2690
  tests: [],
2689
2691
  changedFiles: [...planResult.plan.changedFiles],
@@ -2804,13 +2806,13 @@ export function createSessionCheckoutModule(dependencies) {
2804
2806
  revision: current.revision + 1,
2805
2807
  }));
2806
2808
  if (!finalized) {
2807
- return operationError('checkout_missing', '任务提交已创建,但 Checkout 记录丢失,需要人工检查');
2809
+ return operationError('checkout_missing', hostMessage('theTaskCommitWasCreatedButTheCheckoutRecord'));
2808
2810
  }
2809
2811
  const retention = input.retention ?? 'cleanup';
2810
2812
  if (retention !== 'cleanup') {
2811
2813
  const retained = retainFinalized(finalized, retention);
2812
2814
  if (!retained)
2813
- return operationError('checkout_missing', '任务提交已创建,但保留 Worktree 状态写入失败');
2815
+ return operationError('checkout_missing', hostMessage('theTaskCommitWasCreatedButSavingTheRetained'));
2814
2816
  return {
2815
2817
  status: 'finished',
2816
2818
  target: await inspectIsolated(binding),
@@ -2837,31 +2839,31 @@ export function createSessionCheckoutModule(dependencies) {
2837
2839
  }
2838
2840
  catch {
2839
2841
  // checkout 删除优先;内部无 ref artifact 的清理失败不能阻止 owner 明确收口。
2840
- console.warn('[session-checkout] 清理内部 Session Checkout refs 失败,已保守保留不可见引用');
2842
+ console.warn(hostMessage('internalRefsCleanupFailed'));
2841
2843
  }
2842
2844
  }
2843
2845
  async function operateDiscard(input, binding) {
2844
2846
  if (binding.ownerSessionId !== input.sessionId) {
2845
- return operationError('not_owner', '继承 Session Target 的会话不能执行 Discard');
2847
+ return operationError('not_owner', hostMessage('aSessionThatInheritedItsSessionTargetCannotPerform178'));
2846
2848
  }
2847
2849
  if (binding.target.kind !== 'isolated') {
2848
- return operationError('operation_not_allowed', 'Local Checkout 不支持 Discard');
2850
+ return operationError('operation_not_allowed', hostMessage('localCheckoutDoesNotSupportDiscard'));
2849
2851
  }
2850
2852
  let record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
2851
2853
  if (!record)
2852
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2854
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2853
2855
  if (record.revision !== input.expectedRevision) {
2854
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
2856
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2855
2857
  }
2856
2858
  if (record.delivery.state === 'preview_detached') {
2857
- return operationError('preview_modified', 'Local Preview 已因漂移进入 detached 恢复态;为保留恢复证据,不能删除 Worktree。请先成功撤回 Preview。', await inspectIsolated(binding));
2859
+ return operationError('preview_modified', hostMessage('localPreviewDriftedIntoDetachedRecoveryToPreserveRecovery'), await inspectIsolated(binding));
2858
2860
  }
2859
2861
  if (record.applyBaseOid && (record.delivery.state === 'working' || record.delivery.state === 'ready_for_review')) {
2860
- return operationError('operation_not_allowed', '该历史 Worktree 已通过旧版 Apply 写入 Local;不会自动 Discard,请先人工核对 Local 的未提交修改。', await inspectIsolated(binding));
2862
+ return operationError('operation_not_allowed', hostMessage('thisLegacyWorktreeWasWrittenToLocalThroughAn183'), await inspectIsolated(binding));
2861
2863
  }
2862
2864
  if (record.delivery.state === 'preview_active') {
2863
2865
  if (!input.rollbackPreview) {
2864
- return operationError('preview_not_active', '本任务正在 Local 预览;放弃任务前必须先安全撤回 Preview', await inspectIsolated(binding));
2866
+ return operationError('preview_not_active', hostMessage('thisTaskIsPreviewingInLocalSafelyRollBack'), await inspectIsolated(binding));
2865
2867
  }
2866
2868
  const rollback = await dependencies.applyEngine.rollback({
2867
2869
  localPath: record.localRoot,
@@ -2882,7 +2884,7 @@ export function createSessionCheckoutModule(dependencies) {
2882
2884
  revision: current.revision + 1,
2883
2885
  }));
2884
2886
  if (!rolledBack)
2885
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2887
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2886
2888
  await releasePreviewArtifactsBestEffort(record, previewId);
2887
2889
  record = rolledBack;
2888
2890
  }
@@ -2898,18 +2900,18 @@ export function createSessionCheckoutModule(dependencies) {
2898
2900
  return { status: 'discarded', target: await inspectIsolated(binding) };
2899
2901
  }
2900
2902
  if (record.phase !== 'ready' && record.phase !== 'recovery_required') {
2901
- return operationError('operation_not_allowed', `当前 ${record.phase} 状态不能 Discard`, await inspectIsolated(binding));
2903
+ return operationError('operation_not_allowed', hostMessage('cannotDiscardInTheCurrentState', { p0: record.phase }), await inspectIsolated(binding));
2902
2904
  }
2903
2905
  let inspected;
2904
2906
  let dirty = true;
2905
2907
  if (record.phase === 'ready') {
2906
2908
  inspected = await inspectIsolated(binding);
2907
2909
  if (inspected.checkout.phase !== 'ready') {
2908
- return operationError('recovery_required', 'Isolated Checkout 身份无法确认,需要恢复', inspected);
2910
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutIdentityCannotBeVerifiedRecoveryIs'), inspected);
2909
2911
  }
2910
2912
  record = dependencies.registry.read().managedCheckouts[record.checkoutId];
2911
2913
  if (!record || record.phase !== 'ready') {
2912
- return operationError('recovery_required', 'Isolated Checkout 状态已变化,需要恢复');
2914
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutStateHasChangedRecoveryIsRequired'));
2913
2915
  }
2914
2916
  dirty = (await dependencies.git.status(record.managedRoot)).dirty || (record.checkpoints?.length ?? 0) > 0;
2915
2917
  }
@@ -2924,15 +2926,15 @@ export function createSessionCheckoutModule(dependencies) {
2924
2926
  }
2925
2927
  if (dirty && !input.confirmDirty) {
2926
2928
  const checkpointDetail = (record.checkpoints?.length ?? 0) > 0
2927
- ? `;确认后会永久删除 ${record.checkpoints.length} 个尚未交付到 Local 的阶段`
2929
+ ? hostMessage('confirmationWillPermanentlyDeleteCheckpointsNotYetDeliveredTo', { p0: record.checkpoints.length })
2928
2930
  : '';
2929
- return operationError('dirty_confirmation_required', `Isolated Checkout 含未提交修改、未交付阶段或状态无法确认,需要明确确认${checkpointDetail}`, inspected);
2931
+ return operationError('dirty_confirmation_required', hostMessage('theIsolatedCheckoutHasUncommittedChangesUndeliveredCheckpointsOr', { p0: checkpointDetail }), inspected);
2930
2932
  }
2931
2933
  try {
2932
2934
  await dependencies.git.removeWorktree(record.localRoot, record.managedGitRoot);
2933
2935
  }
2934
2936
  catch {
2935
- return operationError('git_operation_failed', '删除 managed checkout 失败', await inspectIsolated(binding));
2937
+ return operationError('git_operation_failed', hostMessage('failedToDeleteTheManagedCheckout'), await inspectIsolated(binding));
2936
2938
  }
2937
2939
  await releaseApplyBaseBestEffort(record);
2938
2940
  updateManagedCheckout(record.checkoutId, (current) => ({
@@ -2945,27 +2947,27 @@ export function createSessionCheckoutModule(dependencies) {
2945
2947
  }
2946
2948
  async function operateRecover(input, binding) {
2947
2949
  if (binding.ownerSessionId !== input.sessionId) {
2948
- return operationError('not_owner', '继承 Session Target 的会话不能执行 Recover');
2950
+ return operationError('not_owner', hostMessage('aSessionThatInheritedItsSessionTargetCannotPerform192'));
2949
2951
  }
2950
2952
  if (binding.target.kind !== 'isolated') {
2951
- return operationError('operation_not_allowed', 'Local Checkout 不支持 Recover');
2953
+ return operationError('operation_not_allowed', hostMessage('localCheckoutDoesNotSupportRecover'));
2952
2954
  }
2953
2955
  const record = dependencies.registry.read().managedCheckouts[binding.target.checkoutId];
2954
2956
  if (!record)
2955
- return operationError('checkout_missing', 'Isolated Checkout 记录不存在');
2957
+ return operationError('checkout_missing', hostMessage('theIsolatedCheckoutRecordDoesNotExist'));
2956
2958
  if (record.revision !== input.expectedRevision) {
2957
- return operationError('stale_target', 'Session Target 已变化,请刷新后重试', await inspectIsolated(binding));
2959
+ return operationError('stale_target', hostMessage('theSessionTargetHasChangedRefreshAndRetry'), await inspectIsolated(binding));
2958
2960
  }
2959
2961
  const recoverCreate = record.journal?.operation === 'create';
2960
2962
  if ((record.journal !== null && !recoverCreate) || record.phase === 'mutating') {
2961
- return operationError('recovery_unsafe', 'Apply 是否已修改 Local 无法安全确认;不会自动重试或猜测成功', await inspectIsolated(binding));
2963
+ return operationError('recovery_unsafe', hostMessage('cannotSafelyDetermineWhetherApplyModifiedLocalItWill'), await inspectIsolated(binding));
2962
2964
  }
2963
2965
  if (!dependencies.files.exists(record.managedRoot)) {
2964
- return operationError('recovery_required', 'Isolated Checkout 缺失,只能由 owner 明确 Discard 收口');
2966
+ return operationError('recovery_required', hostMessage('theIsolatedCheckoutIsMissingOnlyAnExplicitDiscard'));
2965
2967
  }
2966
2968
  const validated = await validateManagedCheckout(binding, record, recoverCreate);
2967
2969
  if (!validated) {
2968
- return operationError('recovery_unsafe', 'Isolated Checkout 的路径、Git 身份、项目、HEAD 或状态无法完整确认');
2970
+ return operationError('recovery_unsafe', hostMessage('theIsolatedCheckoutPathGitIdentityProjectHEADOr'));
2969
2971
  }
2970
2972
  updateManagedCheckout(record.checkoutId, (current) => ({
2971
2973
  ...current,
@@ -3104,7 +3106,7 @@ export function createSessionCheckoutModule(dependencies) {
3104
3106
  checkoutId: record.checkoutId,
3105
3107
  revision: record.revision,
3106
3108
  ownerSessionId: record.ownerSessionId,
3107
- ownerSessionTitle: dependencies.lookup.getSession(record.ownerSessionId)?.title?.trim() || '已删除的 Agent 会话',
3109
+ ownerSessionTitle: dependencies.lookup.getSession(record.ownerSessionId)?.title?.trim() || hostMessage('deletedAgentSession'),
3108
3110
  project: { id: record.projectId, name: record.projectName },
3109
3111
  iteration: managedIteration(record),
3110
3112
  state,
@@ -3117,7 +3119,7 @@ export function createSessionCheckoutModule(dependencies) {
3117
3119
  retainedAt: delivery.retainedAt,
3118
3120
  expiresAt: delivery.expiresAt,
3119
3121
  } : {}),
3120
- ...(cleanupMessage ? { cleanupMessage } : {}),
3122
+ ...(cleanupMessage ? { cleanupMessage: hostPersistedCleanupMessage(cleanupMessage, hostMessage) } : {}),
3121
3123
  ...(cleanupReason ? { cleanupReason } : {}),
3122
3124
  approximateBytes,
3123
3125
  updatedAt: managedUpdatedAt(record),
@@ -3129,38 +3131,38 @@ export function createSessionCheckoutModule(dependencies) {
3129
3131
  }
3130
3132
  async function inspectCleanupForRecord(record) {
3131
3133
  if (record.delivery.state === 'working')
3132
- return cleanupBlocked('working', '当前轮次仍在修改,尚未形成可清理的交付环境。', record.revision);
3134
+ return cleanupBlocked('working', hostMessage('theCurrentIterationIsStillBeingEditedAndHas'), record.revision);
3133
3135
  if (record.delivery.state === 'ready_for_review')
3134
- return cleanupBlocked('review_pending', '当前轮次正在等待验收,不能清理。', record.revision);
3136
+ return cleanupBlocked('review_pending', hostMessage('theCurrentIterationIsAwaitingAcceptanceAndCannotBe'), record.revision);
3135
3137
  if (record.delivery.state === 'preview_active' || record.delivery.state === 'preview_detached') {
3136
- return cleanupBlocked('preview_active', 'Local Preview 尚未完成安全收口,不能清理。', record.revision);
3138
+ return cleanupBlocked('preview_active', hostMessage('localPreviewHasNotBeenSafelyResolvedAndCannot'), record.revision);
3137
3139
  }
3138
3140
  if (record.delivery.state === 'delivered' || record.phase === 'discarded') {
3139
- return cleanupBlocked('unknown', 'Worktree 已交付并解除管理,无需再次清理。', record.revision);
3141
+ return cleanupBlocked('unknown', hostMessage('worktreeHasBeenDeliveredAndReleasedFromManagementNo'), record.revision);
3140
3142
  }
3141
3143
  if (record.delivery.commitOid && record.delivery.proof) {
3142
3144
  const local = await validateCommittedLocalCheckout(bindingForManagedRecord(record), record);
3143
3145
  if (!local)
3144
- return cleanupBlocked('identity_mismatch', 'Local checkout identity 无法验证,不能证明本轮交付仍存在。', record.revision);
3146
+ return cleanupBlocked('identity_mismatch', hostMessage('theLocalCheckoutIdentityCannotBeVerifiedThisIteration'), record.revision);
3145
3147
  try {
3146
3148
  const delivered = await dependencies.git.isAncestor(local.canonicalLocalRoot, record.delivery.commitOid, local.snapshot.headOid);
3147
3149
  if (!delivered)
3148
- return cleanupBlocked('identity_mismatch', '本轮交付 commit 已不在 Local 历史中,不能清理环境。', record.revision);
3150
+ return cleanupBlocked('identity_mismatch', hostMessage('thisIterationSDeliveryCommitIsNoLongerIn'), record.revision);
3149
3151
  }
3150
3152
  catch {
3151
- return cleanupBlocked('unknown', '无法验证本轮交付 commit 是否仍在 Local 历史中。', record.revision);
3153
+ return cleanupBlocked('unknown', hostMessage('cannotVerifyWhetherThisIterationSDeliveryCommitIs'), record.revision);
3152
3154
  }
3153
3155
  }
3154
3156
  const quarantine = await validateCleanupQuarantine(record);
3155
3157
  const residue = quarantine ? undefined : await validateDetachedCleanupResidue(record, true);
3156
3158
  if (record.journal?.operation === 'cleanup' && record.journal.cleanupQuarantinePath && !quarantine) {
3157
- return cleanupBlocked('identity_mismatch', '清理目录身份无法重新验证,已保留环境。', record.revision);
3159
+ return cleanupBlocked('identity_mismatch', hostMessage('theCleanupDirectoryIdentityCannotBeReverifiedTheEnvironment'), record.revision);
3158
3160
  }
3159
3161
  if (!quarantine && !residue && dependencies.files.exists(record.managedRoot)) {
3160
3162
  const binding = bindingForManagedRecord(record);
3161
3163
  const validated = await validateManagedCheckout(binding, record, false);
3162
3164
  if (!validated)
3163
- return cleanupBlocked('identity_mismatch', 'Worktree checkout identity 无法验证,已保留环境。', record.revision);
3165
+ return cleanupBlocked('identity_mismatch', hostMessage('theWorktreeCheckoutIdentityCannotBeVerifiedTheEnvironment'), record.revision);
3164
3166
  try {
3165
3167
  const snapshot = await dependencies.applyEngine.inspectReview({
3166
3168
  baseOid: record.applyBaseOid ?? record.baseOid,
@@ -3168,25 +3170,26 @@ export function createSessionCheckoutModule(dependencies) {
3168
3170
  localPath: record.localRoot,
3169
3171
  });
3170
3172
  if (snapshot.status !== 'ready' || snapshot.isolatedFingerprint !== record.delivery.isolatedFingerprint) {
3171
- return cleanupBlocked('uncommitted_changes', '提交或保留后检测到新增修改,不能批量清理。', record.revision);
3173
+ return cleanupBlocked('uncommitted_changes', hostMessage('newChangesWereDetectedAfterCommitOrRetentionBulk'), record.revision);
3172
3174
  }
3173
3175
  }
3174
3176
  catch {
3175
- return cleanupBlocked('unknown', '无法证明 Worktree 当前状态安全,已保留环境。', record.revision);
3177
+ return cleanupBlocked('unknown', hostMessage('cannotProveTheCurrentWorktreeStateIsSafeThe'), record.revision);
3176
3178
  }
3177
3179
  }
3178
3180
  if (record.delivery.cleanup === 'blocked' || record.delivery.cleanup === 'pending') {
3179
- const cleanupMessage = record.delivery.cleanupMessage ?? '上次清理未完成,可重新校验后重试。';
3180
- if (cleanupReasonForMessage(cleanupMessage) === 'identity_changed')
3181
+ const cleanupReason = cleanupReasonForMessage(record.delivery.cleanupMessage ?? '');
3182
+ const cleanupMessage = record.delivery.cleanupMessage ? hostPersistedCleanupMessage(record.delivery.cleanupMessage, hostMessage) : hostMessage('thePreviousCleanupDidNotFinishRevalidateAndRetry');
3183
+ if (cleanupReason === 'identity_changed')
3181
3184
  return cleanupBlocked('identity_mismatch', cleanupMessage, record.revision);
3182
- if (cleanupReasonForMessage(cleanupMessage) === 'modified_after_finalize')
3185
+ if (cleanupReason === 'modified_after_finalize')
3183
3186
  return cleanupBlocked('uncommitted_changes', cleanupMessage, record.revision);
3184
3187
  }
3185
3188
  if (record.delivery.state === 'retained'
3186
3189
  && (record.delivery.retention === 'retain_manual' || record.delivery.expiresAt === null || record.delivery.expiresAt > Date.now())) {
3187
- return { eligibility: 'retained', reason: 'retention_active', message: record.delivery.retention === 'retain_manual' ? '按用户选择手动保留。' : '保留期限尚未到期。', inspectedRevision: record.revision };
3190
+ return { eligibility: 'retained', reason: 'retention_active', message: record.delivery.retention === 'retain_manual' ? hostMessage('retainedManuallyAtTheUserSRequest') : hostMessage('theRetentionPeriodHasNotExpired'), inspectedRevision: record.revision };
3188
3191
  }
3189
- return { eligibility: 'safe', reason: 'cleanup_failed', message: record.delivery.cleanupMessage ?? '已通过只读安全巡检,可以清理。', inspectedRevision: record.revision };
3192
+ return { eligibility: 'safe', reason: 'cleanup_failed', message: record.delivery.cleanupMessage ? hostPersistedCleanupMessage(record.delivery.cleanupMessage, hostMessage) : hostMessage('readOnlySafetyInspectionPassedCleanupIsAvailable'), inspectedRevision: record.revision };
3190
3193
  }
3191
3194
  async function inspectManagedWorktreeCleanup(input = {}) {
3192
3195
  const records = Object.values(dependencies.registry.read().managedCheckouts)
@@ -3214,7 +3217,7 @@ export function createSessionCheckoutModule(dependencies) {
3214
3217
  retained.push({
3215
3218
  checkoutId: record.checkoutId,
3216
3219
  iteration: managedIteration(record),
3217
- cleanup: cleanupBlocked('unknown', 'Worktree revision 已变化,未执行清理。', record.revision),
3220
+ cleanup: cleanupBlocked('unknown', hostMessage('theWorktreeRevisionHasChangedCleanupWasNotPerformed'), record.revision),
3218
3221
  });
3219
3222
  continue;
3220
3223
  }
@@ -3228,7 +3231,7 @@ export function createSessionCheckoutModule(dependencies) {
3228
3231
  retained.push({
3229
3232
  checkoutId: record.checkoutId,
3230
3233
  iteration: managedIteration(record),
3231
- cleanup: cleanupBlocked('unknown', 'Worktree 在清理前发生变化,未执行清理。', latest?.revision ?? record.revision),
3234
+ cleanup: cleanupBlocked('unknown', hostMessage('worktreeChangedBeforeCleanupCleanupWasNotPerformed'), latest?.revision ?? record.revision),
3232
3235
  });
3233
3236
  continue;
3234
3237
  }
@@ -3266,7 +3269,7 @@ export function createSessionCheckoutModule(dependencies) {
3266
3269
  const persisted = getPersistedBinding(sessionId);
3267
3270
  const projectId = persisted?.projectId ?? session.projectId;
3268
3271
  if (!projectId)
3269
- throw new SessionCheckoutError('project_not_found', '会话尚未关联项目');
3272
+ throw new SessionCheckoutError('project_not_found', hostMessage('theSessionIsNotAssociatedWithAProject'));
3270
3273
  const allowedCheckoutIds = new Set(Object.values(dependencies.registry.read().managedCheckouts)
3271
3274
  .filter((record) => record.projectId === projectId)
3272
3275
  .filter((record) => record.ownerSessionId === sessionId || record.sourceSessionId === sessionId)
@@ -3278,26 +3281,26 @@ export function createSessionCheckoutModule(dependencies) {
3278
3281
  requireSession(sessionId);
3279
3282
  const record = dependencies.registry.read().managedCheckouts[input.checkoutId];
3280
3283
  if (!record)
3281
- throw new SessionCheckoutError('checkout_missing', 'Worktree 记录不存在');
3284
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theWorktreeRecordDoesNotExist'));
3282
3285
  if (record.ownerSessionId !== sessionId && record.sourceSessionId !== sessionId) {
3283
- throw new SessionCheckoutError('not_owner', '当前 Session 无权管理该 Worktree');
3286
+ throw new SessionCheckoutError('not_owner', hostMessage('theCurrentSessionIsNotAllowedToManageThis'));
3284
3287
  }
3285
3288
  if (record.ownerSessionId !== sessionId && dependencies.lookup.getSession(record.ownerSessionId)) {
3286
- throw new SessionCheckoutError('not_owner', 'Owner Session 已接管该 Worktree,只有 owner 可以管理');
3289
+ throw new SessionCheckoutError('not_owner', hostMessage('theOwnerSessionHasTakenOverThisWorktreeOnly'));
3287
3290
  }
3288
3291
  const persisted = getPersistedBinding(sessionId);
3289
3292
  const callerProjectId = persisted?.projectId ?? dependencies.lookup.getSession(sessionId)?.projectId;
3290
3293
  if (callerProjectId !== record.projectId) {
3291
- throw new SessionCheckoutError('project_mismatch', '当前 Session 与 Worktree 不属于同一原始项目');
3294
+ throw new SessionCheckoutError('project_mismatch', hostMessage('theCurrentSessionAndWorktreeDoNotBelongTo'));
3292
3295
  }
3293
3296
  return manageManagedWorktree(input);
3294
3297
  }
3295
3298
  async function manageManagedWorktree(input) {
3296
3299
  const record = dependencies.registry.read().managedCheckouts[input.checkoutId];
3297
3300
  if (!record)
3298
- throw new SessionCheckoutError('checkout_missing', 'Worktree 记录不存在');
3301
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theWorktreeRecordDoesNotExist'));
3299
3302
  if (record.revision !== input.expectedRevision)
3300
- throw new SessionCheckoutError('stale_target', 'Worktree 状态已变化,请刷新后重试');
3303
+ throw new SessionCheckoutError('stale_target', hostMessage('theWorktreeStateHasChangedRefreshAndRetry'));
3301
3304
  if (input.action === 'discard') {
3302
3305
  // Caller authorization is performed by the scoped wrapper (or a trusted Host manager).
3303
3306
  // The reserved owner Session may not exist yet, so do not re-resolve it through lookup.
@@ -3312,12 +3315,12 @@ export function createSessionCheckoutModule(dependencies) {
3312
3315
  throw new SessionCheckoutError(result.code, result.message);
3313
3316
  const updated = dependencies.registry.read().managedCheckouts[record.checkoutId];
3314
3317
  if (!updated)
3315
- throw new SessionCheckoutError('checkout_missing', 'Worktree 记录不存在');
3318
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theWorktreeRecordDoesNotExist'));
3316
3319
  return summarizeManagedWorktree(updated);
3317
3320
  }
3318
3321
  if (input.action === 'set_retention') {
3319
3322
  if (record.phase !== 'retained' || record.delivery.state !== 'retained' || !input.retention) {
3320
- throw new SessionCheckoutError('operation_not_allowed', '只有已保留的冻结 Worktree 可以调整保留期限');
3323
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('onlyRetainedFrozenWorktreesCanHaveTheirRetentionPeriod'));
3321
3324
  }
3322
3325
  const retainedAt = Date.now();
3323
3326
  const updated = updateManagedCheckout(record.checkoutId, (current) => {
@@ -3337,25 +3340,25 @@ export function createSessionCheckoutModule(dependencies) {
3337
3340
  };
3338
3341
  });
3339
3342
  if (!updated)
3340
- throw new SessionCheckoutError('checkout_missing', 'Worktree 记录不存在');
3343
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theWorktreeRecordDoesNotExist'));
3341
3344
  return summarizeManagedWorktree(updated);
3342
3345
  }
3343
3346
  if (record.delivery.state !== 'retained' && record.delivery.state !== 'finalized') {
3344
- throw new SessionCheckoutError('operation_not_allowed', '当前 Worktree 不处于可清理状态');
3347
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('theCurrentWorktreeIsNotInACleanableState'));
3345
3348
  }
3346
3349
  await cleanupFinalized(record, { allowLegacyResidue: true });
3347
3350
  const updated = dependencies.registry.read().managedCheckouts[record.checkoutId];
3348
3351
  if (!updated)
3349
- throw new SessionCheckoutError('checkout_missing', 'Worktree 记录不存在');
3352
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theWorktreeRecordDoesNotExist'));
3350
3353
  return summarizeManagedWorktree(updated);
3351
3354
  }
3352
3355
  async function resolveManagedRoot(checkoutId) {
3353
3356
  const record = dependencies.registry.read().managedCheckouts[checkoutId];
3354
3357
  if (!record || record.phase === 'discarded')
3355
- throw new SessionCheckoutError('checkout_missing', 'Worktree 目录已不存在');
3358
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theWorktreeDirectoryNoLongerExists'));
3356
3359
  const validated = await validateManagedCheckout(bindingForManagedRecord(record), record, false);
3357
3360
  if (!validated)
3358
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree 目录身份无法验证');
3361
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theWorktreeDirectoryIdentityCannotBeVerified'));
3359
3362
  return validated.canonicalManagedRoot;
3360
3363
  }
3361
3364
  async function cleanupExpiredRetained(now = Date.now()) {
@@ -3383,58 +3386,58 @@ export function createSessionCheckoutModule(dependencies) {
3383
3386
  const registry = dependencies.registry.read();
3384
3387
  const previousBinding = registry.sessionBindings[sessionId];
3385
3388
  if (!previousBinding || previousBinding.target.kind !== 'isolated') {
3386
- throw new SessionCheckoutError('operation_not_allowed', '只有已交付的 Isolated Session 可以开始下一轮');
3389
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('onlyADeliveredIsolatedSessionCanBeginTheNext'));
3387
3390
  }
3388
3391
  const predecessor = registry.managedCheckouts[previousBinding.target.checkoutId];
3389
3392
  if (!predecessor)
3390
- throw new SessionCheckoutError('checkout_missing', '上一轮 Worktree 记录不存在');
3393
+ throw new SessionCheckoutError('checkout_missing', hostMessage('thePreviousIterationSWorktreeRecordDoesNotExist'));
3391
3394
  if (predecessor.ownerSessionId !== sessionId || previousBinding.ownerSessionId !== sessionId) {
3392
- throw new SessionCheckoutError('not_owner', '只有 owner Session 可以开始下一轮');
3395
+ throw new SessionCheckoutError('not_owner', hostMessage('onlyTheOwnerSessionCanBeginTheNextIteration'));
3393
3396
  }
3394
3397
  if (predecessor.revision !== expectedRevision) {
3395
- throw new SessionCheckoutError('stale_target', 'Worktree 状态已变化,请刷新后再开始下一轮');
3398
+ throw new SessionCheckoutError('stale_target', hostMessage('theWorktreeStateHasChangedRefreshBeforeBeginningThe'));
3396
3399
  }
3397
3400
  if (predecessor.phase !== 'discarded' || predecessor.delivery.state !== 'delivered') {
3398
- throw new SessionCheckoutError('operation_not_allowed', '只有已成功清理的交付状态可以开始下一轮');
3401
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('onlyADeliveredStateWithSuccessfulCleanupCanBegin'));
3399
3402
  }
3400
3403
  if (!session.projectId)
3401
- throw new SessionCheckoutError('project_not_found', '当前 Session 尚未关联 Workspace');
3404
+ throw new SessionCheckoutError('project_not_found', hostMessage('theCurrentSessionIsNotAssociatedWithAWorkspace'));
3402
3405
  const ownerWorkspace = dependencies.lookup.getProject(session.projectId);
3403
3406
  if (!ownerWorkspace || !resolvedPathsEqual(ownerWorkspace.root, predecessor.managedRoot)) {
3404
- throw new SessionCheckoutError('project_mismatch', '当前 Session 的 immutable cwd 与上一轮 Worktree 不一致');
3407
+ throw new SessionCheckoutError('project_mismatch', hostMessage('theCurrentSessionSImmutableCwdDoesNotMatch'));
3405
3408
  }
3406
3409
  if (dependencies.files.exists(predecessor.managedGitRoot) || dependencies.files.exists(predecessor.managedRoot)) {
3407
- throw new SessionCheckoutError('checkout_mismatch', '上一轮 Worktree 路径已重新出现,拒绝覆盖未知内容');
3410
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('thePreviousIterationSWorktreePathHasReappearedUnknown'));
3408
3411
  }
3409
3412
  const localProject = dependencies.lookup.getProject(predecessor.projectId);
3410
3413
  if (!localProject || !dependencies.files.exists(localProject.root) || !dependencies.files.exists(predecessor.localRoot)) {
3411
- throw new SessionCheckoutError('project_root_missing', '原始 Local 项目已不可用,不能开始下一轮');
3414
+ throw new SessionCheckoutError('project_root_missing', hostMessage('theOriginalLocalProjectIsUnavailableTheNextIteration'));
3412
3415
  }
3413
3416
  const canonicalProjectRoot = await dependencies.files.canonicalize(localProject.root);
3414
3417
  const canonicalLocalRoot = await dependencies.files.canonicalize(predecessor.localRoot);
3415
3418
  if (!pathsEqual(canonicalProjectRoot, canonicalLocalRoot)) {
3416
- throw new SessionCheckoutError('project_mismatch', '原始 Local 项目身份已变化');
3419
+ throw new SessionCheckoutError('project_mismatch', hostMessage('theOriginalLocalProjectIdentityHasChanged'));
3417
3420
  }
3418
3421
  const snapshot = await dependencies.git.inspect(canonicalLocalRoot);
3419
3422
  if (!snapshot || !pathsEqual(snapshot.commonDir, predecessor.gitCommonDir)) {
3420
- throw new SessionCheckoutError('checkout_mismatch', '原始 Local Git 身份已变化');
3423
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theOriginalLocalGitIdentityHasChanged'));
3421
3424
  }
3422
3425
  const projectRelativePath = relative(snapshot.root, canonicalLocalRoot);
3423
3426
  if (projectRelativePath.startsWith('..') || isAbsolute(projectRelativePath)) {
3424
- throw new SessionCheckoutError('checkout_mismatch', '项目根目录不在其 Git checkout 内');
3427
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theProjectRootIsNotInsideItsGitCheckout'));
3425
3428
  }
3426
3429
  if (!resolvedPathsEqual(resolve(predecessor.managedGitRoot, projectRelativePath), predecessor.managedRoot)) {
3427
- throw new SessionCheckoutError('checkout_mismatch', '上一轮 managed project 路径无法从 Local 身份重建');
3430
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('thePreviousIterationSManagedProjectPathCannotBe'));
3428
3431
  }
3429
3432
  const managedContainer = dirname(predecessor.managedGitRoot);
3430
3433
  if (!dependencies.files.exists(managedContainer))
3431
3434
  dependencies.files.ensureDirectory(managedContainer);
3432
3435
  const containerIdentity = await dependencies.files.inspectDirectoryIdentity(managedContainer);
3433
3436
  if (!containerIdentity)
3434
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree 容器不是可信目录');
3437
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theWorktreeContainerIsNotATrustedDirectory'));
3435
3438
  const canonicalContainer = await dependencies.files.canonicalize(managedContainer);
3436
3439
  if (!resolvedPathsEqual(canonicalContainer, managedContainer)) {
3437
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree 容器路径已被重定向');
3440
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theWorktreeContainerPathHasBeenRedirected'));
3438
3441
  }
3439
3442
  const checkoutId = dependencies.createCheckoutId();
3440
3443
  const iteration = predecessor.delivery.iteration + 1;
@@ -3490,12 +3493,12 @@ export function createSessionCheckoutModule(dependencies) {
3490
3493
  || !pathsEqual(created.root, canonicalManagedGitRoot)
3491
3494
  || !pathsEqual(created.commonDir, snapshot.commonDir)
3492
3495
  || created.headOid !== snapshot.headOid) {
3493
- throw new SessionCheckoutError('checkout_mismatch', '下一轮 checkout 的 Git 身份不匹配');
3496
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theNextIterationSCheckoutGitIdentityDoesNot'));
3494
3497
  }
3495
3498
  const readyRegistry = dependencies.registry.read();
3496
3499
  const current = readyRegistry.managedCheckouts[checkoutId];
3497
3500
  if (!current || current.phase !== 'preparing') {
3498
- throw new SessionCheckoutError('stale_target', '下一轮 Worktree 创建期间状态已变化');
3501
+ throw new SessionCheckoutError('stale_target', hostMessage('theStateChangedWhileCreatingTheNextIterationS'));
3499
3502
  }
3500
3503
  readyRegistry.managedCheckouts[checkoutId] = {
3501
3504
  ...current,
@@ -3537,7 +3540,7 @@ export function createSessionCheckoutModule(dependencies) {
3537
3540
  const current = dependencies.registry.read().managedCheckouts[checkoutId];
3538
3541
  if (current)
3539
3542
  markRecoveryRequired(current);
3540
- throw new SessionCheckoutError('recovery_required', '下一轮 Worktree 创建失败且残余目录包含未知内容,已保留现场');
3543
+ throw new SessionCheckoutError('recovery_required', hostMessage('creatingTheNextIterationSWorktreeFailedAndIts'));
3541
3544
  }
3542
3545
  const failedRegistry = dependencies.registry.read();
3543
3546
  delete failedRegistry.managedCheckouts[checkoutId];
@@ -3582,7 +3585,7 @@ export function createSessionCheckoutModule(dependencies) {
3582
3585
  }
3583
3586
  }
3584
3587
  if (!(choice.kind === 'isolated' && existing.target.kind === 'isolated' && nextIteration > 1)) {
3585
- throw new SessionCheckoutError('target_already_bound', '会话已经绑定 Session Target,不能切换');
3588
+ throw new SessionCheckoutError('target_already_bound', hostMessage('theSessionIsAlreadyBoundToASessionTarget'));
3586
3589
  }
3587
3590
  }
3588
3591
  const { project } = await resolveSessionProject(sourceSessionId);
@@ -3605,8 +3608,10 @@ export function createSessionCheckoutModule(dependencies) {
3605
3608
  return inspectLocal(binding);
3606
3609
  }
3607
3610
  if (!snapshot) {
3608
- throw new SessionCheckoutError('not_git_repository', '非 Git 项目不能创建 Isolated Checkout');
3611
+ throw new SessionCheckoutError('not_git_repository', hostMessage('aNonGitProjectCannotCreateAnIsolatedCheckout'));
3609
3612
  }
3613
+ if (snapshot.headOid === 'unborn')
3614
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('initialConfirmationRequired'));
3610
3615
  // managed Worktree 不再使用全局数量硬上限;生命周期通过交付后清理收口。
3611
3616
  const checkoutId = dependencies.createCheckoutId();
3612
3617
  const localRoot = await dependencies.files.canonicalize(project.root);
@@ -3669,7 +3674,7 @@ export function createSessionCheckoutModule(dependencies) {
3669
3674
  if (usingSibling) {
3670
3675
  return bindTarget(sessionId, choice, createAttempt + 1, requestStartedAt, sourceSessionId);
3671
3676
  }
3672
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree 回退容器不是可信目录,未创建或修改任何 checkout');
3677
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theFallbackWorktreeContainerIsNotATrustedDirectory'));
3673
3678
  }
3674
3679
  const managedGitRoot = pathCandidates
3675
3680
  .map(candidate => usingSibling ? candidate.siblingRoot : candidate.fallbackRoot)
@@ -3678,11 +3683,11 @@ export function createSessionCheckoutModule(dependencies) {
3678
3683
  if (usingSibling) {
3679
3684
  return bindTarget(sessionId, choice, createAttempt + 1, requestStartedAt, sourceSessionId);
3680
3685
  }
3681
- throw new SessionCheckoutError('checkout_mismatch', 'Worktree Checkout identity 路径均已存在,拒绝覆盖未知目录');
3686
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('allWorktreeCheckoutIdentityPathsAlreadyExistUnknownDirectories'));
3682
3687
  }
3683
3688
  const projectRelativePath = relative(localGitRoot, localRoot);
3684
3689
  if (projectRelativePath.startsWith('..') || isAbsolute(projectRelativePath)) {
3685
- throw new SessionCheckoutError('checkout_mismatch', '项目根目录不在其 Git checkout 内');
3690
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theProjectRootIsNotInsideItsGitCheckout'));
3686
3691
  }
3687
3692
  const managedRoot = join(managedGitRoot, projectRelativePath);
3688
3693
  const record = {
@@ -3731,7 +3736,7 @@ export function createSessionCheckoutModule(dependencies) {
3731
3736
  if (!created
3732
3737
  || !pathsEqual(created.root, canonicalManagedGitRoot)
3733
3738
  || !pathsEqual(created.commonDir, snapshot.commonDir)) {
3734
- throw new SessionCheckoutError('checkout_mismatch', '新建 checkout 的 Git common dir 不匹配');
3739
+ throw new SessionCheckoutError('checkout_mismatch', hostMessage('theNewCheckoutSGitCommonDirectoryDoesNot'));
3735
3740
  }
3736
3741
  const readyRegistry = dependencies.registry.read();
3737
3742
  const readyRecord = {
@@ -3773,7 +3778,7 @@ export function createSessionCheckoutModule(dependencies) {
3773
3778
  }
3774
3779
  if (!residueRemoved) {
3775
3780
  markRecoveryRequired(record);
3776
- throw new SessionCheckoutError('recovery_required', 'Worktree 创建失败且残余目录包含未知内容,已保留现场,请查看原因或改用新会话');
3781
+ throw new SessionCheckoutError('recovery_required', hostMessage('worktreeCreationFailedAndTheRemainingDirectoryContainsUnknown'));
3777
3782
  }
3778
3783
  const failedRegistry = dependencies.registry.read();
3779
3784
  delete failedRegistry.managedCheckouts[checkoutId];
@@ -3791,7 +3796,7 @@ export function createSessionCheckoutModule(dependencies) {
3791
3796
  if (createAttempt < 1) {
3792
3797
  return bindTarget(sessionId, choice, createAttempt + 1, requestStartedAt, sourceSessionId);
3793
3798
  }
3794
- throw new SessionCheckoutError('git_operation_failed', 'Worktree 创建失败,已安全清理残余目录,可直接重试');
3799
+ throw new SessionCheckoutError('git_operation_failed', hostMessage('worktreeCreationFailedTheRemainingDirectoryWasSafelyCleaned'));
3795
3800
  }
3796
3801
  }
3797
3802
  return {
@@ -3806,17 +3811,17 @@ export function createSessionCheckoutModule(dependencies) {
3806
3811
  },
3807
3812
  createIsolatedTarget: (sourceSessionId, targetSessionId) => withBindingLock(async () => {
3808
3813
  if (!targetSessionId || targetSessionId === sourceSessionId) {
3809
- throw new SessionCheckoutError('invalid_input', 'Isolated Target 必须使用独立的预分配 Session ID');
3814
+ throw new SessionCheckoutError('invalid_input', hostMessage('anIsolatedTargetRequiresASeparatePreallocatedSessionID'));
3810
3815
  }
3811
3816
  if (dependencies.lookup.getSession(targetSessionId) && !getPersistedBinding(targetSessionId)) {
3812
- throw new SessionCheckoutError('target_already_bound', '目标 Session ID 已被其他 Workspace 使用');
3817
+ throw new SessionCheckoutError('target_already_bound', hostMessage('theTargetSessionIDIsAlreadyUsedByAnother'));
3813
3818
  }
3814
3819
  const sourceBinding = getPersistedBinding(sourceSessionId);
3815
3820
  if (!sourceBinding) {
3816
3821
  await bindTarget(sourceSessionId, { kind: 'local' });
3817
3822
  }
3818
3823
  else if (sourceBinding.target.kind !== 'local') {
3819
- throw new SessionCheckoutError('operation_not_allowed', '只能从 Local Session 创建新的 Isolated Target');
3824
+ throw new SessionCheckoutError('operation_not_allowed', hostMessage('aNewIsolatedTargetCanOnlyBeCreatedFrom'));
3820
3825
  }
3821
3826
  const target = await bindTarget(targetSessionId, { kind: 'isolated' }, 0, Date.now(), sourceSessionId);
3822
3827
  const binding = getPersistedBinding(targetSessionId);
@@ -3824,7 +3829,7 @@ export function createSessionCheckoutModule(dependencies) {
3824
3829
  ? dependencies.registry.read().managedCheckouts[binding.target.checkoutId]
3825
3830
  : undefined;
3826
3831
  if (!record)
3827
- throw new SessionCheckoutError('checkout_missing', 'Isolated Target 创建后记录缺失');
3832
+ throw new SessionCheckoutError('checkout_missing', hostMessage('theIsolatedTargetRecordIsMissingAfterCreation'));
3828
3833
  return { targetSessionId, managedRoot: record.managedRoot, target };
3829
3834
  }),
3830
3835
  beginNextIteration: (sessionId, expectedRevision) => withBindingLock(() => beginNextIterationTarget(sessionId, expectedRevision)),