@bud.sh/app 0.3.0 → 0.4.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 (77) hide show
  1. package/dist/client/assets/bud/design.js +1 -1
  2. package/dist/client/assets/canvas-C8hyPWoT.js +1 -0
  3. package/dist/client/assets/difference-worker-BfF4_N3e.js +8 -0
  4. package/dist/client/assets/files-D_Tm7gCK.js +1 -0
  5. package/dist/client/assets/i18n-BtfXum8P.js +1 -0
  6. package/dist/client/assets/index-Dpxjiok1.js +2 -0
  7. package/dist/client/assets/pages-B-_CKvDS.js +1 -0
  8. package/dist/client/assets/project-branches-DzXdaT9L.js +1 -0
  9. package/dist/client/assets/project-comments-CQkB2jbE.js +1 -0
  10. package/dist/client/assets/project-thread-links-BN7zL0AX.js +1 -0
  11. package/dist/client/assets/{project-threads-DezXiVK6.js → project-threads-CHGG-6fo.js} +104 -104
  12. package/dist/client/assets/{project-work-CB1JHqGW.js → project-work-L5fYMSOu.js} +1 -1
  13. package/dist/client/assets/task-design-DYqcqq1b.js +23 -0
  14. package/dist/client/assets/tasks-A2FKo3_h.js +1 -0
  15. package/dist/client/assets/tasks-request-DGigNdyK.js +1 -0
  16. package/dist/client/assets/workspace-CvWmU2RK.js +2 -0
  17. package/dist/client/index.html +2 -1
  18. package/dist/hosted/assets/{canvas-C69-96GR.js → canvas-MWtOwaWm.js} +69 -41
  19. package/dist/hosted/assets/{comment-data-CiDuvXi2.js → comment-data-DsgJWq4n.js} +7195 -1067
  20. package/dist/hosted/assets/{files-DQL5hzs3.js → files-Wvo11G2A.js} +92 -89
  21. package/dist/hosted/assets/{pages-DFs7jB6M.js → pages-BAmRFVtU.js} +31 -22
  22. package/dist/hosted/assets/{project-branches-CffV4IS1.js → project-branches-BNloVosX.js} +5 -5
  23. package/dist/hosted/assets/{project-thread-links-B1Y2bDUx.js → project-thread-links-BmY8HQXt.js} +12 -12
  24. package/dist/hosted/assets/{screen-BroBb1Z_.js → screen-QmqmI2Aq.js} +18 -18
  25. package/dist/hosted/assets/{tasks-mzmNhe2d.js → tasks-C8iWPrWg.js} +29 -29
  26. package/dist/hosted/assets/{tasks-request-Dcrpd2_8.js → tasks-request-C89fN1dK.js} +7 -7
  27. package/dist/hosted/hosted.js +48 -29
  28. package/dist/node/design.js +6235 -139
  29. package/dist/node/index.js +4 -2
  30. package/dist/node-host/assets/{canvas-BZhzizzt.js → canvas-D_F8SIlm.js} +70 -42
  31. package/dist/node-host/assets/{comment-data-nUlI0szN.js → comment-data-q_8INiZz.js} +7221 -1093
  32. package/dist/node-host/assets/{files-CTzcWGjb.js → files-xazOrNCX.js} +92 -89
  33. package/dist/node-host/assets/{pages-0aWH7z1j.js → pages-D6VkmdfQ.js} +31 -22
  34. package/dist/node-host/assets/{project-branches-1zs_0J_y.js → project-branches-C26hwmo3.js} +5 -5
  35. package/dist/node-host/assets/{project-thread-links-LpUAGcDr.js → project-thread-links-BOzjws5W.js} +12 -12
  36. package/dist/node-host/assets/{screen-DQoTOWYR.js → screen-Dog-YByu.js} +18 -18
  37. package/dist/node-host/assets/{tasks-C0WqnM7Q.js → tasks-A1_bpb3_.js} +30 -30
  38. package/dist/node-host/assets/{tasks-request-Bwky5ORf.js → tasks-request-Bie1PpQP.js} +7 -7
  39. package/dist/node-host/node-host.js +48 -29
  40. package/dist/server/assets/{branch-previews-BryeA_kA.js → branch-previews-ClkoJ0lM.js} +4 -2
  41. package/dist/server/assets/{canvas-D6tIkONI.js → canvas-Dn4RYoU2.js} +70 -42
  42. package/dist/server/assets/{comment-data-BuArfgcc.js → comment-data-B0OLHBGp.js} +7219 -1091
  43. package/dist/server/assets/{files-DkrEB48U.js → files-C5Vilfe4.js} +92 -89
  44. package/dist/server/assets/{listener-oKd5ETMj.js → listener-o1STuLju.js} +43 -29
  45. package/dist/server/assets/{pages-iEdmK_o2.js → pages-BNa0MHEc.js} +31 -22
  46. package/dist/server/assets/{project-branches-B7rtrvMl.js → project-branches-GtQYyOH5.js} +5 -5
  47. package/dist/server/assets/{project-thread-links-ue_ad9IX.js → project-thread-links-Nfz9NIny.js} +12 -12
  48. package/dist/server/assets/{project-work-6aOyja4v.js → project-work-Cy_BpHwR.js} +2 -2
  49. package/dist/server/assets/{screen-DMUB9a-K.js → screen-BtcJmZwj.js} +18 -18
  50. package/dist/server/assets/{server-DN5uwE4k.js → server-CYvuOSBA.js} +1 -1
  51. package/dist/server/assets/{services-Ber8opFE.js → services-DK4fqrlF.js} +2 -2
  52. package/dist/server/assets/{tasks-C2oa2wSC.js → tasks-B82tHwyQ.js} +31 -31
  53. package/dist/server/assets/{tasks-request-Bk5EoY_p.js → tasks-request-BtJBlkxV.js} +7 -6
  54. package/dist/server/capture.js +1 -1
  55. package/dist/server/migration.js +3 -3
  56. package/dist/server/runtime.js +4 -4
  57. package/dist/server/server.js +3 -3
  58. package/dist/types/assets/{config-Cuauq8xY.d.ts → config-DIC2cf_S.d.ts} +3 -0
  59. package/dist/types/assets/{contract-BsCQbbxD.d.ts → contract-CAT-XFNq.d.ts} +3 -1
  60. package/dist/types/companion.d.ts +1 -1
  61. package/dist/types/hosted.d.ts +2 -2
  62. package/dist/types/index.d.ts +1 -1
  63. package/dist/types/node-host.d.ts +2 -2
  64. package/dist/types/screen.d.ts +1 -1
  65. package/package.json +1 -1
  66. package/dist/client/assets/canvas-DxaIItAs.js +0 -1
  67. package/dist/client/assets/difference-worker-BpqPBs5g.js +0 -8
  68. package/dist/client/assets/files-C-7xoSt4.js +0 -1
  69. package/dist/client/assets/index-GPPa1XPO.js +0 -2
  70. package/dist/client/assets/pages-BVrTX_Eq.js +0 -1
  71. package/dist/client/assets/project-branches-DpxQx-T4.js +0 -1
  72. package/dist/client/assets/project-comments-D897aU5O.js +0 -1
  73. package/dist/client/assets/project-thread-links-Bp_TseD0.js +0 -1
  74. package/dist/client/assets/task-design-bktfn_Ok.js +0 -23
  75. package/dist/client/assets/tasks-Cqfj4fQN.js +0 -1
  76. package/dist/client/assets/tasks-request-mWMk9pBo.js +0 -1
  77. package/dist/client/assets/workspace-CznMN7F6.js +0 -2
@@ -1,9 +1,9 @@
1
1
  import { i as __toESM } from "./rolldown-runtime-DktXgydw.js";
