diff --git a/apps/web/components/github/issue-watch-dialog.tsx b/apps/web/components/github/issue-watch-dialog.tsx
index 946cfdc8af..454d43f1e6 100644
--- a/apps/web/components/github/issue-watch-dialog.tsx
+++ b/apps/web/components/github/issue-watch-dialog.tsx
@@ -31,7 +31,7 @@ import {
DEFAULT_ISSUE_WATCH_PROMPT,
} from "@/components/github/issue-watch-placeholders";
import { RepoFilterSelector } from "@/components/github/repo-filter-selector";
-import { STEP_DEFAULT, STEP_DEFAULT_LABEL, resolveProfileId } from "@/lib/watcher-profile-default";
+import { STEP_DEFAULT, resolveProfileId } from "@/lib/watcher-profile-default";
import type {
RepoFilter,
IssueWatch,
@@ -271,6 +271,7 @@ function IssueAutomationFields({
}) {
const { t } = useTranslation();
const { workflows, agentProfiles, allExecutorProfiles } = useWatchFormData(form.workspaceId);
+ const stepDefaultLabel = t("common:useStepDefaultOption");
const { steps: workflowSteps, loading: stepsLoading } = useWorkflowSteps(form.workflowId);
const placeholders = useMemo(() => issueWatchPlaceholders(t), [t]);
@@ -302,9 +303,9 @@ function IssueAutomationFields({
description={t("github:optionalFallsBackToStepDefault")}
value={form.agentProfileId || STEP_DEFAULT}
onChange={(v) => setForm((prev) => ({ ...prev, agentProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...agentProfiles.map((p) => ({
id: p.id,
label: p.label,
@@ -317,9 +318,9 @@ function IssueAutomationFields({
description={t("github:optionalFallsBackToStepDefault")}
value={form.executorProfileId || STEP_DEFAULT}
onChange={(v) => setForm((prev) => ({ ...prev, executorProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...allExecutorProfiles.map((p) => ({ id: p.id, label: p.name })),
]}
/>
diff --git a/apps/web/components/github/review-watch-dialog.tsx b/apps/web/components/github/review-watch-dialog.tsx
index 9e7bb7dc4b..986b221fa4 100644
--- a/apps/web/components/github/review-watch-dialog.tsx
+++ b/apps/web/components/github/review-watch-dialog.tsx
@@ -29,7 +29,7 @@ import {
import { DEFAULT_REVIEW_WATCH_PROMPT } from "@/components/github/review-watch-placeholders";
import { ReviewWatchPromptField } from "@/components/github/review-watch-prompt-field";
import { RepoFilterSelector } from "@/components/github/repo-filter-selector";
-import { STEP_DEFAULT, STEP_DEFAULT_LABEL, resolveProfileId } from "@/lib/watcher-profile-default";
+import { STEP_DEFAULT, resolveProfileId } from "@/lib/watcher-profile-default";
import type {
RepoFilter,
ReviewWatch,
@@ -433,6 +433,7 @@ function ProfileFields({
executorProfiles: Array<{ id: string; name: string }>;
}) {
const { t } = useTranslation();
+ const stepDefaultLabel = t("common:useStepDefaultOption");
return (
setForm((prev) => ({ ...prev, agentProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...agentProfiles.map((p) => ({
id: p.id,
label: p.label,
@@ -469,10 +470,10 @@ function ProfileFields({
}
>
-
+
- {STEP_DEFAULT_LABEL}
+ {stepDefaultLabel}
{executorProfiles.map((p) => (
{p.name}
diff --git a/apps/web/components/gitlab/watch-dialog.tsx b/apps/web/components/gitlab/watch-dialog.tsx
index 4cd07ef2c6..50b2266e4d 100644
--- a/apps/web/components/gitlab/watch-dialog.tsx
+++ b/apps/web/components/gitlab/watch-dialog.tsx
@@ -21,7 +21,7 @@ import { WatcherRepositoryFields } from "@/components/watcher-repository-fields"
import { useSettingsData } from "@/hooks/domains/settings/use-settings-data";
import { useWorkflowSteps, stepPlaceholder } from "@/hooks/use-workflow-steps";
import { useWorkflows } from "@/hooks/use-workflows";
-import { STEP_DEFAULT, STEP_DEFAULT_LABEL, resolveProfileId } from "@/lib/watcher-profile-default";
+import { STEP_DEFAULT, resolveProfileId } from "@/lib/watcher-profile-default";
import type {
CreateIssueWatchRequest,
CreateReviewWatchRequest,
@@ -205,6 +205,7 @@ type FormFieldsProps = {
function AutomationFields({ kind, form, setForm }: FormFieldsProps) {
const { t } = useTranslation();
+ const stepDefaultLabel = t("common:useStepDefaultOption");
const data = useDialogData(form.workspaceId, form.workflowId);
return (
@@ -247,9 +248,9 @@ function AutomationFields({ kind, form, setForm }: FormFieldsProps) {
onChange={(value) =>
setForm((current) => ({ ...current, agentProfileId: resolveProfileId(value) }))
}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...data.agentProfiles.map((item) => ({ id: item.id, label: item.label })),
]}
/>
@@ -260,9 +261,9 @@ function AutomationFields({ kind, form, setForm }: FormFieldsProps) {
onChange={(value) =>
setForm((current) => ({ ...current, executorProfileId: resolveProfileId(value) }))
}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...data.executorProfiles.map((item) => ({ id: item.id, label: item.name })),
]}
/>
diff --git a/apps/web/components/jira/jira-issue-watch-dialog.tsx b/apps/web/components/jira/jira-issue-watch-dialog.tsx
index dc58416ad2..257a4d5eb5 100644
--- a/apps/web/components/jira/jira-issue-watch-dialog.tsx
+++ b/apps/web/components/jira/jira-issue-watch-dialog.tsx
@@ -31,7 +31,7 @@ import {
jiraIssueWatchPlaceholders,
DEFAULT_JIRA_ISSUE_WATCH_PROMPT,
} from "@/components/jira/jira-issue-watch-placeholders";
-import { STEP_DEFAULT, STEP_DEFAULT_LABEL, resolveProfileId } from "@/lib/watcher-profile-default";
+import { STEP_DEFAULT, resolveProfileId } from "@/lib/watcher-profile-default";
import { WatcherRepositoryFields } from "@/components/watcher-repository-fields";
import { clearWorkspaceScopedForm } from "@/lib/watcher-repository-default";
import type {
@@ -339,6 +339,7 @@ function AutomationFields({
setForm: React.Dispatch
>;
}) {
const { t } = useTranslation();
+ const stepDefaultLabel = t("common:useStepDefaultOption");
const { workflows, agentProfiles, allExecutorProfiles } = useFormData(form.workspaceId);
const { steps, loading: stepsLoading } = useWorkflowSteps(form.workflowId);
return (
@@ -377,9 +378,9 @@ function AutomationFields({
description={t("jira:optionalFallsBackToStepDefault")}
value={form.agentProfileId || STEP_DEFAULT}
onChange={(v) => setForm((p) => ({ ...p, agentProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...agentProfiles.map((p) => ({
id: p.id,
label: p.label,
@@ -392,9 +393,9 @@ function AutomationFields({
description={t("jira:optionalFallsBackToStepDefault")}
value={form.executorProfileId || STEP_DEFAULT}
onChange={(v) => setForm((p) => ({ ...p, executorProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...allExecutorProfiles.map((p) => ({ id: p.id, label: p.name })),
]}
/>
diff --git a/apps/web/components/linear/linear-issue-watch-dialog.tsx b/apps/web/components/linear/linear-issue-watch-dialog.tsx
index 7e2b561a3b..553ac95ce3 100644
--- a/apps/web/components/linear/linear-issue-watch-dialog.tsx
+++ b/apps/web/components/linear/linear-issue-watch-dialog.tsx
@@ -26,7 +26,7 @@ import {
import { SettingsFields } from "./linear-issue-watch-fields";
import { FilterFields, SelectField } from "./linear-issue-watch-filter-fields";
import { linearIssueWatchPlaceholders } from "./linear-issue-watch-placeholders";
-import { STEP_DEFAULT, STEP_DEFAULT_LABEL, resolveProfileId } from "@/lib/watcher-profile-default";
+import { STEP_DEFAULT, resolveProfileId } from "@/lib/watcher-profile-default";
import { WatcherRepositoryFields } from "@/components/watcher-repository-fields";
import { clearWorkspaceScopedForm } from "@/lib/watcher-repository-default";
import {
@@ -159,6 +159,7 @@ function AutomationFields({
setForm: React.Dispatch>;
}) {
const { t } = useTranslation();
+ const stepDefaultLabel = t("common:useStepDefaultOption");
const { workflows, agentProfiles, allExecutorProfiles } = useFormData(form.workspaceId);
const { steps, loading: stepsLoading } = useWorkflowSteps(form.workflowId);
return (
@@ -197,9 +198,9 @@ function AutomationFields({
description={t("linear:fallsBackToStepDefault")}
value={form.agentProfileId || STEP_DEFAULT}
onChange={(v) => setForm((p) => ({ ...p, agentProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...agentProfiles.map((p) => ({
id: p.id,
label: p.label,
@@ -212,9 +213,9 @@ function AutomationFields({
description={t("linear:fallsBackToStepDefault")}
value={form.executorProfileId || STEP_DEFAULT}
onChange={(v) => setForm((p) => ({ ...p, executorProfileId: resolveProfileId(v) }))}
- placeholder={STEP_DEFAULT_LABEL}
+ placeholder={stepDefaultLabel}
items={[
- { id: STEP_DEFAULT, label: STEP_DEFAULT_LABEL },
+ { id: STEP_DEFAULT, label: stepDefaultLabel },
...allExecutorProfiles.map((p) => ({ id: p.id, label: p.name })),
]}
/>
diff --git a/apps/web/components/task/chat/messages/chat-message.test.tsx b/apps/web/components/task/chat/messages/chat-message.test.tsx
index 6bf3e4c8a5..1a81653933 100644
--- a/apps/web/components/task/chat/messages/chat-message.test.tsx
+++ b/apps/web/components/task/chat/messages/chat-message.test.tsx
@@ -1,10 +1,11 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import type { ReactNode } from "react";
-import { cleanup, fireEvent, render, screen } from "@testing-library/react";
+import { act, cleanup, fireEvent, render, screen } from "@testing-library/react";
import { StateProvider } from "@/components/state-provider";
import { ChatMessage } from "./chat-message";
import { entityReferenceMarkdown } from "@/lib/entity-references/message-references";
import type { EntityReference } from "@/lib/types/entity-reference";
+import { activateLocale } from "@/lib/i18n";
import {
sessionId as toSessionId,
taskId as toTaskId,
@@ -370,6 +371,26 @@ describe("ChatMessage sender badge", () => {
expect(badge?.textContent).toContain("Old title");
});
+ it("localizes the fallback when no sender task title is available", async () => {
+ await activateLocale("en");
+ const { container } = renderWithSender([], {
+ sender_task_id: "task-deleted",
+ sender_task_title: "",
+ });
+
+ const badge = container.querySelector(SENDER_BADGE_SELECTOR);
+ expect(badge?.textContent).toContain("(unknown task)");
+
+ await act(async () => {
+ await activateLocale("pseudo");
+ });
+
+ expect(badge?.textContent).toContain("(ũńķńōŵń ţàśķ)");
+ await act(async () => {
+ await activateLocale("en");
+ });
+ });
+
it("uses the live title when it differs from the snapshot", () => {
// The badge re-resolves the title from the kanban store so renames are
// reflected without re-sending the message.
diff --git a/apps/web/components/task/chat/messages/sender-task-badge.tsx b/apps/web/components/task/chat/messages/sender-task-badge.tsx
index e849f0e713..4b2f498fba 100644
--- a/apps/web/components/task/chat/messages/sender-task-badge.tsx
+++ b/apps/web/components/task/chat/messages/sender-task-badge.tsx
@@ -50,7 +50,7 @@ export function SenderTaskBadge({ sender, size = "sm" }: SenderTaskBadgeProps) {
const liveSessionName = useAppStore((state) =>
sender.sessionId ? (state.taskSessions.items[sender.sessionId]?.name ?? null) : null,
);
- const fullTitle = liveTask?.title || sender.snapshotTitle || "(unknown task)";
+ const fullTitle = liveTask?.title || sender.snapshotTitle || t("task:unknownTaskFallback");
const sessionName = liveSessionName ?? sender.sessionName ?? "";
const truncated = sessionName
? `${truncateTitle(fullTitle)} · ${truncateTitle(sessionName)}`
diff --git a/apps/web/components/watcher-repository-fields.test.tsx b/apps/web/components/watcher-repository-fields.test.tsx
new file mode 100644
index 0000000000..6cc156ba67
--- /dev/null
+++ b/apps/web/components/watcher-repository-fields.test.tsx
@@ -0,0 +1,49 @@
+import { cleanup, render, screen } from "@testing-library/react";
+import { afterEach, describe, expect, it, vi } from "vitest";
+import { WatcherRepositoryFields } from "./watcher-repository-fields";
+
+const branchState = vi.hoisted(() => ({ loading: false }));
+
+vi.mock("@/hooks/domains/workspace/use-repositories", () => ({
+ useRepositories: () => ({ repositories: [] }),
+}));
+
+vi.mock("@/hooks/domains/workspace/use-repository-branches", () => ({
+ useBranches: () => ({ branches: [], isLoading: branchState.loading }),
+}));
+
+afterEach(() => {
+ cleanup();
+ branchState.loading = false;
+});
+
+describe("WatcherRepositoryFields", () => {
+ it("shows the repository-first placeholder while the branch selector is disabled", () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByLabelText("Base Branch").textContent).toContain("Pick a repository first");
+ });
+
+ it("shows the loading placeholder instead of selecting the default branch", () => {
+ branchState.loading = true;
+ render(
+ ,
+ );
+
+ expect(screen.getByLabelText("Base Branch").textContent).toContain("Loading…");
+ });
+});
diff --git a/apps/web/components/watcher-repository-fields.tsx b/apps/web/components/watcher-repository-fields.tsx
index c63470f21c..2e94be11ff 100644
--- a/apps/web/components/watcher-repository-fields.tsx
+++ b/apps/web/components/watcher-repository-fields.tsx
@@ -7,9 +7,7 @@ import { useRepositories } from "@/hooks/domains/workspace/use-repositories";
import { useBranches } from "@/hooks/domains/workspace/use-repository-branches";
import {
NO_REPOSITORY,
- NO_REPOSITORY_LABEL,
DEFAULT_BRANCH,
- DEFAULT_BRANCH_LABEL,
branchPlaceholder,
resolveBaseBranch,
resolveRepositoryId,
@@ -21,7 +19,7 @@ type PickItem = { id: string; label: string };
function PickSelect(props: {
label: string;
description: string;
- value: string;
+ value: string | undefined;
onChange: (v: string) => void;
placeholder: string;
items: PickItem[];
@@ -83,6 +81,15 @@ export function WatcherRepositoryFields({
const { repositories } = useRepositories(workspaceId, !!workspaceId, true);
const branchSource = repositoryId ? ({ kind: "id", workspaceId, repositoryId } as const) : null;
const { branches, isLoading: branchesLoading } = useBranches(branchSource, !!repositoryId);
+ const noRepositoryLabel = t("common:noRepositoryOption");
+ const defaultBranchLabel = t("common:repositoryDefaultBranchOption");
+ const branchPlaceholderLabels = {
+ defaultBranch: defaultBranchLabel,
+ loading: t("common:watcherLoadingBranchesPlaceholder"),
+ pickRepository: t("common:watcherPickRepositoryPlaceholder"),
+ };
+ const branchPlaceholderLabel =
+ branchPlaceholderLabels[branchPlaceholder(repositoryId, branchesLoading)];
// A branch name can appear twice (local + remote tracking, e.g. "main" and
// origin/"main"), which would emit two — Radix then
// renders every matching item's text in the trigger ("mainmain") and React
@@ -95,20 +102,20 @@ export function WatcherRepositoryFields({
description={t("common:optionalTheRepositoryTheAgentWorks")}
value={repositoryId || NO_REPOSITORY}
onChange={(v) => onRepositoryChange(resolveRepositoryId(v))}
- placeholder={NO_REPOSITORY_LABEL}
+ placeholder={noRepositoryLabel}
items={[
- { id: NO_REPOSITORY, label: NO_REPOSITORY_LABEL },
+ { id: NO_REPOSITORY, label: noRepositoryLabel },
...repositories.map((r) => ({ id: r.id, label: r.name })),
]}
/>
onBaseBranchChange(resolveBaseBranch(v))}
- placeholder={branchPlaceholder(repositoryId, branchesLoading)}
+ placeholder={branchPlaceholderLabel}
items={[
- { id: DEFAULT_BRANCH, label: DEFAULT_BRANCH_LABEL },
+ { id: DEFAULT_BRANCH, label: defaultBranchLabel },
...uniqueBranchNames.map((name) => ({ id: name, label: name })),
]}
disabled={!repositoryId || branchesLoading}
diff --git a/apps/web/e2e/tests/i18n/pseudo-coverage.spec.ts b/apps/web/e2e/tests/i18n/pseudo-coverage.spec.ts
index f4790cff9d..c7da1d52e1 100644
--- a/apps/web/e2e/tests/i18n/pseudo-coverage.spec.ts
+++ b/apps/web/e2e/tests/i18n/pseudo-coverage.spec.ts
@@ -422,10 +422,8 @@ const SCREENS: Screen[] = [
// the nav. `components/integrations/**` is now migrated, which cleared
// `drafted-integration-enabled-control.tsx` ("Enabled"/"Disabled"),
// `auth-status-banner.tsx` ("Authenticated", "· checked ") and the
- // watcher card's loading state. What is left is
- // `components/watcher-repository-fields.tsx` ("Repository", "Base Branch",
- // "(no repository)"), `STEP_DEFAULT_LABEL` and `stepPlaceholder` — all shared
- // with the un-migrated Azure DevOps surface — plus
+ // watcher card's loading state. What is left is `stepPlaceholder`, shared
+ // with the un-migrated Azure DevOps surface, plus
// `components/integrations/settings-section.tsx` chrome and `@kandev/ui`'s
// built-in dialog "Close" label.
//
diff --git a/apps/web/lib/watcher-profile-default.ts b/apps/web/lib/watcher-profile-default.ts
index 118f1e102a..cee8e4afd0 100644
--- a/apps/web/lib/watcher-profile-default.ts
+++ b/apps/web/lib/watcher-profile-default.ts
@@ -5,7 +5,6 @@
// disallows , so the dropdown item carries this sentinel
// value and maps back to "" on change.
export const STEP_DEFAULT = "__step_default__";
-export const STEP_DEFAULT_LABEL = "(use step default)";
// Map a select value back to the stored profile id, collapsing the sentinel to
// "" so the payload keeps signalling "use step default".
diff --git a/apps/web/lib/watcher-repository-default.test.ts b/apps/web/lib/watcher-repository-default.test.ts
index a5c77ad7f6..da2e2b9865 100644
--- a/apps/web/lib/watcher-repository-default.test.ts
+++ b/apps/web/lib/watcher-repository-default.test.ts
@@ -2,7 +2,6 @@ import { describe, it, expect } from "vitest";
import {
NO_REPOSITORY,
DEFAULT_BRANCH,
- DEFAULT_BRANCH_LABEL,
resolveRepositoryId,
resolveBaseBranch,
clearWorkspaceScopedForm,
@@ -29,15 +28,15 @@ describe("resolveBaseBranch", () => {
describe("branchPlaceholder", () => {
it("prompts to pick a repository first when none is selected", () => {
- expect(branchPlaceholder("", false)).toBe("Pick a repository first");
+ expect(branchPlaceholder("", false)).toBe("pickRepository");
// No repo takes precedence over the loading state.
- expect(branchPlaceholder("", true)).toBe("Pick a repository first");
+ expect(branchPlaceholder("", true)).toBe("pickRepository");
});
it("shows a loading hint while branches stream in", () => {
- expect(branchPlaceholder("repo-1", true)).toBe("Loading…");
+ expect(branchPlaceholder("repo-1", true)).toBe("loading");
});
it("shows the default-branch label once a repo is selected and loaded", () => {
- expect(branchPlaceholder("repo-1", false)).toBe(DEFAULT_BRANCH_LABEL);
+ expect(branchPlaceholder("repo-1", false)).toBe("defaultBranch");
});
});
diff --git a/apps/web/lib/watcher-repository-default.ts b/apps/web/lib/watcher-repository-default.ts
index 054885a481..37625b19ee 100644
--- a/apps/web/lib/watcher-repository-default.ts
+++ b/apps/web/lib/watcher-repository-default.ts
@@ -11,9 +11,7 @@
// or repository id (which would otherwise let resolve*() silently rewrite a
// user's selection).
export const NO_REPOSITORY = "kandev:no-repository";
-export const NO_REPOSITORY_LABEL = "(no repository)";
export const DEFAULT_BRANCH = "kandev:default-branch";
-export const DEFAULT_BRANCH_LABEL = "(repository default branch)";
// Map a repository select value back to the stored id, collapsing the sentinel
// to "" so the payload keeps signalling "no repository".
@@ -56,8 +54,10 @@ export function clearWorkspaceScopedForm<
// branchPlaceholder mirrors the workflow-step placeholder pattern: it nudges the
// user to pick a repository first, then shows a loading hint while branches
// stream in.
-export function branchPlaceholder(repositoryId: string, loading: boolean): string {
- if (!repositoryId) return "Pick a repository first";
- if (loading) return "Loading…";
- return DEFAULT_BRANCH_LABEL;
+export type BranchPlaceholder = "pickRepository" | "loading" | "defaultBranch";
+
+export function branchPlaceholder(repositoryId: string, loading: boolean): BranchPlaceholder {
+ if (!repositoryId) return "pickRepository";
+ if (loading) return "loading";
+ return "defaultBranch";
}
diff --git a/apps/web/src/locales/en/agents.json b/apps/web/src/locales/en/agents.json
index fbd4940984..d16b6d20d5 100644
--- a/apps/web/src/locales/en/agents.json
+++ b/apps/web/src/locales/en/agents.json
@@ -161,7 +161,6 @@
"profileNameRequiredTitle": "Profile name is required",
"profileNotFound": "Profile not found.",
"profileSettings": "Profile settings",
- "profileStartModelSettings": "Profile start model settings",
"promptTokenHint": "<0>{{token}}0> will be replaced with your task description or follow-up message.",
"ptyConnectionError": "Connection error",
"refresh": "Refresh",
@@ -185,7 +184,6 @@
"scanningForInstalledAgents": "Scanning for installed agents...",
"searchModels": "Search models...",
"searchModes": "Search modes...",
- "selectAModel": "Select a model...",
"selectAModelShort": "Select a model",
"selectModel": "Select model...",
"sessionEnded": "Session ended.",
diff --git a/apps/web/src/locales/en/common.json b/apps/web/src/locales/en/common.json
index 76c06c8b93..b8e520bcf0 100644
--- a/apps/web/src/locales/en/common.json
+++ b/apps/web/src/locales/en/common.json
@@ -319,6 +319,8 @@
"reloadTheApplicationToTryAgain": "Reload the application to try again.",
"rename": "Rename",
"repository": "Repository",
+ "noRepositoryOption": "(no repository)",
+ "repositoryDefaultBranchOption": "(repository default branch)",
"repositoryName": "Repository name",
"requestFailed": "Request failed",
"reset": "Reset",
@@ -422,6 +424,9 @@
"untitledTask": "Untitled task",
"usefulCommandsAgentSkills": "Useful commands & agent skills",
"useScratchInstead": "Use scratch instead",
+ "useStepDefaultOption": "(use step default)",
+ "watcherLoadingBranchesPlaceholder": "Loading…",
+ "watcherPickRepositoryPlaceholder": "Pick a repository first",
"useThisFolder": "Use this folder",
"utilities": "Utilities",
"viewFullReleaseOnGithub": "View full release on GitHub",
diff --git a/apps/web/src/locales/en/github.json b/apps/web/src/locales/en/github.json
index 3a8b9f3461..cca9655e34 100644
--- a/apps/web/src/locales/en/github.json
+++ b/apps/web/src/locales/en/github.json
@@ -531,7 +531,6 @@
"thisWorkspaceUsesOneCredentialFor": "This workspace uses one credential for repository sync, watches, background jobs, and managed agent GitHub access. Executor profile credentials can still take precedence.",
"titleIssues": "Issues",
"titlePullRequests": "Pull requests",
- "togglePrEventPromptAutomation": "Toggle PR event prompt automation",
"toggleReviewFollowUpAutomation": "Toggle review follow-up automation",
"typeACustomQueryFirst": "Type a custom query first",
"typeOwnerRepoToSearch": "Type {{format}} to search",
diff --git a/apps/web/src/locales/en/settings.json b/apps/web/src/locales/en/settings.json
index 344fe22ac4..d8efeff281 100644
--- a/apps/web/src/locales/en/settings.json
+++ b/apps/web/src/locales/en/settings.json
@@ -81,7 +81,6 @@
"completeTheRequiredEditorFieldsBefore": "Complete the required editor fields before saving.",
"configChatAgentDescription": "Choose which agent profile to use for the Configuration Chat. This agent can manage your workflows, agent profiles, and MCP configuration.",
"configChatAgentNoDefault": "No default",
- "configChatAgentPlaceholder": "Choose an agent profile...",
"configChatAgentTitle": "Configuration Chat Agent",
"configureArchiveSafeguardsAndDefaultsFor": "Configure archive safeguards and defaults for tasks created by agents",
"configureBackendAndExecutionResourceSampling": "Configure backend and execution resource sampling",
@@ -413,8 +412,6 @@
"mergeWithTarget": "Merge with {{target}}",
"messageSubmitKey": "Message Submit Key",
"metrics": "Metrics",
- "mode": "Mode",
- "model": "Model",
"moveTabLeft": "Move tab left",
"moveTabRight": "Move tab right",
"moveTabToSplit": "Move tab to split",
@@ -682,13 +679,8 @@
"utilityCustomAgentsDescription": "Create your own utility agents with custom prompts.",
"utilityCustomAgentsEmpty": "No custom utility agents.",
"utilityCustomAgentsTitle": "Custom utility agents",
- "utilityDefaultModelAriaLabel": "Default utility model settings",
"utilityDefaultModelDescription": "Select the profile used by built-in utility actions. The profile controls the model, permissions, and launch settings.",
"utilityDefaultModelTitle": "Default utility agent model",
- "utilityDefaultWithModel": "Default ({{model}})",
- "utilityModelNotConfigured": "Not configured",
- "utilitySelectAgent": "Select agent...",
- "utilitySelectModel": "Select model...",
"utilityAgentProfile": "Agent profile",
"utilitySelectProfile": "Select profile...",
"utilitySearchProfiles": "Search agent profiles...",
diff --git a/apps/web/src/locales/en/task.json b/apps/web/src/locales/en/task.json
index 6204d98e02..e01ca99d7e 100644
--- a/apps/web/src/locales/en/task.json
+++ b/apps/web/src/locales/en/task.json
@@ -1009,7 +1009,6 @@
"remoteStateLine": "State: {{state}}",
"remoteStatusFailedLine": "Status failed: {{error}}",
"currentPRCommit": "Current PR commit",
- "currentPRCommits": "Current PR commits",
"remoteUrlPressEnter": "<0>Remote URL0>; press Enter to submit it.",
"remove": "Remove",
"remove2": "Remove {{name}}",
@@ -1499,6 +1498,7 @@
"workspaceRepository": "Workspace repository",
"workspaceRequiresConfiguration": "Workspace requires configuration",
"workspaceUnavailable": "Workspace unavailable",
+ "unknownTaskFallback": "(unknown task)",
"worktree": "Worktree",
"wouldCreateABlockerCycle": "Would create a blocker cycle: {{cycle}}",
"writeAComment": "Write a comment…",
diff --git a/apps/web/src/locales/pseudo/agents.json b/apps/web/src/locales/pseudo/agents.json
index 49b530d1ef..f9b7b19369 100644
--- a/apps/web/src/locales/pseudo/agents.json
+++ b/apps/web/src/locales/pseudo/agents.json
@@ -161,7 +161,6 @@
"profileNameRequiredTitle": "Ƥŕōƒĩĺē ńàḿē ĩś ŕēqũĩŕēď",
"profileNotFound": "Ƥŕōƒĩĺē ńōţ ƒōũńď.",
"profileSettings": "Ƥŕōƒĩĺē śēţţĩńĝś",
- "profileStartModelSettings": "Ƥŕōƒĩĺē śţàŕţ ḿōďēĺ śēţţĩńĝś",
"promptTokenHint": "<0>{{token}}0> ŵĩĺĺ ƀē ŕēƥĺàćēď ŵĩţĥ ŷōũŕ ţàśķ ďēśćŕĩƥţĩōń ōŕ ƒōĺĺōŵ-ũƥ ḿēśśàĝē.",
"ptyConnectionError": "Ćōńńēćţĩōń ēŕŕōŕ",
"refresh": "Ŕēƒŕēśĥ",
@@ -185,7 +184,6 @@
"scanningForInstalledAgents": "Śćàńńĩńĝ ƒōŕ ĩńśţàĺĺēď àĝēńţś...",
"searchModels": "Śēàŕćĥ ḿōďēĺś...",
"searchModes": "Śēàŕćĥ ḿōďēś...",
- "selectAModel": "Śēĺēćţ à ḿōďēĺ...",
"selectAModelShort": "Śēĺēćţ à ḿōďēĺ",
"selectModel": "Śēĺēćţ ḿōďēĺ...",
"sessionEnded": "Śēśśĩōń ēńďēď.",
diff --git a/apps/web/src/locales/pseudo/common.json b/apps/web/src/locales/pseudo/common.json
index f2537dfc5b..13b71804b9 100644
--- a/apps/web/src/locales/pseudo/common.json
+++ b/apps/web/src/locales/pseudo/common.json
@@ -319,6 +319,8 @@
"reloadTheApplicationToTryAgain": "Ŕēĺōàď ţĥē àƥƥĺĩćàţĩōń ţō ţŕŷ àĝàĩń.",
"rename": "Ŕēńàḿē",
"repository": "Ŕēƥōśĩţōŕŷ",
+ "noRepositoryOption": "(ńō ŕēƥōśĩţōŕŷ)",
+ "repositoryDefaultBranchOption": "(ŕēƥōśĩţōŕŷ ďēƒàũĺţ ƀŕàńćĥ)",
"repositoryName": "Ŕēƥōśĩţōŕŷ ńàḿē",
"requestFailed": "Ŕēqũēśţ ƒàĩĺēď",
"reset": "Ŕēśēţ",
@@ -422,6 +424,9 @@
"untitledTask": "Ũńţĩţĺēď ţàśķ",
"usefulCommandsAgentSkills": "Ũśēƒũĺ ćōḿḿàńďś & àĝēńţ śķĩĺĺś",
"useScratchInstead": "Ũśē śćŕàţćĥ ĩńśţēàď",
+ "useStepDefaultOption": "(ũśē śţēƥ ďēƒàũĺţ)",
+ "watcherLoadingBranchesPlaceholder": "Ĺōàďĩńĝ…",
+ "watcherPickRepositoryPlaceholder": "Ƥĩćķ à ŕēƥōśĩţōŕŷ ƒĩŕśţ",
"useThisFolder": "Ũśē ţĥĩś ƒōĺďēŕ",
"utilities": "Ũţĩĺĩţĩēś",
"viewFullReleaseOnGithub": "Vĩēŵ ƒũĺĺ ŕēĺēàśē ōń ĜĩţĤũƀ",
diff --git a/apps/web/src/locales/pseudo/github.json b/apps/web/src/locales/pseudo/github.json
index 33629bf795..275751f3f4 100644
--- a/apps/web/src/locales/pseudo/github.json
+++ b/apps/web/src/locales/pseudo/github.json
@@ -531,7 +531,6 @@
"thisWorkspaceUsesOneCredentialFor": "Ţĥĩś ŵōŕķśƥàćē ũśēś ōńē ćŕēďēńţĩàĺ ƒōŕ ŕēƥōśĩţōŕŷ śŷńć, ŵàţćĥēś, ƀàćķĝŕōũńď ĵōƀś, àńď ḿàńàĝēď àĝēńţ ĜĩţĤũƀ àććēśś. Ēxēćũţōŕ ƥŕōƒĩĺē ćŕēďēńţĩàĺś ćàń śţĩĺĺ ţàķē ƥŕēćēďēńćē.",
"titleIssues": "Ĩśśũēś",
"titlePullRequests": "Ƥũĺĺ ŕēqũēśţś",
- "togglePrEventPromptAutomation": "Ţōĝĝĺē ƤŔ ēvēńţ ƥŕōḿƥţ àũţōḿàţĩōń",
"toggleReviewFollowUpAutomation": "Ţōĝĝĺē ŕēvĩēŵ ƒōĺĺōŵ-ũƥ àũţōḿàţĩōń",
"typeACustomQueryFirst": "Ţŷƥē à ćũśţōḿ qũēŕŷ ƒĩŕśţ",
"typeOwnerRepoToSearch": "Ţŷƥē {{format}} ţō śēàŕćĥ",
diff --git a/apps/web/src/locales/pseudo/settings.json b/apps/web/src/locales/pseudo/settings.json
index 5056e76318..72654969e3 100644
--- a/apps/web/src/locales/pseudo/settings.json
+++ b/apps/web/src/locales/pseudo/settings.json
@@ -81,7 +81,6 @@
"completeTheRequiredEditorFieldsBefore": "Ćōḿƥĺēţē ţĥē ŕēqũĩŕēď ēďĩţōŕ ƒĩēĺďś ƀēƒōŕē śàvĩńĝ.",
"configChatAgentDescription": "Ćĥōōśē ŵĥĩćĥ àĝēńţ ƥŕōƒĩĺē ţō ũśē ƒōŕ ţĥē Ćōńƒĩĝũŕàţĩōń Ćĥàţ. Ţĥĩś àĝēńţ ćàń ḿàńàĝē ŷōũŕ ŵōŕķƒĺōŵś, àĝēńţ ƥŕōƒĩĺēś, àńď ḾĆƤ ćōńƒĩĝũŕàţĩōń.",
"configChatAgentNoDefault": "Ńō ďēƒàũĺţ",
- "configChatAgentPlaceholder": "Ćĥōōśē àń àĝēńţ ƥŕōƒĩĺē...",
"configChatAgentTitle": "Ćōńƒĩĝũŕàţĩōń Ćĥàţ Àĝēńţ",
"configureArchiveSafeguardsAndDefaultsFor": "Ćōńƒĩĝũŕē àŕćĥĩvē śàƒēĝũàŕďś àńď ďēƒàũĺţś ƒōŕ ţàśķś ćŕēàţēď ƀŷ àĝēńţś",
"configureBackendAndExecutionResourceSampling": "Ćōńƒĩĝũŕē ƀàćķēńď àńď ēxēćũţĩōń ŕēśōũŕćē śàḿƥĺĩńĝ",
@@ -413,8 +412,6 @@
"mergeWithTarget": "Ḿēŕĝē ŵĩţĥ {{target}}",
"messageSubmitKey": "Ḿēśśàĝē Śũƀḿĩţ Ķēŷ",
"metrics": "Ḿēţŕĩćś",
- "mode": "Ḿōďē",
- "model": "Ḿōďēĺ",
"moveTabLeft": "Ḿōvē ţàƀ ĺēƒţ",
"moveTabRight": "Ḿōvē ţàƀ ŕĩĝĥţ",
"moveTabToSplit": "Ḿōvē ţàƀ ţō śƥĺĩţ",
@@ -682,13 +679,8 @@
"utilityCustomAgentsDescription": "Ćŕēàţē ŷōũŕ ōŵń ũţĩĺĩţŷ àĝēńţś ŵĩţĥ ćũśţōḿ ƥŕōḿƥţś.",
"utilityCustomAgentsEmpty": "Ńō ćũśţōḿ ũţĩĺĩţŷ àĝēńţś.",
"utilityCustomAgentsTitle": "Ćũśţōḿ ũţĩĺĩţŷ àĝēńţś",
- "utilityDefaultModelAriaLabel": "Ďēƒàũĺţ ũţĩĺĩţŷ ḿōďēĺ śēţţĩńĝś",
"utilityDefaultModelDescription": "Śēĺēćţ ţĥē ƥŕōƒĩĺē ũśēď ƀŷ ƀũĩĺţ-ĩń ũţĩĺĩţŷ àćţĩōńś. Ţĥē ƥŕōƒĩĺē ćōńţŕōĺś ţĥē ḿōďēĺ, ƥēŕḿĩśśĩōńś, àńď ĺàũńćĥ śēţţĩńĝś.",
"utilityDefaultModelTitle": "Ďēƒàũĺţ ũţĩĺĩţŷ àĝēńţ ḿōďēĺ",
- "utilityDefaultWithModel": "Ďēƒàũĺţ ({{model}})",
- "utilityModelNotConfigured": "Ńōţ ćōńƒĩĝũŕēď",
- "utilitySelectAgent": "Śēĺēćţ àĝēńţ...",
- "utilitySelectModel": "Śēĺēćţ ḿōďēĺ...",
"utilityAgentProfile": "Àĝēńţ ƥŕōƒĩĺē",
"utilitySelectProfile": "Śēĺēćţ ƥŕōƒĩĺē...",
"utilitySearchProfiles": "Śēàŕćĥ àĝēńţ ƥŕōƒĩĺēś...",
diff --git a/apps/web/src/locales/pseudo/task.json b/apps/web/src/locales/pseudo/task.json
index f8021a5475..cd08d7911b 100644
--- a/apps/web/src/locales/pseudo/task.json
+++ b/apps/web/src/locales/pseudo/task.json
@@ -1009,7 +1009,6 @@
"remoteStateLine": "Śţàţē: {{state}}",
"remoteStatusFailedLine": "Śţàţũś ƒàĩĺēď: {{error}}",
"currentPRCommit": "Ćũŕŕēńţ ƤŔ ćōḿḿĩţ",
- "currentPRCommits": "Ćũŕŕēńţ ƤŔ ćōḿḿĩţś",
"remoteUrlPressEnter": "<0>Ŕēḿōţē ŨŔĹ0>; ƥŕēśś Ēńţēŕ ţō śũƀḿĩţ ĩţ.",
"remove": "Ŕēḿōvē",
"remove2": "Ŕēḿōvē {{name}}",
@@ -1499,6 +1498,7 @@
"workspaceRepository": "Ŵōŕķśƥàćē ŕēƥōśĩţōŕŷ",
"workspaceRequiresConfiguration": "Ŵōŕķśƥàćē ŕēqũĩŕēś ćōńƒĩĝũŕàţĩōń",
"workspaceUnavailable": "Ŵōŕķśƥàćē ũńàvàĩĺàƀĺē",
+ "unknownTaskFallback": "(ũńķńōŵń ţàśķ)",
"worktree": "Ŵōŕķţŕēē",
"wouldCreateABlockerCycle": "Ŵōũĺď ćŕēàţē à ƀĺōćķēŕ ćŷćĺē: {{cycle}}",
"writeAComment": "Ŵŕĩţē à ćōḿḿēńţ…",
diff --git a/apps/web/src/locales/pt-pt/agents.json b/apps/web/src/locales/pt-pt/agents.json
index 100d0d1a30..a26ebdaf91 100644
--- a/apps/web/src/locales/pt-pt/agents.json
+++ b/apps/web/src/locales/pt-pt/agents.json
@@ -153,7 +153,6 @@
"profileNameRequiredTitle": "O nome do perfil é obrigatório",
"profileNotFound": "Perfil não encontrado.",
"profileSettings": "Definições do perfil",
- "profileStartModelSettings": "Definições do modelo inicial do perfil",
"promptTokenHint": "<0>{{token}}0> será substituído pela descrição da sua tarefa ou pela mensagem de seguimento.",
"ptyConnectionError": "Erro de ligação",
"refresh": "Atualizar",
@@ -177,7 +176,6 @@
"scanningForInstalledAgents": "À procura de agentes instalados...",
"searchModels": "Pesquisar modelos...",
"searchModes": "Pesquisar modos...",
- "selectAModel": "Selecione um modelo...",
"selectAModelShort": "Selecionar um modelo",
"selectModel": "Selecionar modelo...",
"sessionEnded": "A sessão terminou.",
diff --git a/apps/web/src/locales/pt-pt/common.json b/apps/web/src/locales/pt-pt/common.json
index fc30c131e1..b2c69907fe 100644
--- a/apps/web/src/locales/pt-pt/common.json
+++ b/apps/web/src/locales/pt-pt/common.json
@@ -312,6 +312,8 @@
"reloadTheApplicationToTryAgain": "Recarregue a aplicação para tentar novamente.",
"rename": "Mudar o nome",
"repository": "Repositório",
+ "noRepositoryOption": "(sem repositório)",
+ "repositoryDefaultBranchOption": "(ramo predefinido do repositório)",
"repositoryName": "Nome do repositório",
"requestFailed": "O pedido falhou",
"reset": "Repor",
@@ -413,6 +415,9 @@
"untitledTask": "Tarefa sem título",
"usefulCommandsAgentSkills": "Comandos úteis e competências do agente",
"useScratchInstead": "Usar antes uma área temporária",
+ "useStepDefaultOption": "(usar predefinição do passo)",
+ "watcherLoadingBranchesPlaceholder": "A carregar…",
+ "watcherPickRepositoryPlaceholder": "Escolha primeiro um repositório",
"useThisFolder": "Usar esta pasta",
"viewFullReleaseOnGithub": "Ver a versão completa no GitHub",
"waitsForCiAndAutomatedReviews": "Aguarda pelo CI e pelas revisões automáticas e depois corrige as falhas e responde aos comentários.",
diff --git a/apps/web/src/locales/pt-pt/github.json b/apps/web/src/locales/pt-pt/github.json
index 645b1838fa..e897e183a6 100644
--- a/apps/web/src/locales/pt-pt/github.json
+++ b/apps/web/src/locales/pt-pt/github.json
@@ -512,7 +512,6 @@
"thisWorkspaceUsesOneCredentialFor": "Esta área de trabalho usa uma credencial para a sincronização de repositórios, as vigilâncias, as tarefas em segundo plano e o acesso ao GitHub dos agentes geridos. As credenciais dos perfis de executor podem continuar a ter precedência.",
"titleIssues": "Issues",
"titlePullRequests": "Pull requests",
- "togglePrEventPromptAutomation": "Alternar a automatização de prompts de eventos de PR",
"typeACustomQueryFirst": "Escreva primeiro uma consulta personalizada",
"typeOwnerRepoToSearch": "Escreva {{format}} para pesquisar",
"unableToLoadTheCurrentTask": "Não foi possível carregar a definição atual de acesso das tarefas.",
diff --git a/apps/web/src/locales/pt-pt/settings.json b/apps/web/src/locales/pt-pt/settings.json
index efda6f9eaf..886cb76ac2 100644
--- a/apps/web/src/locales/pt-pt/settings.json
+++ b/apps/web/src/locales/pt-pt/settings.json
@@ -79,7 +79,6 @@
"completeTheRequiredEditorFieldsBefore": "Preencha os campos obrigatórios do editor antes de guardar.",
"configChatAgentDescription": "Escolha o perfil de agente a usar no Chat de configuração. Este agente pode gerir os seus fluxos de trabalho, perfis de agente e configuração MCP.",
"configChatAgentNoDefault": "Sem pré-definição",
- "configChatAgentPlaceholder": "Escolha um perfil de agente...",
"configChatAgentTitle": "Agente do Chat de configuração",
"configureArchiveSafeguardsAndDefaultsFor": "Configure as salvaguardas de arquivo e as pré-definições das tarefas criadas por agentes",
"configureBackendAndExecutionResourceSampling": "Configure a amostragem de recursos do backend e da execução",
@@ -378,7 +377,6 @@
"manageApiKeysAndCredentialsSecrets": "Faça a gestão das chaves de API e das credenciais. Os segredos são guardados encriptados e injetados nos ambientes dos agentes através das variáveis de ambiente do perfil de executor.",
"globalScope": "Global",
"modelFallbackSuffix": "(alternativo)",
- "mode": "Modo",
"modelWithValue": "Modelo: {{model}}",
"profileFallbackWillBeUsed": "O modelo inicial {{model}} já não está disponível; será usado o alternativo {{fallback}}.",
"profileStartModelUnavailable": "O modelo inicial {{model}} já não está disponível; altere-o no perfil do agente.",
@@ -407,7 +405,6 @@
"mergeWithTarget": "Fundir com {{target}}",
"messageSubmitKey": "Tecla de envio de mensagens",
"metrics": "Métricas",
- "model": "Modelo",
"moveTabLeft": "Mover o separador para a esquerda",
"moveTabRight": "Mover o separador para a direita",
"moveTabToSplit": "Mover o separador para uma divisão",
@@ -667,13 +664,8 @@
"utilityCustomAgentsDescription": "Crie os seus próprios agentes utilitários com prompts personalizados.",
"utilityCustomAgentsEmpty": "Não há agentes utilitários personalizados.",
"utilityCustomAgentsTitle": "Agentes utilitários personalizados",
- "utilityDefaultModelAriaLabel": "Definições do modelo utilitário pré-definido",
"utilityDefaultModelDescription": "Selecione o perfil usado pelas ações utilitárias incorporadas. O perfil define o modelo, as permissões e as definições de execução.",
"utilityDefaultModelTitle": "Modelo pré-definido dos agentes utilitários",
- "utilityDefaultWithModel": "Pré-definido ({{model}})",
- "utilityModelNotConfigured": "Não configurado",
- "utilitySelectAgent": "Selecionar agente...",
- "utilitySelectModel": "Selecionar modelo...",
"utilityAgentProfile": "Perfil do agente",
"utilitySelectProfile": "Selecionar perfil...",
"utilitySearchProfiles": "Pesquisar perfis de agente...",
diff --git a/apps/web/src/locales/pt-pt/task.json b/apps/web/src/locales/pt-pt/task.json
index ddee8438de..82d522fde8 100644
--- a/apps/web/src/locales/pt-pt/task.json
+++ b/apps/web/src/locales/pt-pt/task.json
@@ -1009,7 +1009,6 @@
"remoteStateLine": "Estado: {{state}}",
"remoteStatusFailedLine": "Falha ao obter o estado: {{error}}",
"currentPRCommit": "Commit atual do PR",
- "currentPRCommits": "Commits atuais do PR",
"remoteUrlPressEnter": "<0>URL remoto0>; prima Enter para o submeter.",
"remove": "Remover",
"remove2": "Remover {{name}}",
@@ -1499,6 +1498,7 @@
"workspaceRepository": "Repositório da área de trabalho",
"workspaceRequiresConfiguration": "A área de trabalho requer configuração",
"workspaceUnavailable": "Área de trabalho indisponível",
+ "unknownTaskFallback": "(tarefa desconhecida)",
"worktree": "Worktree",
"wouldCreateABlockerCycle": "Criaria um ciclo de bloqueios: {{cycle}}",
"writeAComment": "Escreva um comentário…",
diff --git a/apps/web/src/locales/zh-cn/agents.json b/apps/web/src/locales/zh-cn/agents.json
index b08b895623..a5be3fc0b5 100644
--- a/apps/web/src/locales/zh-cn/agents.json
+++ b/apps/web/src/locales/zh-cn/agents.json
@@ -161,7 +161,6 @@
"profileNameRequiredTitle": "配置名称为必填项",
"profileNotFound": "未找到配置。",
"profileSettings": "配置设置",
- "profileStartModelSettings": "配置启动模型设置",
"promptTokenHint": "<0>{{token}}0> 将替换为你的任务描述或后续消息。",
"ptyConnectionError": "连接错误",
"refresh": "刷新",
@@ -185,7 +184,6 @@
"scanningForInstalledAgents": "正在扫描已安装的代理…",
"searchModels": "搜索模型…",
"searchModes": "搜索模式…",
- "selectAModel": "选择模型…",
"selectAModelShort": "选择模型",
"selectModel": "选择模型...",
"sessionEnded": "会话已结束。",
diff --git a/apps/web/src/locales/zh-cn/common.json b/apps/web/src/locales/zh-cn/common.json
index 8987bd00a5..eb96399834 100644
--- a/apps/web/src/locales/zh-cn/common.json
+++ b/apps/web/src/locales/zh-cn/common.json
@@ -319,6 +319,8 @@
"reloadTheApplicationToTryAgain": "重新加载应用以重试。",
"rename": "重命名",
"repository": "仓库",
+ "noRepositoryOption": "(无仓库)",
+ "repositoryDefaultBranchOption": "(仓库默认分支)",
"repositoryName": "仓库名称",
"requestFailed": "请求失败",
"reset": "重置",
@@ -422,6 +424,9 @@
"untitledTask": "未命名任务",
"usefulCommandsAgentSkills": "实用命令与代理技能",
"useScratchInstead": "改用临时工作区",
+ "useStepDefaultOption": "(使用步骤默认值)",
+ "watcherLoadingBranchesPlaceholder": "加载中…",
+ "watcherPickRepositoryPlaceholder": "请先选择仓库",
"useThisFolder": "使用此文件夹",
"utilities": "实用工具",
"viewFullReleaseOnGithub": "在 GitHub 上查看完整发行说明",
diff --git a/apps/web/src/locales/zh-cn/github.json b/apps/web/src/locales/zh-cn/github.json
index 6ccb67603d..19e94853aa 100644
--- a/apps/web/src/locales/zh-cn/github.json
+++ b/apps/web/src/locales/zh-cn/github.json
@@ -529,7 +529,6 @@
"thisWorkspaceUsesOneCredentialFor": "此工作区使用一个凭据执行仓库同步、监控、后台任务和托管代理的 GitHub 访问。执行器配置凭据仍可优先使用。",
"titleIssues": "议题",
"titlePullRequests": "拉取请求",
- "togglePrEventPromptAutomation": "切换 PR 事件提示自动化",
"typeACustomQueryFirst": "请先输入自定义查询",
"typeOwnerRepoToSearch": "输入 {{format}} 进行搜索",
"unableToLoadTheCurrentTask": "无法加载当前任务访问设置。",
diff --git a/apps/web/src/locales/zh-cn/settings.json b/apps/web/src/locales/zh-cn/settings.json
index 5fc5256432..18968674aa 100644
--- a/apps/web/src/locales/zh-cn/settings.json
+++ b/apps/web/src/locales/zh-cn/settings.json
@@ -81,7 +81,6 @@
"completeTheRequiredEditorFieldsBefore": "保存前请填写必需的编辑器字段。",
"configChatAgentDescription": "选择用于配置聊天的代理配置。此代理可管理你的工作流、代理配置与 MCP 配置。",
"configChatAgentNoDefault": "无默认",
- "configChatAgentPlaceholder": "选择代理配置…",
"configChatAgentTitle": "配置聊天代理",
"configureArchiveSafeguardsAndDefaultsFor": "配置代理创建任务时的归档保护和默认设置",
"configureBackendAndExecutionResourceSampling": "配置后端和执行资源采样",
@@ -413,8 +412,6 @@
"mergeWithTarget": "与 {{target}} 合并",
"messageSubmitKey": "消息提交快捷键",
"metrics": "指标",
- "mode": "模式",
- "model": "模型",
"moveTabLeft": "左移标签页",
"moveTabRight": "右移标签页",
"moveTabToSplit": "将标签页移至拆分区域",
@@ -682,13 +679,8 @@
"utilityCustomAgentsDescription": "使用自定义提示词创建你自己的实用代理。",
"utilityCustomAgentsEmpty": "无自定义实用代理。",
"utilityCustomAgentsTitle": "自定义实用代理",
- "utilityDefaultModelAriaLabel": "默认实用模型设置",
"utilityDefaultModelDescription": "选择内置实用操作使用的配置。配置包含模型、权限和启动设置。",
"utilityDefaultModelTitle": "默认实用代理模型",
- "utilityDefaultWithModel": "默认({{model}})",
- "utilityModelNotConfigured": "未配置",
- "utilitySelectAgent": "选择代理…",
- "utilitySelectModel": "选择模型…",
"utilityAgentProfile": "代理配置",
"utilitySelectProfile": "选择配置…",
"utilitySearchProfiles": "搜索代理配置…",
diff --git a/apps/web/src/locales/zh-cn/task.json b/apps/web/src/locales/zh-cn/task.json
index e7f1107065..43572a937a 100644
--- a/apps/web/src/locales/zh-cn/task.json
+++ b/apps/web/src/locales/zh-cn/task.json
@@ -1009,7 +1009,6 @@
"remoteStateLine": "状态:{{state}}",
"remoteStatusFailedLine": "状态失败:{{error}}",
"currentPRCommit": "当前 PR 提交",
- "currentPRCommits": "当前 PR 提交",
"remoteUrlPressEnter": "<0>远程 URL0>; 按 Enter 提交。",
"remove": "移除",
"remove2": "移除 {{name}}",
@@ -1499,6 +1498,7 @@
"workspaceRepository": "工作区仓库",
"workspaceRequiresConfiguration": "工作区需要配置",
"workspaceUnavailable": "工作区不可用",
+ "unknownTaskFallback": "(未知任务)",
"worktree": "工作树",
"wouldCreateABlockerCycle": "会形成阻塞循环:{{cycle}}",
"writeAComment": "撰写评论…",
diff --git a/docs/plans/i18n-audit-watcher-copy/plan.md b/docs/plans/i18n-audit-watcher-copy/plan.md
new file mode 100644
index 0000000000..04d0fc4b95
--- /dev/null
+++ b/docs/plans/i18n-audit-watcher-copy/plan.md
@@ -0,0 +1,95 @@
+---
+spec: docs/specs/i18n-audit-watcher-copy/spec.md
+created: 2026-08-12
+status: completed
+---
+
+# Implementation Plan: Watcher And Task Fallback Localization
+
+## Overview
+
+Separate stable watcher domain values from render-time copy, then update every watcher consumer and
+the sender-task fallback. Finish by deleting the 12 audit-confirmed obsolete keys from all catalogs
+and running focused tests plus the required i18n audits. The confirmed root cause is that display
+labels were exported from plain helper modules as English constants or returned as English strings;
+the orphan keys survived UI replacements without source references.
+
+## Frontend
+
+### Watcher profile defaults
+
+- In `apps/web/lib/watcher-profile-default.ts`, retain `STEP_DEFAULT` and `resolveProfileId` as the
+ untranslated domain contract and remove `STEP_DEFAULT_LABEL`.
+- Add a shared catalog key for the step-default display label and resolve it through each dialog's
+ existing `useTranslation()` call in GitHub issue/review, GitLab issue/review, Jira, and Linear
+ watcher dialogs.
+- Keep the sentinel-to-empty-string payload behavior unchanged and update focused helper/dialog tests
+ where they assert the rendered option.
+
+### Watcher repository defaults
+
+- In `apps/web/lib/watcher-repository-default.ts`, retain only sentinel/domain behavior and replace
+ `branchPlaceholder`'s English return values with a locale-neutral state/key result.
+- In `apps/web/components/watcher-repository-fields.tsx`, resolve no-repository, default-branch,
+ repository-first, and loading copy from catalog keys during render. Never translate repository
+ names, IDs, or branch names.
+- Extend `apps/web/lib/watcher-repository-default.test.ts` to prove locale-neutral state selection and
+ unchanged sentinel normalization before changing production behavior.
+
+### Sender task fallback
+
+- In `apps/web/components/task/chat/messages/sender-task-badge.tsx`, resolve the unknown-task fallback
+ from `task` catalog copy inside the component.
+- Extend the nearest existing chat-message component test to render a sender with no live or snapshot
+ title and assert the visible fallback and tooltip text.
+
+### Catalog cleanup
+
+- Remove the following confirmed obsolete entries from English, pseudo, Portuguese, and Simplified
+ Chinese catalogs: `agents:profileStartModelSettings`, `agents:selectAModel`,
+ `github:togglePrEventPromptAutomation`, `settings:configChatAgentPlaceholder`, `settings:mode`,
+ `settings:model`, `settings:utilityDefaultModelAriaLabel`, `settings:utilityDefaultWithModel`,
+ `settings:utilityModelNotConfigured`, `settings:utilitySelectAgent`,
+ `settings:utilitySelectModel`, and `task:currentPRCommits`.
+- The source-history audit ties these keys to superseded profile model controls, profile-based utility
+ agent pickers, per-PR automation controls, configuration chat selection, core Voice Mode, and an old
+ Changes header. Current replacement surfaces already use different, more specific keys.
+
+### Mobile parity
+
+This is copy-only work inside existing responsive dialogs and badges. It changes no composition,
+touch target, scrolling, navigation, or viewport branch, so focused component/rendered tests satisfy
+the mobile-parity exception; no new mobile Playwright scenario is required.
+
+## Tests
+
+- **What:** watcher sentinels remain stable while placeholder selection becomes locale-neutral.
+ **File:** `apps/web/lib/watcher-profile-default.test.ts` and
+ `apps/web/lib/watcher-repository-default.test.ts`. **How:** focused Vitest unit assertions.
+- **What:** translated watcher defaults appear through representative dialog/shared-field render
+ paths without changing submitted IDs. **File:** existing watcher dialog tests and, if the shared
+ fields lack a suitable harness, `apps/web/components/watcher-repository-fields.test.tsx`.
+ **How:** focused Vitest component tests using the initialized test i18n instance.
+- **What:** an absent sender task title renders the translated fallback. **File:**
+ `apps/web/components/task/chat/messages/chat-message.test.tsx` or the closest existing sender badge
+ harness. **How:** focused Vitest component assertion.
+- **What:** catalogs contain no audit-reported orphan keys and new references are valid. **How:**
+ `pnpm run i18n:check` and `pnpm run i18n:sweep -- components lib` from `apps/web`.
+
+## Verification Results
+
+- Focused Vitest: 46 tests passed across 7 files, including repository-first and branch-loading rendered placeholder coverage added during PR review.
+- CI remediation: 31 focused component tests and `pnpm run typecheck` passed after allowing the disabled branch select to carry an unset presentation value; live locale switching is asserted with exact English and pseudo fallback copy.
+- `pnpm run i18n:check`: passed with 0 orphans, pseudo in sync, and 127 unchanged out-of-scope real-locale parity advisories.
+- `pnpm run i18n:sweep -- components lib`: completed across 1,850 files; only the two documented prompt-builder plural findings and 91 unrelated review-by-eye candidates remain.
+
+## Implementation Waves And Parallel Candidates
+
+Wave 1:
+- [x] [task-01-localize-watcher-and-task-fallbacks](task-01-localize-watcher-and-task-fallbacks.md)
+
+Wave 2:
+- [x] [task-02-remove-obsolete-catalog-entries](task-02-remove-obsolete-catalog-entries.md)
+
+Tasks are sequential because both touch shared locale catalogs and the final orphan audit depends on
+the new references from Task 01.
diff --git a/docs/plans/i18n-audit-watcher-copy/task-01-localize-watcher-and-task-fallbacks.md b/docs/plans/i18n-audit-watcher-copy/task-01-localize-watcher-and-task-fallbacks.md
new file mode 100644
index 0000000000..ce177d50f5
--- /dev/null
+++ b/docs/plans/i18n-audit-watcher-copy/task-01-localize-watcher-and-task-fallbacks.md
@@ -0,0 +1,74 @@
+---
+id: "01-localize-watcher-and-task-fallbacks"
+title: "Localize watcher and task fallbacks"
+status: done
+wave: 1
+depends_on: []
+plan: "plan.md"
+spec: "../../specs/i18n-audit-watcher-copy/spec.md"
+---
+
+# Task 01: Localize Watcher And Task Fallbacks
+
+## Acceptance
+
+- Every GitHub, GitLab, Jira, and Linear watcher profile default resolves localized copy during
+ render while sentinel values and submitted empty IDs remain unchanged.
+- Watcher repository empty/loading/default copy resolves during render while repository and branch
+ domain values remain untranslated.
+- A sender badge with no live or snapshot title renders the localized unknown-task fallback.
+
+## Verification
+
+```bash
+cd apps/web && pnpm test -- --run lib/watcher-profile-default.test.ts lib/watcher-repository-default.test.ts components/task/chat/messages/chat-message.test.tsx components/github/review-watch-dialog.test.tsx components/gitlab/issue-watch-dialog.test.tsx components/gitlab/review-watch-dialog.test.tsx
+```
+
+## Files likely touched
+
+- `apps/web/lib/watcher-profile-default.ts`
+- `apps/web/lib/watcher-profile-default.test.ts`
+- `apps/web/lib/watcher-repository-default.ts`
+- `apps/web/lib/watcher-repository-default.test.ts`
+- `apps/web/components/watcher-repository-fields.tsx`
+- focused shared-field test if needed
+- `apps/web/components/github/issue-watch-dialog.tsx`
+- `apps/web/components/github/review-watch-dialog.tsx`
+- `apps/web/components/gitlab/watch-dialog.tsx`
+- `apps/web/components/jira/jira-issue-watch-dialog.tsx`
+- `apps/web/components/linear/linear-issue-watch-dialog.tsx`
+- `apps/web/components/task/chat/messages/sender-task-badge.tsx`
+- closest existing sender badge/chat-message test
+- affected locale namespace files for newly referenced keys
+- this task file and `plan.md`
+
+## Dependencies
+
+None.
+
+## Parallelism
+
+Sequential. The dialogs share helper and catalog contracts.
+
+## Inputs
+
+- Spec scenarios for watcher profile defaults, repository states, and unknown sender tasks.
+- Existing sentinel normalization tests and existing watcher dialog component-test patterns.
+- Frontend i18n rule forbidding module-scope `t()` and translation of domain values.
+
+## Output contract
+
+Report RED/GREEN evidence, exact key ownership, unchanged sentinel/payload behavior, files changed,
+tests run, blockers and risks, then update this task and `plan.md` statuses.
+
+## Results
+
+RED: `cd apps/web && pnpm test -- --run lib/watcher-repository-default.test.ts components/task/chat/messages/chat-message.test.tsx` failed on the three English-returning placeholder states and the pseudo-locale unknown-task fallback. The remaining chat failures were cascading locale leakage after the intended assertion aborted.
+
+GREEN: `cd apps/web && pnpm test -- --run lib/watcher-profile-default.test.ts lib/watcher-repository-default.test.ts components/task/chat/messages/chat-message.test.tsx components/github/review-watch-dialog.test.tsx components/gitlab/issue-watch-dialog.test.tsx components/gitlab/review-watch-dialog.test.tsx` passed 44 tests in 6 files.
+
+PR review remediation: `cd apps/web && pnpm test -- --run components/watcher-repository-fields.test.tsx lib/watcher-profile-default.test.ts lib/watcher-repository-default.test.ts components/task/chat/messages/chat-message.test.tsx components/github/review-watch-dialog.test.tsx components/gitlab/issue-watch-dialog.test.tsx components/gitlab/review-watch-dialog.test.tsx` passed 46 tests in 7 files after proving that repository-first and loading placeholders remain visible while the branch selector is disabled.
+
+CI/review follow-up: `cd apps/web && pnpm test -- --run components/watcher-repository-fields.test.tsx components/task/chat/messages/chat-message.test.tsx && pnpm run typecheck` passed 31 tests in 2 files and the full web TypeScript check. The sender fallback test now proves an already-mounted badge changes from exact English to exact pseudo copy after a live locale switch.
+
+Sentinel values and empty-ID normalization are unchanged. Display copy resolves inside React render paths; no external side effects or security boundaries apply.
diff --git a/docs/plans/i18n-audit-watcher-copy/task-02-remove-obsolete-catalog-entries.md b/docs/plans/i18n-audit-watcher-copy/task-02-remove-obsolete-catalog-entries.md
new file mode 100644
index 0000000000..a662829269
--- /dev/null
+++ b/docs/plans/i18n-audit-watcher-copy/task-02-remove-obsolete-catalog-entries.md
@@ -0,0 +1,62 @@
+---
+id: "02-remove-obsolete-catalog-entries"
+title: "Remove obsolete catalog entries"
+status: done
+wave: 2
+depends_on: ["01-localize-watcher-and-task-fallbacks"]
+plan: "plan.md"
+spec: "../../specs/i18n-audit-watcher-copy/spec.md"
+---
+
+# Task 02: Remove Obsolete Catalog Entries
+
+## Acceptance
+
+- All 12 audit-reported keys, confirmed obsolete through current-source and source-history review,
+ are absent from English, pseudo, Portuguese, and Simplified Chinese catalogs.
+- `i18n:check` reports none of those orphan entries and pseudo remains synchronized; existing
+ real-locale parity advisories are not repaired in this task.
+- The required component/lib sweep reports no hardcoded user-facing copy introduced or retained by
+ this repair.
+
+## Verification
+
+```bash
+cd apps/web && pnpm run i18n:check && pnpm run i18n:sweep -- components lib
+```
+
+## Files likely touched
+
+- `apps/web/src/locales/en/agents.json`
+- `apps/web/src/locales/en/github.json`
+- `apps/web/src/locales/en/settings.json`
+- `apps/web/src/locales/en/task.json`
+- matching files under `apps/web/src/locales/pseudo/`
+- matching files under `apps/web/src/locales/pt-pt/`
+- matching files under `apps/web/src/locales/zh-cn/`
+- this task file and `plan.md`
+
+## Dependencies
+
+Task 01.
+
+## Parallelism
+
+Sequential. It validates shared catalogs after Task 01 adds the new fallback references.
+
+## Inputs
+
+- The source-history classification recorded in `plan.md`.
+- Task 01's final catalog key set.
+- User constraint excluding the real-locale parity finding.
+
+## Output contract
+
+Report the removed key list, exact checker/sweep results including unchanged advisory count, files
+changed, blockers and risks, then update this task and `plan.md` statuses.
+
+## Results
+
+`cd apps/web && pnpm run i18n:check && pnpm run i18n:sweep -- components lib` passed. The checker reports 0 orphan entries, pseudo in sync, and the unchanged 127 out-of-scope Portuguese/Chinese parity advisories. The sweep scanned 1,850 files and reported only the two documented prompt-builder plural concatenations plus 91 review-by-eye literals; none is introduced or retained by this repair.
+
+All 12 named obsolete keys were removed from English, pseudo, Portuguese, and Simplified Chinese catalogs. External side effects and security/trust boundaries: None.
diff --git a/docs/specs/i18n-audit-watcher-copy/spec.md b/docs/specs/i18n-audit-watcher-copy/spec.md
new file mode 100644
index 0000000000..498bf4d4d1
--- /dev/null
+++ b/docs/specs/i18n-audit-watcher-copy/spec.md
@@ -0,0 +1,46 @@
+---
+status: draft
+created: 2026-08-12
+owner: Kandev
+---
+
+# Watcher And Task Fallback Localization
+
+## Why
+
+Watcher dialogs and inter-task message badges expose several English-only fallback labels even
+when another locale is active. Obsolete catalog entries also obscure whether the current UI is
+fully covered by localization checks.
+
+## What
+
+- Watcher profile selectors display the localized equivalent of `(use step default)` while their
+ stored sentinel and submitted empty profile ID remain locale-independent.
+- Watcher repository and branch selectors localize the no-repository option, default-branch option,
+ repository-first prompt, and loading prompt at render time. Repository IDs, branch names, and
+ sentinel values remain untranslated.
+- Inter-task sender badges display a localized unknown-task fallback when neither a live title nor a
+ snapshot title exists.
+- English catalog entries with no current source reference and no current user-interface owner are
+ removed from every catalog. Current behavior is not changed merely to retain an obsolete key.
+- Translation lookup does not occur at module scope.
+
+## Scenarios
+
+- **GIVEN** any GitHub issue/review, GitLab issue/review, Jira, or Linear watcher dialog is rendered
+ in a non-English locale, **WHEN** no agent or executor profile override is selected, **THEN** the
+ step-default option and placeholder use that locale while saving still submits an empty profile ID.
+- **GIVEN** a watcher repository picker is rendered in a non-English locale, **WHEN** repository and
+ branch selection move through empty, loading, and loaded states, **THEN** only UI fallback copy is
+ translated and all repository/branch domain values remain unchanged.
+- **GIVEN** an inter-task message has no resolvable live or snapshot task title, **WHEN** its sender
+ badge renders, **THEN** the badge and tooltip use the localized unknown-task fallback.
+- **GIVEN** the catalogs contain the 12 audit-reported unreferenced keys, **WHEN** the i18n checker
+ runs after cleanup, **THEN** it reports no orphan entries from that set and pseudo remains in sync.
+
+## Out of scope
+
+- Resolving the existing Portuguese and Simplified Chinese catalog parity advisories.
+- Changing watcher persistence, payload contracts, repository selection behavior, dialog layout, or
+ mobile interaction behavior.
+- Restoring UI that was previously removed or replaced solely to consume an old catalog key.