2
- import { $ as FileSearchPanel, $n as resolveLanguage, A as parseEditorPreferences, An as reviewConflictIdentity, At as defaultReviewView, Bn as markWorkerErrorReported, Bt as fileHref, D as ReviewActionDialog, E as FileConflictPanel, F as FileWorkspace, Fn as areDiffTargetsEqual, Ft as reviewComparison, Gn as areThemesEqual, Gt as fileRoutes, Hn as renderFileWithHighlighter, Ht as readFileLocation, I as defaultFileDestination, In as WorkerPoolTaskCanceledError, It as reviewContextKey, Jn as validateResolvedThemeName, Kn as getSharedHighlighter, L as fileActionIntent, Ln as WorkerPoolTerminatedError, Lt as reviewHref, M as FileMutationDialog, Mn as renderDiffWithHighlighter, Mt as parseReviewSession, N as FileReviewPanel, Nn as areDiffRenderOptionsEqual, Nt as readReviewLocation, O as FileEditorPanel, On as createCodeAnchor, P as codeThemes, Pn as areFilesEqual, Pt as rememberReviewPosition, Qn as getResolvedOrResolveLanguage, R as mutationFileView, Rn as WorkerPoolWorkerError, Rt as closeFileTab, St as isCodeConversation, Tt as readConversationLocation, Un as areFileRenderOptionsEqual, Ut as reconcileFileView, Vn as isFilePlainText, Vt as parseFileView, Wn as hasResolvedThemes, Wt as rememberFile, Xn as themeResolver, Yn as attachResolvedThemes, Zn as getThemes, _r as parseFileSearchResult, ar as parseFileSaveRequest, br as parseFileIndex, bt as conversationHref, cn as toast, cr as parseMutationPlan, dn as Text, dr as parseReviewDiff, er as areLanguagesAttached, f as storeDocument, fr as parseReviewHistory, gr as parseFileSearchQuery, hr as parseReviewSource, ir as parseReviewActionResult, j as FileRecoveryDialog, jn as isDiffPlainText, k as defaultEditorPreferences, kn as parseFileUpdate, kt as defaultReviewPosition, l as projectStore, ln as readPreference, lr as parseMutationResult, m as storedFiles, mr as parseReviewSnapshot, nr as parseReviewActionPlan, or as parseFileSaveResult, p as storedDocument, pr as parseReviewRepository, qn as prepareThemeResolution, rr as parseReviewActionRecoveries, s as applyFileUpdate, sr as maxFileSaveBytes, t as commentsUnavailable, tr as ResolvedLanguages, tt as ConversationSidebar, u as saveFiles, un as writePreference, ur as parseRecoveries, v as projectLive, vr as parseFileChange, vt as codeCommentCounts, wt as locateCodeConversations, xr as parseFilePath, y as routes, yr as parseFileDocument, z as remainingMutationIntent, zn as isHandledWorkerPoolError, zt as defaultFileView } from "./comment-data-nUlI0szN.js";
2
+ import { $ as FileSearchPanel, $n as attachResolvedThemes, A as parseEditorPreferences, At as defaultReviewView, Bn as WorkerPoolTaskCanceledError, Bt as fileHref, Cr as parseFileDocument, D as ReviewActionDialog, E as FileConflictPanel, F as FileWorkspace, Fn as isDiffPlainText, Ft as reviewComparison, Gn as isFilePlainText, Gt as fileRoutes, Hn as WorkerPoolWorkerError, Ht as readFileLocation, I as defaultFileDestination, In as renderDiffWithHighlighter, It as reviewContextKey, Jn as hasResolvedThemes, Kn as renderFileWithHighlighter, L as fileActionIntent, Ln as areDiffRenderOptionsEqual, Lt as reviewHref, M as FileMutationDialog, Mn as createCodeAnchor, Mt as parseReviewSession, N as FileReviewPanel, Nn as parseFileUpdate, Nt as readReviewLocation, O as FileEditorPanel, P as codeThemes, Pn as reviewConflictIdentity, Pt as rememberReviewPosition, Qn as validateResolvedThemeName, R as mutationFileView, Rn as areFilesEqual, Rt as closeFileTab, Sr as parseFileChange, St as isCodeConversation, Tr as parseFilePath, Tt as readConversationLocation, Un as isHandledWorkerPoolError, Ut as reconcileFileView, Vn as WorkerPoolTerminatedError, Vt as parseFileView, Wn as markWorkerErrorReported, Wt as rememberFile, Xn as getSharedHighlighter, Yn as areThemesEqual, Zn as prepareThemeResolution, _r as parseReviewRepository, ar as ResolvedLanguages, br as parseFileSearchQuery, bt as conversationHref, cn as toast, cr as parseReviewActionResult, dr as maxFileSaveBytes, er as themeResolver, f as storeDocument, fr as parseMutationPlan, gr as parseReviewHistory, hn as Text, hr as parseReviewDiff, ir as areLanguagesAttached, j as FileRecoveryDialog, k as defaultEditorPreferences, kt as defaultReviewPosition, l as projectStore, ln as readPreference, lr as parseFileSaveRequest, m as storedFiles, mr as parseRecoveries, nr as getResolvedOrResolveLanguage, or as parseReviewActionPlan, p as storedDocument, pn as t, pr as parseMutationResult, qn as areFileRenderOptionsEqual, rr as resolveLanguage, s as applyFileUpdate, sr as parseReviewActionRecoveries, tr as getThemes, tt as ConversationSidebar, u as saveFiles, un as writePreference, ur as parseFileSaveResult, v as projectLive, vr as parseReviewSnapshot, vt as codeCommentCounts, wr as parseFileIndex, wt as locateCodeConversations, xr as parseFileSearchResult, y as routes, yr as parseReviewSource, z as remainingMutationIntent, zn as areDiffTargetsEqual, zt as defaultFileView } from "./comment-data-q_8INiZz.js";
3
3
  import { B as DEFAULT_THEMES, C as getFiletypeFromFileName, S as getCustomExtensionsVersion, x as getCustomExtensionsMap } from "./cloneFileDiffMetadata-C1BcNpxN.js";
4
- import { n as createProjectComments, t as defineScreen } from "./screen-DQoTOWYR.js";
4
+ import { n as createProjectComments, t as defineScreen } from "./screen-Dog-YByu.js";
5
5
  import { t as require_lru } from "./lru-C0_oUet4.js";
6
- import { t as ProjectThreadLinks } from "./project-thread-links-LpUAGcDr.js";
6
+ import { t as ProjectThreadLinks } from "./project-thread-links-BOzjws5W.js";
7
7
  import { ref } from "remix/component";
8
8
  import { jsx, jsxs } from "remix/component/jsx-runtime";
9
9
  //#region ../../node_modules/.pnpm/@pierre+diffs@1.5.2_@shikijs+themes@4.5.0_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@pierre/diffs/dist/highlighter/languages/getResolvedLanguages.js
@@ -1039,7 +1039,7 @@ var FilesRequestError = class extends Error {
1039
1039
  async function requestFiles(url, token, signal, parse, fetcher = fetch, action) {
1040
1040
  let parsed = new URL(url, "http://bud.invalid");
1041
1041
  let mutation = parsed.pathname === "/api/files/mutations/prepare" || parsed.pathname === "/api/files/mutations/apply" || parsed.pathname === "/api/files/review-actions/prepare" || parsed.pathname === "/api/files/review-actions/apply" || parsed.pathname === "/api/files/save";
1042
- if (!url.startsWith("/api/files") || url.startsWith("//") || parsed.origin !== "http://bud.invalid" || parsed.hash || !endpoints.has(parsed.pathname) || (parsed.pathname === "/api/files/refresh" || parsed.pathname === "/api/files/save" || parsed.pathname.startsWith("/api/files/review-actions/") || parsed.pathname.startsWith("/api/files/mutations/")) && parsed.search || mutation !== Boolean(action)) throw new FilesRequestError("Invalid file endpoint.", "input");
1042
+ if (!url.startsWith("/api/files") || url.startsWith("//") || parsed.origin !== "http://bud.invalid" || parsed.hash || !endpoints.has(parsed.pathname) || (parsed.pathname === "/api/files/refresh" || parsed.pathname === "/api/files/save" || parsed.pathname.startsWith("/api/files/review-actions/") || parsed.pathname.startsWith("/api/files/mutations/")) && parsed.search || mutation !== Boolean(action)) throw new FilesRequestError(t("app.client.filesRequest.invalidEndpoint"), "input");
1043
1043
  signal.throwIfAborted();
1044
1044
  let response = await fetcher(url, {
1045
1045
  method: mutation || parsed.pathname === "/api/files/refresh" ? "POST" : "GET",
@@ -1054,7 +1054,7 @@ async function requestFiles(url, token, signal, parse, fetcher = fetch, action)
1054
1054
  signal
1055
1055
  });
1056
1056
  let reader = response.body?.getReader();
1057
- if (!reader) throw new FilesRequestError("The file service returned an empty response.", "response", response.status);
1057
+ if (!reader) throw new FilesRequestError(t("app.client.filesRequest.emptyResponse"), "response", response.status);
1058
1058
  let chunks = [];
1059
1059
  let size = 0;
1060
1060
  let cancel = () => {
@@ -1068,7 +1068,7 @@ async function requestFiles(url, token, signal, parse, fetcher = fetch, action)
1068
1068
  signal.throwIfAborted();
1069
1069
  if (part.done) break;
1070
1070
  size += part.value.byteLength;
1071
- if (size > 16777216) throw new FilesRequestError("This file response exceeds the display limit. Narrow the file view and try again.", "limit", response.status);
1071
+ if (size > 16777216) throw new FilesRequestError(t("app.client.filesRequest.responseExceedsDisplayLimit"), "limit", response.status);
1072
1072
  chunks.push(part.value);
1073
1073
  }
1074
1074
  } catch (error) {
@@ -1088,13 +1088,13 @@ async function requestFiles(url, token, signal, parse, fetcher = fetch, action)
1088
1088
  try {
1089
1089
  value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
1090
1090
  } catch {
1091
- throw new FilesRequestError("The file service returned invalid data. Refresh and try again.", "response", response.status);
1091
+ throw new FilesRequestError(t("app.client.filesRequest.invalidData"), "response", response.status);
1092
1092
  }
1093
- if (!response.ok) throw new FilesRequestError(value && typeof value === "object" && "error" in value && typeof value.error === "string" ? value.error.slice(0, 1e3) : "Could not load files. Try again.", value && typeof value === "object" && "code" in value && typeof value.code === "string" ? value.code.slice(0, 100) : "request", response.status);
1093
+ if (!response.ok) throw new FilesRequestError(value && typeof value === "object" && "error" in value && typeof value.error === "string" ? value.error.slice(0, 1e3) : t("app.client.filesRequest.couldNotLoadFiles"), value && typeof value === "object" && "code" in value && typeof value.code === "string" ? value.code.slice(0, 100) : "request", response.status);
1094
1094
  try {
1095
1095
  return parse(value);
1096
1096
  } catch {
1097
- throw new FilesRequestError("The file service returned unexpected data. Refresh and try again.", "response", response.status);
1097
+ throw new FilesRequestError(t("app.client.filesRequest.unexpectedData"), "response", response.status);
1098
1098
  }
1099
1099
  }
1100
1100
  //#endregion
@@ -1125,17 +1125,17 @@ function createFileMutationGuards() {
1125
1125
  };
1126
1126
  }
1127
1127
  function message$4(cause) {
1128
- return cause instanceof Error ? cause.message : "The file action could not be completed.";
1128
+ return cause instanceof Error ? cause.message : t("app.client.fileMutationController.actionCouldNotBeCompleted");
1129
1129
  }
1130
1130
  function assertPlan(intent, plan) {
1131
- if (intent.kind !== plan.kind) throw new Error("The service returned a different file action.");
1131
+ if (intent.kind !== plan.kind) throw new Error(t("app.client.fileMutationController.differentFileAction"));
1132
1132
  if (intent.kind === "restore") return;
1133
1133
  let expected = "entries" in intent ? intent.entries.map((item) => [item.path, item.destination]) : intent.kind === "delete" ? intent.paths.map((source) => [source, null]) : [[null, intent.path]];
1134
1134
  let actual = plan.items.map((item) => [item.source, item.destination]);
1135
- if (JSON.stringify(expected) !== JSON.stringify(actual)) throw new Error("The service returned different file paths. Refresh before continuing.");
1135
+ if (JSON.stringify(expected) !== JSON.stringify(actual)) throw new Error(t("app.client.fileMutationController.differentFilePaths"));
1136
1136
  }
1137
1137
  function assertResult(plan, result) {
1138
- if (result.id !== plan.id || result.items.length !== plan.items.length || result.items.some((item, index) => item.source !== plan.items[index].source || item.destination !== plan.items[index].destination)) throw new Error("The file result does not match its confirmed plan. Refresh and check Recovery before retrying.");
1138
+ if (result.id !== plan.id || result.items.length !== plan.items.length || result.items.some((item, index) => item.source !== plan.items[index].source || item.destination !== plan.items[index].destination)) throw new Error(t("app.client.fileMutationController.resultDoesNotMatchPlan"));
1139
1139
  }
1140
1140
  /**
1141
1141
  * Coordinates validated plans without hiding partial results or retrying writes.
@@ -1214,7 +1214,7 @@ function createFileMutationController(options) {
1214
1214
  ...state,
1215
1215
  phase: "editing",
1216
1216
  plan: null,
1217
- error: "This confirmation expired. Review the current files again."
1217
+ error: t("app.client.fileMutationController.confirmationExpired")
1218
1218
  };
1219
1219
  changed();
1220
1220
  return;
@@ -1248,7 +1248,7 @@ function createFileMutationController(options) {
1248
1248
  try {
1249
1249
  await options.guards.afterApply(current, result);
1250
1250
  } catch (cause) {
1251
- draftError = `Files changed, but retained draft metadata could not be updated. ${message$4(cause)}`;
1251
+ draftError = t("app.client.fileMutationController.draftMetadataCouldNotBeUpdated", { error: message$4(cause) });
1252
1252
  }
1253
1253
  await options.onApplied(current, result);
1254
1254
  if (turn !== sequence || !state) return;
@@ -1273,7 +1273,7 @@ function createFileMutationController(options) {
1273
1273
  await options.onUncertain().catch(() => {});
1274
1274
  if (state && turn === sequence) state = {
1275
1275
  ...state,
1276
- error: `${message$4(cause)} Refresh and check Recovery before retrying.`
1276
+ error: t("app.client.fileMutationController.refreshAndCheckRecovery", { error: message$4(cause) })
1277
1277
  };
1278
1278
  }
1279
1279
  changed();
@@ -1417,7 +1417,7 @@ function comparisonQuery(comparison) {
1417
1417
  * @returns Exact source snapshots plus explicit per-file failures.
1418
1418
  */
1419
1419
  async function readReviewPage(snapshot, paths, token, signal, fetcher = fetch) {
1420
- if (paths.length > 20 || paths.some((path) => !snapshot.entries.some((entry) => entry.path === path))) throw new FilesRequestError("The selected files are outside this comparison page.", "input");
1420
+ if (paths.length > 20 || paths.some((path) => !snapshot.entries.some((entry) => entry.path === path))) throw new FilesRequestError(t("app.client.projectFileReviewData.filesOutsidePage"), "input");
1421
1421
  let result = /* @__PURE__ */ new Map();
1422
1422
  let failures = {};
1423
1423
  let cursor = 0;
@@ -1435,7 +1435,7 @@ async function readReviewPage(snapshot, paths, token, signal, fetcher = fetch) {
1435
1435
  query.set("expectedRevision", snapshot.revision);
1436
1436
  try {
1437
1437
  let diff = await requestFiles(`${routes.fileReviewApi.diff.href()}?${query}`, token, lifetime, parseReviewDiff, fetcher);
1438
- if (diff.entry.path !== path || diff.metadataRevision !== snapshot.revision || JSON.stringify(diff.comparison) !== JSON.stringify(snapshot.comparison)) throw new FilesRequestError("The comparison changed while reading. Refresh before continuing.", "changed", 409);
1438
+ if (diff.entry.path !== path || diff.metadataRevision !== snapshot.revision || JSON.stringify(diff.comparison) !== JSON.stringify(snapshot.comparison)) throw new FilesRequestError(t("app.client.projectFileReviewData.comparisonChanged"), "changed", 409);
1439
1439
  let bytes = [
1440
1440
  diff.oldFile,
1441
1441
  diff.newFile,
@@ -1443,14 +1443,14 @@ async function readReviewPage(snapshot, paths, token, signal, fetcher = fetch) {
1443
1443
  diff.conflict?.ours,
1444
1444
  diff.conflict?.theirs
1445
1445
  ].reduce((total, file) => total + (file?.contents?.length ?? 0) * 2, 0);
1446
- if (retainedBytes + bytes > 33554432) failures[path] = "This page reached its memory limit. Open this file individually.";
1446
+ if (retainedBytes + bytes > 33554432) failures[path] = t("app.client.projectFileReviewData.memoryLimit");
1447
1447
  else {
1448
1448
  retainedBytes += bytes;
1449
1449
  result.set(path, diff);
1450
1450
  }
1451
1451
  } catch (cause) {
1452
1452
  if (lifetime.aborted || cause instanceof FilesRequestError && (cause.status === 409 || cause.status === 401 || cause.status === 403)) throw cause;
1453
- failures[path] = cause instanceof Error ? cause.message : "Could not read this comparison.";
1453
+ failures[path] = cause instanceof Error ? cause.message : t("app.client.projectFileReviewData.couldNotReadComparison");
1454
1454
  }
1455
1455
  }
1456
1456
  } catch (cause) {
@@ -1502,19 +1502,19 @@ function within(path, parent) {
1502
1502
  */
1503
1503
  function parseDrafts(value, projectId) {
1504
1504
  if (!value) return [];
1505
- if (value.length > maxStoredCharacters) throw new Error("The local draft record exceeds its limit.");
1505
+ if (value.length > maxStoredCharacters) throw new Error(t("app.client.fileDrafts.recordExceedsLimit"));
1506
1506
  let parsed = JSON.parse(value);
1507
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Invalid local draft record.");
1507
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(t("app.client.fileDrafts.invalidRecord"));
1508
1508
  let record = parsed;
1509
1509
  if (record.version !== 1 || record.projectId !== projectId || !Array.isArray(record.drafts) || record.drafts.length > maxDrafts || Object.keys(record).some((key) => ![
1510
1510
  "version",
1511
1511
  "projectId",
1512
1512
  "drafts"
1513
- ].includes(key))) throw new Error("Invalid local draft record.");
1513
+ ].includes(key))) throw new Error(t("app.client.fileDrafts.invalidRecord"));
1514
1514
  let seen = /* @__PURE__ */ new Set();
1515
1515
  let total = 0;
1516
1516
  return record.drafts.map((input) => {
1517
- if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("Invalid local draft.");
1517
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error(t("app.client.fileDrafts.invalidDraft"));
1518
1518
  let item = input;
1519
1519
  if (Object.keys(item).some((key) => ![
1520
1520
  "id",
@@ -1523,7 +1523,7 @@ function parseDrafts(value, projectId) {
1523
1523
  "baseContents",
1524
1524
  "contents",
1525
1525
  "updatedAt"
1526
- ].includes(key)) || typeof item.id !== "string" || !/^[a-zA-Z0-9-]{1,80}$/.test(item.id) || !Number.isSafeInteger(item.updatedAt) || Number(item.updatedAt) < 0) throw new Error("Invalid local draft.");
1526
+ ].includes(key)) || typeof item.id !== "string" || !/^[a-zA-Z0-9-]{1,80}$/.test(item.id) || !Number.isSafeInteger(item.updatedAt) || Number(item.updatedAt) < 0) throw new Error(t("app.client.fileDrafts.invalidDraft"));
1527
1527
  parseFileSaveRequest({
1528
1528
  path: item.path,
1529
1529
  expectedRevision: item.baseRevision,
@@ -1535,10 +1535,10 @@ function parseDrafts(value, projectId) {
1535
1535
  contents: item.contents
1536
1536
  });
1537
1537
  let draft = item;
1538
- if (seen.has(draft.path)) throw new Error("Duplicate local draft path.");
1538
+ if (seen.has(draft.path)) throw new Error(t("app.client.fileDrafts.duplicateDraftPath"));
1539
1539
  seen.add(draft.path);
1540
1540
  total += bytes(draft);
1541
- if (total > maxDraftBytes) throw new Error("The local drafts exceed their memory limit.");
1541
+ if (total > maxDraftBytes) throw new Error(t("app.client.fileDrafts.draftsExceedMemoryLimit"));
1542
1542
  return { ...draft };
1543
1543
  });
1544
1544
  }
@@ -1556,7 +1556,7 @@ function createFileDrafts(projectId, storage, now = Date.now) {
1556
1556
  try {
1557
1557
  for (let draft of parseDrafts(storage?.getItem(key) ?? null, projectId)) drafts.set(draft.path, draft);
1558
1558
  } catch {
1559
- warning = "Local drafts could not be read. The stored record has been left untouched.";
1559
+ warning = t("app.client.fileDrafts.readFailed");
1560
1560
  }
1561
1561
  let unreadable = Boolean(warning);
1562
1562
  function persist() {
@@ -1572,16 +1572,16 @@ function createFileDrafts(projectId, storage, now = Date.now) {
1572
1572
  warning = "";
1573
1573
  return true;
1574
1574
  } catch {
1575
- warning = "This draft is kept in this tab only. Browser storage is unavailable or full; save or download it before closing the tab.";
1575
+ warning = t("app.client.fileDrafts.tabOnlyWarning");
1576
1576
  return false;
1577
1577
  }
1578
1578
  }
1579
1579
  function put(draft) {
1580
- if (encoder.encode(draft.contents).length > 2097152 || !draft.contents.isWellFormed() || draft.contents.includes("\0")) throw new Error("This draft exceeds the text editor limit or contains unsupported text. Undo the last edit before saving.");
1580
+ if (encoder.encode(draft.contents).length > 2097152 || !draft.contents.isWellFormed() || draft.contents.includes("\0")) throw new Error(t("app.client.fileDrafts.unsupportedDraftText"));
1581
1581
  let clean = [...drafts.values()].filter((item) => item.path !== draft.path && !draftDirty(item));
1582
1582
  for (let item of clean) drafts.delete(item.path);
1583
1583
  let others = [...drafts.values()].filter((item) => item.path !== draft.path);
1584
- if (others.length >= maxDrafts || others.reduce((sum, item) => sum + bytes(item), bytes(draft)) > maxDraftBytes) throw new Error("Save or discard another draft before editing more files. Your existing drafts have been kept.");
1584
+ if (others.length >= maxDrafts || others.reduce((sum, item) => sum + bytes(item), bytes(draft)) > maxDraftBytes) throw new Error(t("app.client.fileDrafts.draftLimitReached"));
1585
1585
  drafts.set(draft.path, draft);
1586
1586
  persist();
1587
1587
  return draft;
@@ -1615,7 +1615,7 @@ function createFileDrafts(projectId, storage, now = Date.now) {
1615
1615
  },
1616
1616
  change(path, contents) {
1617
1617
  let draft = drafts.get(path);
1618
- if (!draft) throw new Error("This draft is no longer open.");
1618
+ if (!draft) throw new Error(t("app.client.fileDrafts.draftNoLongerOpen"));
1619
1619
  return put({
1620
1620
  ...draft,
1621
1621
  contents,
@@ -1634,7 +1634,7 @@ function createFileDrafts(projectId, storage, now = Date.now) {
1634
1634
  },
1635
1635
  rebase(path, revision, contents) {
1636
1636
  let draft = drafts.get(path);
1637
- if (!draft) throw new Error("This draft is no longer open.");
1637
+ if (!draft) throw new Error(t("app.client.fileDrafts.draftNoLongerOpen"));
1638
1638
  return put({
1639
1639
  ...draft,
1640
1640
  id: crypto.randomUUID(),
@@ -1650,11 +1650,11 @@ function createFileDrafts(projectId, storage, now = Date.now) {
1650
1650
  persist,
1651
1651
  beforeMutation(intent, plan) {
1652
1652
  let dirty = [...drafts.values()].filter(draftDirty);
1653
- if (intent.kind === "delete" && dirty.some((draft) => intent.paths.some((path) => within(draft.path, path)))) return "Save or discard the unsaved drafts in this selection before deleting it.";
1654
- if (intent.kind === "restore" && dirty.some((draft) => plan.items.some((item) => item.destination && within(draft.path, item.destination)))) return "Save or discard the unsaved drafts at these original paths before restoring them.";
1653
+ if (intent.kind === "delete" && dirty.some((draft) => intent.paths.some((path) => within(draft.path, path)))) return t("app.client.fileDrafts.deleteWithUnsavedDrafts");
1654
+ if (intent.kind === "restore" && dirty.some((draft) => plan.items.some((item) => item.destination && within(draft.path, item.destination)))) return t("app.client.fileDrafts.restoreWithUnsavedDrafts");
1655
1655
  if (intent.kind === "move") {
1656
- if (dirty.some((draft) => intent.entries.some((entry) => within(draft.path, entry.destination) && !within(draft.path, entry.path)))) return "A destination has an unsaved draft. Save or discard it before moving files here.";
1657
- if (dirty.some((draft) => intent.entries.some((entry) => within(draft.path, entry.path))) && !persist()) return "Save or download your drafts before moving these files; local draft storage is unavailable.";
1656
+ if (dirty.some((draft) => intent.entries.some((entry) => within(draft.path, entry.destination) && !within(draft.path, entry.path)))) return t("app.client.fileDrafts.destinationHasDraft");
1657
+ if (dirty.some((draft) => intent.entries.some((entry) => within(draft.path, entry.path))) && !persist()) return t("app.client.fileDrafts.storageUnavailableForMove");
1658
1658
  }
1659
1659
  return null;
1660
1660
  },
@@ -1675,7 +1675,7 @@ function createFileDrafts(projectId, storage, now = Date.now) {
1675
1675
  }
1676
1676
  for (let { draft, path } of moved) {
1677
1677
  let destination = next.get(path);
1678
- if (destination && draftDirty(destination)) throw new Error("The destination acquired an unsaved draft while the move was running. Both drafts remain available at their original paths; download or review them before continuing.");
1678
+ if (destination && draftDirty(destination)) throw new Error(t("app.client.fileDrafts.destinationDraftConflict"));
1679
1679
  next.set(path, {
1680
1680
  ...draft,
1681
1681
  id: crypto.randomUUID(),
@@ -1710,7 +1710,7 @@ function projectFileDrafts(projectId, storage) {
1710
1710
  let existing = openProjects.get(projectId);
1711
1711
  if (existing) return existing;
1712
1712
  for (let [id, drafts] of openProjects) if (!drafts.dirty.length) openProjects.delete(id);
1713
- if (openProjects.size >= 4) throw new Error("Save or discard drafts in another project before opening more editors.");
1713
+ if (openProjects.size >= 4) throw new Error(t("app.client.fileDrafts.projectDraftLimitReached"));
1714
1714
  let drafts = createFileDrafts(projectId, storage);
1715
1715
  openProjects.set(projectId, drafts);
1716
1716
  return drafts;
@@ -1718,11 +1718,11 @@ function projectFileDrafts(projectId, storage) {
1718
1718
  //#endregion
1719
1719
  //#region app/client/file-editor-controller.ts
1720
1720
  function message$3(cause) {
1721
- return cause instanceof Error ? cause.message : "The file could not be saved. Your draft has been kept.";
1721
+ return cause instanceof Error ? cause.message : t("app.client.fileEditorController.saveFailed");
1722
1722
  }
1723
1723
  function readable(document, path) {
1724
- if (document.entry.path !== path) throw new Error("The source response belongs to another file.");
1725
- if (document.contents === null || !document.revision) throw new Error("Only regular UTF-8 text files within the editor size limit can be edited.");
1724
+ if (document.entry.path !== path) throw new Error(t("app.client.fileEditorController.wrongFileResponse"));
1725
+ if (document.contents === null || !document.revision) throw new Error(t("app.client.fileEditorController.unsupportedFile"));
1726
1726
  return {
1727
1727
  revision: document.revision,
1728
1728
  contents: document.contents
@@ -1766,7 +1766,7 @@ function createFileEditorController(options) {
1766
1766
  state = {
1767
1767
  ...state,
1768
1768
  conflict: true,
1769
- error: "This file changed outside the editor. Your draft has been kept. Compare with the latest file before saving."
1769
+ error: t("app.client.fileEditorController.changedOutsideEditor")
1770
1770
  };
1771
1771
  changed();
1772
1772
  }
@@ -1800,12 +1800,12 @@ function createFileEditorController(options) {
1800
1800
  contents: draft.baseContents
1801
1801
  },
1802
1802
  mode,
1803
- baselineLabel: useIndex ? "Index" : "Opened version",
1803
+ baselineLabel: useIndex ? t("app.client.fileEditorController.index") : t("app.client.fileEditorController.openedVersion"),
1804
1804
  saving: saves.has(path),
1805
1805
  conflict,
1806
1806
  latest: null,
1807
- error: conflict ? "This recovered draft belongs to an older file version. Compare it with the latest file before saving." : "",
1808
- status: draftDirty(draft) ? "Recovered unsaved draft." : ""
1807
+ error: conflict ? t("app.client.fileEditorController.recoveredDraftOldVersion") : "",
1808
+ status: draftDirty(draft) ? t("app.client.fileEditorController.recoveredUnsavedDraft") : ""
1809
1809
  };
1810
1810
  } catch (cause) {
1811
1811
  if (!signal.aborted) {
@@ -1822,12 +1822,12 @@ function createFileEditorController(options) {
1822
1822
  contents: retained.baseContents
1823
1823
  },
1824
1824
  mode: "file",
1825
- baselineLabel: "Opened version",
1825
+ baselineLabel: t("app.client.fileEditorController.openedVersion"),
1826
1826
  saving: saves.has(path),
1827
1827
  conflict: true,
1828
1828
  latest: null,
1829
- error: `The current project file could not be read. ${message$3(cause)}`,
1830
- status: "Your unsaved draft is available below. Download it, or restore the project file and compare with its latest contents before saving."
1829
+ error: t("app.client.fileEditorController.projectFileUnreadable", { detail: message$3(cause) }),
1830
+ status: t("app.client.fileEditorController.unsavedDraftAvailable")
1831
1831
  };
1832
1832
  else openError = message$3(cause);
1833
1833
  }
@@ -1873,7 +1873,7 @@ function createFileEditorController(options) {
1873
1873
  expectedRevision: draft.baseRevision,
1874
1874
  contents: draft.contents
1875
1875
  }, options.signal);
1876
- if (result.path !== draft.path || result.previousRevision !== draft.baseRevision) throw new Error("The save response belongs to a different file revision. Check the latest file before retrying.");
1876
+ if (result.path !== draft.path || result.previousRevision !== draft.baseRevision) throw new Error(t("app.client.fileEditorController.saveRevisionMismatch"));
1877
1877
  let next = options.drafts.acknowledge(draft.path, draft.contents, result.revision);
1878
1878
  if (state?.draft.path === draft.path && next) {
1879
1879
  state = {
@@ -1882,9 +1882,9 @@ function createFileEditorController(options) {
1882
1882
  status: "",
1883
1883
  error: ""
1884
1884
  };
1885
- if (result.refresh === "failed") toast.error("Saved, but the file browser could not refresh", { description: "Refresh it before continuing." });
1886
- else if (draftDirty(next)) toast.success("Saved to your project", { description: "Newer edits are still unsaved." });
1887
- else toast.success("Saved to your project");
1885
+ if (result.refresh === "failed") toast.error(t("app.client.fileEditorController.savedRefreshFailed"), { description: t("app.client.fileEditorController.refreshBeforeContinuing") });
1886
+ else if (draftDirty(next)) toast.success(t("app.client.fileEditorController.savedToProject"), { description: t("app.client.fileEditorController.newerEditsUnsaved") });
1887
+ else toast.success(t("app.client.fileEditorController.savedToProject"));
1888
1888
  }
1889
1889
  options.onSaved();
1890
1890
  } catch (cause) {
@@ -1928,11 +1928,11 @@ function createFileEditorController(options) {
1928
1928
  contents: current.contents
1929
1929
  },
1930
1930
  mode: "diff",
1931
- baselineLabel: "Latest file",
1931
+ baselineLabel: t("app.client.fileEditorController.latestFile"),
1932
1932
  latest: document,
1933
1933
  conflict: true,
1934
1934
  error: "",
1935
- status: "Your draft is on the new side. No file is changed until you review it and save."
1935
+ status: t("app.client.fileEditorController.draftOnNewSide")
1936
1936
  };
1937
1937
  } catch (cause) {
1938
1938
  if (!signal.aborted && state) state = {
@@ -1953,7 +1953,7 @@ function createFileEditorController(options) {
1953
1953
  latest: null,
1954
1954
  conflict: false,
1955
1955
  error: "",
1956
- status: "Reviewed against the latest file. Save when your merged draft is ready."
1956
+ status: t("app.client.fileEditorController.reviewedAgainstLatest")
1957
1957
  };
1958
1958
  changed();
1959
1959
  }
@@ -1986,7 +1986,7 @@ function createFileEditorController(options) {
1986
1986
  guard: {
1987
1987
  async beforeApply(intent, plan, signal) {
1988
1988
  signal.throwIfAborted();
1989
- if ([...saves].some((path) => plan.items.some((item) => item.source && inside(path, item.source) || item.destination && inside(path, item.destination)))) return "Wait for the file save to finish before changing these paths.";
1989
+ if ([...saves].some((path) => plan.items.some((item) => item.source && inside(path, item.source) || item.destination && inside(path, item.destination)))) return t("app.client.fileEditorController.waitForSave");
1990
1990
  return options.drafts.beforeMutation(intent, plan);
1991
1991
  },
1992
1992
  afterApply(intent, result) {
@@ -2000,7 +2000,7 @@ function createFileEditorController(options) {
2000
2000
  //#endregion
2001
2001
  //#region app/client/file-review-actions-controller.ts
2002
2002
  function message$2(cause) {
2003
- return cause instanceof Error ? cause.message : "The review action could not be completed. Refresh and inspect retained undo before trying again.";
2003
+ return cause instanceof Error ? cause.message : t("app.client.fileReviewActionsController.actionCouldNotBeCompleted");
2004
2004
  }
2005
2005
  /**
2006
2006
  * Runs review actions, such as staging or discarding changes, one at a time: plans one, applies
@@ -2044,7 +2044,7 @@ function createFileReviewActionsController(options) {
2044
2044
  if (intent.kind !== "undo") options.guard([intent.path], intent.kind === "discard" ? "worktree" : "index");
2045
2045
  let plan = await options.prepare(intent, signal);
2046
2046
  signal.throwIfAborted();
2047
- if (plan.kind !== intent.kind || intent.kind !== "undo" && !plan.paths.includes(intent.path)) throw new Error("The prepared review belongs to a different action or file.");
2047
+ if (plan.kind !== intent.kind || intent.kind !== "undo" && !plan.paths.includes(intent.path)) throw new Error(t("app.client.fileReviewActionsController.preparedReviewMismatch"));
2048
2048
  options.guard(plan.paths, plan.target);
2049
2049
  if (turn === generation) state = {
2050
2050
  phase: "ready",
@@ -2081,7 +2081,7 @@ function createFileReviewActionsController(options) {
2081
2081
  revision: plan.revision
2082
2082
  }, signal);
2083
2083
  signal.throwIfAborted();
2084
- if (result.id !== plan.id || result.target !== plan.target || result.changedPaths.some((path) => !plan.paths.includes(path))) throw new Error("The write response could not be confirmed. Refresh and inspect retained undo.");
2084
+ if (result.id !== plan.id || result.target !== plan.target || result.changedPaths.some((path) => !plan.paths.includes(path))) throw new Error(t("app.client.fileReviewActionsController.writeResponseUnconfirmed"));
2085
2085
  if (turn === generation) {
2086
2086
  let refreshError = "";
2087
2087
  try {
@@ -2210,11 +2210,11 @@ function reviewCommentSources(document, diffs, source) {
2210
2210
  * @returns The code anchor.
2211
2211
  */
2212
2212
  function captureCodeSelection(selection, sources, expectedRevision) {
2213
- if (selection.endSide && selection.endSide !== selection.side) throw new Error("Select consecutive lines on one side before commenting.");
2213
+ if (selection.endSide && selection.endSide !== selection.side) throw new Error(t("app.client.projectCodeComments.selectConsecutiveLines"));
2214
2214
  let side = selection.side === "deletions" ? "old" : "new";
2215
2215
  let source = sources.find((source) => (source.viewPath ?? source.path) === selection.path && (!source.side || source.side === side));
2216
- if (!source || source.contents === null || !source.revision) throw new Error("Comments require readable text with an exact source revision.");
2217
- if (expectedRevision && source.revision !== expectedRevision) throw new Error("Those lines belong to an older source. Select them again before commenting.");
2216
+ if (!source || source.contents === null || !source.revision) throw new Error(t("app.client.projectCodeComments.commentsRequireReadableText"));
2217
+ if (expectedRevision && source.revision !== expectedRevision) throw new Error(t("app.client.projectCodeComments.linesBelongToOlderSource"));
2218
2218
  return createCodeAnchor({
2219
2219
  path: source.path,
2220
2220
  revision: source.revision,
@@ -2262,7 +2262,7 @@ function createFileSearchController(options) {
2262
2262
  function notify() {
2263
2263
  if (!options.signal.aborted) options.onChange();
2264
2264
  }
2265
- function cancel(notice = "Search cancelled.") {
2265
+ function cancel(notice = t("app.client.fileSearchController.searchCancelled")) {
2266
2266
  active?.abort();
2267
2267
  active = void 0;
2268
2268
  state = {
@@ -2294,7 +2294,7 @@ function createFileSearchController(options) {
2294
2294
  try {
2295
2295
  let query = parseFileSearchQuery(input);
2296
2296
  let result = await options.request(query, signal);
2297
- if (fileSearchParameters(result.query).toString() !== fileSearchParameters(query).toString()) throw new FilesRequestError("The service returned results for a different search.", "response");
2297
+ if (fileSearchParameters(result.query).toString() !== fileSearchParameters(query).toString()) throw new FilesRequestError(t("app.client.fileSearchController.differentSearchResults"), "response");
2298
2298
  if (signal.aborted || active !== owner) return;
2299
2299
  state = {
2300
2300
  loading: false,
@@ -2307,7 +2307,7 @@ function createFileSearchController(options) {
2307
2307
  state = {
2308
2308
  loading: false,
2309
2309
  result: null,
2310
- error: cause instanceof Error ? cause.message : "Could not search this project.",
2310
+ error: cause instanceof Error ? cause.message : t("app.client.fileSearchController.searchFailed"),
2311
2311
  notice: ""
2312
2312
  };
2313
2313
  } finally {
@@ -2327,7 +2327,7 @@ function createFileSearchController(options) {
2327
2327
  * @returns A verified source-review position, or an explicit outdated-result error.
2328
2328
  */
2329
2329
  function searchMatchPosition(document, match) {
2330
- if (document.entry.path !== match.path || document.revision !== match.revision || document.entry.content !== "text" || typeof document.contents !== "string" || match.start < 0 || match.end < match.start || match.end > document.contents.length) throw new Error("This search result is outdated. Search again to locate the current text; any unsaved draft is retained.");
2330
+ if (document.entry.path !== match.path || document.revision !== match.revision || document.entry.content !== "text" || typeof document.contents !== "string" || match.start < 0 || match.end < match.start || match.end > document.contents.length) throw new Error(t("app.client.fileSearchController.outdatedResult"));
2331
2331
  let position = (offset) => {
2332
2332
  let line = 1, start = 0;
2333
2333
  for (let ending of document.contents.matchAll(/\r\n|\r|\n/g)) {
@@ -2342,7 +2342,7 @@ function searchMatchPosition(document, match) {
2342
2342
  };
2343
2343
  };
2344
2344
  let before = position(match.start), end = position(match.end);
2345
- if (before.line !== match.startLine || before.column !== match.startColumn || end.line !== match.endLine || end.column !== match.endColumn) throw new Error("This search result has invalid coordinates. Search again.");
2345
+ if (before.line !== match.startLine || before.column !== match.startColumn || end.line !== match.endLine || end.column !== match.endColumn) throw new Error(t("app.client.fileSearchController.invalidCoordinates"));
2346
2346
  return {
2347
2347
  page: 0,
2348
2348
  scroll: 0,
@@ -2357,7 +2357,7 @@ function searchMatchPosition(document, match) {
2357
2357
  //#endregion
2358
2358
  //#region app/client/project-file-review.tsx
2359
2359
  function message$1(cause) {
2360
- return cause instanceof Error ? cause.message : "Could not read the project.";
2360
+ return cause instanceof Error ? cause.message : t("app.client.projectFileReview.readProjectError");
2361
2361
  }
2362
2362
  /**
2363
2363
  * Owns validated review requests, the worker pool and bounded project view persistence.
@@ -2516,7 +2516,7 @@ function ProjectFileReview(handle) {
2516
2516
  try {
2517
2517
  if (immutable) {
2518
2518
  let next = await requestFiles(`${routes.fileReviewApi.source.href()}?${new URLSearchParams(immutable)}`, project.token, signal, parseReviewSource);
2519
- if (next.path !== immutable.path || next.commit !== immutable.commit) throw new FilesRequestError("The source response belongs to another commit or file.", "response");
2519
+ if (next.path !== immutable.path || next.commit !== immutable.commit) throw new FilesRequestError(t("app.client.projectFileReview.sourceResponseCommitMismatch"), "response");
2520
2520
  if (!signal.aborted) {
2521
2521
  source = next;
2522
2522
  displayedKey = nextDisplay;
@@ -2531,7 +2531,7 @@ function ProjectFileReview(handle) {
2531
2531
  changed();
2532
2532
  }
2533
2533
  let next = await requestFiles(`${routes.filesApi.read.href()}?${new URLSearchParams({ path: selected })}`, project.token, signal, parseFileDocument);
2534
- if (next.entry.path !== selected) throw new FilesRequestError("The source response belongs to another file.", "response");
2534
+ if (next.entry.path !== selected) throw new FilesRequestError(t("app.client.projectFileReview.sourceResponseFileMismatch"), "response");
2535
2535
  if (store) storeDocument(store, next).catch(() => {});
2536
2536
  if (!signal.aborted) {
2537
2537
  document = document?.revision === next.revision && document.entry.path === next.entry.path ? document : next;
@@ -2542,7 +2542,10 @@ function ProjectFileReview(handle) {
2542
2542
  pendingSearch = void 0;
2543
2543
  try {
2544
2544
  savePosition(searchMatchPosition(next, match), true);
2545
- searchNotice = `Search match at ${match.startLine}:${match.startColumn}. Any unsaved draft is retained.`;
2545
+ searchNotice = t("app.client.projectFileReview.searchMatchNotice", {
2546
+ line: match.startLine,
2547
+ column: match.startColumn
2548
+ });
2546
2549
  } catch (cause) {
2547
2550
  searchNotice = message$1(cause);
2548
2551
  }
@@ -2551,7 +2554,7 @@ function ProjectFileReview(handle) {
2551
2554
  }
2552
2555
  } else for (let attempt = 0; attempt < 2; attempt++) {
2553
2556
  let next = await requestFiles(`${routes.fileReviewApi.compare.href()}?${comparisonQuery(comparison)}`, project.token, signal, parseReviewSnapshot);
2554
- if (next.comparison.mode !== comparison.mode) throw new FilesRequestError("The service returned a different comparison.", "response");
2557
+ if (next.comparison.mode !== comparison.mode) throw new FilesRequestError(t("app.client.projectFileReview.comparisonMismatch"), "response");
2555
2558
  let page = Math.min(position().page, Math.max(0, Math.ceil(next.entries.length / 20) - 1));
2556
2559
  let restoredPath = position().selection?.path;
2557
2560
  if (restoredPath && settings.multiple && next.entries.some((entry) => entry.path === restoredPath)) page = Math.floor(next.entries.findIndex((entry) => entry.path === restoredPath) / 20);
@@ -2611,7 +2614,7 @@ function ProjectFileReview(handle) {
2611
2614
  changed();
2612
2615
  try {
2613
2616
  let next = await requestFiles(`${routes.fileReviewApi.history.href()}?${query}`, project.token, signal, parseReviewHistory);
2614
- if (next.path !== path) throw new FilesRequestError("The history response belongs to another path.", "response");
2617
+ if (next.path !== path) throw new FilesRequestError(t("app.client.projectFileReview.historyPathMismatch"), "response");
2615
2618
  if (!signal.aborted) history = next;
2616
2619
  } catch (cause) {
2617
2620
  if (!signal.aborted) historyError = message$1(cause);
@@ -2751,7 +2754,7 @@ function ProjectFileReview(handle) {
2751
2754
  commentError = "";
2752
2755
  try {
2753
2756
  let editing = editor?.state;
2754
- if (fromEditor && editing && (draftDirty(editing.draft) || editing.conflict || editing.saving)) throw new Error("Save this draft before creating a code comment. Existing discussions remain available, and your draft is kept.");
2757
+ if (fromEditor && editing && (draftDirty(editing.draft) || editing.conflict || editing.saving)) throw new Error(t("app.client.projectFileReview.saveDraftBeforeComment"));
2755
2758
  draftAnchor = captureCodeSelection(selection, fromEditor && editing && selection.side !== "deletions" ? [{
2756
2759
  path: editing.draft.path,
2757
2760
  revision: editing.draft.baseRevision,
@@ -2765,8 +2768,8 @@ function ProjectFileReview(handle) {
2765
2768
  changed();
2766
2769
  }
2767
2770
  async function createComment(body) {
2768
- if (!draftAnchor) throw new Error("Select code lines again before commenting.");
2769
- if (editor?.state && draftDirty(editor.state.draft)) throw new Error("Save your draft before sending this code comment. The message is kept.");
2771
+ if (!draftAnchor) throw new Error(t("app.client.projectFileReview.selectCodeLinesAgain"));
2772
+ if (editor?.state && draftDirty(editor.state.draft)) throw new Error(t("app.client.projectFileReview.saveDraftBeforeSendingComment"));
2770
2773
  selectedThread = (await handle.props.comments.write({
2771
2774
  anchor: draftAnchor,
2772
2775
  body
@@ -2804,11 +2807,11 @@ function ProjectFileReview(handle) {
2804
2807
  apply: (body, signal) => requestFiles(routes.fileReviewActionsApi.apply.href(), project.token, signal, parseReviewActionResult, fetch, { body }),
2805
2808
  recoveries: (signal) => requestFiles(routes.fileReviewActionsApi.recoveries.href(), project.token, signal, parseReviewActionRecoveries),
2806
2809
  guard(paths) {
2807
- if (editor?.state?.saving) throw new Error("Wait for the current save to finish before reviewing changes.");
2810
+ if (editor?.state?.saving) throw new Error(t("app.client.projectFileReview.waitForSaveBeforeReview"));
2808
2811
  if (paths.some((path) => {
2809
2812
  let draft = drafts?.get(path);
2810
2813
  return draft && draftDirty(draft);
2811
- })) throw new Error("Save or explicitly discard the unsaved draft for this file before applying review actions. Your draft has been kept.");
2814
+ })) throw new Error(t("app.client.projectFileReview.saveOrDiscardDraftBeforeActions"));
2812
2815
  },
2813
2816
  async onApplied(result) {
2814
2817
  if (result.target === "worktree") editor?.close();
@@ -2829,7 +2832,7 @@ function ProjectFileReview(handle) {
2829
2832
  if (handle.signal.aborted || reading === active || !reading) break;
2830
2833
  current = reading;
2831
2834
  }
2832
- if (error) throw new Error(`The write completed, but the review could not refresh: ${error}`);
2835
+ if (error) throw new Error(t("app.client.projectFileReview.writeCompletedRefreshError", { error }));
2833
2836
  },
2834
2837
  onChange: changed
2835
2838
  });
@@ -2965,7 +2968,7 @@ function ProjectFileReview(handle) {
2965
2968
  handle.queueTask(() => {
2966
2969
  owned.pool.setRenderOptions({ lineDiffType: session.view.highlights }).catch((cause) => {
2967
2970
  if (!handle.signal.aborted) {
2968
- error = `Could not update highlighting. ${message$1(cause)}`;
2971
+ error = t("app.client.projectFileReview.updateHighlightingError", { error: message$1(cause) });
2969
2972
  changed();
2970
2973
  }
2971
2974
  });
@@ -3064,7 +3067,7 @@ function ProjectFileReview(handle) {
3064
3067
  tone: "muted",
3065
3068
  role: "status",
3066
3069
  class: "shrink-0 border-b border-line px-3 py-1.5",
3067
- children: commentsUnavailable
3070
+ children: t("app.client.projectFileReview.commentsUnavailable")
3068
3071
  }) : null,
3069
3072
  searchNotice ? /* @__PURE__ */ jsx(Text, {
3070
3073
  as: "p",
@@ -3085,7 +3088,7 @@ function ProjectFileReview(handle) {
3085
3088
  variant: "ui-caption",
3086
3089
  role: "status",
3087
3090
  class: "sr-only",
3088
- children: "Reading current file for editing…"
3091
+ children: t("app.client.projectFileReview.readingFileForEditing")
3089
3092
  }) : null,
3090
3093
  editing && editor && merge?.path === editing.draft.path ? /* @__PURE__ */ jsx(FileConflictPanel, {
3091
3094
  chrome: handle.props.chrome,
@@ -3195,7 +3198,7 @@ function ProjectFileReview(handle) {
3195
3198
  onResolve: (diff) => {
3196
3199
  resolveConflict(diff);
3197
3200
  },
3198
- editLabel: handle.props.path && drafts?.get(handle.props.path) && draftDirty(drafts.get(handle.props.path)) ? "Resume draft" : "Edit file",
3201
+ editLabel: handle.props.path && drafts?.get(handle.props.path) && draftDirty(drafts.get(handle.props.path)) ? t("app.client.projectFileReview.resumeDraft") : t("app.client.projectFileReview.editFile"),
3199
3202
  onChange: changeView,
3200
3203
  onPosition: savePosition,
3201
3204
  onSelect: selectPath,
@@ -3306,7 +3309,7 @@ function ProjectFileReview(handle) {
3306
3309
  //#endregion
3307
3310
  //#region app/client/project-files.tsx
3308
3311
  function message(error) {
3309
- return error instanceof Error ? error.message : "Could not load project files.";
3312
+ return error instanceof Error ? error.message : t("app.client.projectFiles.couldNotLoadProjectFiles");
3310
3313
  }
3311
3314
  function requestProjectFiles(token, view, signal) {
3312
3315
  let params = new URLSearchParams({
@@ -3459,8 +3462,8 @@ function ProjectFiles(handle) {
3459
3462
  async onApplied(intent, result) {
3460
3463
  view = mutationFileView(view, intent.kind, result);
3461
3464
  let count = result.items.filter((item) => item.status === "applied").length;
3462
- if (count) toast.success(`${count} file action${count === 1 ? "" : "s"} completed`, { description: result.recoveryId ? "Original contents are available in Recovery." : void 0 });
3463
- else toast.error("The file action could not be applied", { description: "Your project was refreshed." });
3465
+ if (count) toast.success(t("app.client.projectFiles.fileActionsCompleted", { count }), { description: result.recoveryId ? t("app.client.projectFiles.originalContentsAvailableInRecovery") : void 0 });
3466
+ else toast.error(t("app.client.projectFiles.fileActionCouldNotBeApplied"), { description: t("app.client.projectFiles.projectWasRefreshed") });
3464
3467
  location(true);
3465
3468
  persist();
3466
3469
  pendingContentRefresh = true;
@@ -3523,7 +3526,7 @@ function ProjectFiles(handle) {
3523
3526
  function closeTab(path) {
3524
3527
  if (dirty.includes(path)) {
3525
3528
  select(path, [path]);
3526
- toast("Save or discard this draft to close its tab");
3529
+ toast(t("app.client.projectFiles.saveOrDiscardDraftToCloseTab"));
3527
3530
  changed();
3528
3531
  return;
3529
3532
  }
@@ -3635,7 +3638,7 @@ function ProjectFiles(handle) {
3635
3638
  }, { once: true });
3636
3639
  });
3637
3640
  function foreignNotice(foreign) {
3638
- notice = foreign ? "This file link belongs to another project. Choose a file from this project to continue." : "";
3641
+ notice = foreign ? t("app.client.projectFiles.fileLinkBelongsToAnotherProject") : "";
3639
3642
  }
3640
3643
  return () => {
3641
3644
  if (renderedHref !== handle.props.href) {