From 295d726768e552dbb5a36e1a317be45913c9d0d5 Mon Sep 17 00:00:00 2001 From: Tom Durrant Date: Fri, 5 Jun 2026 10:07:27 +1000 Subject: [PATCH 001/112] fix: pass OPENCODE_API_KEY env var when syncing opencode-go models discoverOpencodeGoModels() spawns 'opencode models opencode --refresh' but never passed the saved API key as OPENCODE_API_KEY. The opencode CLI's internal OpencodePlugin checks this env var to decide whether to show paid models; without it, only free (cost.input === 0) models appear. Now threads the apiKey from auth storage through to the spawned process environment, so the CLI sees the user's Go subscription and returns the full model catalog including paid models like Claude, GPT-5.x, Gemini, etc. Callers in serve.ts, daemon.ts, and dashboard.ts all updated to read the key from dashboardAuthStorage and pass it to refreshOpencodeGoModels. syncStartupModels reads from authStorage in StartupSyncOptions. --- packages/cli/src/commands/daemon.ts | 2 ++ packages/cli/src/commands/dashboard.ts | 4 ++++ packages/cli/src/commands/serve.ts | 2 ++ packages/cli/src/commands/startup-model-sync.ts | 15 +++++++++++---- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/commands/daemon.ts b/packages/cli/src/commands/daemon.ts index 27d1af4f67..ead75bf96b 100644 --- a/packages/cli/src/commands/daemon.ts +++ b/packages/cli/src/commands/daemon.ts @@ -724,9 +724,11 @@ export async function runDaemon(opts: DaemonOptions = {}) { if (settings.opencodeGoModelSync === false) { return { registeredCount: 0, reason: "disabled-by-settings" }; } + const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); return await refreshOpencodeGoModels({ modelRegistry, log: (scope, message) => console.log(`[${scope}] ${message}`), + apiKey: opencodeGoKey, }); }, getClaudeCliExtensionStatus: () => { diff --git a/packages/cli/src/commands/dashboard.ts b/packages/cli/src/commands/dashboard.ts index 8df4be7de2..a41f7b8055 100644 --- a/packages/cli/src/commands/dashboard.ts +++ b/packages/cli/src/commands/dashboard.ts @@ -1764,9 +1764,11 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?: if (settings.opencodeGoModelSync === false) { return { registeredCount: 0, reason: "disabled-by-settings" }; } + const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); return await refreshOpencodeGoModels({ modelRegistry, log: (scope, message) => logSink.log(message, scope), + apiKey: opencodeGoKey, }); }, getClaudeCliExtensionStatus: () => { @@ -2085,9 +2087,11 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?: if (settings.opencodeGoModelSync === false) { return { registeredCount: 0, reason: "disabled-by-settings" }; } + const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); return await refreshOpencodeGoModels({ modelRegistry, log: (scope, message) => logSink.log(message, scope), + apiKey: opencodeGoKey, }); }, getClaudeCliExtensionStatus: () => { diff --git a/packages/cli/src/commands/serve.ts b/packages/cli/src/commands/serve.ts index 8f01b2c798..2d6a315d6c 100644 --- a/packages/cli/src/commands/serve.ts +++ b/packages/cli/src/commands/serve.ts @@ -831,9 +831,11 @@ export async function runServe( if (settings.opencodeGoModelSync === false) { return { registeredCount: 0, reason: "disabled-by-settings" }; } + const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); return await refreshOpencodeGoModels({ modelRegistry, log: (scope, message) => console.log(`[${scope}] ${message}`), + apiKey: opencodeGoKey, }); }, getClaudeCliExtensionStatus: () => { diff --git a/packages/cli/src/commands/startup-model-sync.ts b/packages/cli/src/commands/startup-model-sync.ts index 79d3b88220..7322d6cf5b 100644 --- a/packages/cli/src/commands/startup-model-sync.ts +++ b/packages/cli/src/commands/startup-model-sync.ts @@ -233,10 +233,15 @@ export function parseOpencodeModelsOutput(stdout: string): string[] { return [...ids]; } -export async function discoverOpencodeGoModels(): Promise { +export async function discoverOpencodeGoModels(apiKey?: string): Promise { return await new Promise((resolve, reject) => { + const env: Record = { ...process.env as Record }; + if (apiKey) { + env.OPENCODE_API_KEY = apiKey; + } const proc = spawn("opencode", ["models", "opencode", "--refresh"], { stdio: ["ignore", "pipe", "pipe"], + env, }); let stdout = ""; @@ -272,10 +277,11 @@ export async function discoverOpencodeGoModels(): Promise { export async function refreshOpencodeGoModels(options: { modelRegistry: ModelRegistryLike; log: (scope: string, message: string) => void; + apiKey?: string; }): Promise { try { - const { modelRegistry, log } = options; - const modelIds = await discoverOpencodeGoModels(); + const { modelRegistry, log, apiKey } = options; + const modelIds = await discoverOpencodeGoModels(apiKey); if (modelIds.length === 0) { log("opencode-go", "No models discovered from opencode CLI refresh"); return { registeredCount: 0, reason: "no-models-from-cli" }; @@ -310,6 +316,7 @@ export async function syncStartupModels(options: StartupSyncOptions): Promise Date: Fri, 5 Jun 2026 10:40:01 +1000 Subject: [PATCH 002/112] fix: strip provider prefix from opencode-go model IDs normalizeOpencodeGoModel was prefixing model IDs with 'opencode-go/' (e.g. 'opencode-go/deepseek-v4-flash'), but the Pi SDK sends the model id field as the model name in API requests. The OpenCode API expects bare model names (e.g. 'deepseek-v4-flash'), not prefixed ones. Now strips the 'opencode/' or 'opencode-go/' prefix entirely so the registered model ID matches what the API expects. --- packages/cli/src/commands/startup-model-sync.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/startup-model-sync.ts b/packages/cli/src/commands/startup-model-sync.ts index 7322d6cf5b..ef5a1d30c2 100644 --- a/packages/cli/src/commands/startup-model-sync.ts +++ b/packages/cli/src/commands/startup-model-sync.ts @@ -205,15 +205,18 @@ async function syncOpenRouterModels(options: StartupSyncOptions, settings: Setti export function normalizeOpencodeGoModel(modelId: string): ModelConfig { const trimmed = modelId.trim(); - const normalizedId = trimmed.startsWith("opencode/") - ? `opencode-go/${trimmed.slice("opencode/".length)}` - : trimmed.startsWith("opencode-go/") - ? trimmed - : `opencode-go/${trimmed}`; + // Strip the provider prefix (opencode/ or opencode-go/) — the Pi SDK + // already routes requests by provider, and the OpenCode API expects the + // bare model name (e.g. "deepseek-v4-flash", not "opencode-go/deepseek-v4-flash"). + const bareModel = trimmed.startsWith("opencode-go/") + ? trimmed.slice("opencode-go/".length) + : trimmed.startsWith("opencode/") + ? trimmed.slice("opencode/".length) + : trimmed; return { - id: normalizedId, - name: normalizedId, + id: bareModel, + name: bareModel, reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, From 978d07c96caa873db07ad27f2699cb005a337ac6 Mon Sep 17 00:00:00 2001 From: Tom Durrant Date: Fri, 5 Jun 2026 11:12:40 +1000 Subject: [PATCH 003/112] Address PR review comments - Update test assertions for bare model IDs - Add deduplication guard for models with same bare ID - Add validation for empty model IDs after prefix stripping - Add test for API key forwarded as env var to spawn - Add test for deduplication and empty model ID guard - Extract shared handleOpencodeGoApiKeySaved helper - Add changeset for the published package --- .changeset/fix-opencode-go-api-key-env.md | 15 +++++ .../__tests__/startup-model-sync.test.ts | 56 +++++++++++++++++-- packages/cli/src/commands/daemon.ts | 16 ++---- packages/cli/src/commands/dashboard.ts | 30 ++++------ packages/cli/src/commands/serve.ts | 16 ++---- .../cli/src/commands/startup-model-sync.ts | 34 ++++++++++- 6 files changed, 123 insertions(+), 44 deletions(-) create mode 100644 .changeset/fix-opencode-go-api-key-env.md diff --git a/.changeset/fix-opencode-go-api-key-env.md b/.changeset/fix-opencode-go-api-key-env.md new file mode 100644 index 0000000000..d43e43e884 --- /dev/null +++ b/.changeset/fix-opencode-go-api-key-env.md @@ -0,0 +1,15 @@ +--- +"@runfusion/fusion": patch +--- + +Fix opencode-go model sync: pass API key to CLI and strip provider prefix from model IDs + +Two bugs when using OpenCode Go as a provider: + +1. **Model discovery only returned free models** — the saved Go API key was never passed as `OPENCODE_API_KEY` to the spawned `opencode models opencode --refresh` process. The CLI's internal plugin checks this env var and, when absent, disables all paid models (those with `cost.input > 0`). Only 20 free models appeared instead of all 67. + +2. **API requests failed with 401** — `normalizeOpencodeGoModel` was registering models with prefixed IDs like `opencode-go/deepseek-v4-flash`. The Pi SDK sends `model.id` verbatim in API requests; the OpenCode API expects bare model names (e.g. `deepseek-v4-flash`). The prefix is now stripped during normalization. + +Also deduplicates models when the CLI emits both `opencode/foo` and `opencode-go/foo` for the same model, guards against empty model IDs, and refactors the duplicated `onApiKeySaved` handler into a shared `handleOpencodeGoApiKeySaved` helper. + +After this change, users must re-select their opencode-go model in Settings because model IDs have changed from prefixed to bare names. diff --git a/packages/cli/src/commands/__tests__/startup-model-sync.test.ts b/packages/cli/src/commands/__tests__/startup-model-sync.test.ts index 4daa09537b..9e2d09ac07 100644 --- a/packages/cli/src/commands/__tests__/startup-model-sync.test.ts +++ b/packages/cli/src/commands/__tests__/startup-model-sync.test.ts @@ -9,7 +9,7 @@ vi.mock("node:child_process", () => ({ spawn: mockSpawn, })); -import { parseOpencodeModelsOutput, refreshOpencodeGoModels, syncStartupModels } from "../startup-model-sync.js"; +import { normalizeOpencodeGoModel, parseOpencodeModelsOutput, refreshOpencodeGoModels, syncStartupModels } from "../startup-model-sync.js"; type MockProcess = EventEmitter & { stdout: EventEmitter; @@ -75,8 +75,8 @@ describe("startup-model-sync", () => { expect(registerProvider).toHaveBeenCalledWith("openrouter", expect.objectContaining({ models: expect.any(Array) })); expect(registerProvider).toHaveBeenCalledWith("opencode-go", expect.objectContaining({ models: expect.arrayContaining([ - expect.objectContaining({ id: "opencode-go/gpt-5" }), - expect.objectContaining({ id: "opencode-go/custom" }), + expect.objectContaining({ id: "gpt-5" }), + expect.objectContaining({ id: "custom" }), ]), })); expect(log).toHaveBeenCalledWith("openrouter", expect.stringContaining("Synced")); @@ -257,7 +257,7 @@ describe("startup-model-sync", () => { expect(result).toEqual({ registeredCount: 1 }); expect(registerProvider).toHaveBeenCalledWith("opencode-go", expect.objectContaining({ - models: [expect.objectContaining({ id: "opencode-go/gpt-5" })], + models: [expect.objectContaining({ id: "gpt-5" })], })); }); @@ -319,4 +319,52 @@ describe("startup-model-sync", () => { "opencode-go/custom", ]); }); + + it("deduplicates models when CLI emits both prefix forms", async () => { + mockSpawn.mockImplementation(() => { + const proc = createSpawnProcess(); + queueMicrotask(() => { + proc.stdout.emit("data", Buffer.from("opencode/foo\nopencode-go/foo\nopencode/bar\n")); + proc.emit("exit", 0); + }); + return proc; + }); + + const registerProvider = vi.fn(); + await refreshOpencodeGoModels({ modelRegistry: { registerProvider }, log: vi.fn() }); + + expect(registerProvider).toHaveBeenCalledWith("opencode-go", expect.objectContaining({ + models: [ + expect.objectContaining({ id: "foo" }), + expect.objectContaining({ id: "bar" }), + ], + })); + }); + + it("throws on empty model ID after prefix stripping", () => { + expect(() => normalizeOpencodeGoModel("opencode/")).toThrow("no model name"); + expect(() => normalizeOpencodeGoModel("opencode-go/")).toThrow("no model name"); + }); + + it("accepts apiKey and passes it as env var to spawn", async () => { + mockSpawn.mockImplementation(() => { + const proc = createSpawnProcess(); + queueMicrotask(() => { + proc.stdout.emit("data", Buffer.from("opencode/foo\n")); + proc.emit("exit", 0); + }); + return proc; + }); + + const registerProvider = vi.fn(); + await refreshOpencodeGoModels({ modelRegistry: { registerProvider }, log: vi.fn(), apiKey: "test-key" }); + + expect(mockSpawn).toHaveBeenCalledWith( + "opencode", + ["models", "opencode", "--refresh"], + expect.objectContaining({ + env: expect.objectContaining({ OPENCODE_API_KEY: "test-key" }), + }), + ); + }); }); diff --git a/packages/cli/src/commands/daemon.ts b/packages/cli/src/commands/daemon.ts index ead75bf96b..31172e6bb7 100644 --- a/packages/cli/src/commands/daemon.ts +++ b/packages/cli/src/commands/daemon.ts @@ -71,7 +71,7 @@ import { createReadOnlyAuthFileStorage, mergeAuthStorageReads, wrapAuthStorageWi import { getClaudeCodeCredentialPaths, getCodexCliAuthPath, getFusionAuthPath, getLegacyAuthPaths, getModelRegistryModelsPath, getPackageManagerAgentDir } from "./auth-paths.js"; import { resolveProject } from "../project-context.js"; import { ensureBundledDependencyGraphPluginInstalled } from "../plugins/bundled-plugin-install.js"; -import { refreshOpencodeGoModels, syncStartupModels } from "./startup-model-sync.js"; +import { handleOpencodeGoApiKeySaved, syncStartupModels } from "./startup-model-sync.js"; import { ensureCwdProjectRegistered } from "./ensure-project-registered.js"; const DIAGNOSTIC_INTERVAL_MS = 30 * 60 * 1000; // 30 minutes @@ -720,16 +720,12 @@ export async function runDaemon(opts: DaemonOptions = {}) { if (providerId !== "opencode" && providerId !== "opencode-go") { return undefined; } - const settings = await store.getSettings(); - if (settings.opencodeGoModelSync === false) { - return { registeredCount: 0, reason: "disabled-by-settings" }; - } - const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); - return await refreshOpencodeGoModels({ + return await handleOpencodeGoApiKeySaved( + dashboardAuthStorage, + store, modelRegistry, - log: (scope, message) => console.log(`[${scope}] ${message}`), - apiKey: opencodeGoKey, - }); + (scope, message) => console.log(`[${scope}] ${message}`), + ); }, getClaudeCliExtensionStatus: () => { const r = getCachedClaudeCliResolution(); diff --git a/packages/cli/src/commands/dashboard.ts b/packages/cli/src/commands/dashboard.ts index a41f7b8055..21cbfbba65 100644 --- a/packages/cli/src/commands/dashboard.ts +++ b/packages/cli/src/commands/dashboard.ts @@ -83,7 +83,7 @@ import { getCachedUpdateStatus, isUpdateCheckEnabled } from "../update-cache.js" import { resolveSelfExtension } from "./self-extension.js"; import { ensureBundledDependencyGraphPluginInstalled, ensureBundledPluginInstalled, isBundledPluginId } from "../plugins/bundled-plugin-install.js"; import { registerCustomProviders, reregisterCustomProviders } from "./custom-provider-registry.js"; -import { refreshOpencodeGoModels, syncStartupModels } from "./startup-model-sync.js"; +import { handleOpencodeGoApiKeySaved, syncStartupModels } from "./startup-model-sync.js"; import { DashboardTUI, DashboardLogSink, isTTYAvailable, type SystemInfo, type GitStatus, type GitCommit, type GitCommitDetail, type GitBranch, type GitWorktree, type FileEntry, type FileReadResult, type TaskStep as TUITaskStep, type TaskLogEntry as TUITaskLogEntry, type TaskDetailData, type TaskEvent } from "./dashboard-tui/index.js"; import { DASHBOARD_STARTUP_STATUS, runTuiStartupPrelude } from "./dashboard-startup-chain.js"; @@ -1760,16 +1760,12 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?: if (providerId !== "opencode" && providerId !== "opencode-go") { return undefined; } - const settings = await store.getSettings(); - if (settings.opencodeGoModelSync === false) { - return { registeredCount: 0, reason: "disabled-by-settings" }; - } - const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); - return await refreshOpencodeGoModels({ + return await handleOpencodeGoApiKeySaved( + dashboardAuthStorage, + store, modelRegistry, - log: (scope, message) => logSink.log(message, scope), - apiKey: opencodeGoKey, - }); + (scope, message) => logSink.log(message, scope), + ); }, getClaudeCliExtensionStatus: () => { const r = getCachedClaudeCliResolution(); @@ -2083,16 +2079,12 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?: if (providerId !== "opencode" && providerId !== "opencode-go") { return undefined; } - const settings = await store.getSettings(); - if (settings.opencodeGoModelSync === false) { - return { registeredCount: 0, reason: "disabled-by-settings" }; - } - const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); - return await refreshOpencodeGoModels({ + return await handleOpencodeGoApiKeySaved( + dashboardAuthStorage, + store, modelRegistry, - log: (scope, message) => logSink.log(message, scope), - apiKey: opencodeGoKey, - }); + (scope, message) => logSink.log(message, scope), + ); }, getClaudeCliExtensionStatus: () => { const r = getCachedClaudeCliResolution(); diff --git a/packages/cli/src/commands/serve.ts b/packages/cli/src/commands/serve.ts index 2d6a315d6c..a19b35813a 100644 --- a/packages/cli/src/commands/serve.ts +++ b/packages/cli/src/commands/serve.ts @@ -71,7 +71,7 @@ import { } from "./llama-cpp-extension.js"; import { resolveSelfExtension } from "./self-extension.js"; import { registerCustomProviders, reregisterCustomProviders } from "./custom-provider-registry.js"; -import { refreshOpencodeGoModels, syncStartupModels } from "./startup-model-sync.js"; +import { handleOpencodeGoApiKeySaved, syncStartupModels } from "./startup-model-sync.js"; import { ensureBundledDependencyGraphPluginInstalled, ensureBundledPluginInstalled, isBundledPluginId } from "../plugins/bundled-plugin-install.js"; import { ensureCwdProjectRegistered } from "./ensure-project-registered.js"; @@ -827,16 +827,12 @@ export async function runServe( if (providerId !== "opencode" && providerId !== "opencode-go") { return undefined; } - const settings = await store.getSettings(); - if (settings.opencodeGoModelSync === false) { - return { registeredCount: 0, reason: "disabled-by-settings" }; - } - const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); - return await refreshOpencodeGoModels({ + return await handleOpencodeGoApiKeySaved( + dashboardAuthStorage, + store, modelRegistry, - log: (scope, message) => console.log(`[${scope}] ${message}`), - apiKey: opencodeGoKey, - }); + (scope, message) => console.log(`[${scope}] ${message}`), + ); }, getClaudeCliExtensionStatus: () => { const r = getCachedClaudeCliResolution(); diff --git a/packages/cli/src/commands/startup-model-sync.ts b/packages/cli/src/commands/startup-model-sync.ts index ef5a1d30c2..2700c448d6 100644 --- a/packages/cli/src/commands/startup-model-sync.ts +++ b/packages/cli/src/commands/startup-model-sync.ts @@ -214,6 +214,10 @@ export function normalizeOpencodeGoModel(modelId: string): ModelConfig { ? trimmed.slice("opencode/".length) : trimmed; + if (!bareModel) { + throw new Error(`Invalid opencode-go model ID: "${modelId}" has no model name after provider prefix`); + } + return { id: bareModel, name: bareModel, @@ -290,7 +294,15 @@ export async function refreshOpencodeGoModels(options: { return { registeredCount: 0, reason: "no-models-from-cli" }; } - const models = modelIds.map(normalizeOpencodeGoModel); + const normalized = modelIds.map(normalizeOpencodeGoModel); + // Deduplicate: CLI can emit both "opencode/foo" and "opencode-go/foo" + // which normalize to the same bare ID. + const seen = new Set(); + const models = normalized.filter((m) => { + if (seen.has(m.id)) return false; + seen.add(m.id); + return true; + }); modelRegistry.registerProvider("opencode-go", { baseUrl: "https://api.opencode.ai/v1", apiKey: "OPENCODE_API_KEY", @@ -323,3 +335,23 @@ export async function syncStartupModels(options: StartupSyncOptions): Promise Promise }, + modelRegistry: ModelRegistryLike, + log: (scope: string, message: string) => void, +): Promise { + const settings = await store.getSettings(); + if (settings.opencodeGoModelSync === false) { + return { registeredCount: 0, reason: "disabled-by-settings" }; + } + const opencodeGoKey = await dashboardAuthStorage.getApiKey("opencode-go") ?? await dashboardAuthStorage.getApiKey("opencode"); + return await refreshOpencodeGoModels({ modelRegistry, log, apiKey: opencodeGoKey }); +} From 297a00d3de5b2531b20453664be82671a475bc25 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 4 Jun 2026 19:26:48 -0700 Subject: [PATCH 004/112] feat(dashboard): redesign workflow nodes as card-style with config summaries --- ...at-node-editor-visual-edge-upgrade-plan.md | 267 ++++++++++++++++++ .../app/components/WorkflowNodeEditor.css | 87 +++++- .../app/components/WorkflowNodeEditor.tsx | 45 ++- .../__tests__/WorkflowNodeEditor.test.tsx | 29 +- .../__tests__/workflow-flow-mapping.test.ts | 20 ++ .../nodes/WorkflowEditorCatalogContext.ts | 13 + .../components/nodes/WorkflowNodeTypes.tsx | 37 ++- .../nodes/__tests__/node-summary.test.ts | 145 ++++++++++ .../app/components/nodes/node-summary.ts | 165 +++++++++++ .../app/components/workflow-flow-mapping.ts | 18 +- packages/i18n/locales/en/app.json | 9 +- packages/i18n/locales/es/app.json | 9 +- packages/i18n/locales/fr/app.json | 9 +- packages/i18n/locales/ko/app.json | 9 +- packages/i18n/locales/zh-CN/app.json | 9 +- packages/i18n/locales/zh-TW/app.json | 9 +- packages/i18n/src/resources.d.ts | 97 ++++++- 17 files changed, 943 insertions(+), 34 deletions(-) create mode 100644 docs/plans/2026-06-04-002-feat-node-editor-visual-edge-upgrade-plan.md create mode 100644 packages/dashboard/app/components/nodes/WorkflowEditorCatalogContext.ts create mode 100644 packages/dashboard/app/components/nodes/__tests__/node-summary.test.ts create mode 100644 packages/dashboard/app/components/nodes/node-summary.ts diff --git a/docs/plans/2026-06-04-002-feat-node-editor-visual-edge-upgrade-plan.md b/docs/plans/2026-06-04-002-feat-node-editor-visual-edge-upgrade-plan.md new file mode 100644 index 0000000000..46eaafc59c --- /dev/null +++ b/docs/plans/2026-06-04-002-feat-node-editor-visual-edge-upgrade-plan.md @@ -0,0 +1,267 @@ +--- +title: "feat: Node editor visual redesign + success/failure edge authoring" +type: feat +status: active +date: 2026-06-04 +depth: standard +origin: none (solo planning bootstrap) +--- + +# feat: Node editor visual redesign + success/failure edge authoring + +## Summary + +Upgrade the workflow node editor's authoring experience: redesign graph nodes from small icon+label pills into larger card-style nodes with kind accent colors and config summaries; generalize edge-condition authoring so success/failure is selectable on regular edges (today only step-review edges are editable) with distinct visual styling; and round out editor power/polish — safe node/edge deletion, proper dialogs replacing `window.prompt`/`window.confirm`, inline rename/description, dirty-state guard, auto-layout, and a real empty/onboarding state. UI/authoring layer only — no engine, IR-schema, or compiler-semantics changes. + +--- + +## Problem Frame + +The editor (`packages/dashboard/app/components/WorkflowNodeEditor.tsx`, built on `@xyflow/react`) has grown to 13 editor node kinds with swimlane columns and an edge inspector, but the authoring surface lags the capability underneath: + +- **Nodes are unreadable at a glance.** `NodeShell` (`packages/dashboard/app/components/nodes/WorkflowNodeTypes.tsx`) renders icon + label + tiny badges. A prompt node configured with a model, an agent, or a CLI command looks identical to an unconfigured one; users must click every node to see what it does. +- **Failure edges exist everywhere except the editor.** The IR accepts any `edge.condition` (`parseWorkflowIr` never validates condition values), and the graph executor natively traverses `failure` edges (`shouldTraverseEdge`, `packages/engine/src/workflow-graph-executor.ts:385-392`). But `onConnect` hardcodes every new edge to `success`, and the edge inspector only offers condition controls when the source node is `step-review`. There is no way to author the branching the engine already supports. +- **Authoring chrome is crude.** `window.prompt` for workflow names, `window.confirm` for deletes, no keyboard deletion, no dirty tracking (switching workflows silently discards edits), no auto-layout, and a bare "Select or create a workflow" empty state. + +--- + +## Scope Boundaries + +### In scope +- Card-style node redesign with config summaries and kind accent colors. +- Success/failure edge-condition authoring on regular edges, with distinct edge styling and an honest "interpreter-only" presentation when branching makes the graph non-compilable to the linear step engine. +- Deletion UX (keyboard + buttons) with explicit cascade semantics. +- Dialogs, inline rename/description, dirty-state guard, auto-layout, empty/onboarding state. + +### Deferred to Follow-Up Work +- Undo/redo history for the canvas. +- Workflow import/export, versioning, templates gallery. +- Localizing edge condition labels (kept as canonical IR tokens — see KTD-8). +- Auto-layout inside `foreach` template groups beyond the existing seeded row. + +### Outside this product's identity +- Changing edge/branching **execution** semantics. The graph interpreter, `parseWorkflowIr` graph validation, and the linear-step compiler keep their current behavior; this plan only lets users author what they already support and presents their limits honestly. + +--- + +## Requirements + +**Visual** +- R1 — Graph nodes render as card-style nodes: kind accent color, icon, label, and a config-summary line (model/agent/skill/CLI for prompt nodes; script name; gate mode; hold release; join mode; parser; review type), with a defined header-overflow priority and truncation; existing badges and error badges preserved. +- R2 — Success, failure, and rework edges are distinguishable by at least two independent visual channels: the condition label is always rendered, and failure edges use a distinct dash pattern from success edges; color (token-only, both themes) is a third channel, never the only one. + +**Edge authoring** +- R3 — A user can set a regular edge's condition to `success` or `failure` from the edge inspector via a native `` gated per KTD-2 inside the existing disabled fieldset; compile-banner suffix match + info tone (KTD-4); `interactionWidth` on edges for a forgiving hit target (touch + pointer). +- `packages/dashboard/app/components/workflow-flow-mapping.ts` (modify) — edge `className` for failure edges in `irEdgeToFlow`; always-rendered condition labels; dash styling hooks; ancestor-reachability helper for the cycle guard. +- `packages/dashboard/app/components/WorkflowNodeEditor.css` (modify) — `.wf-edge-failure` (distinct dash pattern + `--ws-error`-derived stroke), success default styling, info-tone banner. +- `packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts` (extend) — mapping-level edge tests. +- `packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx` (extend) — inspector gating tests. +**Approach:** Edge-level behavior is tested at the mapping layer (React Flow doesn't render edges under jsdom). The inspector reuses `updateSelectedEdge` unchanged — only the rendering gate widens, and the condition control is a native ` updateSelectedEdge({ condition: e.target.value })} + > + + + + ) : (

{t( diff --git a/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx b/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx index 0ad766257b..53f752aea5 100644 --- a/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx +++ b/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx @@ -652,3 +652,56 @@ describe("WorkflowNodeEditor — built-in stepwise selection render path", () => expect(approve?.kind).toBeUndefined(); }); }); + +// ── U2: edge-condition authoring (compile-banner split) ───────────────────── +describe("WorkflowNodeEditor — U2 interpreter-only banner", () => { + beforeEach(() => { + vi.mocked(fetchTraits).mockResolvedValue(TRAIT_CATALOG); + vi.mocked(fetchStepParsers).mockResolvedValue(["step-headings", "json-steps"]); + vi.mocked(updateWorkflow).mockImplementation(async (_id, updates) => ({ + ...v2Def(), + ...(updates as object), + })); + }); + afterEach(() => { + cleanup(); + vi.clearAllMocks(); + }); + + async function saveActive() { + await screen.findByText("Save"); + await waitFor(() => expect(screen.getAllByLabelText(/Column name/i).length).toBeGreaterThan(0)); + fireEvent.click(screen.getByText("Save").closest("button")!); + await waitFor(() => expect(updateWorkflow).toHaveBeenCalled()); + } + + it("shows an info-tone status banner (not an error) when compile rejects with the interpreter-deferred suffix", async () => { + vi.mocked(fetchWorkflows).mockResolvedValue([v2Def()]); + vi.mocked(compileWorkflow).mockRejectedValue( + new Error( + "node 'step' branches into 2 edges — graphs with branches require the workflow interpreter (deferred)", + ), + ); + + render( {}} addToast={() => {}} />); + await saveActive(); + + const banner = await screen.findByTestId("wf-interpreter-only-banner"); + expect(banner).toHaveAttribute("role", "status"); + expect(banner.className).toMatch(/wf-editor-banner--info/); + // No alert-toned error banner. + expect(screen.queryByRole("alert")).not.toBeInTheDocument(); + }); + + it("keeps the warning error banner for other (non-interpreter) compile errors", async () => { + vi.mocked(fetchWorkflows).mockResolvedValue([v2Def()]); + vi.mocked(compileWorkflow).mockRejectedValue(new Error("node 'step' has no outgoing edge")); + + render( {}} addToast={() => {}} />); + await saveActive(); + + const banner = await screen.findByRole("alert"); + expect(banner).toHaveTextContent(/no outgoing edge/i); + expect(screen.queryByTestId("wf-interpreter-only-banner")).not.toBeInTheDocument(); + }); +}); diff --git a/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts b/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts index c35206cebb..fba698414a 100644 --- a/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts +++ b/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts @@ -14,6 +14,10 @@ import { foreachChildFlowId, templateNodeIdFromChild, shortConditionLabel, + edgeClassName, + edgeConditionEditability, + wouldCreateCycle, + buildConnectionEdge, COLUMN_BAND_HEIGHT, WF_CARD_WIDTH, WF_CARD_MAX_WIDTH, @@ -457,3 +461,143 @@ describe("card dimension constants (U1)", () => { expect(FOREACH_CHILD_Y + WF_CARD_HEIGHT).toBeLessThanOrEqual(FOREACH_GROUP_HEIGHT); }); }); + +describe("edge-condition authoring (U2)", () => { + it("round-trips a failure condition through flowToIr → irToFlow with class + label", () => { + const ir: WorkflowDefinition["ir"] = { + version: "v1", + name: "wf", + nodes: [ + { id: "start", kind: "start" }, + { id: "n1", kind: "prompt", config: { prompt: "do" } }, + { id: "ok", kind: "prompt", config: { prompt: "ok" } }, + { id: "bad", kind: "prompt", config: { prompt: "bad" } }, + { id: "end", kind: "end" }, + ], + edges: [ + { from: "start", to: "n1", condition: "success" }, + { from: "n1", to: "ok", condition: "success" }, + { from: "n1", to: "bad", condition: "failure" }, + { from: "ok", to: "end", condition: "success" }, + { from: "bad", to: "end", condition: "success" }, + ], + }; + const { nodes, edges } = irToFlow(makeDef(ir)); + const failFlow = edges.find((e) => e.source === "n1" && e.target === "bad")!; + expect(failFlow.data?.condition).toBe("failure"); + expect(failFlow.label).toBe("failure"); + expect(failFlow.className).toBe("wf-edge-failure"); + + const { ir: out } = flowToIr("wf", nodes, edges); + const irFail = out.edges.find((e) => e.from === "n1" && e.to === "bad"); + expect(irFail?.condition).toBe("failure"); + }); + + it("preserves parallel success+failure edges between the same pair through the round-trip", () => { + const flowNodes: FlowNode[] = [ + { id: "a", type: "prompt", position: { x: 0, y: 0 }, data: { kind: "prompt", label: "a" } }, + { id: "b", type: "prompt", position: { x: 100, y: 0 }, data: { kind: "prompt", label: "b" } }, + ]; + const flowEdges = [ + { id: "e-1", source: "a", target: "b", data: { condition: "success" } }, + { id: "e-2", source: "a", target: "b", data: { condition: "failure" } }, + ]; + const { ir } = flowToIr("wf", flowNodes, flowEdges); + expect(ir.edges).toHaveLength(2); + expect(ir.edges.map((e) => e.condition).sort()).toEqual(["failure", "success"]); + + const { edges: reFlow } = irToFlow(makeDef(ir)); + expect(reFlow).toHaveLength(2); + const ids = new Set(reFlow.map((e) => e.id)); + expect(ids.size).toBe(2); + }); + + it("edgeClassName: failure → wf-edge-failure, rework precedence, success → undefined", () => { + expect(edgeClassName("failure", false)).toBe("wf-edge-failure"); + expect(edgeClassName("success", false)).toBeUndefined(); + expect(edgeClassName("failure", true)).toBe("wf-edge-rework"); + }); + + it("edgeConditionEditability gates by source kind (KTD-2)", () => { + expect(edgeConditionEditability("step-review")).toBe("verdicts"); + expect(edgeConditionEditability("prompt")).toBe("conditions"); + expect(edgeConditionEditability("script")).toBe("conditions"); + expect(edgeConditionEditability("gate")).toBe("conditions"); + expect(edgeConditionEditability("code")).toBe("conditions"); + expect(edgeConditionEditability("foreach")).toBe("conditions"); + expect(edgeConditionEditability("split")).toBe("readonly"); + expect(edgeConditionEditability("parse-steps")).toBe("readonly"); + expect(edgeConditionEditability("start")).toBe("readonly"); + expect(edgeConditionEditability(undefined)).toBe("readonly"); + }); + + it("wouldCreateCycle detects back-edges and ignores forward + rework edges", () => { + const chain = [ + { id: "1", source: "a", target: "b", data: { condition: "success" } }, + { id: "2", source: "b", target: "c", data: { condition: "success" } }, + ]; + // c → a closes the loop a→b→c→a. + expect(wouldCreateCycle(chain, "c", "a")).toBe(true); + // a → c is forward, no cycle. + expect(wouldCreateCycle(chain, "a", "c")).toBe(false); + // self-loop. + expect(wouldCreateCycle(chain, "a", "a")).toBe(true); + + // rework edges are excluded from the reachability walk. + const withRework = [ + { id: "1", source: "a", target: "b", data: { condition: "success" } }, + { id: "2", source: "b", target: "c", data: { condition: "success", kind: "rework" } }, + ]; + // c only reachable from b via a rework edge, so c→a is NOT a (non-rework) cycle. + expect(wouldCreateCycle(withRework, "c", "a")).toBe(false); + }); + + it("buildConnectionEdge: builds a success edge, rejects missing endpoints, duplicates, cycles", () => { + const nodes: FlowNode[] = [ + { id: "a", type: "prompt", position: { x: 0, y: 0 }, data: { kind: "prompt", label: "a" } }, + { id: "b", type: "prompt", position: { x: 100, y: 0 }, data: { kind: "prompt", label: "b" } }, + { id: "c", type: "prompt", position: { x: 200, y: 0 }, data: { kind: "prompt", label: "c" } }, + ]; + const edges = [ + { id: "1", source: "a", target: "b", data: { condition: "success" } }, + { id: "2", source: "b", target: "c", data: { condition: "success" } }, + ]; + + // happy path: new success edge with a unique id + interactionWidth. + const ok = buildConnectionEdge({ source: "a", target: "c" }, edges, nodes); + expect("edge" in ok).toBe(true); + if ("edge" in ok) { + expect(ok.edge.data?.condition).toBe("success"); + expect(ok.edge.label).toBe("success"); + expect(ok.edge.interactionWidth).toBeGreaterThan(0); + expect(typeof ok.edge.id).toBe("string"); + } + + // missing endpoint. + expect(buildConnectionEdge({ source: "a", target: null }, edges, nodes)).toEqual({ + error: "missing-endpoint", + }); + + // duplicate of the same condition. + expect(buildConnectionEdge({ source: "a", target: "b" }, edges, nodes)).toEqual({ + error: "duplicate", + }); + + // cycle: c→a closes a→b→c→a. + expect(buildConnectionEdge({ source: "c", target: "a" }, edges, nodes)).toEqual({ + error: "cycle", + }); + }); + + it("buildConnectionEdge exempts intra-foreach-template connections from the cycle guard", () => { + const nodes: FlowNode[] = [ + { id: "g", type: "foreach", position: { x: 0, y: 0 }, data: { kind: "foreach", label: "g" } }, + { id: "g::a", type: "prompt", position: { x: 0, y: 0 }, parentId: "g", data: { kind: "prompt", label: "a" } }, + { id: "g::b", type: "prompt", position: { x: 0, y: 0 }, parentId: "g", data: { kind: "prompt", label: "b" } }, + ]; + const edges = [{ id: "1", source: "g::a", target: "g::b", data: { condition: "success" } }]; + // b→a would be a cycle, but both are children of the same group → allowed. + const res = buildConnectionEdge({ source: "g::b", target: "g::a" }, edges, nodes); + expect("edge" in res).toBe(true); + }); +}); diff --git a/packages/dashboard/app/components/workflow-flow-mapping.ts b/packages/dashboard/app/components/workflow-flow-mapping.ts index cc8a5c9f52..84c15b0795 100644 --- a/packages/dashboard/app/components/workflow-flow-mapping.ts +++ b/packages/dashboard/app/components/workflow-flow-mapping.ts @@ -152,8 +152,19 @@ function foreachConfigOf(node: WorkflowIrNode): WorkflowForeachConfig | undefine return cfg as WorkflowForeachConfig; } +/** CSS class for an edge given its condition + rework kind. Rework takes + * precedence; failure edges get the distinct failure styling; success and other + * conditions get no class (default styling). R2's two-channel rule (label always + * rendered + dash pattern) plus color is enforced by the CSS for these classes. */ +export function edgeClassName(condition: string, isRework: boolean): string | undefined { + if (isRework) return "wf-edge-rework"; + if (condition === "failure") return "wf-edge-failure"; + return undefined; +} + /** Build a React Flow edge from an IR edge. Rework edges (KTD-5) carry kind so - * the editor renders them dashed in the accent color. */ + * the editor renders them dashed in the accent color. Failure edges (R2) carry + * the wf-edge-failure class for a distinct dash + error-token stroke. */ function irEdgeToFlow(edge: WorkflowIrEdge, index: number, idScope = ""): FlowEdge { const condition = edge.condition ?? "success"; const isRework = edge.kind === "rework"; @@ -165,11 +176,16 @@ function irEdgeToFlow(edge: WorkflowIrEdge, index: number, idScope = ""): FlowEd data: { condition, kind: isRework ? "rework" : undefined }, type: isRework ? "step" : undefined, animated: isRework, - className: isRework ? "wf-edge-rework" : undefined, + className: edgeClassName(condition, isRework), + interactionWidth: WF_EDGE_INTERACTION_WIDTH, markerEnd: undefined, }; } +/** Default edge hit-target width (px) so edges are clickable/tappable even when + * visually thin. Applied per-edge (defaultEdgeOptions only seeds new edges). */ +export const WF_EDGE_INTERACTION_WIDTH = 24; + /** Short display label for an edge condition. `outcome:` conditions * render as the verdict alone (KTD-4); everything else verbatim. */ export function shortConditionLabel(condition: string): string { @@ -399,6 +415,123 @@ function flowEdgeToIr(edge: FlowEdge, groupId?: string): WorkflowIrEdge { return { from, to, condition, ...(isRework ? { kind: "rework" as const } : {}) }; } +// ── Edge-condition authoring (U2) ──────────────────────────────────────────── + +/** Editor node kinds whose edges expose a success/failure condition select + * (KTD-2). step-review uses verdict controls; all other kinds are read-only. */ +const CONDITION_EDITABLE_KINDS = new Set(["prompt", "script", "gate", "code", "foreach"]); + +/** Decide what the edge inspector renders for an edge sourced from `sourceKind`: + * - "verdicts": step-review verdict select + rework checkbox (existing); + * - "conditions": success/failure native select (KTD-2); + * - "readonly": a read-only condition note. Pure so the gating is unit-testable + * without rendering edges (jsdom can't). */ +export function edgeConditionEditability( + sourceKind: string | undefined, +): "verdicts" | "conditions" | "readonly" { + if (sourceKind === "step-review") return "verdicts"; + if (sourceKind && CONDITION_EDITABLE_KINDS.has(sourceKind)) return "conditions"; + return "readonly"; +} + +/** True when adding an edge source→target would create a cycle, i.e. `target` + * can already reach `source` by walking existing non-rework edges (rework edges + * are the only legal cycles and are excluded from the reachability walk, per + * KTD-9). Pure + exported so the connect-time guard is testable at the mapping + * layer. */ +export function wouldCreateCycle(edges: FlowEdge[], source: string, target: string): boolean { + if (source === target) return true; + // Build adjacency over non-rework edges only. + const adj = new Map(); + for (const e of edges) { + if ((e.data?.kind as string | undefined) === "rework") continue; + const arr = adj.get(e.source) ?? []; + arr.push(e.target); + adj.set(e.source, arr); + } + // Can `target` reach `source`? If so, the new source→target edge closes a loop. + const seen = new Set(); + const stack = [target]; + while (stack.length) { + const cur = stack.pop()!; + if (cur === source) return true; + if (seen.has(cur)) continue; + seen.add(cur); + for (const next of adj.get(cur) ?? []) stack.push(next); + } + return false; +} + +let edgeSeq = 0; +/** Allocate a globally-unique edge id (mirrors the editor's newNodeId pattern). + * Used by buildConnectionEdge so parallel success+failure edges between the same + * pair don't collide (KTD-3). */ +export function newEdgeId(): string { + edgeSeq += 1; + return `e-${Date.now().toString(36)}-${edgeSeq}`; +} + +/** Result of attempting to build an edge from a React Flow connection. */ +export type BuildConnectionResult = + | { edge: FlowEdge } + | { error: "missing-endpoint" | "duplicate" | "cycle" }; + +/** Construct a new success edge for a React Flow connection, reimplementing the + * sanity guards React Flow's addEdge provided (KTD-3) plus the author-time cycle + * guard (KTD-9). Returns an error tag instead of an edge when the connection is + * rejected so the caller can surface a toast: + * - missing-endpoint: source or target absent; + * - duplicate: an edge with the same source+target+condition already exists + * (parallel edges of a DIFFERENT condition between the same pair ARE allowed); + * - cycle: the connection would close a non-rework loop, and the endpoints are + * not both children of the same foreach template (intra-template rework + * cycles are authored separately and exempt). + */ +export function buildConnectionEdge( + connection: { source?: string | null; target?: string | null }, + edges: FlowEdge[], + nodes: FlowNode[], +): BuildConnectionResult { + const source = connection.source ?? undefined; + const target = connection.target ?? undefined; + if (!source || !target) return { error: "missing-endpoint" }; + + const condition = "success"; + // Skip exact duplicates of the SAME condition (a second identical edge is + // pointless); different conditions between the same pair are allowed. + const isDuplicate = edges.some( + (e) => + e.source === source && + e.target === target && + ((e.data?.condition as string | undefined) ?? "success") === condition, + ); + if (isDuplicate) return { error: "duplicate" }; + + // Cycle guard (KTD-9). Exempt connections where both endpoints are children of + // the same foreach template — those may legitimately be rework cycles authored + // separately; the simplest correct rule applies the guard only to non-template + // connections. + const srcNode = nodes.find((n) => n.id === source); + const tgtNode = nodes.find((n) => n.id === target); + const bothTemplateChildren = + !!srcNode?.parentId && srcNode.parentId === tgtNode?.parentId; + if (!bothTemplateChildren && wouldCreateCycle(edges, source, target)) { + return { error: "cycle" }; + } + + return { + edge: { + id: newEdgeId(), + source, + target, + label: shortConditionLabel(condition), + data: { condition, kind: undefined }, + className: edgeClassName(condition, false), + interactionWidth: WF_EDGE_INTERACTION_WIDTH, + }, + }; +} + // ── Client-side validation (U10) ───────────────────────────────────────────── // // The server's parseWorkflowIr (run on PATCH) is the authority for structural diff --git a/packages/i18n/locales/en/app.json b/packages/i18n/locales/en/app.json index b1b294daf4..b3abf434ca 100644 --- a/packages/i18n/locales/en/app.json +++ b/packages/i18n/locales/en/app.json @@ -6112,6 +6112,12 @@ "switchToPlainText": "Switch to plain text", "yes": "Yes" }, + "taskFields": { + "moreFields": "Additional fields", + "orphaned": "Orphaned fields", + "saveFailed": "Failed to save field", + "unset": "—" + }, "taskForm": { "addDependencies": "Add dependencies", "attachHint": "You can also paste images or drag & drop", @@ -6734,8 +6740,8 @@ "optionColor": "Option color", "optionLabel": "Option label", "optionN": "Option {{n}}", - "optionValue": "Option value", "options": "Options", + "optionValue": "Option value", "placement": "Placement", "placementCard": "Card badge", "placementDetail": "Detail (inline)", @@ -6754,6 +6760,8 @@ "codeNote": "Runs sandboxed TypeScript. Syntax is validated at save.", "codeSource": "Source (TypeScript)", "codeTimeout": "Timeout (ms)", + "cycleBlocked": "That connection would create a cycle — only rework edges inside a for-each template may loop back", + "edgeCondition": "Condition", "edgeConditionLabel": "Condition: {{condition}}", "edgeInspector": "Edge", "edgeNoVerdict": "— success (no verdict) —", @@ -6775,6 +6783,7 @@ "foreachWorktree": "Per-step worktree", "gateBlocks": "Gate (blocks)", "gateMode": "Gate mode", + "interpreterOnly": "This workflow branches, so it runs on the graph interpreter — it can't compile to the linear step engine, but it will still run.", "joinAll": "All branches", "joinAny": "Any branch", "joinMode": "Join mode", @@ -6795,14 +6804,7 @@ "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "Branches run concurrently from this node. Execute and merge seams are not allowed inside a branch.", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "Waits for user input", - "summaryCodeDefault": "TypeScript", - "summaryGateAdvisory": "Advisory", - "summaryGateBlocks": "Gate (blocks)", - "summaryHoldRelease": "Release: {{release}}", - "summaryNotConfigured": "Not configured", - "summaryReviewType": "{{type}} review" + "stepExecuteLabel": "Step execute" }, "workflows": { "duplicateToCustomize": "Duplicate to customize", @@ -6833,11 +6835,5 @@ "installRequestTitle": "Worktrunk install request", "sha256": "SHA-256", "version": "Version" - }, - "taskFields": { - "unset": "—", - "moreFields": "Additional fields", - "orphaned": "Orphaned fields", - "saveFailed": "Failed to save field" } } diff --git a/packages/i18n/locales/en/common.json b/packages/i18n/locales/en/common.json index df3c04e712..99135c414e 100644 --- a/packages/i18n/locales/en/common.json +++ b/packages/i18n/locales/en/common.json @@ -1,9 +1,4 @@ { - "actions": { - "cancel": "Cancel", - "close": "Close", - "save": "Save" - }, "agents": { "ratings": { "trendDeclining": "↓ Declining", @@ -34,7 +29,6 @@ "minutesAgo_other": "{{count}}m ago" } }, - "archive": "Archive", "board": { "rejection": { "capacityExhausted": "That column is at capacity. Try again when a slot frees up.", @@ -44,7 +38,6 @@ "workflowMismatch": "Drag can't move a card between workflows. Use the workflow switcher instead." } }, - "cancel": "Cancel", "chat": { "failedToGetResponse": "Failed to get response", "failureReferenceId": "ID", @@ -54,25 +47,15 @@ "openMailboxMessage": "Open mailbox message", "toolCallArgsPrefix": "args", "toolCallResultPrefix": "result", + "toolCallsCount_one": "{{count}} tool calls", + "toolCallsCount_other": "{{count}} tool calls", + "toolCallsHeader": "Tool calls", "toolCallStatusCompleted": "completed", "toolCallStatusError": "error", "toolCallStatusErrors": "errors", "toolCallStatusRunning": "running", - "toolCallsCount_one": "{{count}} tool calls", - "toolCallsCount_other": "{{count}} tool calls", - "toolCallsHeader": "Tool calls", "viewFailureDetails": "View failure details" }, - "close": "Close", - "columns": { - "archived": "Archived", - "done": "Done", - "in-progress": "In Progress", - "in-review": "In Review", - "todo": "Todo", - "triage": "Planning" - }, - "delete": "Delete", "health": { "anomaly": { "duplicateActiveId": "Duplicate active task ID", @@ -110,13 +93,6 @@ "modelSetToDefault": "{{label}} model set to default" } }, - "nodeStatus": { - "connecting": "Connecting", - "error": "Error", - "offline": "Offline", - "online": "Online", - "unknown": "Unknown" - }, "nodes": { "auth": { "differ": "Auth credentials differ", @@ -137,7 +113,13 @@ "stopped": "Stopped" } }, - "refresh": "Refresh", + "nodeStatus": { + "connecting": "Connecting", + "error": "Error", + "offline": "Offline", + "online": "Online", + "unknown": "Unknown" + }, "research": { "providerGitHub": "GitHub", "providerLlmSynthesis": "LLM Synthesis", @@ -145,7 +127,6 @@ "providerPageFetch": "Page Fetch", "providerWebSearch": "Web Search" }, - "retry": "Retry", "routing": { "policyLabel": { "block": "Block execution", @@ -205,7 +186,6 @@ "zai": "GLM models by Zhipu AI — strong multilingual support" } }, - "skip": "Skip", "taskForm": { "nodeStatusConnecting": "Connecting", "nodeStatusError": "Error", @@ -220,7 +200,6 @@ "refreshSourceInitialLoad": "Initial load", "refreshSourceManual": "Manual" }, - "tryAgain": "Try Again", "workflow": { "postMerge": "Post-merge", "preMerge": "Pre-merge", @@ -230,5 +209,14 @@ "statusRunning": "Running…", "statusSkipped": "Skipped", "waitingForOutput": "Waiting for agent output…" + }, + "workflowNodes": { + "summaryAwaitInput": "Waits for user input", + "summaryCodeDefault": "TypeScript", + "summaryGateAdvisory": "Advisory", + "summaryGateBlocks": "Gate (blocks)", + "summaryHoldRelease": "Release: {{release}}", + "summaryNotConfigured": "Not configured", + "summaryReviewType": "{{type}} review" } } diff --git a/packages/i18n/locales/es/app.json b/packages/i18n/locales/es/app.json index 59023a0349..abeb62cc89 100644 --- a/packages/i18n/locales/es/app.json +++ b/packages/i18n/locales/es/app.json @@ -6112,6 +6112,12 @@ "switchToPlainText": "Cambiar a texto sin formato", "yes": "Sí" }, + "taskFields": { + "moreFields": "Campos adicionales", + "orphaned": "Campos huérfanos", + "saveFailed": "No se pudo guardar el campo", + "unset": "—" + }, "taskForm": { "addDependencies": "Agregar dependencias", "attachHint": "También puedes pegar imágenes o arrastrar y soltar", @@ -6715,11 +6721,47 @@ "unplacedCount_one": "", "unplacedCount_other": "" }, + "workflowFields": { + "add": "Agregar campo", + "addOption": "Agregar opción", + "badge": "Mostrar como insignia", + "default": "Predeterminado", + "defaultLabel": "Valor predeterminado", + "defaultTrue": "Activado por defecto", + "duplicateId": "Ya existe un campo con ese id", + "editId": "Editar id", + "empty": "Aún no hay campos personalizados. Agrega un campo para ampliar el formulario y las tarjetas de la tarea.", + "idLabel": "Id del campo", + "idWarn": "Cambiar el id descarta los valores almacenados con el id anterior (quitar + agregar).", + "nameLabel": "Nombre del campo", + "newFieldName": "Nuevo campo", + "newOptionLabel": "Opción 1", + "noDefault": "— ninguno —", + "optionColor": "Color de la opción", + "optionLabel": "Etiqueta de la opción", + "optionN": "Opción {{n}}", + "options": "Opciones", + "optionValue": "Valor de la opción", + "placement": "Ubicación", + "placementCard": "Insignia de tarjeta", + "placementDetail": "Detalle (en línea)", + "placementSection": "Sección de detalle", + "readOnlyHint": "Los flujos de trabajo integrados son de solo lectura: duplica para editar", + "remove": "Quitar campo", + "removeOption": "Quitar opción", + "required": "Obligatorio", + "title": "Campos", + "typeLabel": "Tipo", + "widget": "Control", + "widgetDefault": "Predeterminado" + }, "workflowNodes": { "advisory": "", "codeNote": "Ejecuta TypeScript en un entorno aislado. La sintaxis se valida al guardar.", "codeSource": "Origen (TypeScript)", "codeTimeout": "Tiempo de espera (ms)", + "cycleBlocked": "", + "edgeCondition": "", "edgeConditionLabel": "Condición: {{condition}}", "edgeInspector": "Conexión", "edgeNoVerdict": "— éxito (sin veredicto) —", @@ -6741,6 +6783,7 @@ "foreachWorktree": "Árbol de trabajo por paso", "gateBlocks": "Compuerta (bloquea)", "gateMode": "Modo de compuerta", + "interpreterOnly": "", "joinAll": "Todas las ramas", "joinAny": "Cualquier rama", "joinMode": "Modo de unión", @@ -6761,14 +6804,7 @@ "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "Las ramas se ejecutan de forma concurrente desde este nodo. No se permiten uniones de ejecución y fusión dentro de una rama.", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "", - "summaryCodeDefault": "", - "summaryGateAdvisory": "", - "summaryGateBlocks": "", - "summaryHoldRelease": "", - "summaryNotConfigured": "", - "summaryReviewType": "" + "stepExecuteLabel": "Step execute" }, "workflows": { "duplicateToCustomize": "", @@ -6799,45 +6835,5 @@ "installRequestTitle": "Solicitud de instalación de Worktrunk", "sha256": "SHA-256", "version": "Versión" - }, - "taskFields": { - "unset": "—", - "moreFields": "Campos adicionales", - "orphaned": "Campos huérfanos", - "saveFailed": "No se pudo guardar el campo" - }, - "workflowFields": { - "add": "Agregar campo", - "addOption": "Agregar opción", - "badge": "Mostrar como insignia", - "default": "Predeterminado", - "defaultLabel": "Valor predeterminado", - "defaultTrue": "Activado por defecto", - "duplicateId": "Ya existe un campo con ese id", - "editId": "Editar id", - "empty": "Aún no hay campos personalizados. Agrega un campo para ampliar el formulario y las tarjetas de la tarea.", - "idLabel": "Id del campo", - "idWarn": "Cambiar el id descarta los valores almacenados con el id anterior (quitar + agregar).", - "nameLabel": "Nombre del campo", - "newFieldName": "Nuevo campo", - "newOptionLabel": "Opción 1", - "noDefault": "— ninguno —", - "optionColor": "Color de la opción", - "optionLabel": "Etiqueta de la opción", - "optionN": "Opción {{n}}", - "optionValue": "Valor de la opción", - "options": "Opciones", - "placement": "Ubicación", - "placementCard": "Insignia de tarjeta", - "placementDetail": "Detalle (en línea)", - "placementSection": "Sección de detalle", - "readOnlyHint": "Los flujos de trabajo integrados son de solo lectura: duplica para editar", - "remove": "Quitar campo", - "removeOption": "Quitar opción", - "required": "Obligatorio", - "title": "Campos", - "typeLabel": "Tipo", - "widget": "Control", - "widgetDefault": "Predeterminado" } } diff --git a/packages/i18n/locales/es/common.json b/packages/i18n/locales/es/common.json index cd3a95ec14..f9fb7e049a 100644 --- a/packages/i18n/locales/es/common.json +++ b/packages/i18n/locales/es/common.json @@ -1,9 +1,4 @@ { - "actions": { - "cancel": "Cancelar", - "close": "Cerrar", - "save": "Guardar" - }, "agents": { "ratings": { "trendDeclining": "", @@ -34,7 +29,6 @@ "minutesAgo_other": "" } }, - "archive": "Archivar", "board": { "rejection": { "capacityExhausted": "", @@ -44,7 +38,6 @@ "workflowMismatch": "" } }, - "cancel": "Cancelar", "chat": { "failedToGetResponse": "", "failureReferenceId": "", @@ -54,25 +47,15 @@ "openMailboxMessage": "", "toolCallArgsPrefix": "", "toolCallResultPrefix": "", + "toolCallsCount_one": "", + "toolCallsCount_other": "", + "toolCallsHeader": "", "toolCallStatusCompleted": "", "toolCallStatusError": "", "toolCallStatusErrors": "", "toolCallStatusRunning": "", - "toolCallsCount_one": "", - "toolCallsCount_other": "", - "toolCallsHeader": "", "viewFailureDetails": "" }, - "close": "Cerrar", - "columns": { - "archived": "Archivado", - "done": "Hecho", - "in-progress": "En progreso", - "in-review": "En revisión", - "todo": "Por hacer", - "triage": "Planificación" - }, - "delete": "Eliminar", "health": { "anomaly": { "duplicateActiveId": "", @@ -110,13 +93,6 @@ "modelSetToDefault": "" } }, - "nodeStatus": { - "connecting": "", - "error": "", - "offline": "", - "online": "", - "unknown": "" - }, "nodes": { "auth": { "differ": "", @@ -137,7 +113,13 @@ "stopped": "" } }, - "refresh": "Actualizar", + "nodeStatus": { + "connecting": "", + "error": "", + "offline": "", + "online": "", + "unknown": "" + }, "research": { "providerGitHub": "", "providerLlmSynthesis": "", @@ -145,7 +127,6 @@ "providerPageFetch": "", "providerWebSearch": "" }, - "retry": "Reintentar", "routing": { "policyLabel": { "block": "", @@ -205,7 +186,6 @@ "zai": "" } }, - "skip": "Omitir", "taskForm": { "nodeStatusConnecting": "", "nodeStatusError": "", @@ -220,7 +200,6 @@ "refreshSourceInitialLoad": "", "refreshSourceManual": "" }, - "tryAgain": "Reintentar", "workflow": { "postMerge": "", "preMerge": "", @@ -230,5 +209,14 @@ "statusRunning": "", "statusSkipped": "", "waitingForOutput": "" + }, + "workflowNodes": { + "summaryAwaitInput": "", + "summaryCodeDefault": "", + "summaryGateAdvisory": "", + "summaryGateBlocks": "", + "summaryHoldRelease": "", + "summaryNotConfigured": "", + "summaryReviewType": "" } } diff --git a/packages/i18n/locales/fr/app.json b/packages/i18n/locales/fr/app.json index 68bd38fe3d..562e0af93f 100644 --- a/packages/i18n/locales/fr/app.json +++ b/packages/i18n/locales/fr/app.json @@ -6112,6 +6112,12 @@ "switchToPlainText": "Basculer vers du texte brut", "yes": "Oui" }, + "taskFields": { + "moreFields": "Champs supplémentaires", + "orphaned": "Champs orphelins", + "saveFailed": "Échec de l'enregistrement du champ", + "unset": "—" + }, "taskForm": { "addDependencies": "Ajouter des dépendances", "attachHint": "Vous pouvez aussi coller des images ou les glisser-déposer", @@ -6715,11 +6721,47 @@ "unplacedCount_one": "", "unplacedCount_other": "" }, + "workflowFields": { + "add": "Ajouter un champ", + "addOption": "Ajouter une option", + "badge": "Afficher comme badge", + "default": "Par défaut", + "defaultLabel": "Valeur par défaut", + "defaultTrue": "Activé par défaut", + "duplicateId": "Un champ avec cet id existe déjà", + "editId": "Modifier l'id", + "empty": "Aucun champ personnalisé pour l'instant. Ajoutez un champ pour étendre le formulaire et les cartes de la tâche.", + "idLabel": "Id du champ", + "idWarn": "Modifier l'id supprime les valeurs stockées sous l'ancien id (retirer + ajouter).", + "nameLabel": "Nom du champ", + "newFieldName": "Nouveau champ", + "newOptionLabel": "Option 1", + "noDefault": "— aucun —", + "optionColor": "Couleur de l'option", + "optionLabel": "Libellé de l'option", + "optionN": "Option {{n}}", + "options": "Options", + "optionValue": "Valeur de l'option", + "placement": "Emplacement", + "placementCard": "Badge de carte", + "placementDetail": "Détail (en ligne)", + "placementSection": "Section de détail", + "readOnlyHint": "Les flux de travail intégrés sont en lecture seule — dupliquez pour modifier", + "remove": "Retirer le champ", + "removeOption": "Retirer l'option", + "required": "Obligatoire", + "title": "Champs", + "typeLabel": "Type", + "widget": "Composant", + "widgetDefault": "Par défaut" + }, "workflowNodes": { "advisory": "", "codeNote": "Exécute du TypeScript en bac à sable. La syntaxe est validée à l’enregistrement.", "codeSource": "Source (TypeScript)", "codeTimeout": "Délai d’expiration (ms)", + "cycleBlocked": "", + "edgeCondition": "", "edgeConditionLabel": "Condition : {{condition}}", "edgeInspector": "Lien", "edgeNoVerdict": "— succès (aucun verdict) —", @@ -6741,6 +6783,7 @@ "foreachWorktree": "Arbre de travail par étape", "gateBlocks": "Barrière (bloque)", "gateMode": "Mode de barrière", + "interpreterOnly": "", "joinAll": "Toutes les branches", "joinAny": "N’importe quelle branche", "joinMode": "Mode de jointure", @@ -6761,14 +6804,7 @@ "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "Les branches s’exécutent simultanément depuis ce nœud. Les jointures d’exécution et de fusion ne sont pas autorisées dans une branche.", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "", - "summaryCodeDefault": "", - "summaryGateAdvisory": "", - "summaryGateBlocks": "", - "summaryHoldRelease": "", - "summaryNotConfigured": "", - "summaryReviewType": "" + "stepExecuteLabel": "Step execute" }, "workflows": { "duplicateToCustomize": "", @@ -6799,45 +6835,5 @@ "installRequestTitle": "Demande d'installation de Worktrunk", "sha256": "SHA-256", "version": "Version" - }, - "taskFields": { - "unset": "—", - "moreFields": "Champs supplémentaires", - "orphaned": "Champs orphelins", - "saveFailed": "Échec de l'enregistrement du champ" - }, - "workflowFields": { - "add": "Ajouter un champ", - "addOption": "Ajouter une option", - "badge": "Afficher comme badge", - "default": "Par défaut", - "defaultLabel": "Valeur par défaut", - "defaultTrue": "Activé par défaut", - "duplicateId": "Un champ avec cet id existe déjà", - "editId": "Modifier l'id", - "empty": "Aucun champ personnalisé pour l'instant. Ajoutez un champ pour étendre le formulaire et les cartes de la tâche.", - "idLabel": "Id du champ", - "idWarn": "Modifier l'id supprime les valeurs stockées sous l'ancien id (retirer + ajouter).", - "nameLabel": "Nom du champ", - "newFieldName": "Nouveau champ", - "newOptionLabel": "Option 1", - "noDefault": "— aucun —", - "optionColor": "Couleur de l'option", - "optionLabel": "Libellé de l'option", - "optionN": "Option {{n}}", - "optionValue": "Valeur de l'option", - "options": "Options", - "placement": "Emplacement", - "placementCard": "Badge de carte", - "placementDetail": "Détail (en ligne)", - "placementSection": "Section de détail", - "readOnlyHint": "Les flux de travail intégrés sont en lecture seule — dupliquez pour modifier", - "remove": "Retirer le champ", - "removeOption": "Retirer l'option", - "required": "Obligatoire", - "title": "Champs", - "typeLabel": "Type", - "widget": "Composant", - "widgetDefault": "Par défaut" } } diff --git a/packages/i18n/locales/fr/common.json b/packages/i18n/locales/fr/common.json index 3e950dc4b7..f9fb7e049a 100644 --- a/packages/i18n/locales/fr/common.json +++ b/packages/i18n/locales/fr/common.json @@ -1,9 +1,4 @@ { - "actions": { - "cancel": "Annuler", - "close": "Fermer", - "save": "Enregistrer" - }, "agents": { "ratings": { "trendDeclining": "", @@ -34,7 +29,6 @@ "minutesAgo_other": "" } }, - "archive": "Archiver", "board": { "rejection": { "capacityExhausted": "", @@ -44,7 +38,6 @@ "workflowMismatch": "" } }, - "cancel": "Annuler", "chat": { "failedToGetResponse": "", "failureReferenceId": "", @@ -54,25 +47,15 @@ "openMailboxMessage": "", "toolCallArgsPrefix": "", "toolCallResultPrefix": "", + "toolCallsCount_one": "", + "toolCallsCount_other": "", + "toolCallsHeader": "", "toolCallStatusCompleted": "", "toolCallStatusError": "", "toolCallStatusErrors": "", "toolCallStatusRunning": "", - "toolCallsCount_one": "", - "toolCallsCount_other": "", - "toolCallsHeader": "", "viewFailureDetails": "" }, - "close": "Fermer", - "columns": { - "archived": "Archivé", - "done": "Terminé", - "in-progress": "En cours", - "in-review": "En revue", - "todo": "À faire", - "triage": "Planification" - }, - "delete": "Supprimer", "health": { "anomaly": { "duplicateActiveId": "", @@ -110,13 +93,6 @@ "modelSetToDefault": "" } }, - "nodeStatus": { - "connecting": "", - "error": "", - "offline": "", - "online": "", - "unknown": "" - }, "nodes": { "auth": { "differ": "", @@ -137,7 +113,13 @@ "stopped": "" } }, - "refresh": "Actualiser", + "nodeStatus": { + "connecting": "", + "error": "", + "offline": "", + "online": "", + "unknown": "" + }, "research": { "providerGitHub": "", "providerLlmSynthesis": "", @@ -145,7 +127,6 @@ "providerPageFetch": "", "providerWebSearch": "" }, - "retry": "Réessayer", "routing": { "policyLabel": { "block": "", @@ -205,7 +186,6 @@ "zai": "" } }, - "skip": "Ignorer", "taskForm": { "nodeStatusConnecting": "", "nodeStatusError": "", @@ -220,7 +200,6 @@ "refreshSourceInitialLoad": "", "refreshSourceManual": "" }, - "tryAgain": "Réessayer", "workflow": { "postMerge": "", "preMerge": "", @@ -230,5 +209,14 @@ "statusRunning": "", "statusSkipped": "", "waitingForOutput": "" + }, + "workflowNodes": { + "summaryAwaitInput": "", + "summaryCodeDefault": "", + "summaryGateAdvisory": "", + "summaryGateBlocks": "", + "summaryHoldRelease": "", + "summaryNotConfigured": "", + "summaryReviewType": "" } } diff --git a/packages/i18n/locales/ko/app.json b/packages/i18n/locales/ko/app.json index a6020eccaa..7e45c6f55a 100644 --- a/packages/i18n/locales/ko/app.json +++ b/packages/i18n/locales/ko/app.json @@ -65,13 +65,13 @@ "notMerged": "병합되지 않음", "refresh": "새로고침", "time": { + "daysAgo_one": "", "daysAgo_other": "", + "hoursAgo_one": "", "hoursAgo_other": "", "justNow": "방금", - "minutesAgo_other": "", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "" + "minutesAgo_one": "", + "minutesAgo_other": "" }, "title": "활동 로그" }, @@ -112,18 +112,18 @@ "showToolOutput": "도구 출력 표시", "switchMarkdown": "마크다운 모드로 전환", "switchPlainText": "일반 텍스트 모드로 전환", + "timeDaysAgo_one": "", "timeDaysAgo_other": "", + "timeHoursAgo_one": "", "timeHoursAgo_other": "", "timeJustNow": "방금", + "timeMinutesAgo_one": "", "timeMinutesAgo_other": "", + "toolEntriesHidden_one": "", "toolEntriesHidden_other": "", "toolsOff": "도구: 끔", "toolsOn": "도구: 켬", - "usingDefault": "기본값 사용 중", - "timeDaysAgo_one": "", - "timeHoursAgo_one": "", - "timeMinutesAgo_one": "", - "toolEntriesHidden_one": "" + "usingDefault": "기본값 사용 중" }, "agentMention": { "membersOf": "#{{roomName}} 멤버", @@ -278,6 +278,7 @@ }, "agents": { "activate": "활성화", + "activeAgents_one": "", "activeAgents_other": "", "activePrefix": "활성: ", "advancedSettingsDesc": "이 에이전트의 하위 수준 설정 옵션.", @@ -288,6 +289,7 @@ "agentMail": "에이전트 메일", "agentModelLabel": "에이전트 모델", "agentPlural": "에이전트들", + "agentsFound_one": "", "agentsFound_other": "", "agentSingular": "에이전트", "agentsLabel": "에이전트", @@ -327,6 +329,7 @@ "bulkActions": "일괄 작업", "bulkActionsLoadFailed": "일괄 에이전트 작업 불러오기 실패: {{error}}", "bulkAgentActions": "에이전트 일괄 작업", + "bulkConfirmMessage_one": "", "bulkConfirmMessage_other": "", "bulkNoEligible": "해당 에이전트 없음", "bulkResult_one": "{{agentWord}} {{successCount}}개 {{action}}; {{skippedCount}}개 건너뜀", @@ -469,6 +472,7 @@ "healthError": "오류", "heartbeat": "하트비트:", "heartbeatAndHealth": "하트비트 및 상태", + "heartbeatClampedToMin_one": "", "heartbeatClampedToMin_other": "", "heartbeatCustom": "커스텀 하트비트 실행", "heartbeatEnabled": "하트비트 활성화", @@ -524,8 +528,10 @@ "importButton": "{{label}} 가져오기", "importComplete": "가져오기 완료", "importDescription": "Agent Companies 패키지에서 에이전트를 가져옵니다. companies.sh 카탈로그에서 공개된 에이전트를 찾아보고, AGENTS.md 파일을 업로드하거나, 디렉터리를 선택하거나, 매니페스트 내용을 붙여넣으세요.", + "importingAgents_one": "", "importingAgents_other": "", "importingAgentsAndSkills": "에이전트 {{agentCount}}개{{agentPlural}}와 스킬 {{skillCount}}개{{skillPlural}} 가져오는 중...", + "importingSkills_one": "", "importingSkills_other": "", "inbox": "받은 편지함", "inheritingProjectDefault": "프로젝트 기본값을 상속 중", @@ -591,6 +597,7 @@ "loadingSkillContent": "스킬 내용 불러오는 중...", "loadingTasks": "작업 불러오는 중...", "loadTasksFailed": "작업을 불러오지 못했습니다", + "logEntries_one": "", "logEntries_other": "", "logsWillAppear": "에이전트가 실행되면 로그가 여기에 표시됩니다.", "logsWillAppearActive": "로그가 여기에 표시됩니다.", @@ -747,15 +754,20 @@ "pauseAgentsFailed": "에이전트를 일시정지하지 못했습니다: {{error}}", "pauseAll": "모두 일시정지", "pauseAllAgents": "모든 에이전트 일시정지", + "pauseAllConfirm_one": "", "pauseAllConfirm_other": "", "pauseAllTitle": "모든 에이전트 일시정지", "pauseCountHint_one": "활성/실행 중인 에이전트 {{count}}개 일시정지", "pauseCountHint_other": "활성/실행 중인 에이전트 {{count}}개 일시정지", + "pauseCountHint_one_one": "", "pauseCountHint_one_other": "", + "pauseCountHint_other_one": "", "pauseCountHint_other_other": "", "pausedPast": "일시정지됨", + "pausedSummary_one": "", "pausedSummary_other": "", "pendingApprovals": "승인 대기 중", + "pendingApprovalsCount_one": "", "pendingApprovalsCount_other": "", "performance": { "avgDuration": "평균 소요 시간", @@ -787,6 +799,7 @@ "categorySelect": "카테고리 선택...", "categorySpeed": "속도", "commentPlaceholder": "선택적 댓글...", + "count_one": "", "count_other": "", "deleteError": "평가를 삭제하지 못했습니다: {{error}}", "deleteRating": "평가 삭제", @@ -795,12 +808,11 @@ "loadError": "평가를 불러오지 못했습니다: {{error}}", "loading": "평가 불러오는 중...", "noRatings": "아직 평가 없음", + "starCount_one": "", "starCount_other": "", "submitRating": "평가 제출", "submitting": "제출 중...", - "title": "사용자 평가", - "count_one": "", - "starCount_one": "" + "title": "사용자 평가" }, "recentRuns": "최근 실행", "reflections": { @@ -837,21 +849,28 @@ "resetDayWeekly": "요일 (0=일요일)", "resetting": "초기화 중...", "result": "결과", + "resultCreated_one": "", "resultCreated_other": "", + "resultErrors_one": "", "resultErrors_other": "", + "resultSkipped_one": "", "resultSkipped_other": "", "resume": "재개", "resumeAction": "재개", "resumeAgentsFailed": "에이전트를 재개하지 못했습니다: {{error}}", "resumeAll": "모두 재개", "resumeAllAgents": "모든 에이전트 재개", + "resumeAllConfirm_one": "", "resumeAllConfirm_other": "", "resumeAllTitle": "모든 에이전트 재개", "resumeCountHint_one": "일시정지된 에이전트 {{count}}개 재개", "resumeCountHint_other": "일시정지된 에이전트 {{count}}개 재개", + "resumeCountHint_one_one": "", "resumeCountHint_one_other": "", + "resumeCountHint_other_one": "", "resumeCountHint_other_other": "", "resumedPast": "재개됨", + "resumedSummary_one": "", "resumedSummary_other": "", "retry": "재시도", "reviewConfiguration": "생성된 구성 검토", @@ -886,6 +905,7 @@ "stopMessage": "이 실행을 중지하시겠습니까?", "stopTitle": "실행 중지" }, + "runsCount_one": "", "runsCount_other": "", "runsSuccessRate": "성공률 {{rate}}%", "runStarted": "실행이 시작되었습니다", @@ -926,7 +946,9 @@ "selectCompany": "", "selectDirectory": "디렉터리 선택", "selected": "선택됨:", + "selectedAgentLabel_one": "", "selectedAgentLabel_other": "", + "selectedSkillLabel_one": "", "selectedSkillLabel_other": "", "selectMemoryFile": "메모리 파일 선택", "selectModel": "모델", @@ -940,12 +962,17 @@ "showSystemAgents": "시스템 에이전트 표시", "skills": "스킬", "skillsDescription": "이 에이전트에서 사용할 수 있는 스킬을 관리합니다.", + "skillsErrors_one": "", "skillsErrors_other": "", + "skillsFound_one": "", "skillsFound_other": "", "skillsHint": "이 에이전트에 할당할 선택적 스킬", + "skillsImported_one": "", "skillsImported_other": "", "skillsNone": "할당된 스킬 없음", + "skillsSelected_one": "", "skillsSelected_other": "", + "skillsSkipped_one": "", "skillsSkipped_other": "", "skillsTitle": "스킬", "skipHeartbeatWhenIdle": "유휴 상태일 때 하트비트 건너뜀", @@ -1049,34 +1076,7 @@ "weekly": "주간", "workingOn": "작업 중", "zoomIn": "확대", - "zoomOut": "축소", - "activeAgents_one": "", - "agentsFound_one": "", - "bulkConfirmMessage_one": "", - "heartbeatClampedToMin_one": "", - "importingAgents_one": "", - "importingSkills_one": "", - "logEntries_one": "", - "pauseAllConfirm_one": "", - "pauseCountHint_one_one": "", - "pauseCountHint_other_one": "", - "pausedSummary_one": "", - "pendingApprovalsCount_one": "", - "resultCreated_one": "", - "resultErrors_one": "", - "resultSkipped_one": "", - "resumeAllConfirm_one": "", - "resumeCountHint_one_one": "", - "resumeCountHint_other_one": "", - "resumedSummary_one": "", - "runsCount_one": "", - "selectedAgentLabel_one": "", - "selectedSkillLabel_one": "", - "skillsErrors_one": "", - "skillsFound_one": "", - "skillsImported_one": "", - "skillsSelected_one": "", - "skillsSkipped_one": "" + "zoomOut": "축소" }, "app": { "backendError": { @@ -1086,12 +1086,12 @@ }, "approval": { "dismissBanner": "승인 알림 배너 닫기", + "needAttention_one": "", "needAttention_other": "", "openMailbox": "메일함 열기", "requestPlural": "요청들", "requests": "승인 요청", - "requestSingular": "요청", - "needAttention_one": "" + "requestSingular": "요청" }, "auth": { "clearAndRetry": "토큰 초기화 후 재시도", @@ -1117,8 +1117,11 @@ "confirmMessage": "이 세션은 다른 탭에서 활성화되어 있습니다. 그래도 여시겠습니까?", "confirmTitle": "활성 세션 열기", "dismissButton": "닫기", + "pillLabel_one": "", "pillLabel_other": "", + "pillTitle_one": "", "pillTitle_other": "", + "pillTitleWithInput_one": "", "pillTitleWithInput_other": "", "popoverHeader": "백그라운드 작업", "status": { @@ -1133,10 +1136,7 @@ "planning": "계획", "sliceInterview": "슬라이스 인터뷰", "subtask": "하위 작업 분류" - }, - "pillLabel_one": "", - "pillTitle_one": "", - "pillTitleWithInput_one": "" + } }, "board": { "archived": "보관됨", @@ -1249,9 +1249,12 @@ "openQuickChat": "빠른 채팅 열기", "queuedMessage": "대기 중: {{preview}}", "quickChatTitle": "빠른 채팅", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "방금", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", "removeAttachment": "{{name}} 첨부 파일 제거", "resizePanelBottom": "아래에서 패널 크기 조정", @@ -1265,6 +1268,7 @@ "resizeSidebar": "채팅 사이드바 크기 조정", "responseCopied": "응답이 복사되었습니다", "responseFailed": "응답 실패", + "roomMemberCount_one": "", "roomMemberCount_other": "", "roomsGroupLabel": "방", "scopeDirect": "다이렉트", @@ -1293,16 +1297,12 @@ "thinkingLabel": "생각 중", "thinkingStatus": "생각 중…", "toolCalls": "도구 호출", + "toolCallsCount_one": "", "toolCallsCount_other": "", "typeMessage": "메시지를 입력하세요...", "unreadMessages": "읽지 않은 메시지", "untitledSession": "제목 없음", - "you": "나", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "roomMemberCount_one": "", - "toolCallsCount_one": "" + "you": "나" }, "chatRooms": { "error": { @@ -1349,8 +1349,10 @@ "actionsTitle": "열 작업", "archiveAllDoneAriaLabel": "완료된 모든 작업 보관", "archiveAllDoneTitle": "완료된 모든 작업 보관", + "archiveAllMessage_one": "", "archiveAllMessage_other": "", "archiveAllTitle": "완료된 모든 작업 보관", + "archivedTasks_one": "", "archivedTasks_other": "", "autoMerge": "자동 병합", "autoMergeDisabled": "자동 병합 비활성화됨", @@ -1362,19 +1364,25 @@ "expandArchivedTitle": "보관된 작업 펼치기", "failedToArchive": "작업 보관에 실패했습니다", "keepProgress": "진행 상황 유지", + "loadMore_one": "", "loadMore_other": "", "moveAllToTodo": "모두 할 일로 이동", + "moveAllToTodoMessage_one": "", "moveAllToTodoMessage_other": "", "moveAllToTodoTitle": "모두 할 일로 이동", + "movedToPlanning_one": "", "movedToPlanning_other": "", + "movedToTodo_one": "", "movedToTodo_other": "", "movePartialFailure": "{{total}}개 중 {{moved}}개 이동됨; {{failed}}개 실패", + "moveToTodoHint_one": "", "moveToTodoHint_other": "", "moveToTodoPartialFailure": "{{total}}개 중 {{moved}}개를 할 일로 이동함; {{failed}}개 실패", "newTask": "새 작업", "noManuallyPausableTasks": "수동으로 일시 중지 가능한 작업이 없습니다", "noTasks": "작업 없음", "noTasksInColumn": "이 열에 작업이 없습니다", + "pauseHint_one": "", "pauseHint_other": "", "preserveProgressMessage": "이 작업에는 완료된 단계가 있습니다. 이동하기 전에 진행 상황을 유지하시겠습니까?", "preserveProgressMoveTodoMessage": "일부 작업에 완료된 단계가 있습니다. 할 일로 이동하기 전에 진행 상황을 유지하시겠습니까?", @@ -1382,7 +1390,9 @@ "promote": "", "promoting": "", "replanAll": "모두 재계획", + "replanAllHint_one": "", "replanAllHint_other": "", + "replanAllMessage_one": "", "replanAllMessage_other": "", "replanAllTitle": "모든 작업 재계획", "resetProgress": "진행 상황 초기화", @@ -1391,22 +1401,12 @@ "resetProgressMoveTodoMessage": "할 일로 이동하기 전에 작업의 단계 진행 상황을 초기화하시겠습니까?", "resetProgressTitle": "진행 상황을 초기화하시겠습니까?", "stopAll": "모두 중지", + "stopAllMessage_one": "", "stopAllMessage_other": "", "stopAllTitle": "모든 작업 중지", "stopPartialFailure": "{{total}}개 중 {{paused}}개 중지됨; {{failed}}개 실패", - "stoppedTasks_other": "", - "archiveAllMessage_one": "", - "archivedTasks_one": "", - "loadMore_one": "", - "moveAllToTodoMessage_one": "", - "movedToPlanning_one": "", - "movedToTodo_one": "", - "moveToTodoHint_one": "", - "pauseHint_one": "", - "replanAllHint_one": "", - "replanAllMessage_one": "", - "stopAllMessage_one": "", - "stoppedTasks_one": "" + "stoppedTasks_one": "", + "stoppedTasks_other": "" }, "comments": { "addButton": "댓글 추가", @@ -1421,8 +1421,8 @@ "updatedSuccess": "댓글이 업데이트되었습니다" }, "commit": { - "filesChanged_other": "", - "filesChanged_one": "" + "filesChanged_one": "", + "filesChanged_other": "" }, "commitDiff": { "error": "커밋 차이 로드 오류: {{error}}", @@ -1564,6 +1564,7 @@ "filterBySeverity": "심각도별 로그 필터", "info": "정보", "lines": "{{count}}줄", + "lines_one": "", "lines_other": "", "loading": "로드 중...", "loadingConfig": "개발 서버 설정 로드 중...", @@ -1573,6 +1574,7 @@ "logs": "로그", "lostConnection": "로그 스트림 연결이 끊겼습니다.", "manual": "수동", + "matchCount_one": "", "matchCount_other": "", "newLogs": "새 로그", "noLogsYet": "아직 로그가 없습니다. 개발 서버를 시작하면 출력이 표시됩니다.", @@ -1621,9 +1623,7 @@ "started": "개발 서버가 시작되었습니다.", "stopped": "개발 서버가 중지되었습니다." }, - "warn": "경고", - "lines_one": "", - "matchCount_one": "" + "warn": "경고" }, "dirPicker": { "ariaLabel": "디렉터리 브라우저", @@ -1742,6 +1742,7 @@ "clearSearch": "검색 지우기", "collapse": "접기", "collapseContent": "내용 접기", + "docCount_one": "", "docCount_other": "", "documentsCreatedIn": "문서는 작업 상세 탭에서 만들어집니다.", "expand": "펼치기", @@ -1762,6 +1763,7 @@ "plain": "일반 텍스트", "projectFiles": "프로젝트 파일", "projectFilesTab": "프로젝트 파일", + "resultCount_one": "", "resultCount_other": "", "retry": "다시 시도", "retryLoading": "문서 다시 불러오기", @@ -1778,9 +1780,7 @@ "taskDocuments": "작업 문서", "taskDocumentsTab": "작업 문서", "title": "문서", - "untitled": "제목 없음", - "docCount_one": "", - "resultCount_one": "" + "untitled": "제목 없음" }, "droidCli": { "active": "활성", @@ -1843,20 +1843,25 @@ }, "executor": { "blocked": "차단됨", + "daysAgo_one": "", "daysAgo_other": "", "escalated": "에스컬레이션됨", "escalatedSuffix": " (에스컬레이션됨)", "hideProjectDir": "프로젝트 디렉터리 숨기기", + "hoursAgo_one": "", "hoursAgo_other": "", "inReview": "검토 중", "justNow": "방금 전", "loading": "불러오는 중...", + "minutesAgo_one": "", "minutesAgo_other": "", "noActivity": "활동 없음", + "overlapBottleneck_one": "", "overlapBottleneck_other": "", "overlapQueue": "중복 대기열", "queued": "대기 중", "running": "실행 중", + "secondsAgo_one": "", "secondsAgo_other": "", "showProjectDir": "프로젝트 디렉터리 보기", "stateIdle": "유휴", @@ -1864,12 +1869,7 @@ "stateRunning": "실행 중", "status": "실행기 상태", "stuck": "중단됨", - "temporary": "임시", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "", - "overlapBottleneck_one": "", - "secondsAgo_one": "" + "temporary": "임시" }, "fileBrowser": { "back": "파일 목록으로 돌아가기", @@ -1943,7 +1943,9 @@ "advancesHelpItem2": "reachable / subsumed / orphaned / superseded — 이미 처리되었습니다 (동등한 내용이 이미 반영되었거나, 원본 SHA가 사라졌거나, HEAD가 이미 재작성된 통합 끝점에 맞춰진 경우 포함).", "advancesHelpItem3": "pending + off / not run — 자동 동기화가 설정에서 비활성화되어 있습니다. 브랜치 ref는 이동했지만 작업 트리가 따라가지 않았습니다.", "advancesHelpItem4": "pending + stash-failed / would-conflict / 유사 — 자동 동기화를 시도했지만 조정할 수 없었습니다 (로컬 편집이 새 커밋과 충돌하는 경우가 일반적).", + "advancesNeedAction_one": "", "advancesNeedAction_other": "", + "aheadOfUpstream_one": "", "aheadOfUpstream_other": "", "aligned": "정렬됨", "apply": "적용", @@ -1960,6 +1962,7 @@ "backToIssuesList": "이슈 목록으로 돌아가기", "backToPullsList": "풀 리퀘스트 목록으로 돌아가기", "baseHead": "기준: HEAD", + "behindUpstream_one": "", "behindUpstream_other": "", "branchLabel": "브랜치:", "cancel": "취소", @@ -1975,10 +1978,14 @@ "commitMessagePlaceholder": "커밋 메시지...", "commitsOnBranch": "{{name}}의 커밋", "commitStagedChanges": "스테이지된 변경 사항 커밋", + "commitsToPull_one": "", "commitsToPull_other": "", + "commitsToPush_one": "", "commitsToPush_other": "", + "commitsToPushHeader_one": "", "commitsToPushHeader_other": "", "committedHash": "커밋됨: {{hash}}", + "conflictedCount_one": "", "conflictedCount_other": "", "conflictReclaimFailed": "충돌 복구 대기 등록 실패", "conflictReclaimQueued": "충돌 복구 대기 등록됨", @@ -2009,8 +2016,10 @@ "deletedBranch": "브랜치 {{name}} 삭제됨", "detectingRemotes": "감지 중…", "diffColon": "diff:", + "discardChangesMessage_one": "", "discardChangesMessage_other": "", "discardChangesTitle": "변경 사항 버리기", + "discardedFiles_one": "", "discardedFiles_other": "", "discardSelected": "선택 항목 버리기", "dismiss": "닫기", @@ -2062,7 +2071,9 @@ "forceDeletedBranch": "브랜치 {{name}} 강제 삭제됨", "fullShaAbbrev": "전체", "ghAuthLoginHint": "PR 생성을 활성화하려면 {{code}}을(를) 실행하세요.", + "headAheadOfIntegration_one": "", "headAheadOfIntegration_other": "", + "headAheadOfOriginIntegration_one": "", "headAheadOfOriginIntegration_other": "", "headVsIntegration": "HEAD vs {{branch}}", "headVsOriginIntegration": "HEAD vs origin/{{branch}}", @@ -2070,11 +2081,14 @@ "hideExplanation": "설명 숨기기", "import": "가져오기", "imported": "가져옴", + "importedCount_one": "", "importedCount_other": "", "importFromGitHub": "GitHub에서 가져오기", "importSubtitle": "감지된 원격을 선택하고 열린 이슈 또는 풀 리퀘스트를 불러온 뒤 보드로 가져오세요.", "importTypeAriaLabel": "가져오기 유형", + "integrationAheadOfHead_one": "", "integrationAheadOfHead_other": "", + "issueCount_one": "", "issueCount_other": "", "load": "불러오기", "loadFromRepoAriaLabel": "저장소에서 {{tab}} 불러오기", @@ -2088,7 +2102,9 @@ "loadingTitle": "불러오는 중…", "loadMoreCommits": "커밋 더 불러오기", "loadTabTitle": "{{tab}} 불러오기", + "localAheadOfOriginIntegration_one": "", "localAheadOfOriginIntegration_other": "", + "localBehindOriginIntegration_one": "", "localBehindOriginIntegration_other": "", "localVsOrigin": "로컬 {{branch}} vs origin", "manualPrFlowHint": "이 작업에 대해 PR 우선 완료를 실행하려면 하단 작업을 사용하세요.", @@ -2104,6 +2120,7 @@ "mergingStatus": "병합 중…", "modalTitle": "Git 관리자", "modified": "수정됨", + "modifiedCount_one": "", "modifiedCount_other": "", "newBranchName": "새 브랜치 이름", "noAheadCommitsFound": "앞선 커밋을 찾을 수 없습니다 (먼저 페치가 필요할 수 있습니다)", @@ -2139,6 +2156,7 @@ "notOnIntegrationBranchTitle": "현재 비통합 브랜치에 있습니다", "noUnstagedChanges": "언스테이지된 변경 사항 없음", "openPullsFrom": "{{remote}}의 열린 풀 리퀘스트", + "originIntegrationAheadOfHead_one": "", "originIntegrationAheadOfHead_other": "", "pop": "팝", "popStashTitle": "스태시 팝 (적용 후 삭제)", @@ -2163,6 +2181,7 @@ "prUnlinked": "PR #{{number}} 연결 해제됨", "pull": "풀", "pullCompleted": "풀 완료", + "pullCount_one": "", "pullCount_other": "", "pullFailed": "풀 실패", "pullOptions": "풀 옵션", @@ -2170,6 +2189,7 @@ "pullRebase": "Pull --rebase", "pullRebaseCompleted": "Pull --rebase 완료", "pullRequestHeading": "풀 리퀘스트", + "pullRequestsCount_one": "", "pullRequestsCount_other": "", "push": "푸시", "pushCompleted": "푸시 완료", @@ -2222,10 +2242,14 @@ "stageAll": "모두 스테이지", "stageAllAndCommit": "모두 스테이지 후 커밋", "stageAllAndCommitTitle": "전체 스테이징 및 커밋", + "stageCount_one": "", "stageCount_other": "", "staged": "스테이징됨", + "stagedChanges_one": "", "stagedChanges_other": "", + "stagedCount_one": "", "stagedCount_other": "", + "stagedFiles_one": "", "stagedFiles_other": "", "stageFile": "파일 스테이징", "stageSelected": "선택 항목 스테이징", @@ -2274,13 +2298,17 @@ "unlinkButton": "연결 해제", "unresolvedMergeConflicts": "해결되지 않은 병합 충돌", "unstageAll": "전체 스테이징 취소", + "unstageCount_one": "", "unstageCount_other": "", "unstaged": "스테이징 취소됨", + "unstagedChanges_one": "", "unstagedChanges_other": "", + "unstagedFiles_one": "", "unstagedFiles_other": "", "unstageFile": "파일 스테이징 취소", "unstageSelected": "선택 항목 스테이징 취소", "untracked": "추적되지 않음", + "untrackedCount_one": "", "untrackedCount_other": "", "upToDate": "최신 상태", "view": "보기", @@ -2291,40 +2319,13 @@ "workingTreeModified": "수정됨", "worktreeBadgeBare": "bare", "worktreeBadgeMain": "main", - "worktreesInUse_other": "", - "worktreesTotal_other": "", - "advancesNeedAction_one": "", - "aheadOfUpstream_one": "", - "behindUpstream_one": "", - "commitsToPull_one": "", - "commitsToPush_one": "", - "commitsToPushHeader_one": "", - "conflictedCount_one": "", - "discardChangesMessage_one": "", - "discardedFiles_one": "", - "headAheadOfIntegration_one": "", - "headAheadOfOriginIntegration_one": "", - "importedCount_one": "", - "integrationAheadOfHead_one": "", - "issueCount_one": "", - "localAheadOfOriginIntegration_one": "", - "localBehindOriginIntegration_one": "", - "modifiedCount_one": "", - "originIntegrationAheadOfHead_one": "", - "pullCount_one": "", - "pullRequestsCount_one": "", - "stageCount_one": "", - "stagedChanges_one": "", - "stagedCount_one": "", - "stagedFiles_one": "", - "unstageCount_one": "", - "unstagedChanges_one": "", - "unstagedFiles_one": "", - "untrackedCount_one": "", "worktreesInUse_one": "", - "worktreesTotal_one": "" + "worktreesInUse_other": "", + "worktreesTotal_one": "", + "worktreesTotal_other": "" }, "goals": { + "activeCount_one": "", "activeCount_other": "", "addGoal": "목표 추가", "archive": "보관", @@ -2343,8 +2344,7 @@ "title": "목표", "titleRequired": "제목은 필수입니다.", "unarchive": "보관 해제", - "updateError": "현재 목표 상태를 업데이트할 수 없습니다. 다시 시도해 주세요.", - "activeCount_one": "" + "updateError": "현재 목표 상태를 업데이트할 수 없습니다. 다시 시도해 주세요." }, "groupTask": { "abandonGroup": "", @@ -2365,6 +2365,7 @@ "unavailable": "브랜치 그룹을 사용할 수 없습니다." }, "header": { + "activePlanningSessions_one": "", "activePlanningSessions_other": "", "addFirstScript": "첫 번째 스크립트 추가", "additionalHeaderActions": "추가 헤더 작업", @@ -2391,6 +2392,7 @@ "localNode": "로컬", "mailbox": "메일함", "mailboxView": "메일함 보기", + "mailboxWithCount_one": "", "mailboxWithCount_other": "", "manageProjects": "프로젝트 관리", "manageScripts": "스크립트 관리...", @@ -2413,6 +2415,7 @@ "reliabilityView": "안정성", "researchView": "리서치", "resumePlanningSession": "계획 세션 재개", + "resumePlanningSessionCount_one": "", "resumePlanningSessionCount_other": "", "resumeScheduling": "스케줄링 재개", "scripts": "스크립트", @@ -2434,16 +2437,13 @@ "terminal": "터미널", "todosView": "할 일", "unreadChatResponse": "읽지 않은 채팅 응답", + "unreadMessages_one": "", "unreadMessages_other": "", "viewActivityLog": "활동 로그 보기", "viewProjects": "프로젝트 보기", "viewUsage": "사용량 보기", "workflowSteps": "워크플로 단계", - "workingBranch": "작업 브랜치", - "activePlanningSessions_one": "", - "mailboxWithCount_one": "", - "resumePlanningSessionCount_one": "", - "unreadMessages_one": "" + "workingBranch": "작업 브랜치" }, "health": { "activeTasks": "활성 작업", @@ -2515,6 +2515,7 @@ "expandTaskOptions": "고급 작업 옵션 펼치기", "hintEnterEsc": "Enter로 생성 · Esc로 취소", "loadingAgents": "에이전트 불러오는 중...", + "model_one": "", "model_other": "", "models": "모델", "noAgentsAvailable": "사용 가능한 에이전트 없음", @@ -2533,8 +2534,7 @@ "selectExecutionNode": "실행 노드 선택", "subtask": "하위 작업", "useDefault": "기본값 사용", - "whatNeedsToBeDone": "무엇을 해야 하나요?", - "model_one": "" + "whatNeedsToBeDone": "무엇을 해야 하나요?" }, "insights": { "allInsights": "모든 인사이트", @@ -2580,6 +2580,7 @@ "runCompleted": "{{created}}개 생성됨, {{updated}}개 업데이트됨", "showAllInsights": "모든 인사이트 표시", "showArchived": "보관된 인사이트 표시", + "showArchivedLabel_one": "", "showArchivedLabel_other": "", "showBacklogHealth": "백로그 상태 인사이트만 표시", "taskCreated": "\"{{title}}\"에서 작업 생성됨", @@ -2591,8 +2592,7 @@ "unarchiveLabel": "이 인사이트 보관 해제", "unarchiveTitle": "이 인사이트 보관 해제", "unarchiving": "\"{{title}}\" 보관 해제 중...", - "usePlanningDefault": "계획 기본값 사용", - "showArchivedLabel_one": "" + "usePlanningDefault": "계획 기본값 사용" }, "interview": { "addContextDirection": "추가 컨텍스트나 방향을 입력하세요...", @@ -2647,13 +2647,16 @@ "archiveSelectedTitle": "완료된 선택 작업 보관", "archiveUnavailable": "보관 작업을 사용할 수 없습니다.", "archiveViaButton": "작업은 보관 버튼을 통해서만 보관할 수 있습니다.", + "bulkArchiveDone_one": "", "bulkArchiveDone_other": "", + "bulkArchiveMessage_one": "", "bulkArchiveMessage_other": "", "bulkArchiveNoTasks": "보관할 수 있는 선택된 작업이 없습니다 (완료된 작업만 가능)", "bulkArchiveSummary": "{{archived}}개 보관됨 · {{skipped}}개 건너뜀 · {{failed}}개 실패", "bulkArchiveTitle": "선택된 작업 보관", "bulkDeleteAll": "전체 삭제", "bulkDeleteArchiveSummary": "{{archived}}개 보관됨, {{deleted}}개 삭제됨, {{failed}}개 실패", + "bulkDeleteMessage_one": "", "bulkDeleteMessage_other": "", "bulkDeleteNoTasks": "삭제할 수 있는 선택된 작업이 없습니다 (보관된 작업 제외)", "bulkDeleteSummary_one": "{{count}}개 작업 삭제됨 · {{skipped}}개 보관됨 건너뜀 · {{failed}}개 실패", @@ -2669,6 +2672,7 @@ "bulkUnpauseSummary": "{{unpaused}}개 재개됨 · {{skipped}}개 건너뜀 · {{failed}}개 실패", "bulkUpdateFailed": "모델 업데이트에 실패했습니다", "bulkUpdateNoTasks": "업데이트할 유효한 작업이 없습니다 (보관된 작업은 수정할 수 없습니다)", + "bulkUpdateSuccess_one": "", "bulkUpdateSuccess_other": "", "cancelMove": "이동 취소", "clear": "지우기", @@ -2689,6 +2693,7 @@ "filterChip": "필터: {{column}}", "forceDelete": "강제 삭제", "forceDeleteTitle": "작업 강제 삭제", + "hidden_one": "", "hidden_other": "", "hideDone": "완료 숨기기", "hideDoneTitle": "완료된 작업 숨기기", @@ -2719,6 +2724,7 @@ "resizeSidebar": "작업 목록 사이드바 크기 조정", "reviewerModel": "검토 모델", "selectAll": "표시된 모든 작업 선택", + "selectedCount_one": "", "selectedCount_other": "", "selectTask": "{{taskId}} 선택", "selectTaskPrompt": "작업을 선택하여 세부 정보를 확인하세요", @@ -2730,7 +2736,9 @@ "staleOnlyTitle": "오래된 작업만 표시", "stalePausedReview": "오래된 일시정지 검토", "stalePausedReviewTitle": "오래된 일시정지 검토 작업만 표시", + "stats_one": "", "stats_other": "", + "statsInColumn_one": "", "statsInColumn_other": "", "statusMergingFix": "수정 사항 병합 중…", "stuck": "막힘", @@ -2739,15 +2747,7 @@ "unpauseSelectedTitle": "현재 일시정지된 선택된 작업을 재개합니다", "unpauseUnavailable": "재개 작업을 사용할 수 없습니다", "useProjectDefault": "프로젝트 기본값 사용", - "viewOptions": "보기 옵션", - "bulkArchiveDone_one": "", - "bulkArchiveMessage_one": "", - "bulkDeleteMessage_one": "", - "bulkUpdateSuccess_one": "", - "hidden_one": "", - "selectedCount_one": "", - "stats_one": "", - "statsInColumn_one": "" + "viewOptions": "보기 옵션" }, "mailbox": { "agent": "에이전트", @@ -2791,6 +2791,7 @@ "markAllRead": "모두 읽음으로 표시", "markAllReadButton": "모두 읽음으로 표시", "markAllReadTitle": "모두 읽음으로 표시", + "markedAsRead_one": "", "markedAsRead_other": "", "markReadFailed": "메시지를 읽음으로 표시하는 데 실패했습니다", "messageDeleted": "메시지가 삭제되었습니다", @@ -2817,9 +2818,12 @@ "replyLoadFailed": "답장한 메시지를 불러오는 데 실패했습니다. 다시 시도하려면 클릭하세요.", "selectMessageToRead": "읽을 메시지를 선택하세요", "system": "시스템", + "timeDaysAgo_one": "", "timeDaysAgo_other": "", + "timeHoursAgo_one": "", "timeHoursAgo_other": "", "timeJustNow": "방금", + "timeMinsAgo_one": "", "timeMinsAgo_other": "", "title": "메일함", "to": "받는 사람", @@ -2830,11 +2834,7 @@ "typeSystem": "시스템", "typeUserToAgent": "나 → 에이전트", "user": "사용자", - "you": "나", - "markedAsRead_one": "", - "timeDaysAgo_one": "", - "timeHoursAgo_one": "", - "timeMinsAgo_one": "" + "you": "나" }, "memory": { "auditChecksTitle": "감사 검사", @@ -2851,6 +2851,7 @@ "capReadable": "읽기 가능", "capWritable": "쓰기 가능", "categories": "카테고리", + "charCount_one": "", "charCount_other": "", "compactFailed": "메모리 압축에 실패했습니다", "compacting": "압축 중…", @@ -2886,7 +2887,9 @@ "healthIssues": "문제 발견됨", "healthStatusTitle": "상태", "healthWarning": "경고", + "insightCount_one": "", "insightCount_other": "", + "insightsExtracted_one": "", "insightsExtracted_other": "", "insightsMemoryLabel": "인사이트 메모리", "insightsSaved": "인사이트가 저장되었습니다", @@ -2937,6 +2940,7 @@ "saveSettingsFailed": "메모리 설정 저장에 실패했습니다", "saving": "저장 중…", "searchPlaceholder": "qmd로 메모리 검색", + "sectionCount_one": "", "sectionCount_other": "", "settingsNote": "참고: 백엔드 유형 변경은", "settingsNoteLink": "설정 → 메모리", @@ -2948,18 +2952,14 @@ "tabWorking": "작업 메모리", "testing": "테스트 중…", "testMemorySearchTitle": "메모리 검색 테스트", + "testResultCount_one": "", "testResultCount_other": "", "testResultStatus": "qmd {{qmdStatus}} · {{fallbackStatus}}", "testRetrieval": "검색 테스트", "testSearchHint": "에이전트가 사용하는 동일한 qmd 기반 memory_search 경로를 실행합니다.", "title": "메모리", "totalInsights": "총 인사이트", - "workingMemoryLabel": "작업 메모리", - "charCount_one": "", - "insightCount_one": "", - "insightsExtracted_one": "", - "sectionCount_one": "", - "testResultCount_one": "" + "workingMemoryLabel": "작업 메모리" }, "merge": { "advanced": "고급", @@ -2980,6 +2980,7 @@ "pr": "PR", "pulling": "가져오는 중…", "pushForceWithLease": "푸시 (force-with-lease)", + "pushHeading_one": "", "pushHeading_other": "", "pushing": "푸시 중…", "pushSuccess": "origin/{{branch}} @ {{sha}}에 푸시되었습니다.", @@ -2988,8 +2989,7 @@ "shortstatTitle": "최종 커밋 요약; 모든 작업 커밋에 걸친 전체 랜딩 diff는 변경 탭을 참조하세요.", "smartPull": "스마트 풀", "status": "상태", - "title": "병합 세부 정보", - "pushHeading_one": "" + "title": "병합 세부 정보" }, "mesh": { "ariaLabel": "노드 메시 토폴로지 시각화", @@ -3030,6 +3030,7 @@ "assertionTitlePlaceholder": "어설션 제목", "assertionUpdated": "어설션이 업데이트되었습니다", "assertionUpdateFailed": "어설션 업데이트에 실패했습니다", + "attemptRetries_one": "", "attemptRetries_other": "", "autopilotActivatingSlice": "슬라이스 활성화 중", "autopilotCompleting": "완료 중", @@ -3116,6 +3117,7 @@ "featureLinkFailed": "기능 연결에 실패했습니다", "featureLinkTaskFailed": "기능과 작업 연결에 실패했습니다", "featureSaveFailed": "기능 저장에 실패했습니다", + "featuresCount_one": "", "featuresCount_other": "", "featureTitlePlaceholder": "기능 제목", "featureTitleRequired": "기능 제목을 입력해야 합니다", @@ -3153,7 +3155,9 @@ "lastValidatorStatus": "마지막 {{status}}", "linkAFeature": "기능 연결", "linkButton": "연결", + "linkedCount_one": "", "linkedCount_other": "", + "linkedFeaturesCount_one": "", "linkedFeaturesCount_other": "", "linkedFeaturesLabel": "연결된 기능", "linkedGoals": "연결된 목표", @@ -3175,6 +3179,7 @@ "milestoneDeleteFailed": "마일스톤 삭제에 실패했습니다", "milestoneDescriptionPlaceholder": "마일스톤 설명...", "milestoneSaveFailed": "마일스톤 저장에 실패했습니다", + "milestonesCount_one": "", "milestonesCount_other": "", "milestoneTitlePlaceholder": "마일스톤 제목", "milestoneTitleRequired": "마일스톤 제목을 입력해야 합니다", @@ -3211,11 +3216,15 @@ "planStatePlanned": "계획됨", "planTitle": "AI로 미션 계획", "prepareQuestion": "다음 질문 준비 중...", + "progressText_one": "", "progressText_other": "", "reconnecting": "재연결 중…", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "방금 전", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", "removeFeature": "기능 제거", "removeMilestone": "마일스톤 제거", @@ -3250,9 +3259,11 @@ "sliceDeleted": "슬라이스가 삭제되었습니다", "sliceDeleteFailed": "슬라이스 삭제에 실패했습니다", "sliceSaveFailed": "슬라이스 저장에 실패했습니다", + "slicesCount_one": "", "slicesCount_other": "", "sliceTitlePlaceholder": "슬라이스 제목", "sliceTitleRequired": "슬라이스 제목을 입력해야 합니다", + "sliceTriaged_one": "", "sliceTriaged_other": "", "sliceTriageFailed": "슬라이스 기능 분류에 실패했습니다", "sliceUpdated": "슬라이스가 업데이트되었습니다", @@ -3277,8 +3288,10 @@ "statusTriaged": "분류됨", "stopFailed": "미션 중지에 실패했습니다", "stopMission": "미션 중지", + "stopped_one": "", "stopped_other": "", "summaryStats": "{{milestones}}개 마일스톤, {{features}}개 기능. 승인 전에 검토 및 편집하세요.", + "tabActivity_one": "", "tabActivity_other": "", "tabStructure": "구조", "takeControl": "제어권 가져오기", @@ -3287,6 +3300,7 @@ "targetBranchPlaceholder": "예: main", "taskIdPlaceholder": "작업 ID (예: FN-001)", "taskIdRequired": "작업 ID를 입력해야 합니다", + "tasksFailed_one": "", "tasksFailed_other": "", "title": "미션", "titleLabel": "미션 제목", @@ -3304,7 +3318,9 @@ "updateButton": "업데이트", "updated": "미션이 업데이트되었습니다", "validateFeature": "기능 검증", + "validationRoundsCount_one": "", "validationRoundsCount_other": "", + "validationRoundsLabel_one": "", "validationRoundsLabel_other": "", "validationRuns": "검증 실행", "validationState": "검증 상태", @@ -3315,23 +3331,7 @@ "verification": "검증:", "verificationCriteria": "검증 기준", "viewMissionFailures": "미션 실패 보기", - "whatToBuild": "무엇을 만들고 싶으신가요?", - "attemptRetries_one": "", - "featuresCount_one": "", - "linkedCount_one": "", - "linkedFeaturesCount_one": "", - "milestonesCount_one": "", - "progressText_one": "", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "slicesCount_one": "", - "sliceTriaged_one": "", - "stopped_one": "", - "tabActivity_one": "", - "tasksFailed_one": "", - "validationRoundsCount_one": "", - "validationRoundsLabel_one": "" + "whatToBuild": "무엇을 만들고 싶으신가요?" }, "modalManager": { "createdFromPlanning": "계획 모드에서 {{id}}를 생성했습니다", @@ -3347,6 +3347,7 @@ "addToFavorites": "즐겨찾기에 추가", "addToFavoritesAriaLabel": "{{name}}을(를) 즐겨찾기에 추가", "clearFilter": "필터 지우기", + "count_one": "", "count_other": "", "descriptions": { "executor": "이 작업을 구현하는 데 사용되는 AI 모델입니다.", @@ -3401,8 +3402,7 @@ "titles": { "configuration": "모델 구성" }, - "useDefault": "기본값 사용", - "count_one": "" + "useDefault": "기본값 사용" }, "modelSelection": { "choose": "이 작업에 사용할 모델을 선택하세요. 선택하지 않으면 기본 모델이 사용됩니다.", @@ -3477,11 +3477,11 @@ "noAvailableTasks": "사용 가능한 작업 없음", "searchTasks": "작업 검색…", "selectAgent": "에이전트 선택", + "selectedCount_one": "", "selectedCount_other": "", "taskCreated": "{{taskId}} 생성됨", "title": "새 작업", - "unsavedChanges": "저장되지 않은 변경 사항이 있습니다. 버리시겠습니까?", - "selectedCount_one": "" + "unsavedChanges": "저장되지 않은 변경 사항이 있습니다. 버리시겠습니까?" }, "nodes": { "actions": { @@ -3555,6 +3555,7 @@ "containerLogs": "컨테이너 로그", "description": "연결 세부 정보와 동시 실행 설정을 입력하여 기존 Fusion 노드를 등록하세요.", "discoverBeforeAdding": "이 노드를 추가하기 전에 원격 프로젝트를 검색하세요.", + "discoveredCount_one": "", "discoveredCount_other": "", "discovering": "검색 중...", "discoverRemoteProjects": "원격 프로젝트 검색", @@ -3694,6 +3695,7 @@ "refreshing": "새로고침 중...", "refreshStatus": "상태 새로고침", "registered": "노드 \"{{name}}\"이(가) 등록되었습니다", + "registeredCount_one": "", "registeredCount_other": "", "registerFailed": "노드 등록에 실패했습니다", "remote": "원격", @@ -3746,9 +3748,7 @@ "portRange": "포트는 1에서 65535 사이여야 합니다" }, "viewLogsButton": "로그 보기", - "yes": "예", - "discoveredCount_one": "", - "registeredCount_one": "" + "yes": "예" }, "nodeStatus": { "local": "로컬" @@ -4007,10 +4007,14 @@ "questionsLabel": "질문 수", "reconnecting": "재연결 중…", "refineFurther": "추가 다듬기", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "방금 전", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", + "relativeTimeWeeks_one": "", "relativeTimeWeeks_other": "", "remove": "제거", "retryFailed": "재시도 실패. 다시 시도해 주세요.", @@ -4050,11 +4054,7 @@ "untitledSession": "제목 없는 세션", "usingDefault": "기본값 사용", "whatToBuild": "무엇을 만들고 싶으신가요?", - "whatToBuildPlaceholder": "예: 로그인, 회원가입, 비밀번호 재설정이 포함된 사용자 인증 시스템 구축...", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "relativeTimeWeeks_one": "" + "whatToBuildPlaceholder": "예: 로그인, 회원가입, 비밀번호 재설정이 포함된 사용자 인증 시스템 구축..." }, "plugins": { "addItem": "항목 추가", @@ -4089,6 +4089,7 @@ "enablePlugin": "{{name}} 활성화", "enablePluginFailed": "플러그인 활성화 실패: {{error}}", "experimental": "실험적", + "findings_one": "", "findings_other": "", "homepage": "홈페이지:", "install": "설치", @@ -4145,8 +4146,7 @@ "uninstallTitle": "플러그인 전역 제거", "unknownError": "알 수 없는 오류", "updateFailed": "플러그인 업데이트 실패: {{error}}", - "version": "버전:", - "findings_one": "" + "version": "버전:" }, "pr": { "authFail": "gh auth login을 실행한 후 다시 시도하세요.", @@ -4193,11 +4193,15 @@ "confirm": "확인", "confirmRemove": "제거 확인", "confirmRemoveProject": "프로젝트 제거 확인", + "daysAgo_one": "", "daysAgo_other": "", + "hoursAgo_one": "", "hoursAgo_other": "", "justNow": "방금 전", "lastActivity": "마지막 활동:", + "minutesAgo_one": "", "minutesAgo_other": "", + "moreItems_one": "", "moreItems_other": "", "never": "없음", "nodeAvailability": "프로젝트 노드 가용성", @@ -4208,11 +4212,7 @@ "pauseProject": "프로젝트 일시 중지", "removeProject": "프로젝트 제거", "resume": "재개", - "resumeProject": "프로젝트 재개", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "", - "moreItems_one": "" + "resumeProject": "프로젝트 재개" }, "projectDetection": { "editName": "이름 편집", @@ -4221,12 +4221,12 @@ "noDbWarning": "fn 데이터베이스를 찾을 수 없습니다 - 초기화됩니다", "registerAll": "모두 등록", "registering": "등록 중...", - "registerSelected_other": "", - "selectAll_other": "", - "selectedCount_other": "", "registerSelected_one": "", + "registerSelected_other": "", "selectAll_one": "", - "selectedCount_one": "" + "selectAll_other": "", + "selectedCount_one": "", + "selectedCount_other": "" }, "projects": { "actions": { @@ -4284,10 +4284,10 @@ "detecting": "감지 중…", "detectModels": "모델 감지", "detectModelsTitle": "공급자의 /models 엔드포인트를 호출하여 사용 가능한 모델을 검색합니다", + "removeModel_one": "", "removeModel_other": "", "save": "공급자 저장", - "saving": "저장 중...", - "removeModel_one": "" + "saving": "저장 중..." }, "addCustom": "사용자 정의 공급자 추가", "apiKeyLabel": "API 키", @@ -4386,10 +4386,10 @@ "p95": "P95", "p95Raw": "P95 원시값: {{value}} ms", "reason": "사유: {{reason}}", - "sampleCount_other": "", - "samples_other": "", "sampleCount_one": "", - "samples_one": "" + "sampleCount_other": "", + "samples_one": "", + "samples_other": "" }, "failureRate": "실패율: {{rate}}", "heading": "안정성", @@ -4398,14 +4398,14 @@ "insufficientData": "데이터 부족 — {{reason}}", "mergeAttempts": { "heading": "병합 시도", + "histogramTotal_one": "", "histogramTotal_other": "", "max": "최대", "mean": "평균", "moreStats": "추가 통계", "reason": "사유: {{reason}}", - "tasksCounted_other": "", - "histogramTotal_one": "", - "tasksCounted_one": "" + "tasksCounted_one": "", + "tasksCounted_other": "" }, "reason": "사유: {{reason}}", "resetBaseline": "기준선 초기화: {{date}}", @@ -4486,6 +4486,7 @@ "viewLabel": "리서치 보기" }, "routine": { + "andMore_one": "", "andMore_other": "", "delete": "삭제", "deleteMessage": "루틴 {{name}}을(를) 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", @@ -4499,14 +4500,13 @@ "enableName": "{{name}} 활성화", "resultFailed": "실패", "resultSuccess": "성공", + "runHistory_one": "", "runHistory_other": "", "runNameNow": "{{name}} 지금 실행", "running": "실행 중…", "runNow": "지금 실행", - "stepCount_other": "", - "andMore_one": "", - "runHistory_one": "", - "stepCount_one": "" + "stepCount_one": "", + "stepCount_other": "" }, "routing": { "cannotChangeWhileActive": "작업이 활성화된 동안에는 노드 재정의를 변경할 수 없습니다.", @@ -4555,10 +4555,12 @@ "advancedMode": "다단계", "advancedModeHelp": "여러 단계를 순차적으로 실행 (명령어 및 AI 프롬프트)", "aiPromptType": "AI 프롬프트", + "andMore_one": "", "andMore_other": "", "apiEndpointHint": "이 루틴을 트리거하는 API 엔드포인트 경로", "apiEndpointLabel": "API 엔드포인트", "apiEndpointPlaceholder": "/api/routine/my-routine", + "automationCount_one": "", "automationCount_other": "", "cancelButton": "취소", "catchUpPolicyHint": "예약된 실행이 누락되었을 때 처리 방법", @@ -4698,6 +4700,7 @@ "routineSuccess": "\"{{name}}\" 성공적으로 완료됨", "routineUpdated": "루틴이 업데이트되었습니다", "runError": "루틴 실행에 실패했습니다", + "runHistory_one": "", "runHistory_other": "", "runNameNow": "{{name}} 지금 실행", "running": "실행 중…", @@ -4718,6 +4721,7 @@ "simpleMode": "단순", "simpleModeHelp": "단일 셸 명령어 또는 AI 프롬프트 실행", "stepCommandRequired": "단계 {{index}}: 명령어는 필수입니다", + "stepCount_one": "", "stepCount_other": "", "stepName": "단계 이름", "stepNamePlaceholder": "예: 테스트 실행", @@ -4778,11 +4782,7 @@ "webhookPathPlaceholder": "/trigger/my-routine", "webhookSecretHint": "서명 검증용 HMAC 시크릿. 미인증 웹훅은 비워두세요.", "webhookSecretLabel": "Webhook 시크릿 (선택 사항)", - "webhookSecretPlaceholder": "선택 사항 — 미인증 웹훅은 비워두세요", - "andMore_one": "", - "automationCount_one": "", - "runHistory_one": "", - "stepCount_one": "" + "webhookSecretPlaceholder": "선택 사항 — 미인증 웹훅은 비워두세요" }, "scriptsModal": { "addScript": "스크립트 추가", @@ -4807,6 +4807,7 @@ "saving": "저장 중...", "scriptAlreadyExists": "같은 이름의 스크립트가 이미 존재합니다", "scriptCommandRequired": "스크립트 명령이 필요합니다", + "scriptCount_one": "", "scriptCount_other": "", "scriptCreated": "스크립트가 생성되었습니다", "scriptDeleted": "스크립트가 삭제되었습니다", @@ -4814,8 +4815,7 @@ "scriptNamePlaceholder": "예: build, test, lint", "scriptNameRequired": "스크립트 이름이 필요합니다", "scriptUpdated": "스크립트가 업데이트되었습니다", - "title": "스크립트", - "scriptCount_one": "" + "title": "스크립트" }, "secrets": { "accessPolicyAuto": "auto", @@ -4880,17 +4880,17 @@ "failed": "실패", "headerAwaitingAndErrorPlural": "AI 세션 {{awaitingCount}}개가 입력을 기다리고 있으며, {{errorCount}}개가 실패했습니다", "headerAwaitingAndErrorSingular": "AI 세션 {{awaitingCount}}개가 입력을 기다리고 있으며, {{errorCount}}개가 실패했습니다", + "headerAwaitingPlural_one": "", "headerAwaitingPlural_other": "", + "headerAwaitingSingular_one": "", "headerAwaitingSingular_other": "", + "headerErrorPlural_one": "", "headerErrorPlural_other": "", + "headerErrorSingular_one": "", "headerErrorSingular_other": "", "regionLabel": "입력 대기 중이거나 실패한 AI 세션", "resume": "재개", - "retry": "재시도", - "headerAwaitingPlural_one": "", - "headerAwaitingSingular_one": "", - "headerErrorPlural_one": "", - "headerErrorSingular_one": "" + "retry": "재시도" }, "settings": { "actions": { @@ -5253,7 +5253,9 @@ "projectSelected": "프로젝트 선택됨 — 작업 생성 및 가져오기를 사용할 수 있습니다.", "projectSetupDescription": "작업을 생성하거나 가져오기 전에 첫 번째 프로젝트를 선택하세요. 기존 로컬 디렉터리를 등록하거나, 설정 마법사를 통해 GitHub 저장소 URL을 클론할 수 있습니다.", "providersConnectedSummary": "✓ {{total}}개 제공자 중 {{connected}}개 연결됨", + "providersSkippedSummary_one_one": "", "providersSkippedSummary_one_other": "", + "providersSkippedSummary_other_one": "", "providersSkippedSummary_other_other": "", "quickStartProviders": "빠른 시작 제공자", "readinessAiProviderConnected": "{{name}} 연결됨 — AI 에이전트가 작업을 처리할 수 있습니다", @@ -5360,9 +5362,7 @@ "withoutGitHub1": "작업 수동 생성", "withoutGitHub2": "AI 에이전트를 위한 작업 설명", "withoutGitHub3": "보드에서 진행 상황 추적", - "withoutGitHubHeading": "GitHub 없이 (지금 사용 가능):", - "providersSkippedSummary_one_one": "", - "providersSkippedSummary_other_one": "" + "withoutGitHubHeading": "GitHub 없이 (지금 사용 가능):" }, "shell": { "activePill": "활성", @@ -5396,6 +5396,7 @@ "disabled": "스킬 비활성화됨", "disableSkill": "{{name}} 비활성화", "discovered": "검색됨", + "discoveredCount_one": "", "discoveredCount_other": "", "discoveredSection": "검색된 스킬", "enabled": "스킬 활성화됨", @@ -5427,8 +5428,7 @@ "title": "스킬", "toggleError": "스킬 전환 실패", "toggleFailed": "스킬 전환 실패: {{message}}", - "viewDetails": "{{name}} 상세 보기", - "discoveredCount_one": "" + "viewDetails": "{{name}} 상세 보기" }, "specEditor": { "edit": "편집", @@ -5459,17 +5459,17 @@ "dropTitle": "고아 스태시를 삭제하시겠습니까?", "failedToLoadDiff": "diff 로드 실패", "failedToLoadOrphans": "고아 항목 로드 실패", + "fileCount_one": "", "fileCount_other": "", "inspectDiff": "diff 검사", "loadingDiff": "diff 로드 중…", "noDiffOutput": "사용 가능한 diff 출력이 없습니다.", "noOrphans": "고아 merger 자동 스태시가 없습니다.", + "orphanCount_one": "", "orphanCount_other": "", "shaLabel": "SHA", "title": "스태시 복구", - "unknownSource": "알 수 없는 출처", - "fileCount_one": "", - "orphanCount_one": "" + "unknownSource": "알 수 없는 출처" }, "stepType": { "aiPrompt": "AI 프롬프트", @@ -5539,6 +5539,7 @@ "untitled": "제목 없음" }, "syncLog": { + "entryCount_one": "", "entryCount_other": "", "filterAll": "전체", "filterAllNodes": "모든 노드", @@ -5550,8 +5551,7 @@ "noHistory": "사용 가능한 동기화 기록이 없습니다", "resultConflict": "충돌", "resultError": "오류", - "resultSuccess": "성공", - "entryCount_one": "" + "resultSuccess": "성공" }, "systemStats": { "agentActive": "활성", @@ -5572,6 +5572,7 @@ "errorLoadVitestSettings": "vitest 설정 로드 실패", "errorSaveVitestSettings": "vitest 설정 저장 실패", "footerRefreshFailed": "최신 새로 고침 실패: {{error}}", + "killedProcesses_one": "", "killedProcesses_other": "", "killThresholdInputAriaLabel": "종료 임계값 (%)", "killThresholdLabel": "종료 임계값 (%)", @@ -5615,8 +5616,7 @@ "title": "시스템 통계", "updatedAt": "{{time}} 업데이트됨", "vitestProcesses": "Vitest 프로세스", - "waitingFirstUpdate": "첫 업데이트 대기 중", - "killedProcesses_one": "" + "waitingFirstUpdate": "첫 업데이트 대기 중" }, "taskChanges": { "attributionFailed": "착륙된 파일 집합에 외부 커밋이 포함될 수 있습니다 (기여 정보 없음).", @@ -5625,6 +5625,7 @@ "error": "변경 사항 로드 오류: {{error}}", "expandDiff": "전체 화면 diff 보기로 확장", "expandDiffView": "diff 보기 확장", + "filesChangedHeading_one": "", "filesChangedHeading_other": "", "loadError": "작업 변경 사항을 불러오지 못했습니다", "loading": "변경 사항 로드 중...", @@ -5640,8 +5641,7 @@ "previousFile": "이전 파일", "summaryHint": "최종 커밋 요약: {{files}}개 파일{{plural}} 변경, +{{additions}} 추가, -{{deletions}} 삭제. 전체 작업 계보가 아닌 기록된 병합/스쿼시 커밋만 포함됩니다.", "toggleWordWrap": "자동 줄 바꿈 전환", - "unavailable": "상세 파일 변경 사항을 사용할 수 없습니다.", - "filesChangedHeading_one": "" + "unavailable": "상세 파일 변경 사항을 사용할 수 없습니다." }, "taskDetail": { "actions": { @@ -5693,11 +5693,11 @@ "reattachBtn": "브랜치 재연결", "reattached": "{{id}}의 브랜치가 재연결되었습니다 ({{branch}})", "reattachedResult": "{{branch}} 재연결됨 ({{base}} 기준 {{count}}개 커밋 앞).", + "reattachedResult_one": "", "reattachedResult_other": "", "reattaching": "재연결 중…", "skipped": "{{id}}의 브랜치 재연결을 건너뜀: {{reason}}", - "skippedResult": "재연결 건너뜀: {{reason}}", - "reattachedResult_one": "" + "skippedResult": "재연결 건너뜀: {{reason}}" }, "cacheBreakdown": "(읽기 {{read}} / 쓰기 {{write}} / 입력 {{input}})", "cacheHitRatio": "캐시 적중률:", @@ -5838,8 +5838,8 @@ "activityHeading": "활동", "agentLog": "에이전트 로그", "noActivity": "(활동 없음)", - "truncated_other": "", - "truncated_one": "" + "truncated_one": "", + "truncated_other": "" }, "longestTimingEvent": "가장 긴 타이밍 이벤트", "longestWorkflowStep": "가장 긴 워크플로 단계", @@ -5930,8 +5930,8 @@ "progress": { "heading": "진행 상태", "noSteps": "(정의된 단계 없음)", - "stepCount_other": "", - "stepCount_one": "" + "stepCount_one": "", + "stepCount_other": "" }, "provenance": { "createdBy": "작성자", @@ -5940,6 +5940,7 @@ "recoveryState": "복구 상태", "refine": { "btn": "개선", + "charCount_one": "", "charCount_other": "", "createBtn": "개선 작업 생성", "creating": "생성 중...", @@ -5948,8 +5949,7 @@ "help": "개선하거나 향상시킬 내용을 설명하세요...", "modalTitle": "개선", "placeholder": "피드백을 입력하세요...", - "taskCreated": "개선 작업 생성됨: {{id}}", - "charCount_one": "" + "taskCreated": "개선 작업 생성됨: {{id}}" }, "reset": { "btn": "초기화", @@ -6112,6 +6112,12 @@ "switchToPlainText": "일반 텍스트로 전환", "yes": "예" }, + "taskFields": { + "moreFields": "추가 필드", + "orphaned": "고아 필드", + "saveFailed": "필드 저장 실패", + "unset": "—" + }, "taskForm": { "addDependencies": "의존성 추가", "attachHint": "이미지를 붙여넣거나 끌어다 놓을 수도 있습니다", @@ -6139,6 +6145,7 @@ "branchStrategyLabel": "브랜치 전략", "collapseDescription": "설명 접기", "dependenciesLabel": "의존성", + "dependenciesSelected_one": "", "dependenciesSelected_other": "", "descriptionLabel": "설명", "descriptionPlaceholder": "무엇을 해야 하나요?", @@ -6212,8 +6219,7 @@ "usingPreset": "프리셋 사용 중: {{name}}", "workflowStepsDescription": "작업 구현 완료 후 실행할 단계 선택", "workflowStepsLabel": "워크플로우 단계", - "workingBranchLabel": "작업 브랜치", - "dependenciesSelected_one": "" + "workingBranchLabel": "작업 브랜치" }, "taskHandlers": { "githubImported": "GitHub에서 {{id}}를 가져왔습니다" @@ -6236,6 +6242,7 @@ "noReviewItems": "아직 검토 항목이 없습니다.", "perTaskAutoMerge": "작업별 자동 병합", "plain": "일반 텍스트", + "prSummaryLine_one": "", "prSummaryLine_other": "", "queueing": "대기열에 추가 중…", "refresh": "새로 고침", @@ -6245,6 +6252,7 @@ "refreshing": "새로 고침 중…", "refreshStatusLine": "{{status}} · 마지막 갱신: {{timestamp}} · {{source}}", "requestRevision": "재검토 요청", + "reviewerSummaryLine_one": "", "reviewerSummaryLine_other": "", "revisionQueueFailed": "개정 대기열 추가에 실패했습니다", "revisionStarted": "선택한 검토 피드백을 기반으로 동일 작업 AI 개정이 시작되었습니다", @@ -6253,9 +6261,7 @@ "showRawText": "원시 텍스트 표시", "startedAtSep": " · 시작: {{timestamp}}", "updateFailed": "{{taskId}} 업데이트에 실패했습니다: {{error}}", - "upToDate": "최신 상태", - "prSummaryLine_one": "", - "reviewerSummaryLine_one": "" + "upToDate": "최신 상태" }, "tasks": { "addTaskPlaceholder": "작업 추가...", @@ -6269,6 +6275,7 @@ "archiveTask": "작업 보관", "assignedTo": "{{name}}에게 할당됨", "attach": "첨부", + "attachCount_one": "", "attachCount_other": "", "attachedFile": "{{taskId}}에 {{fileName}}을(를) 첨부했습니다", "attachFileFailed": "{{fileName}} 첨부에 실패했습니다: {{error}}", @@ -6306,6 +6313,7 @@ "deleteTitle": "작업 삭제", "dependencyConflict": "{{taskId}}은(는) {{dependentList}}의 의존성입니다.\n\n이 의존성 참조를 먼저 제거하고 삭제하시겠습니까?", "deps": "의존성", + "depsCount_one": "", "depsCount_other": "", "descriptionPlaceholder": "작업 설명", "descriptionRefined": "AI로 설명이 다듬어졌습니다", @@ -6326,10 +6334,13 @@ "fanoutEscalated": "에스컬레이션된 중복", "fanoutEscalationSuffix": " · 차단 열에서 {{minutes}}분 후 에스컬레이션됨", "fanoutHighFanoutSuffix": " (중복 병목 임계값: {{threshold}})", + "fanoutStale_one": "", "fanoutStale_other": "", + "fanoutTooltip_one": "", "fanoutTooltip_other": "", "fast": "빠름", "fastMode": "빠른 모드", + "filesChanged_one": "", "filesChanged_other": "", "forceDeleteTitle": "작업 강제 삭제", "githubTrackingDefaultOff": "끔", @@ -6365,6 +6376,7 @@ "modelPlan": "계획", "modelReviewer": "검토자", "models": "모델", + "modelsCount_one": "", "modelsCount_other": "", "moreOptions": "추가 옵션", "move": "이동", @@ -6403,6 +6415,7 @@ "resetProgress": "진행 상황 초기화", "resetProgressMessage": "이 작업을 이동하기 전에 모든 단계 진행 상황을 초기화하시겠습니까?", "resetProgressTitle": "진행 상황을 초기화하시겠습니까?", + "retriesAriaLabel_one": "", "retriesAriaLabel_other": "", "retry": "재시도", "retryFailed": "{{taskId}} 재시도에 실패했습니다: {{error}}", @@ -6419,6 +6432,7 @@ "showSteps": "단계 표시", "stalled": "중단됨", "statusMergingFix": "수정 사항 병합 중…", + "stepCount_one": "", "stepCount_other": "", "stuck": "막힘", "subtask": "하위 작업", @@ -6434,15 +6448,7 @@ "usingDefault": "기본값 사용 중", "viewDependency": "클릭하여 {{depId}} 보기", "workflow": "워크플로우", - "workflowCheck": "워크플로우 확인", - "attachCount_one": "", - "depsCount_one": "", - "fanoutStale_one": "", - "fanoutTooltip_one": "", - "filesChanged_one": "", - "modelsCount_one": "", - "retriesAriaLabel_one": "", - "stepCount_one": "" + "workflowCheck": "워크플로우 확인" }, "terminal": { "clear": "지우기", @@ -6560,14 +6566,14 @@ "resetsInDaysHours": "{{days}}일 {{hours}}시간 후 초기화", "resetsInHours": "{{hours}}시간 후 초기화", "resetsInMinutes": "{{mins}}분 후 초기화", + "showHidden_one": "", "showHidden_other": "", "statusError": "오류", "statusNotConfigured": "구성되지 않음", "title": "사용량", "viewModeLabel": "사용량 보기 모드", "viewModeRemaining": "남은 양", - "viewModeUsed": "사용량", - "showHidden_one": "" + "viewModeUsed": "사용량" }, "workflow": { "add": "추가", @@ -6668,6 +6674,7 @@ "selectStepsDescription": "작업 구현 완료 후 실행할 단계를 선택하세요", "showOutput": "출력 표시", "started": "시작됨:", + "stepCount_one": "", "stepCount_other": "", "stepCreated": "워크플로 단계 생성됨", "stepDefinitionNotFound": "단계 정의를 찾을 수 없습니다.", @@ -6675,28 +6682,27 @@ "steps": "워크플로 단계", "stepsExplanation": "병합 전 단계는 구현 후, 병합 전에 실행됩니다. 병합 후 단계는 병합 성공 후 실행됩니다.", "stepUpdated": "워크플로 단계 업데이트됨", + "summaryAdvisory_one": "", "summaryAdvisory_other": "", + "summaryFailed_one": "", "summaryFailed_other": "", + "summaryPassed_one": "", "summaryPassed_other": "", + "summaryRunning_one": "", "summaryRunning_other": "", "summarySeparator": " · ", + "summarySkipped_one": "", "summarySkipped_other": "", + "summaryStepCount_one": "", "summaryStepCount_other": "", "switchToMarkdown": "Markdown으로 전환", "switchToPlain": "일반 텍스트로 전환", + "tabMySteps_one": "", "tabMySteps_other": "", + "tabTemplates_one": "", "tabTemplates_other": "", "templateAdded": "{{name}} 워크플로 단계 추가됨", - "useDefault": "기본값 사용", - "stepCount_one": "", - "summaryAdvisory_one": "", - "summaryFailed_one": "", - "summaryPassed_one": "", - "summaryRunning_one": "", - "summarySkipped_one": "", - "summaryStepCount_one": "", - "tabMySteps_one": "", - "tabTemplates_one": "" + "useDefault": "기본값 사용" }, "workflowColumns": { "add": "", @@ -6712,14 +6718,50 @@ "title": "", "traits": "", "traitsLoadFailed": "", - "unplacedCount_other": "", - "unplacedCount_one": "" + "unplacedCount_one": "", + "unplacedCount_other": "" + }, + "workflowFields": { + "add": "필드 추가", + "addOption": "옵션 추가", + "badge": "배지로 표시", + "default": "기본값", + "defaultLabel": "기본값", + "defaultTrue": "기본 켜짐", + "duplicateId": "해당 id를 가진 필드가 이미 있습니다", + "editId": "id 편집", + "empty": "아직 사용자 지정 필드가 없습니다. 필드를 추가하여 작업 양식과 카드를 확장하세요.", + "idLabel": "필드 id", + "idWarn": "id를 변경하면 이전 id로 저장된 값이 삭제됩니다(제거 후 추가).", + "nameLabel": "필드 이름", + "newFieldName": "새 필드", + "newOptionLabel": "옵션 1", + "noDefault": "— 없음 —", + "optionColor": "옵션 색상", + "optionLabel": "옵션 레이블", + "optionN": "옵션 {{n}}", + "options": "옵션", + "optionValue": "옵션 값", + "placement": "배치", + "placementCard": "카드 배지", + "placementDetail": "세부 정보(인라인)", + "placementSection": "세부 정보 섹션", + "readOnlyHint": "기본 제공 워크플로는 읽기 전용입니다 — 편집하려면 복제하세요", + "remove": "필드 제거", + "removeOption": "옵션 제거", + "required": "필수", + "title": "필드", + "typeLabel": "유형", + "widget": "위젯", + "widgetDefault": "기본값" }, "workflowNodes": { "advisory": "", "codeNote": "샌드박스에서 TypeScript를 실행합니다. 구문은 저장 시 검증됩니다.", "codeSource": "소스(TypeScript)", "codeTimeout": "제한 시간(ms)", + "cycleBlocked": "", + "edgeCondition": "", "edgeConditionLabel": "조건: {{condition}}", "edgeInspector": "에지", "edgeNoVerdict": "— 성공(판정 없음) —", @@ -6741,6 +6783,7 @@ "foreachWorktree": "단계별 워크트리", "gateBlocks": "게이트(차단)", "gateMode": "게이트 모드", + "interpreterOnly": "", "joinAll": "모든 분기", "joinAny": "임의 분기", "joinMode": "조인 모드", @@ -6761,14 +6804,7 @@ "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "분기는 이 노드에서 동시에 실행됩니다. 분기 내에서는 실행 및 병합 이음새가 허용되지 않습니다.", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "", - "summaryCodeDefault": "", - "summaryGateAdvisory": "", - "summaryGateBlocks": "", - "summaryHoldRelease": "", - "summaryNotConfigured": "", - "summaryReviewType": "" + "stepExecuteLabel": "Step execute" }, "workflows": { "duplicateToCustomize": "", @@ -6799,45 +6835,5 @@ "installRequestTitle": "Worktrunk 설치 요청", "sha256": "SHA-256", "version": "버전" - }, - "taskFields": { - "unset": "—", - "moreFields": "추가 필드", - "orphaned": "고아 필드", - "saveFailed": "필드 저장 실패" - }, - "workflowFields": { - "add": "필드 추가", - "addOption": "옵션 추가", - "badge": "배지로 표시", - "default": "기본값", - "defaultLabel": "기본값", - "defaultTrue": "기본 켜짐", - "duplicateId": "해당 id를 가진 필드가 이미 있습니다", - "editId": "id 편집", - "empty": "아직 사용자 지정 필드가 없습니다. 필드를 추가하여 작업 양식과 카드를 확장하세요.", - "idLabel": "필드 id", - "idWarn": "id를 변경하면 이전 id로 저장된 값이 삭제됩니다(제거 후 추가).", - "nameLabel": "필드 이름", - "newFieldName": "새 필드", - "newOptionLabel": "옵션 1", - "noDefault": "— 없음 —", - "optionColor": "옵션 색상", - "optionLabel": "옵션 레이블", - "optionN": "옵션 {{n}}", - "optionValue": "옵션 값", - "options": "옵션", - "placement": "배치", - "placementCard": "카드 배지", - "placementDetail": "세부 정보(인라인)", - "placementSection": "세부 정보 섹션", - "readOnlyHint": "기본 제공 워크플로는 읽기 전용입니다 — 편집하려면 복제하세요", - "remove": "필드 제거", - "removeOption": "옵션 제거", - "required": "필수", - "title": "필드", - "typeLabel": "유형", - "widget": "위젯", - "widgetDefault": "기본값" } } diff --git a/packages/i18n/locales/ko/cli.json b/packages/i18n/locales/ko/cli.json index 6249b54533..f75f42a4f4 100644 --- a/packages/i18n/locales/ko/cli.json +++ b/packages/i18n/locales/ko/cli.json @@ -21,6 +21,7 @@ "agentRunLogsBackHint": "[Esc/q] 실행 목록으로 돌아가기", "agentRunLogsTitle": "실행 로그 ({{index}})", "agentsFooterHints": "[s] 시작 [x] 중지 [D] 삭제 [r] 새로고침 [Tab] 포커스 ↑↓ 선택", + "agentsListTitle_one": "", "agentsListTitle_other": "", "agentsNoAgents": "에이전트가 없습니다.", "agentStarted": "에이전트 시작됨", @@ -44,6 +45,7 @@ "filesEmpty": "(비어 있음)", "filesEmptyFile": "(빈 파일)", "filesFooterHints": "[Tab] 창 전환 [↑↓/jk] 이동 [Enter] 열기 [←/→] 접기/펼치기 [.] 숨김 [w] 줄 바꿈 [p] 프로젝트 [r] 새로고침", + "filesMoreLines_one": "", "filesMoreLines_other": "", "filesSelectProject": "프로젝트 선택", "filesSelectToPreview": "미리볼 파일을 선택하세요", @@ -151,6 +153,7 @@ "settingsFooterHints": "[Tab] 패널 전환 ↑↓ 설정 선택 [Space] 불리언 토글 [+/-] 숫자 조정 [←/→] 열거형 순환 [C/V/X/P/L/U/K/R] 원격 작업", "settingsInteractivePanelTitle": "설정", "settingsLoadingSettings": "설정 불러오는 중…", + "settingsMoreModels_one": "", "settingsMoreModels_other": "", "settingsPanelTitle": "설정", "settingsPersistentTokenRegenerated": "영구 토큰이 재생성됨", @@ -218,9 +221,6 @@ "utilitiesKillVitest": "Vitest 프로세스 종료", "utilitiesPanelTitle": "유틸리티", "utilitiesRefreshStats": "통계 새로고침", - "utilitiesToggleEnginePause": "엔진 일시 정지 전환", - "agentsListTitle_one": "", - "filesMoreLines_one": "", - "settingsMoreModels_one": "" + "utilitiesToggleEnginePause": "엔진 일시 정지 전환" } } diff --git a/packages/i18n/locales/ko/common.json b/packages/i18n/locales/ko/common.json index 2cb648e1f7..f9fb7e049a 100644 --- a/packages/i18n/locales/ko/common.json +++ b/packages/i18n/locales/ko/common.json @@ -1,9 +1,4 @@ { - "actions": { - "cancel": "취소", - "close": "닫기", - "save": "저장" - }, "agents": { "ratings": { "trendDeclining": "", @@ -34,7 +29,6 @@ "minutesAgo_other": "" } }, - "archive": "보관", "board": { "rejection": { "capacityExhausted": "", @@ -44,7 +38,6 @@ "workflowMismatch": "" } }, - "cancel": "취소", "chat": { "failedToGetResponse": "", "failureReferenceId": "", @@ -54,25 +47,15 @@ "openMailboxMessage": "", "toolCallArgsPrefix": "", "toolCallResultPrefix": "", + "toolCallsCount_one": "", + "toolCallsCount_other": "", + "toolCallsHeader": "", "toolCallStatusCompleted": "", "toolCallStatusError": "", "toolCallStatusErrors": "", "toolCallStatusRunning": "", - "toolCallsCount_one": "", - "toolCallsCount_other": "", - "toolCallsHeader": "", "viewFailureDetails": "" }, - "close": "닫기", - "columns": { - "archived": "보관됨", - "done": "완료", - "in-progress": "진행 중", - "in-review": "검토 중", - "todo": "할 일", - "triage": "계획" - }, - "delete": "삭제", "health": { "anomaly": { "duplicateActiveId": "", @@ -110,13 +93,6 @@ "modelSetToDefault": "" } }, - "nodeStatus": { - "connecting": "", - "error": "", - "offline": "", - "online": "", - "unknown": "" - }, "nodes": { "auth": { "differ": "", @@ -137,7 +113,13 @@ "stopped": "" } }, - "refresh": "새로고침", + "nodeStatus": { + "connecting": "", + "error": "", + "offline": "", + "online": "", + "unknown": "" + }, "research": { "providerGitHub": "", "providerLlmSynthesis": "", @@ -145,7 +127,6 @@ "providerPageFetch": "", "providerWebSearch": "" }, - "retry": "재시도", "routing": { "policyLabel": { "block": "", @@ -205,7 +186,6 @@ "zai": "" } }, - "skip": "건너뛰기", "taskForm": { "nodeStatusConnecting": "", "nodeStatusError": "", @@ -220,7 +200,6 @@ "refreshSourceInitialLoad": "", "refreshSourceManual": "" }, - "tryAgain": "다시 시도", "workflow": { "postMerge": "", "preMerge": "", @@ -230,5 +209,14 @@ "statusRunning": "", "statusSkipped": "", "waitingForOutput": "" + }, + "workflowNodes": { + "summaryAwaitInput": "", + "summaryCodeDefault": "", + "summaryGateAdvisory": "", + "summaryGateBlocks": "", + "summaryHoldRelease": "", + "summaryNotConfigured": "", + "summaryReviewType": "" } } diff --git a/packages/i18n/locales/zh-CN/app.json b/packages/i18n/locales/zh-CN/app.json index ec6d49ca93..8b6d98c993 100644 --- a/packages/i18n/locales/zh-CN/app.json +++ b/packages/i18n/locales/zh-CN/app.json @@ -65,13 +65,13 @@ "notMerged": "未合并", "refresh": "刷新", "time": { + "daysAgo_one": "", "daysAgo_other": "", + "hoursAgo_one": "", "hoursAgo_other": "", "justNow": "刚刚", - "minutesAgo_other": "", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "" + "minutesAgo_one": "", + "minutesAgo_other": "" }, "title": "活动日志" }, @@ -112,18 +112,18 @@ "showToolOutput": "显示工具输出", "switchMarkdown": "切换到 markdown 模式", "switchPlainText": "切换到纯文本模式", + "timeDaysAgo_one": "", "timeDaysAgo_other": "", + "timeHoursAgo_one": "", "timeHoursAgo_other": "", "timeJustNow": "刚刚", + "timeMinutesAgo_one": "", "timeMinutesAgo_other": "", + "toolEntriesHidden_one": "", "toolEntriesHidden_other": "", "toolsOff": "工具:关闭", "toolsOn": "工具:开启", - "usingDefault": "使用默认值", - "timeDaysAgo_one": "", - "timeHoursAgo_one": "", - "timeMinutesAgo_one": "", - "toolEntriesHidden_one": "" + "usingDefault": "使用默认值" }, "agentMention": { "membersOf": "#{{roomName}} 的成员", @@ -278,6 +278,7 @@ }, "agents": { "activate": "激活", + "activeAgents_one": "", "activeAgents_other": "", "activePrefix": "活跃:", "advancedSettingsDesc": "此代理的底层配置选项。", @@ -288,6 +289,7 @@ "agentMail": "代理邮件", "agentModelLabel": "代理模型", "agentPlural": "代理", + "agentsFound_one": "", "agentsFound_other": "", "agentSingular": "代理", "agentsLabel": "代理", @@ -327,6 +329,7 @@ "bulkActions": "批量操作", "bulkActionsLoadFailed": "加载批量智能体操作失败:{{error}}", "bulkAgentActions": "批量智能体操作", + "bulkConfirmMessage_one": "", "bulkConfirmMessage_other": "", "bulkNoEligible": "没有符合条件的代理", "bulkResult_one": "{{action}} {{successCount}} 个{{agentWord}};跳过 {{skippedCount}} 个", @@ -469,6 +472,7 @@ "healthError": "错误", "heartbeat": "心跳:", "heartbeatAndHealth": "心跳与健康", + "heartbeatClampedToMin_one": "", "heartbeatClampedToMin_other": "", "heartbeatCustom": "自定义心跳运行", "heartbeatEnabled": "启用心跳", @@ -524,8 +528,10 @@ "importButton": "导入{{label}}", "importComplete": "导入完成", "importDescription": "从Agent Companies包导入代理。浏览companies.sh目录以发现已发布的代理、上载AGENTS.md文件、选择目录或粘贴清单内容。", + "importingAgents_one": "", "importingAgents_other": "", "importingAgentsAndSkills": "正在导入 {{agentCount}} 个 Agent 和 {{skillCount}} 个技能...", + "importingSkills_one": "", "importingSkills_other": "", "inbox": "收件箱", "inheritingProjectDefault": "继承项目默认值", @@ -591,6 +597,7 @@ "loadingSkillContent": "正在加载技能内容...", "loadingTasks": "正在加载任务...", "loadTasksFailed": "加载任务失败", + "logEntries_one": "", "logEntries_other": "", "logsWillAppear": "代理开始运行后,日志将显示在此处。", "logsWillAppearActive": "日志将显示在此处。", @@ -747,15 +754,20 @@ "pauseAgentsFailed": "暂停智能体失败:{{error}}", "pauseAll": "暂停全部", "pauseAllAgents": "暂停所有智能体", + "pauseAllConfirm_one": "", "pauseAllConfirm_other": "", "pauseAllTitle": "暂停所有智能体", "pauseCountHint_one": "暂停 {{count}} 个活跃/运行中的代理", "pauseCountHint_other": "暂停 {{count}} 个活跃/运行中的代理", + "pauseCountHint_one_one": "", "pauseCountHint_one_other": "", + "pauseCountHint_other_one": "", "pauseCountHint_other_other": "", "pausedPast": "已暂停", + "pausedSummary_one": "", "pausedSummary_other": "", "pendingApprovals": "待审批", + "pendingApprovalsCount_one": "", "pendingApprovalsCount_other": "", "performance": { "avgDuration": "平均时长", @@ -787,6 +799,7 @@ "categorySelect": "选择分类...", "categorySpeed": "速度", "commentPlaceholder": "可选备注...", + "count_one": "", "count_other": "", "deleteError": "删除评分失败:{{error}}", "deleteRating": "删除评分", @@ -795,12 +808,11 @@ "loadError": "加载评分失败:{{error}}", "loading": "加载评分中...", "noRatings": "暂无评分", + "starCount_one": "", "starCount_other": "", "submitRating": "提交评分", "submitting": "提交中...", - "title": "用户评分", - "count_one": "", - "starCount_one": "" + "title": "用户评分" }, "recentRuns": "最近运行", "reflections": { @@ -837,21 +849,28 @@ "resetDayWeekly": "星期几(0=周日)", "resetting": "正在重置...", "result": "结果", + "resultCreated_one": "", "resultCreated_other": "", + "resultErrors_one": "", "resultErrors_other": "", + "resultSkipped_one": "", "resultSkipped_other": "", "resume": "恢复", "resumeAction": "恢复", "resumeAgentsFailed": "恢复智能体失败:{{error}}", "resumeAll": "恢复全部", "resumeAllAgents": "恢复所有智能体", + "resumeAllConfirm_one": "", "resumeAllConfirm_other": "", "resumeAllTitle": "恢复所有智能体", "resumeCountHint_one": "恢复 {{count}} 个已暂停的代理", "resumeCountHint_other": "恢复 {{count}} 个已暂停的代理", + "resumeCountHint_one_one": "", "resumeCountHint_one_other": "", + "resumeCountHint_other_one": "", "resumeCountHint_other_other": "", "resumedPast": "已恢复", + "resumedSummary_one": "", "resumedSummary_other": "", "retry": "重试", "reviewConfiguration": "查看生成的配置", @@ -886,6 +905,7 @@ "stopMessage": "停止此运行?", "stopTitle": "停止运行" }, + "runsCount_one": "", "runsCount_other": "", "runsSuccessRate": "{{rate}}% 成功率", "runStarted": "运行已启动", @@ -926,7 +946,9 @@ "selectCompany": "", "selectDirectory": "选择目录", "selected": "已选择:", + "selectedAgentLabel_one": "", "selectedAgentLabel_other": "", + "selectedSkillLabel_one": "", "selectedSkillLabel_other": "", "selectMemoryFile": "选择一个记忆文件", "selectModel": "模型", @@ -940,12 +962,17 @@ "showSystemAgents": "显示系统智能体", "skills": "技能", "skillsDescription": "管理此代理可用的技能。", + "skillsErrors_one": "", "skillsErrors_other": "", + "skillsFound_one": "", "skillsFound_other": "", "skillsHint": "可选择分配给此代理的技能", + "skillsImported_one": "", "skillsImported_other": "", "skillsNone": "未分配技能", + "skillsSelected_one": "", "skillsSelected_other": "", + "skillsSkipped_one": "", "skillsSkipped_other": "", "skillsTitle": "技能", "skipHeartbeatWhenIdle": "空闲时跳过心跳", @@ -1049,34 +1076,7 @@ "weekly": "每周", "workingOn": "正在处理:", "zoomIn": "放大", - "zoomOut": "缩小", - "activeAgents_one": "", - "agentsFound_one": "", - "bulkConfirmMessage_one": "", - "heartbeatClampedToMin_one": "", - "importingAgents_one": "", - "importingSkills_one": "", - "logEntries_one": "", - "pauseAllConfirm_one": "", - "pauseCountHint_one_one": "", - "pauseCountHint_other_one": "", - "pausedSummary_one": "", - "pendingApprovalsCount_one": "", - "resultCreated_one": "", - "resultErrors_one": "", - "resultSkipped_one": "", - "resumeAllConfirm_one": "", - "resumeCountHint_one_one": "", - "resumeCountHint_other_one": "", - "resumedSummary_one": "", - "runsCount_one": "", - "selectedAgentLabel_one": "", - "selectedSkillLabel_one": "", - "skillsErrors_one": "", - "skillsFound_one": "", - "skillsImported_one": "", - "skillsSelected_one": "", - "skillsSkipped_one": "" + "zoomOut": "缩小" }, "app": { "backendError": { @@ -1086,12 +1086,12 @@ }, "approval": { "dismissBanner": "关闭审批通知横幅", + "needAttention_one": "", "needAttention_other": "", "openMailbox": "打开邮箱", "requestPlural": "请求", "requests": "审批请求", - "requestSingular": "请求", - "needAttention_one": "" + "requestSingular": "请求" }, "auth": { "clearAndRetry": "清除令牌并重试", @@ -1117,8 +1117,11 @@ "confirmMessage": "此会话在另一个标签页中处于活跃状态。仍然打开?", "confirmTitle": "打开活跃会话", "dismissButton": "关闭", + "pillLabel_one": "", "pillLabel_other": "", + "pillTitle_one": "", "pillTitle_other": "", + "pillTitleWithInput_one": "", "pillTitleWithInput_other": "", "popoverHeader": "后台任务", "status": { @@ -1133,10 +1136,7 @@ "planning": "规划", "sliceInterview": "切片采访", "subtask": "子任务分解" - }, - "pillLabel_one": "", - "pillTitle_one": "", - "pillTitleWithInput_one": "" + } }, "board": { "archived": "已归档", @@ -1249,9 +1249,12 @@ "openQuickChat": "打开快速聊天", "queuedMessage": "已排队:{{preview}}", "quickChatTitle": "快速聊天", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "刚刚", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", "removeAttachment": "移除 {{name}}", "resizePanelBottom": "从底部调整面板大小", @@ -1265,6 +1268,7 @@ "resizeSidebar": "调整侧边栏大小", "responseCopied": "已复制回复", "responseFailed": "响应失败", + "roomMemberCount_one": "", "roomMemberCount_other": "", "roomsGroupLabel": "频道", "scopeDirect": "直接", @@ -1293,16 +1297,12 @@ "thinkingLabel": "思考", "thinkingStatus": "思考中……", "toolCalls": "工具调用", + "toolCallsCount_one": "", "toolCallsCount_other": "", "typeMessage": "输入消息...", "unreadMessages": "未读消息", "untitledSession": "无标题", - "you": "你", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "roomMemberCount_one": "", - "toolCallsCount_one": "" + "you": "你" }, "chatRooms": { "error": { @@ -1349,8 +1349,10 @@ "actionsTitle": "列操作", "archiveAllDoneAriaLabel": "存档所有已完成的任务", "archiveAllDoneTitle": "存档所有已完成的任务", + "archiveAllMessage_one": "", "archiveAllMessage_other": "", "archiveAllTitle": "全部存档已完成", + "archivedTasks_one": "", "archivedTasks_other": "", "autoMerge": "自动合并", "autoMergeDisabled": "自动合并已禁用", @@ -1362,19 +1364,25 @@ "expandArchivedTitle": "展开已存档的任务", "failedToArchive": "存档任务失败", "keepProgress": "保留进度", + "loadMore_one": "", "loadMore_other": "", "moveAllToTodo": "全部移至待办", + "moveAllToTodoMessage_one": "", "moveAllToTodoMessage_other": "", "moveAllToTodoTitle": "全部移至待办", + "movedToPlanning_one": "", "movedToPlanning_other": "", + "movedToTodo_one": "", "movedToTodo_other": "", "movePartialFailure": "已移动 {{total}} 个任务中的 {{moved}} 个;{{failed}} 个失败", + "moveToTodoHint_one": "", "moveToTodoHint_other": "", "moveToTodoPartialFailure": "已将 {{total}} 个任务中的 {{moved}} 个移至待办;{{failed}} 个失败", "newTask": "新任务", "noManuallyPausableTasks": "没有可手动暂停的任务", "noTasks": "没有任务", "noTasksInColumn": "此列中没有任务", + "pauseHint_one": "", "pauseHint_other": "", "preserveProgressMessage": "此任务已完成步骤。在移动前保留进度?", "preserveProgressMoveTodoMessage": "某些任务已完成步骤。在移至待办前保留进度?", @@ -1382,7 +1390,9 @@ "promote": "", "promoting": "", "replanAll": "全部重新计划", + "replanAllHint_one": "", "replanAllHint_other": "", + "replanAllMessage_one": "", "replanAllMessage_other": "", "replanAllTitle": "重新计划所有任务", "resetProgress": "重置进度", @@ -1391,22 +1401,12 @@ "resetProgressMoveTodoMessage": "在移至待办前重置任务的步骤进度?", "resetProgressTitle": "重置进度?", "stopAll": "全部停止", + "stopAllMessage_one": "", "stopAllMessage_other": "", "stopAllTitle": "停止所有任务", "stopPartialFailure": "已停止 {{total}} 个任务中的 {{paused}} 个;{{failed}} 个失败", - "stoppedTasks_other": "", - "archiveAllMessage_one": "", - "archivedTasks_one": "", - "loadMore_one": "", - "moveAllToTodoMessage_one": "", - "movedToPlanning_one": "", - "movedToTodo_one": "", - "moveToTodoHint_one": "", - "pauseHint_one": "", - "replanAllHint_one": "", - "replanAllMessage_one": "", - "stopAllMessage_one": "", - "stoppedTasks_one": "" + "stoppedTasks_one": "", + "stoppedTasks_other": "" }, "comments": { "addButton": "添加评论", @@ -1421,8 +1421,8 @@ "updatedSuccess": "评论已更新" }, "commit": { - "filesChanged_other": "", - "filesChanged_one": "" + "filesChanged_one": "", + "filesChanged_other": "" }, "commitDiff": { "error": "加载提交差异出错:{{error}}", @@ -1564,6 +1564,7 @@ "filterBySeverity": "按严重程度筛选日志", "info": "信息", "lines": "行", + "lines_one": "", "lines_other": "", "loading": "加载中...", "loadingConfig": "加载开发服务器配置...", @@ -1573,6 +1574,7 @@ "logs": "日志", "lostConnection": "日志流连接已断开。", "manual": "手动", + "matchCount_one": "", "matchCount_other": "", "newLogs": "新日志", "noLogsYet": "暂无日志。启动开发服务器查看输出。", @@ -1621,9 +1623,7 @@ "started": "开发服务器已启动。", "stopped": "开发服务器已停止。" }, - "warn": "警告", - "lines_one": "", - "matchCount_one": "" + "warn": "警告" }, "dirPicker": { "ariaLabel": "目录浏览器", @@ -1742,6 +1742,7 @@ "clearSearch": "清除搜索", "collapse": "折叠", "collapseContent": "折叠内容", + "docCount_one": "", "docCount_other": "", "documentsCreatedIn": "文档在任务详细信息选项卡中创建。", "expand": "展开", @@ -1762,6 +1763,7 @@ "plain": "纯文本", "projectFiles": "项目文件", "projectFilesTab": "项目文件", + "resultCount_one": "", "resultCount_other": "", "retry": "重试", "retryLoading": "重试加载文档", @@ -1778,9 +1780,7 @@ "taskDocuments": "任务文档", "taskDocumentsTab": "任务文档", "title": "文档", - "untitled": "未命名", - "docCount_one": "", - "resultCount_one": "" + "untitled": "未命名" }, "droidCli": { "active": "活跃", @@ -1843,20 +1843,25 @@ }, "executor": { "blocked": "已阻止", + "daysAgo_one": "", "daysAgo_other": "", "escalated": "已升级", "escalatedSuffix": " (已升级)", "hideProjectDir": "隐藏项目目录", + "hoursAgo_one": "", "hoursAgo_other": "", "inReview": "审查中", "justNow": "刚刚", "loading": "加载中...", + "minutesAgo_one": "", "minutesAgo_other": "", "noActivity": "无活动", + "overlapBottleneck_one": "", "overlapBottleneck_other": "", "overlapQueue": "重叠队列", "queued": "已排队", "running": "运行中", + "secondsAgo_one": "", "secondsAgo_other": "", "showProjectDir": "显示项目目录", "stateIdle": "空闲", @@ -1864,12 +1869,7 @@ "stateRunning": "运行中", "status": "执行器状态", "stuck": "卡顿", - "temporary": "临时", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "", - "overlapBottleneck_one": "", - "secondsAgo_one": "" + "temporary": "临时" }, "fileBrowser": { "back": "返回文件列表", @@ -1943,7 +1943,9 @@ "advancesHelpItem2": "reachable / subsumed / orphaned / superseded — 已处理(包括等效内容已落地、原始 SHA 已消失或 HEAD 已与重写的集成提示对齐的历史重写情况)。", "advancesHelpItem3": "pending + off / not run — 设置中禁用了自动同步;分支引用已移动,但工作树未跟进。", "advancesHelpItem4": "pending + stash-failed / would-conflict / 类似情况 — 自动同步尝试了但无法调和(通常是本地编辑与新提交冲突)。", + "advancesNeedAction_one": "", "advancesNeedAction_other": "", + "aheadOfUpstream_one": "", "aheadOfUpstream_other": "", "aligned": "已对齐", "apply": "应用", @@ -1960,6 +1962,7 @@ "backToIssuesList": "返回 Issue 列表", "backToPullsList": "返回 PR 列表", "baseHead": "基于:HEAD", + "behindUpstream_one": "", "behindUpstream_other": "", "branchLabel": "分支:", "cancel": "取消", @@ -1975,10 +1978,14 @@ "commitMessagePlaceholder": "提交信息……", "commitsOnBranch": "{{name}} 上的提交", "commitStagedChanges": "提交已暂存更改", + "commitsToPull_one": "", "commitsToPull_other": "", + "commitsToPush_one": "", "commitsToPush_other": "", + "commitsToPushHeader_one": "", "commitsToPushHeader_other": "", "committedHash": "已提交:{{hash}}", + "conflictedCount_one": "", "conflictedCount_other": "", "conflictReclaimFailed": "添加冲突修复任务失败", "conflictReclaimQueued": "冲突修复任务已加入队列", @@ -2009,8 +2016,10 @@ "deletedBranch": "已删除分支 {{name}}", "detectingRemotes": "检测中……", "diffColon": "差异:", + "discardChangesMessage_one": "", "discardChangesMessage_other": "", "discardChangesTitle": "放弃更改", + "discardedFiles_one": "", "discardedFiles_other": "", "discardSelected": "放弃选中", "dismiss": "忽略", @@ -2062,7 +2071,9 @@ "forceDeletedBranch": "已强制删除分支 {{name}}", "fullShaAbbrev": "完整", "ghAuthLoginHint": "运行 {{code}} 以启用 PR 创建。", + "headAheadOfIntegration_one": "", "headAheadOfIntegration_other": "", + "headAheadOfOriginIntegration_one": "", "headAheadOfOriginIntegration_other": "", "headVsIntegration": "HEAD 与 {{branch}} 对比", "headVsOriginIntegration": "HEAD 与 origin/{{branch}} 对比", @@ -2070,11 +2081,14 @@ "hideExplanation": "隐藏说明", "import": "导入", "imported": "已导入", + "importedCount_one": "", "importedCount_other": "", "importFromGitHub": "从 GitHub 导入", "importSubtitle": "选择检测到的远端,加载开放中的 Issue 或 PR,并导入到看板。", "importTypeAriaLabel": "导入类型", + "integrationAheadOfHead_one": "", "integrationAheadOfHead_other": "", + "issueCount_one": "", "issueCount_other": "", "load": "加载", "loadFromRepoAriaLabel": "从仓库加载 {{tab}}", @@ -2088,7 +2102,9 @@ "loadingTitle": "加载中……", "loadMoreCommits": "加载更多提交", "loadTabTitle": "加载 {{tab}}", + "localAheadOfOriginIntegration_one": "", "localAheadOfOriginIntegration_other": "", + "localBehindOriginIntegration_one": "", "localBehindOriginIntegration_other": "", "localVsOrigin": "本地 {{branch}} 与 origin 对比", "manualPrFlowHint": "使用底部操作为此任务运行 PR 优先完成流程。", @@ -2104,6 +2120,7 @@ "mergingStatus": "合并中……", "modalTitle": "Git 管理器", "modified": "已修改", + "modifiedCount_one": "", "modifiedCount_other": "", "newBranchName": "新分支名称", "noAheadCommitsFound": "未找到领先提交(可能需要先 Fetch)", @@ -2139,6 +2156,7 @@ "notOnIntegrationBranchTitle": "当前位于非集成分支", "noUnstagedChanges": "无未暂存更改", "openPullsFrom": "来自 {{remote}} 的开放 PR", + "originIntegrationAheadOfHead_one": "", "originIntegrationAheadOfHead_other": "", "pop": "弹出", "popStashTitle": "弹出储藏(应用并删除)", @@ -2163,6 +2181,7 @@ "prUnlinked": "已取消关联 PR #{{number}}", "pull": "Pull", "pullCompleted": "Pull 完成", + "pullCount_one": "", "pullCount_other": "", "pullFailed": "Pull 失败", "pullOptions": "Pull 选项", @@ -2170,6 +2189,7 @@ "pullRebase": "Pull --rebase", "pullRebaseCompleted": "Pull --rebase 完成", "pullRequestHeading": "拉取请求", + "pullRequestsCount_one": "", "pullRequestsCount_other": "", "push": "Push", "pushCompleted": "Push 完成", @@ -2222,10 +2242,14 @@ "stageAll": "全部暂存", "stageAllAndCommit": "全部暂存并提交", "stageAllAndCommitTitle": "全部暂存并提交", + "stageCount_one": "", "stageCount_other": "", "staged": "已暂存", + "stagedChanges_one": "", "stagedChanges_other": "", + "stagedCount_one": "", "stagedCount_other": "", + "stagedFiles_one": "", "stagedFiles_other": "", "stageFile": "暂存文件", "stageSelected": "暂存选中", @@ -2274,13 +2298,17 @@ "unlinkButton": "取消关联", "unresolvedMergeConflicts": "未解决的合并冲突", "unstageAll": "全部取消暂存", + "unstageCount_one": "", "unstageCount_other": "", "unstaged": "未暂存", + "unstagedChanges_one": "", "unstagedChanges_other": "", + "unstagedFiles_one": "", "unstagedFiles_other": "", "unstageFile": "取消暂存文件", "unstageSelected": "取消暂存选中", "untracked": "未跟踪", + "untrackedCount_one": "", "untrackedCount_other": "", "upToDate": "已是最新", "view": "查看", @@ -2291,40 +2319,13 @@ "workingTreeModified": "已修改", "worktreeBadgeBare": "裸库", "worktreeBadgeMain": "主", - "worktreesInUse_other": "", - "worktreesTotal_other": "", - "advancesNeedAction_one": "", - "aheadOfUpstream_one": "", - "behindUpstream_one": "", - "commitsToPull_one": "", - "commitsToPush_one": "", - "commitsToPushHeader_one": "", - "conflictedCount_one": "", - "discardChangesMessage_one": "", - "discardedFiles_one": "", - "headAheadOfIntegration_one": "", - "headAheadOfOriginIntegration_one": "", - "importedCount_one": "", - "integrationAheadOfHead_one": "", - "issueCount_one": "", - "localAheadOfOriginIntegration_one": "", - "localBehindOriginIntegration_one": "", - "modifiedCount_one": "", - "originIntegrationAheadOfHead_one": "", - "pullCount_one": "", - "pullRequestsCount_one": "", - "stageCount_one": "", - "stagedChanges_one": "", - "stagedCount_one": "", - "stagedFiles_one": "", - "unstageCount_one": "", - "unstagedChanges_one": "", - "unstagedFiles_one": "", - "untrackedCount_one": "", "worktreesInUse_one": "", - "worktreesTotal_one": "" + "worktreesInUse_other": "", + "worktreesTotal_one": "", + "worktreesTotal_other": "" }, "goals": { + "activeCount_one": "", "activeCount_other": "", "addGoal": "添加目标", "archive": "存档", @@ -2343,8 +2344,7 @@ "title": "目标", "titleRequired": "标题是必需的。", "unarchive": "取消存档", - "updateError": "现在无法更新目标状态。请重试。", - "activeCount_one": "" + "updateError": "现在无法更新目标状态。请重试。" }, "groupTask": { "abandonGroup": "", @@ -2365,6 +2365,7 @@ "unavailable": "分支组不可用" }, "header": { + "activePlanningSessions_one": "", "activePlanningSessions_other": "", "addFirstScript": "添加第一个脚本", "additionalHeaderActions": "更多标题栏操作", @@ -2391,6 +2392,7 @@ "localNode": "本地", "mailbox": "邮箱", "mailboxView": "邮箱视图", + "mailboxWithCount_one": "", "mailboxWithCount_other": "", "manageProjects": "管理项目", "manageScripts": "管理脚本…", @@ -2413,6 +2415,7 @@ "reliabilityView": "可靠性", "researchView": "研究", "resumePlanningSession": "恢复规划会话", + "resumePlanningSessionCount_one": "", "resumePlanningSessionCount_other": "", "resumeScheduling": "恢复调度", "scripts": "脚本", @@ -2434,16 +2437,13 @@ "terminal": "终端", "todosView": "待办事项", "unreadChatResponse": "未读聊天回复", + "unreadMessages_one": "", "unreadMessages_other": "", "viewActivityLog": "查看活动日志", "viewProjects": "查看项目", "viewUsage": "查看用量", "workflowSteps": "工作流步骤", - "workingBranch": "工作分支", - "activePlanningSessions_one": "", - "mailboxWithCount_one": "", - "resumePlanningSessionCount_one": "", - "unreadMessages_one": "" + "workingBranch": "工作分支" }, "health": { "activeTasks": "活动任务", @@ -2515,6 +2515,7 @@ "expandTaskOptions": "展开高级任务选项", "hintEnterEsc": "按 Enter 创建 · Esc 取消", "loadingAgents": "加载代理...", + "model_one": "", "model_other": "", "models": "模型", "noAgentsAvailable": "没有可用的代理", @@ -2533,8 +2534,7 @@ "selectExecutionNode": "选择执行节点", "subtask": "子任务", "useDefault": "使用默认值", - "whatNeedsToBeDone": "需要做什么?", - "model_one": "" + "whatNeedsToBeDone": "需要做什么?" }, "insights": { "allInsights": "所有洞察", @@ -2580,6 +2580,7 @@ "runCompleted": "已创建 {{created}} 个,已更新 {{updated}} 个", "showAllInsights": "显示所有洞察", "showArchived": "显示已存档的洞察", + "showArchivedLabel_one": "", "showArchivedLabel_other": "", "showBacklogHealth": "仅显示积压健康洞察", "taskCreated": "从\"{{title}}\"创建的任务", @@ -2591,8 +2592,7 @@ "unarchiveLabel": "取消存档此洞察", "unarchiveTitle": "取消存档此洞察", "unarchiving": "正在取消存档\"{{title}}\"...", - "usePlanningDefault": "使用规划默认值", - "showArchivedLabel_one": "" + "usePlanningDefault": "使用规划默认值" }, "interview": { "addContextDirection": "添加任何额外的上下文或方向...", @@ -2647,13 +2647,16 @@ "archiveSelectedTitle": "归档选中的已完成任务", "archiveUnavailable": "归档操作不可用", "archiveViaButton": "任务只能通过归档按钮归档", + "bulkArchiveDone_one": "", "bulkArchiveDone_other": "", + "bulkArchiveMessage_one": "", "bulkArchiveMessage_other": "", "bulkArchiveNoTasks": "没有可以归档的选中任务(只有已完成的任务)", "bulkArchiveSummary": "已归档 {{archived}} · {{skipped}} 已跳过 · {{failed}} 失败", "bulkArchiveTitle": "归档选中的任务", "bulkDeleteAll": "全部删除", "bulkDeleteArchiveSummary": "已归档 {{archived}},已删除 {{deleted}},失败 {{failed}}", + "bulkDeleteMessage_one": "", "bulkDeleteMessage_other": "", "bulkDeleteNoTasks": "没有可删除的选中任务(已归档的任务除外)", "bulkDeleteSummary_one": "已删除 {{count}} 个任务 · 跳过 {{skipped}} 个已归档 · {{failed}} 个失败", @@ -2669,6 +2672,7 @@ "bulkUnpauseSummary": "已恢复 {{unpaused}} · {{skipped}} 已跳过 · {{failed}} 失败", "bulkUpdateFailed": "更新模型失败", "bulkUpdateNoTasks": "没有可更新的有效任务(已归档的任务无法修改)", + "bulkUpdateSuccess_one": "", "bulkUpdateSuccess_other": "", "cancelMove": "取消移动", "clear": "清除", @@ -2689,6 +2693,7 @@ "filterChip": "过滤:{{column}}", "forceDelete": "强制删除", "forceDeleteTitle": "强制删除任务", + "hidden_one": "", "hidden_other": "", "hideDone": "隐藏已完成", "hideDoneTitle": "隐藏已完成的任务", @@ -2719,6 +2724,7 @@ "resizeSidebar": "调整任务列表侧边栏大小", "reviewerModel": "审查器模型", "selectAll": "选择所有可见任务", + "selectedCount_one": "", "selectedCount_other": "", "selectTask": "选择 {{taskId}}", "selectTaskPrompt": "选择一个任务以查看详情", @@ -2730,7 +2736,9 @@ "staleOnlyTitle": "仅显示过期任务", "stalePausedReview": "过期暂停审核", "stalePausedReviewTitle": "仅显示过期暂停审核任务", + "stats_one": "", "stats_other": "", + "statsInColumn_one": "", "statsInColumn_other": "", "statusMergingFix": "合并修复中…", "stuck": "卡住", @@ -2739,15 +2747,7 @@ "unpauseSelectedTitle": "恢复当前已暂停的选中任务", "unpauseUnavailable": "恢复操作不可用", "useProjectDefault": "使用项目默认", - "viewOptions": "视图选项", - "bulkArchiveDone_one": "", - "bulkArchiveMessage_one": "", - "bulkDeleteMessage_one": "", - "bulkUpdateSuccess_one": "", - "hidden_one": "", - "selectedCount_one": "", - "stats_one": "", - "statsInColumn_one": "" + "viewOptions": "视图选项" }, "mailbox": { "agent": "代理", @@ -2791,6 +2791,7 @@ "markAllRead": "全部已读", "markAllReadButton": "全部标记为已读", "markAllReadTitle": "全部标记为已读", + "markedAsRead_one": "", "markedAsRead_other": "", "markReadFailed": "无法将消息标记为已读", "messageDeleted": "消息已删除", @@ -2817,9 +2818,12 @@ "replyLoadFailed": "加载回复消息失败。点击重试。", "selectMessageToRead": "选择要阅读的消息", "system": "系统", + "timeDaysAgo_one": "", "timeDaysAgo_other": "", + "timeHoursAgo_one": "", "timeHoursAgo_other": "", "timeJustNow": "刚刚", + "timeMinsAgo_one": "", "timeMinsAgo_other": "", "title": "邮箱", "to": "至", @@ -2830,11 +2834,7 @@ "typeSystem": "系统", "typeUserToAgent": "你 → 代理", "user": "用户", - "you": "你", - "markedAsRead_one": "", - "timeDaysAgo_one": "", - "timeHoursAgo_one": "", - "timeMinsAgo_one": "" + "you": "你" }, "memory": { "auditChecksTitle": "审计检查", @@ -2851,6 +2851,7 @@ "capReadable": "可读", "capWritable": "可写", "categories": "分类", + "charCount_one": "", "charCount_other": "", "compactFailed": "压缩记忆失败", "compacting": "正在压缩…", @@ -2886,7 +2887,9 @@ "healthIssues": "发现问题", "healthStatusTitle": "健康状态", "healthWarning": "警告", + "insightCount_one": "", "insightCount_other": "", + "insightsExtracted_one": "", "insightsExtracted_other": "", "insightsMemoryLabel": "洞察记忆", "insightsSaved": "洞察已保存", @@ -2937,6 +2940,7 @@ "saveSettingsFailed": "保存记忆设置失败", "saving": "正在保存…", "searchPlaceholder": "使用 qmd 搜索记忆", + "sectionCount_one": "", "sectionCount_other": "", "settingsNote": "注意:在以下位置更改后端类型:", "settingsNoteLink": "设置 → 记忆", @@ -2948,18 +2952,14 @@ "tabWorking": "工作记忆", "testing": "正在测试…", "testMemorySearchTitle": "测试记忆搜索", + "testResultCount_one": "", "testResultCount_other": "", "testResultStatus": "qmd {{qmdStatus}} · {{fallbackStatus}}", "testRetrieval": "测试检索", "testSearchHint": "运行与代理使用的相同 qmd 支持的 memory_search 路径。", "title": "记忆", "totalInsights": "洞察总数", - "workingMemoryLabel": "工作记忆", - "charCount_one": "", - "insightCount_one": "", - "insightsExtracted_one": "", - "sectionCount_one": "", - "testResultCount_one": "" + "workingMemoryLabel": "工作记忆" }, "merge": { "advanced": "高级", @@ -2980,6 +2980,7 @@ "pr": "PR", "pulling": "拉取中…", "pushForceWithLease": "推送 (force-with-lease)", + "pushHeading_one": "", "pushHeading_other": "", "pushing": "推送中…", "pushSuccess": "已推送到 origin/{{branch}} @ {{sha}}。", @@ -2988,8 +2989,7 @@ "shortstatTitle": "最终提交简统计;有关所有任务提交的完整着陆差异,请参见 Changes 标签。", "smartPull": "智能拉取", "status": "状态", - "title": "合并详情", - "pushHeading_one": "" + "title": "合并详情" }, "mesh": { "ariaLabel": "节点网格拓扑可视化", @@ -3030,6 +3030,7 @@ "assertionTitlePlaceholder": "断言标题", "assertionUpdated": "断言已更新", "assertionUpdateFailed": "更新断言失败", + "attemptRetries_one": "", "attemptRetries_other": "", "autopilotActivatingSlice": "正在激活切片", "autopilotCompleting": "完成中", @@ -3116,6 +3117,7 @@ "featureLinkFailed": "链接功能失败", "featureLinkTaskFailed": "将功能链接到任务失败", "featureSaveFailed": "保存功能失败", + "featuresCount_one": "", "featuresCount_other": "", "featureTitlePlaceholder": "功能标题", "featureTitleRequired": "功能标题不能为空", @@ -3153,7 +3155,9 @@ "lastValidatorStatus": "最近 {{status}}", "linkAFeature": "关联功能", "linkButton": "链接", + "linkedCount_one": "", "linkedCount_other": "", + "linkedFeaturesCount_one": "", "linkedFeaturesCount_other": "", "linkedFeaturesLabel": "关联功能", "linkedGoals": "关联目标", @@ -3175,6 +3179,7 @@ "milestoneDeleteFailed": "删除里程碑失败", "milestoneDescriptionPlaceholder": "里程碑描述...", "milestoneSaveFailed": "保存里程碑失败", + "milestonesCount_one": "", "milestonesCount_other": "", "milestoneTitlePlaceholder": "里程碑标题", "milestoneTitleRequired": "里程碑标题不能为空", @@ -3211,11 +3216,15 @@ "planStatePlanned": "已规划", "planTitle": "用 AI 规划任务", "prepareQuestion": "准备下一个问题...", + "progressText_one": "", "progressText_other": "", "reconnecting": "正在重新连接…", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "刚刚", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", "removeFeature": "删除功能", "removeMilestone": "删除里程碑", @@ -3250,9 +3259,11 @@ "sliceDeleted": "切片已删除", "sliceDeleteFailed": "删除切片失败", "sliceSaveFailed": "保存切片失败", + "slicesCount_one": "", "slicesCount_other": "", "sliceTitlePlaceholder": "切片标题", "sliceTitleRequired": "切片标题不能为空", + "sliceTriaged_one": "", "sliceTriaged_other": "", "sliceTriageFailed": "分类切片功能失败", "sliceUpdated": "切片已更新", @@ -3277,8 +3288,10 @@ "statusTriaged": "已分类", "stopFailed": "停止任务失败", "stopMission": "停止任务", + "stopped_one": "", "stopped_other": "", "summaryStats": "{{milestones}} 个里程碑,{{features}} 个功能。批准前请审查和编辑。", + "tabActivity_one": "", "tabActivity_other": "", "tabStructure": "结构", "takeControl": "接管", @@ -3287,6 +3300,7 @@ "targetBranchPlaceholder": "例如 main", "taskIdPlaceholder": "任务 ID(例如 FN-001)", "taskIdRequired": "任务 ID 不能为空", + "tasksFailed_one": "", "tasksFailed_other": "", "title": "任务", "titleLabel": "任务标题", @@ -3304,7 +3318,9 @@ "updateButton": "更新", "updated": "任务已更新", "validateFeature": "验证功能", + "validationRoundsCount_one": "", "validationRoundsCount_other": "", + "validationRoundsLabel_one": "", "validationRoundsLabel_other": "", "validationRuns": "验证运行", "validationState": "验证状态", @@ -3315,23 +3331,7 @@ "verification": "验证:", "verificationCriteria": "验证标准", "viewMissionFailures": "查看任务失败", - "whatToBuild": "你想要构建什么?", - "attemptRetries_one": "", - "featuresCount_one": "", - "linkedCount_one": "", - "linkedFeaturesCount_one": "", - "milestonesCount_one": "", - "progressText_one": "", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "slicesCount_one": "", - "sliceTriaged_one": "", - "stopped_one": "", - "tabActivity_one": "", - "tasksFailed_one": "", - "validationRoundsCount_one": "", - "validationRoundsLabel_one": "" + "whatToBuild": "你想要构建什么?" }, "modalManager": { "createdFromPlanning": "在规划模式中创建了 {{id}}", @@ -3347,6 +3347,7 @@ "addToFavorites": "添加到收藏", "addToFavoritesAriaLabel": "将 {{name}} 添加到收藏", "clearFilter": "清除筛选", + "count_one": "", "count_other": "", "descriptions": { "executor": "用于实现此任务的 AI 模型。", @@ -3401,8 +3402,7 @@ "titles": { "configuration": "模型配置" }, - "useDefault": "使用默认值", - "count_one": "" + "useDefault": "使用默认值" }, "modelSelection": { "choose": "为此任务选择模型。如果未选择,将使用默认模型。", @@ -3477,11 +3477,11 @@ "noAvailableTasks": "没有可用的任务", "searchTasks": "搜索任务…", "selectAgent": "选择代理", + "selectedCount_one": "", "selectedCount_other": "", "taskCreated": "已创建 {{taskId}}", "title": "新任务", - "unsavedChanges": "您有未保存的更改。放弃它们吗?", - "selectedCount_one": "" + "unsavedChanges": "您有未保存的更改。放弃它们吗?" }, "nodes": { "actions": { @@ -3555,6 +3555,7 @@ "containerLogs": "容器日志", "description": "通过提供连接详情和并发设置来注册现有的Fusion节点。", "discoverBeforeAdding": "在添加此节点之前发现远程项目。", + "discoveredCount_one": "", "discoveredCount_other": "", "discovering": "正在发现...", "discoverRemoteProjects": "发现远程项目", @@ -3694,6 +3695,7 @@ "refreshing": "刷新中…", "refreshStatus": "刷新状态", "registered": "节点\"{{name}}\"已注册", + "registeredCount_one": "", "registeredCount_other": "", "registerFailed": "无法注册节点", "remote": "远程", @@ -3746,9 +3748,7 @@ "portRange": "端口必须在1到65535之间" }, "viewLogsButton": "查看日志", - "yes": "是", - "discoveredCount_one": "", - "registeredCount_one": "" + "yes": "是" }, "nodeStatus": { "local": "本地" @@ -4007,10 +4007,14 @@ "questionsLabel": "问题数量", "reconnecting": "重新连接中…", "refineFurther": "进一步完善", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "刚刚", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", + "relativeTimeWeeks_one": "", "relativeTimeWeeks_other": "", "remove": "移除", "retryFailed": "重试失败,请再试一次。", @@ -4050,11 +4054,7 @@ "untitledSession": "无标题会话", "usingDefault": "使用默认", "whatToBuild": "您想构建什么?", - "whatToBuildPlaceholder": "例如,构建一个包含登录、注册和密码重置的用户认证系统...", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "relativeTimeWeeks_one": "" + "whatToBuildPlaceholder": "例如,构建一个包含登录、注册和密码重置的用户认证系统..." }, "plugins": { "addItem": "添加项目", @@ -4089,6 +4089,7 @@ "enablePlugin": "启用 {{name}}", "enablePluginFailed": "启用插件失败:{{error}}", "experimental": "实验性", + "findings_one": "", "findings_other": "", "homepage": "主页:", "install": "安装", @@ -4145,8 +4146,7 @@ "uninstallTitle": "全局卸载插件", "unknownError": "未知错误", "updateFailed": "更新插件失败:{{error}}", - "version": "版本:", - "findings_one": "" + "version": "版本:" }, "pr": { "authFail": "运行 gh auth login 并重试。", @@ -4193,11 +4193,15 @@ "confirm": "确认", "confirmRemove": "确认删除", "confirmRemoveProject": "确认删除项目", + "daysAgo_one": "", "daysAgo_other": "", + "hoursAgo_one": "", "hoursAgo_other": "", "justNow": "刚刚", "lastActivity": "最后活动:", + "minutesAgo_one": "", "minutesAgo_other": "", + "moreItems_one": "", "moreItems_other": "", "never": "从未", "nodeAvailability": "项目节点可用性", @@ -4208,11 +4212,7 @@ "pauseProject": "暂停项目", "removeProject": "删除项目", "resume": "恢复", - "resumeProject": "恢复项目", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "", - "moreItems_one": "" + "resumeProject": "恢复项目" }, "projectDetection": { "editName": "编辑名称", @@ -4221,12 +4221,12 @@ "noDbWarning": "未找到 fn 数据库 - 将初始化", "registerAll": "全部注册", "registering": "注册中...", - "registerSelected_other": "", - "selectAll_other": "", - "selectedCount_other": "", "registerSelected_one": "", + "registerSelected_other": "", "selectAll_one": "", - "selectedCount_one": "" + "selectAll_other": "", + "selectedCount_one": "", + "selectedCount_other": "" }, "projects": { "actions": { @@ -4284,10 +4284,10 @@ "detecting": "检测中…", "detectModels": "检测模型", "detectModelsTitle": "调用提供者的/models端点来发现可用模型", + "removeModel_one": "", "removeModel_other": "", "save": "保存提供者", - "saving": "保存中...", - "removeModel_one": "" + "saving": "保存中..." }, "addCustom": "添加自定义提供程序", "apiKeyLabel": "API 密钥", @@ -4386,10 +4386,10 @@ "p95": "P95", "p95Raw": "P95 原始: {{value}} ms", "reason": "原因: {{reason}}", - "sampleCount_other": "", - "samples_other": "", "sampleCount_one": "", - "samples_one": "" + "sampleCount_other": "", + "samples_one": "", + "samples_other": "" }, "failureRate": "失败率: {{rate}}", "heading": "可靠性", @@ -4398,14 +4398,14 @@ "insufficientData": "数据不足 — {{reason}}", "mergeAttempts": { "heading": "合并尝试", + "histogramTotal_one": "", "histogramTotal_other": "", "max": "最大值", "mean": "平均值", "moreStats": "更多统计", "reason": "原因: {{reason}}", - "tasksCounted_other": "", - "histogramTotal_one": "", - "tasksCounted_one": "" + "tasksCounted_one": "", + "tasksCounted_other": "" }, "reason": "原因: {{reason}}", "resetBaseline": "重置基线: {{date}}", @@ -4486,6 +4486,7 @@ "viewLabel": "研究视图" }, "routine": { + "andMore_one": "", "andMore_other": "", "delete": "删除", "deleteMessage": "删除例程 {{name}}?此操作无法撤销。", @@ -4499,14 +4500,13 @@ "enableName": "启用 {{name}}", "resultFailed": "失败", "resultSuccess": "成功", + "runHistory_one": "", "runHistory_other": "", "runNameNow": "立即运行 {{name}}", "running": "运行中…", "runNow": "立即运行", - "stepCount_other": "", - "andMore_one": "", - "runHistory_one": "", - "stepCount_one": "" + "stepCount_one": "", + "stepCount_other": "" }, "routing": { "cannotChangeWhileActive": "任务处于活动状态时无法更改节点覆盖。", @@ -4555,10 +4555,12 @@ "advancedMode": "多步骤", "advancedModeHelp": "按顺序运行多个步骤(命令和 AI 提示)", "aiPromptType": "AI 提示词", + "andMore_one": "", "andMore_other": "", "apiEndpointHint": "触发此例程的 API 端点路径", "apiEndpointLabel": "API 端点", "apiEndpointPlaceholder": "/api/routine/my-routine", + "automationCount_one": "", "automationCount_other": "", "cancelButton": "取消", "catchUpPolicyHint": "当计划运行被错过时的处理方式", @@ -4698,6 +4700,7 @@ "routineSuccess": "{{name}} 已成功完成", "routineUpdated": "例程已更新", "runError": "运行例程失败", + "runHistory_one": "", "runHistory_other": "", "runNameNow": "立即运行 {{name}}", "running": "运行中…", @@ -4718,6 +4721,7 @@ "simpleMode": "简单", "simpleModeHelp": "运行单个 shell 命令或 AI 提示", "stepCommandRequired": "步骤 {{index}}:命令为必填项", + "stepCount_one": "", "stepCount_other": "", "stepName": "步骤名称", "stepNamePlaceholder": "例如:运行测试", @@ -4778,11 +4782,7 @@ "webhookPathPlaceholder": "/trigger/my-routine", "webhookSecretHint": "用于签名验证的 HMAC 密钥。无需身份验证的 webhook 请留空。", "webhookSecretLabel": "Webhook 密钥(可选)", - "webhookSecretPlaceholder": "可选——无需身份验证的 webhook 请留空", - "andMore_one": "", - "automationCount_one": "", - "runHistory_one": "", - "stepCount_one": "" + "webhookSecretPlaceholder": "可选——无需身份验证的 webhook 请留空" }, "scriptsModal": { "addScript": "添加脚本", @@ -4807,6 +4807,7 @@ "saving": "正在保存...", "scriptAlreadyExists": "已经存在同名脚本", "scriptCommandRequired": "需要脚本命令", + "scriptCount_one": "", "scriptCount_other": "", "scriptCreated": "脚本已创建", "scriptDeleted": "脚本已删除", @@ -4814,8 +4815,7 @@ "scriptNamePlaceholder": "例如,build、test、lint", "scriptNameRequired": "需要脚本名称", "scriptUpdated": "脚本已更新", - "title": "脚本", - "scriptCount_one": "" + "title": "脚本" }, "secrets": { "accessPolicyAuto": "自动", @@ -4880,17 +4880,17 @@ "failed": "失败", "headerAwaitingAndErrorPlural": "{{awaitingCount}} 个 AI 会话需要您的输入,{{errorCount}} 个失败", "headerAwaitingAndErrorSingular": "{{awaitingCount}} 个 AI 会话需要您的输入,{{errorCount}} 个失败", + "headerAwaitingPlural_one": "", "headerAwaitingPlural_other": "", + "headerAwaitingSingular_one": "", "headerAwaitingSingular_other": "", + "headerErrorPlural_one": "", "headerErrorPlural_other": "", + "headerErrorSingular_one": "", "headerErrorSingular_other": "", "regionLabel": "需要输入或已失败的 AI 会话", "resume": "继续", - "retry": "重试", - "headerAwaitingPlural_one": "", - "headerAwaitingSingular_one": "", - "headerErrorPlural_one": "", - "headerErrorSingular_one": "" + "retry": "重试" }, "settings": { "actions": { @@ -5253,7 +5253,9 @@ "projectSelected": "已选择项目——任务创建和导入功能已可用。", "projectSetupDescription": "在创建或导入任务之前,请选择您的第一个项目。您可以注册现有的本地目录,或通过设置向导克隆 GitHub 仓库 URL。", "providersConnectedSummary": "✓ {{total}} 个提供商中已连接 {{connected}} 个", + "providersSkippedSummary_one_one": "", "providersSkippedSummary_one_other": "", + "providersSkippedSummary_other_one": "", "providersSkippedSummary_other_other": "", "quickStartProviders": "快速启动提供商", "readinessAiProviderConnected": "{{name}} 已连接——AI 代理可以处理任务", @@ -5360,9 +5362,7 @@ "withoutGitHub1": "手动创建任务", "withoutGitHub2": "为 AI 代理描述工作", "withoutGitHub3": "在看板上跟踪进度", - "withoutGitHubHeading": "不使用 GitHub(现在可用):", - "providersSkippedSummary_one_one": "", - "providersSkippedSummary_other_one": "" + "withoutGitHubHeading": "不使用 GitHub(现在可用):" }, "shell": { "activePill": "活跃", @@ -5396,6 +5396,7 @@ "disabled": "技能已禁用", "disableSkill": "禁用 {{name}}", "discovered": "已发现", + "discoveredCount_one": "", "discoveredCount_other": "", "discoveredSection": "已发现的技能", "enabled": "技能已启用", @@ -5427,8 +5428,7 @@ "title": "技能", "toggleError": "切换技能失败", "toggleFailed": "切换技能失败: {{message}}", - "viewDetails": "查看 {{name}} 的详情", - "discoveredCount_one": "" + "viewDetails": "查看 {{name}} 的详情" }, "specEditor": { "edit": "编辑", @@ -5459,17 +5459,17 @@ "dropTitle": "删除孤立的隐藏?", "failedToLoadDiff": "加载差异失败", "failedToLoadOrphans": "加载孤立记录失败", + "fileCount_one": "", "fileCount_other": "", "inspectDiff": "检查差异", "loadingDiff": "正在加载差异…", "noDiffOutput": "没有可用的差异输出。", "noOrphans": "未发现孤立的合并自动隐藏。", + "orphanCount_one": "", "orphanCount_other": "", "shaLabel": "SHA", "title": "储存恢复", - "unknownSource": "未知来源", - "fileCount_one": "", - "orphanCount_one": "" + "unknownSource": "未知来源" }, "stepType": { "aiPrompt": "AI 提示", @@ -5539,6 +5539,7 @@ "untitled": "无标题" }, "syncLog": { + "entryCount_one": "", "entryCount_other": "", "filterAll": "全部", "filterAllNodes": "全部节点", @@ -5550,8 +5551,7 @@ "noHistory": "没有同步历史可用", "resultConflict": "冲突", "resultError": "错误", - "resultSuccess": "成功", - "entryCount_one": "" + "resultSuccess": "成功" }, "systemStats": { "agentActive": "活跃", @@ -5572,6 +5572,7 @@ "errorLoadVitestSettings": "加载 vitest 设置失败", "errorSaveVitestSettings": "保存 vitest 设置失败", "footerRefreshFailed": "最新刷新失败:{{error}}", + "killedProcesses_one": "", "killedProcesses_other": "", "killThresholdInputAriaLabel": "终止阈值 (%)", "killThresholdLabel": "终止阈值 (%)", @@ -5615,8 +5616,7 @@ "title": "系统统计", "updatedAt": "已更新 {{time}}", "vitestProcesses": "Vitest 进程", - "waitingFirstUpdate": "等待首次更新", - "killedProcesses_one": "" + "waitingFirstUpdate": "等待首次更新" }, "taskChanges": { "attributionFailed": "已落地文件集可能包含外来提交(归因不可用)。", @@ -5625,6 +5625,7 @@ "error": "加载更改出错: {{error}}", "expandDiff": "扩展为全屏差异视图", "expandDiffView": "扩展差异视图", + "filesChangedHeading_one": "", "filesChangedHeading_other": "", "loadError": "加载任务更改失败", "loading": "正在加载更改...", @@ -5640,8 +5641,7 @@ "previousFile": "上一个文件", "summaryHint": "最终提交摘要: {{files}} 个文件{{plural}}已更改, +{{additions}} 次添加, -{{deletions}} 次删除。仅计算记录的合并/压缩提交,不计算完整的任务血统。", "toggleWordWrap": "切换自动换行", - "unavailable": "详细文件更改不可用。", - "filesChangedHeading_one": "" + "unavailable": "详细文件更改不可用。" }, "taskDetail": { "actions": { @@ -5693,11 +5693,11 @@ "reattachBtn": "重新绑定分支", "reattached": "已为 {{id}} 重新绑定分支 ({{branch}})", "reattachedResult": "已重新绑定 {{branch}}(领先 {{base}} {{count}} 次提交)。", + "reattachedResult_one": "", "reattachedResult_other": "", "reattaching": "正在重新绑定…", "skipped": "{{id}} 的分支重新绑定已跳过:{{reason}}", - "skippedResult": "重新绑定已跳过:{{reason}}", - "reattachedResult_one": "" + "skippedResult": "重新绑定已跳过:{{reason}}" }, "cacheBreakdown": "(读取 {{read}} / 写入 {{write}} / 输入 {{input}})", "cacheHitRatio": "缓存命中率:", @@ -5838,8 +5838,8 @@ "activityHeading": "活动", "agentLog": "代理日志", "noActivity": "(无活动)", - "truncated_other": "", - "truncated_one": "" + "truncated_one": "", + "truncated_other": "" }, "longestTimingEvent": "最长计时事件", "longestWorkflowStep": "最长工作流步骤", @@ -5930,8 +5930,8 @@ "progress": { "heading": "进度", "noSteps": "(未定义步骤)", - "stepCount_other": "", - "stepCount_one": "" + "stepCount_one": "", + "stepCount_other": "" }, "provenance": { "createdBy": "创建者:", @@ -5940,6 +5940,7 @@ "recoveryState": "恢复状态", "refine": { "btn": "细化", + "charCount_one": "", "charCount_other": "", "createBtn": "创建细化任务", "creating": "正在创建...", @@ -5948,8 +5949,7 @@ "help": "描述需要细化或改进的内容...", "modalTitle": "细化", "placeholder": "在此输入您的反馈...", - "taskCreated": "细化任务已创建:{{id}}", - "charCount_one": "" + "taskCreated": "细化任务已创建:{{id}}" }, "reset": { "btn": "重置", @@ -6112,6 +6112,12 @@ "switchToPlainText": "切换到纯文本", "yes": "是" }, + "taskFields": { + "moreFields": "其他字段", + "orphaned": "孤立字段", + "saveFailed": "保存字段失败", + "unset": "—" + }, "taskForm": { "addDependencies": "添加依赖", "attachHint": "您也可以粘贴图片或拖放", @@ -6139,6 +6145,7 @@ "branchStrategyLabel": "分支策略", "collapseDescription": "收起描述", "dependenciesLabel": "依赖关系", + "dependenciesSelected_one": "", "dependenciesSelected_other": "", "descriptionLabel": "描述", "descriptionPlaceholder": "需要完成什么?", @@ -6212,8 +6219,7 @@ "usingPreset": "使用预设:{{name}}", "workflowStepsDescription": "选择任务实现完成后要运行的步骤", "workflowStepsLabel": "工作流步骤", - "workingBranchLabel": "工作分支", - "dependenciesSelected_one": "" + "workingBranchLabel": "工作分支" }, "taskHandlers": { "githubImported": "从 GitHub 导入了 {{id}}" @@ -6236,6 +6242,7 @@ "noReviewItems": "尚无评审项目。", "perTaskAutoMerge": "按任务自动合并", "plain": "纯文本", + "prSummaryLine_one": "", "prSummaryLine_other": "", "queueing": "加入队列中…", "refresh": "刷新", @@ -6245,6 +6252,7 @@ "refreshing": "刷新中…", "refreshStatusLine": "{{status}} · 最后刷新:{{timestamp}} · {{source}}", "requestRevision": "请求修订", + "reviewerSummaryLine_one": "", "reviewerSummaryLine_other": "", "revisionQueueFailed": "无法将修订加入队列", "revisionStarted": "从选定的评审反馈开始了同任务人工智能修订", @@ -6253,9 +6261,7 @@ "showRawText": "显示原始文本", "startedAtSep": " · 已开始:{{timestamp}}", "updateFailed": "更新 {{taskId}} 失败:{{error}}", - "upToDate": "最新", - "prSummaryLine_one": "", - "reviewerSummaryLine_one": "" + "upToDate": "最新" }, "tasks": { "addTaskPlaceholder": "添加任务……", @@ -6269,6 +6275,7 @@ "archiveTask": "归档任务", "assignedTo": "已分配给 {{name}}", "attach": "附件", + "attachCount_one": "", "attachCount_other": "", "attachedFile": "已将 {{fileName}} 附加到 {{taskId}}", "attachFileFailed": "附加 {{fileName}} 失败:{{error}}", @@ -6306,6 +6313,7 @@ "deleteTitle": "删除任务", "dependencyConflict": "{{taskId}} 是 {{dependentList}} 的依赖项。\n\n仍要先移除这些依赖引用并删除吗?", "deps": "依赖", + "depsCount_one": "", "depsCount_other": "", "descriptionPlaceholder": "任务描述", "descriptionRefined": "已用 AI 优化描述", @@ -6326,10 +6334,13 @@ "fanoutEscalated": "升级的重叠", "fanoutEscalationSuffix": " · 在阻塞列中 {{minutes}} 分钟后升级", "fanoutHighFanoutSuffix": "(重叠瓶颈阈值:{{threshold}})", + "fanoutStale_one": "", "fanoutStale_other": "", + "fanoutTooltip_one": "", "fanoutTooltip_other": "", "fast": "快速", "fastMode": "快速模式", + "filesChanged_one": "", "filesChanged_other": "", "forceDeleteTitle": "强制删除任务", "githubTrackingDefaultOff": "关", @@ -6365,6 +6376,7 @@ "modelPlan": "规划", "modelReviewer": "审阅者", "models": "模型", + "modelsCount_one": "", "modelsCount_other": "", "moreOptions": "更多选项", "move": "移动", @@ -6403,6 +6415,7 @@ "resetProgress": "重置进度", "resetProgressMessage": "移动此任务前重置所有步骤进度?", "resetProgressTitle": "重置进度?", + "retriesAriaLabel_one": "", "retriesAriaLabel_other": "", "retry": "重试", "retryFailed": "重试 {{taskId}} 失败:{{error}}", @@ -6419,6 +6432,7 @@ "showSteps": "显示步骤", "stalled": "停滞", "statusMergingFix": "正在合并修复…", + "stepCount_one": "", "stepCount_other": "", "stuck": "卡住", "subtask": "子任务", @@ -6434,15 +6448,7 @@ "usingDefault": "使用默认", "viewDependency": "点击查看 {{depId}}", "workflow": "工作流", - "workflowCheck": "工作流检查", - "attachCount_one": "", - "depsCount_one": "", - "fanoutStale_one": "", - "fanoutTooltip_one": "", - "filesChanged_one": "", - "modelsCount_one": "", - "retriesAriaLabel_one": "", - "stepCount_one": "" + "workflowCheck": "工作流检查" }, "terminal": { "clear": "清空", @@ -6560,14 +6566,14 @@ "resetsInDaysHours": "在 {{days}} 天 {{hours}} 小时后重置", "resetsInHours": "在 {{hours}} 小时后重置", "resetsInMinutes": "在 {{mins}} 分钟后重置", + "showHidden_one": "", "showHidden_other": "", "statusError": "错误", "statusNotConfigured": "未配置", "title": "使用情况", "viewModeLabel": "使用情况视图模式", "viewModeRemaining": "剩余", - "viewModeUsed": "已使用", - "showHidden_one": "" + "viewModeUsed": "已使用" }, "workflow": { "add": "添加", @@ -6668,6 +6674,7 @@ "selectStepsDescription": "选择任务实现完成后要运行的步骤", "showOutput": "显示输出", "started": "开始于:", + "stepCount_one": "", "stepCount_other": "", "stepCreated": "工作流步骤已创建", "stepDefinitionNotFound": "未找到步骤定义。", @@ -6675,28 +6682,27 @@ "steps": "工作流步骤", "stepsExplanation": "合并前步骤在实现后、合并前运行。合并后步骤在合并成功后运行。", "stepUpdated": "工作流步骤已更新", + "summaryAdvisory_one": "", "summaryAdvisory_other": "", + "summaryFailed_one": "", "summaryFailed_other": "", + "summaryPassed_one": "", "summaryPassed_other": "", + "summaryRunning_one": "", "summaryRunning_other": "", "summarySeparator": " · ", + "summarySkipped_one": "", "summarySkipped_other": "", + "summaryStepCount_one": "", "summaryStepCount_other": "", "switchToMarkdown": "切换到 Markdown", "switchToPlain": "切换到纯文本", + "tabMySteps_one": "", "tabMySteps_other": "", + "tabTemplates_one": "", "tabTemplates_other": "", "templateAdded": "已添加工作流步骤「{{name}}」", - "useDefault": "使用默认", - "stepCount_one": "", - "summaryAdvisory_one": "", - "summaryFailed_one": "", - "summaryPassed_one": "", - "summaryRunning_one": "", - "summarySkipped_one": "", - "summaryStepCount_one": "", - "tabMySteps_one": "", - "tabTemplates_one": "" + "useDefault": "使用默认" }, "workflowColumns": { "add": "", @@ -6712,14 +6718,50 @@ "title": "", "traits": "", "traitsLoadFailed": "", - "unplacedCount_other": "", - "unplacedCount_one": "" + "unplacedCount_one": "", + "unplacedCount_other": "" + }, + "workflowFields": { + "add": "添加字段", + "addOption": "添加选项", + "badge": "显示为徽章", + "default": "默认", + "defaultLabel": "默认值", + "defaultTrue": "默认开启", + "duplicateId": "已存在使用该 id 的字段", + "editId": "编辑 id", + "empty": "尚无自定义字段。添加字段以扩展任务表单和卡片。", + "idLabel": "字段 id", + "idWarn": "更改 id 会丢弃以旧 id 存储的值(移除 + 添加)。", + "nameLabel": "字段名称", + "newFieldName": "新字段", + "newOptionLabel": "选项 1", + "noDefault": "— 无 —", + "optionColor": "选项颜色", + "optionLabel": "选项标签", + "optionN": "选项 {{n}}", + "options": "选项", + "optionValue": "选项值", + "placement": "放置位置", + "placementCard": "卡片徽章", + "placementDetail": "详情(内联)", + "placementSection": "详情区块", + "readOnlyHint": "内置工作流为只读 — 复制以进行编辑", + "remove": "移除字段", + "removeOption": "移除选项", + "required": "必填", + "title": "字段", + "typeLabel": "类型", + "widget": "控件", + "widgetDefault": "默认" }, "workflowNodes": { "advisory": "", "codeNote": "在沙箱中运行 TypeScript。语法在保存时校验。", "codeSource": "源代码(TypeScript)", "codeTimeout": "超时(毫秒)", + "cycleBlocked": "", + "edgeCondition": "", "edgeConditionLabel": "条件:{{condition}}", "edgeInspector": "连线", "edgeNoVerdict": "— 成功(无裁定)—", @@ -6741,6 +6783,7 @@ "foreachWorktree": "每步骤工作树", "gateBlocks": "关卡(阻断)", "gateMode": "关卡模式", + "interpreterOnly": "", "joinAll": "所有分支", "joinAny": "任意分支", "joinMode": "合并模式", @@ -6761,14 +6804,7 @@ "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "分支从此节点并发运行。分支内不允许执行和合并接缝。", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "", - "summaryCodeDefault": "", - "summaryGateAdvisory": "", - "summaryGateBlocks": "", - "summaryHoldRelease": "", - "summaryNotConfigured": "", - "summaryReviewType": "" + "stepExecuteLabel": "Step execute" }, "workflows": { "duplicateToCustomize": "", @@ -6799,45 +6835,5 @@ "installRequestTitle": "Worktrunk 安装请求", "sha256": "SHA-256", "version": "版本" - }, - "taskFields": { - "unset": "—", - "moreFields": "其他字段", - "orphaned": "孤立字段", - "saveFailed": "保存字段失败" - }, - "workflowFields": { - "add": "添加字段", - "addOption": "添加选项", - "badge": "显示为徽章", - "default": "默认", - "defaultLabel": "默认值", - "defaultTrue": "默认开启", - "duplicateId": "已存在使用该 id 的字段", - "editId": "编辑 id", - "empty": "尚无自定义字段。添加字段以扩展任务表单和卡片。", - "idLabel": "字段 id", - "idWarn": "更改 id 会丢弃以旧 id 存储的值(移除 + 添加)。", - "nameLabel": "字段名称", - "newFieldName": "新字段", - "newOptionLabel": "选项 1", - "noDefault": "— 无 —", - "optionColor": "选项颜色", - "optionLabel": "选项标签", - "optionN": "选项 {{n}}", - "optionValue": "选项值", - "options": "选项", - "placement": "放置位置", - "placementCard": "卡片徽章", - "placementDetail": "详情(内联)", - "placementSection": "详情区块", - "readOnlyHint": "内置工作流为只读 — 复制以进行编辑", - "remove": "移除字段", - "removeOption": "移除选项", - "required": "必填", - "title": "字段", - "typeLabel": "类型", - "widget": "控件", - "widgetDefault": "默认" } } diff --git a/packages/i18n/locales/zh-CN/cli.json b/packages/i18n/locales/zh-CN/cli.json index 3e985e03d2..7ebb6396aa 100644 --- a/packages/i18n/locales/zh-CN/cli.json +++ b/packages/i18n/locales/zh-CN/cli.json @@ -21,6 +21,7 @@ "agentRunLogsBackHint": "[Esc/q] 返回运行列表", "agentRunLogsTitle": "运行日志({{index}})", "agentsFooterHints": "[s] 启动 [x] 停止 [D] 删除 [r] 刷新 [Tab] 焦点 ↑↓ 选择", + "agentsListTitle_one": "", "agentsListTitle_other": "", "agentsNoAgents": "未找到代理。", "agentStarted": "代理已启动", @@ -44,6 +45,7 @@ "filesEmpty": "(空)", "filesEmptyFile": "(空文件)", "filesFooterHints": "[Tab] 切换面板 [↑↓/jk] 移动 [Enter] 打开 [←/→] 折叠/展开 [.] 隐藏文件 [w] 换行 [p] 项目 [r] 重载", + "filesMoreLines_one": "", "filesMoreLines_other": "", "filesSelectProject": "选择项目", "filesSelectToPreview": "选择文件以预览", @@ -151,6 +153,7 @@ "settingsFooterHints": "[Tab] 切换面板 ↑↓ 选择设置 [Space] 切换布尔 [+/-] 调整数值 [←/→] 循环枚举 [C/V/X/P/L/U/K/R] 远程操作", "settingsInteractivePanelTitle": "设置", "settingsLoadingSettings": "正在加载设置…", + "settingsMoreModels_one": "", "settingsMoreModels_other": "", "settingsPanelTitle": "设置", "settingsPersistentTokenRegenerated": "持久令牌已重新生成", @@ -218,9 +221,6 @@ "utilitiesKillVitest": "终止 Vitest 进程", "utilitiesPanelTitle": "工具", "utilitiesRefreshStats": "刷新统计", - "utilitiesToggleEnginePause": "切换引擎暂停", - "agentsListTitle_one": "", - "filesMoreLines_one": "", - "settingsMoreModels_one": "" + "utilitiesToggleEnginePause": "切换引擎暂停" } } diff --git a/packages/i18n/locales/zh-CN/common.json b/packages/i18n/locales/zh-CN/common.json index b75b3a1f75..f9fb7e049a 100644 --- a/packages/i18n/locales/zh-CN/common.json +++ b/packages/i18n/locales/zh-CN/common.json @@ -1,9 +1,4 @@ { - "actions": { - "cancel": "取消", - "close": "关闭", - "save": "保存" - }, "agents": { "ratings": { "trendDeclining": "", @@ -34,7 +29,6 @@ "minutesAgo_other": "" } }, - "archive": "归档", "board": { "rejection": { "capacityExhausted": "", @@ -44,7 +38,6 @@ "workflowMismatch": "" } }, - "cancel": "取消", "chat": { "failedToGetResponse": "", "failureReferenceId": "", @@ -54,25 +47,15 @@ "openMailboxMessage": "", "toolCallArgsPrefix": "", "toolCallResultPrefix": "", + "toolCallsCount_one": "", + "toolCallsCount_other": "", + "toolCallsHeader": "", "toolCallStatusCompleted": "", "toolCallStatusError": "", "toolCallStatusErrors": "", "toolCallStatusRunning": "", - "toolCallsCount_one": "", - "toolCallsCount_other": "", - "toolCallsHeader": "", "viewFailureDetails": "" }, - "close": "关闭", - "columns": { - "archived": "已归档", - "done": "已完成", - "in-progress": "进行中", - "in-review": "审核中", - "todo": "待办", - "triage": "规划" - }, - "delete": "删除", "health": { "anomaly": { "duplicateActiveId": "", @@ -110,13 +93,6 @@ "modelSetToDefault": "" } }, - "nodeStatus": { - "connecting": "", - "error": "", - "offline": "", - "online": "", - "unknown": "" - }, "nodes": { "auth": { "differ": "", @@ -137,7 +113,13 @@ "stopped": "" } }, - "refresh": "刷新", + "nodeStatus": { + "connecting": "", + "error": "", + "offline": "", + "online": "", + "unknown": "" + }, "research": { "providerGitHub": "", "providerLlmSynthesis": "", @@ -145,7 +127,6 @@ "providerPageFetch": "", "providerWebSearch": "" }, - "retry": "重试", "routing": { "policyLabel": { "block": "", @@ -205,7 +186,6 @@ "zai": "" } }, - "skip": "跳过", "taskForm": { "nodeStatusConnecting": "", "nodeStatusError": "", @@ -220,7 +200,6 @@ "refreshSourceInitialLoad": "", "refreshSourceManual": "" }, - "tryAgain": "重试", "workflow": { "postMerge": "", "preMerge": "", @@ -230,5 +209,14 @@ "statusRunning": "", "statusSkipped": "", "waitingForOutput": "" + }, + "workflowNodes": { + "summaryAwaitInput": "", + "summaryCodeDefault": "", + "summaryGateAdvisory": "", + "summaryGateBlocks": "", + "summaryHoldRelease": "", + "summaryNotConfigured": "", + "summaryReviewType": "" } } diff --git a/packages/i18n/locales/zh-TW/app.json b/packages/i18n/locales/zh-TW/app.json index fdb7176a90..ffb98650ec 100644 --- a/packages/i18n/locales/zh-TW/app.json +++ b/packages/i18n/locales/zh-TW/app.json @@ -65,13 +65,13 @@ "notMerged": "未合併", "refresh": "重新整理", "time": { + "daysAgo_one": "", "daysAgo_other": "", + "hoursAgo_one": "", "hoursAgo_other": "", "justNow": "剛剛", - "minutesAgo_other": "", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "" + "minutesAgo_one": "", + "minutesAgo_other": "" }, "title": "活動日誌" }, @@ -112,18 +112,18 @@ "showToolOutput": "顯示工具輸出", "switchMarkdown": "切換至 markdown 模式", "switchPlainText": "切換至純文字模式", + "timeDaysAgo_one": "", "timeDaysAgo_other": "", + "timeHoursAgo_one": "", "timeHoursAgo_other": "", "timeJustNow": "剛才", + "timeMinutesAgo_one": "", "timeMinutesAgo_other": "", + "toolEntriesHidden_one": "", "toolEntriesHidden_other": "", "toolsOff": "工具:關閉", "toolsOn": "工具:開啟", - "usingDefault": "使用預設值", - "timeDaysAgo_one": "", - "timeHoursAgo_one": "", - "timeMinutesAgo_one": "", - "toolEntriesHidden_one": "" + "usingDefault": "使用預設值" }, "agentMention": { "membersOf": "#{{roomName}} 的成員", @@ -278,6 +278,7 @@ }, "agents": { "activate": "啟動", + "activeAgents_one": "", "activeAgents_other": "", "activePrefix": "活躍:", "advancedSettingsDesc": "此代理的底層配置選項。", @@ -288,6 +289,7 @@ "agentMail": "代理郵件", "agentModelLabel": "代理模型", "agentPlural": "代理人", + "agentsFound_one": "", "agentsFound_other": "", "agentSingular": "代理人", "agentsLabel": "代理", @@ -327,6 +329,7 @@ "bulkActions": "批量操作", "bulkActionsLoadFailed": "載入批次智能體操作失敗:{{error}}", "bulkAgentActions": "批次智能體操作", + "bulkConfirmMessage_one": "", "bulkConfirmMessage_other": "", "bulkNoEligible": "沒有符合條件的代理", "bulkResult_one": "{{action}} {{successCount}} 個{{agentWord}};略過 {{skippedCount}} 個", @@ -469,6 +472,7 @@ "healthError": "錯誤", "heartbeat": "心跳:", "heartbeatAndHealth": "心跳與健康", + "heartbeatClampedToMin_one": "", "heartbeatClampedToMin_other": "", "heartbeatCustom": "自訂心跳執行", "heartbeatEnabled": "啟用心跳", @@ -524,8 +528,10 @@ "importButton": "匯入{{label}}", "importComplete": "匯入完成", "importDescription": "從 Agent Companies 套件匯入代理。瀏覽 companies.sh 目錄以探索已發佈的代理、上傳 AGENTS.md 檔案、選取目錄或貼上資訊清單內容。", + "importingAgents_one": "", "importingAgents_other": "", "importingAgentsAndSkills": "正在匯入 {{agentCount}} 個 Agent 和 {{skillCount}} 個技能...", + "importingSkills_one": "", "importingSkills_other": "", "inbox": "收件匣", "inheritingProjectDefault": "繼承專案預設值", @@ -591,6 +597,7 @@ "loadingSkillContent": "正在載入技能內容...", "loadingTasks": "正在載入任務...", "loadTasksFailed": "載入任務失敗", + "logEntries_one": "", "logEntries_other": "", "logsWillAppear": "代理開始執行後,日誌將顯示在此處。", "logsWillAppearActive": "日誌將顯示在此處。", @@ -747,15 +754,20 @@ "pauseAgentsFailed": "暫停智能體失敗:{{error}}", "pauseAll": "暫停全部", "pauseAllAgents": "暫停所有智能體", + "pauseAllConfirm_one": "", "pauseAllConfirm_other": "", "pauseAllTitle": "暫停所有智能體", "pauseCountHint_one": "暫停 {{count}} 個活躍/執行中的代理人", "pauseCountHint_other": "暫停 {{count}} 個活躍/執行中的代理人", + "pauseCountHint_one_one": "", "pauseCountHint_one_other": "", + "pauseCountHint_other_one": "", "pauseCountHint_other_other": "", "pausedPast": "已暫停", + "pausedSummary_one": "", "pausedSummary_other": "", "pendingApprovals": "待審批", + "pendingApprovalsCount_one": "", "pendingApprovalsCount_other": "", "performance": { "avgDuration": "平均時長", @@ -787,6 +799,7 @@ "categorySelect": "選擇分類...", "categorySpeed": "速度", "commentPlaceholder": "選填備註...", + "count_one": "", "count_other": "", "deleteError": "刪除評分失敗:{{error}}", "deleteRating": "刪除評分", @@ -795,12 +808,11 @@ "loadError": "載入評分失敗:{{error}}", "loading": "載入評分中...", "noRatings": "尚無評分", + "starCount_one": "", "starCount_other": "", "submitRating": "提交評分", "submitting": "提交中...", - "title": "使用者評分", - "count_one": "", - "starCount_one": "" + "title": "使用者評分" }, "recentRuns": "最近執行", "reflections": { @@ -837,21 +849,28 @@ "resetDayWeekly": "星期幾(0=週日)", "resetting": "正在重置...", "result": "結果", + "resultCreated_one": "", "resultCreated_other": "", + "resultErrors_one": "", "resultErrors_other": "", + "resultSkipped_one": "", "resultSkipped_other": "", "resume": "恢復", "resumeAction": "恢復", "resumeAgentsFailed": "恢復智能體失敗:{{error}}", "resumeAll": "恢復全部", "resumeAllAgents": "恢復所有智能體", + "resumeAllConfirm_one": "", "resumeAllConfirm_other": "", "resumeAllTitle": "恢復所有智能體", "resumeCountHint_one": "恢復 {{count}} 個已暫停的代理人", "resumeCountHint_other": "恢復 {{count}} 個已暫停的代理人", + "resumeCountHint_one_one": "", "resumeCountHint_one_other": "", + "resumeCountHint_other_one": "", "resumeCountHint_other_other": "", "resumedPast": "已恢復", + "resumedSummary_one": "", "resumedSummary_other": "", "retry": "重試", "reviewConfiguration": "檢閱生成的設定", @@ -886,6 +905,7 @@ "stopMessage": "停止此執行?", "stopTitle": "停止執行" }, + "runsCount_one": "", "runsCount_other": "", "runsSuccessRate": "{{rate}}% 成功率", "runStarted": "執行已啟動", @@ -926,7 +946,9 @@ "selectCompany": "", "selectDirectory": "選取目錄", "selected": "已選取:", + "selectedAgentLabel_one": "", "selectedAgentLabel_other": "", + "selectedSkillLabel_one": "", "selectedSkillLabel_other": "", "selectMemoryFile": "選擇一個記憶檔案", "selectModel": "模型", @@ -940,12 +962,17 @@ "showSystemAgents": "顯示系統智能體", "skills": "技能", "skillsDescription": "管理此代理可用的技能。", + "skillsErrors_one": "", "skillsErrors_other": "", + "skillsFound_one": "", "skillsFound_other": "", "skillsHint": "可選擇指派給此代理程式的技能", + "skillsImported_one": "", "skillsImported_other": "", "skillsNone": "未分配技能", + "skillsSelected_one": "", "skillsSelected_other": "", + "skillsSkipped_one": "", "skillsSkipped_other": "", "skillsTitle": "技能", "skipHeartbeatWhenIdle": "閒置時跳過心跳", @@ -1049,34 +1076,7 @@ "weekly": "每週", "workingOn": "正在處理:", "zoomIn": "放大", - "zoomOut": "縮小", - "activeAgents_one": "", - "agentsFound_one": "", - "bulkConfirmMessage_one": "", - "heartbeatClampedToMin_one": "", - "importingAgents_one": "", - "importingSkills_one": "", - "logEntries_one": "", - "pauseAllConfirm_one": "", - "pauseCountHint_one_one": "", - "pauseCountHint_other_one": "", - "pausedSummary_one": "", - "pendingApprovalsCount_one": "", - "resultCreated_one": "", - "resultErrors_one": "", - "resultSkipped_one": "", - "resumeAllConfirm_one": "", - "resumeCountHint_one_one": "", - "resumeCountHint_other_one": "", - "resumedSummary_one": "", - "runsCount_one": "", - "selectedAgentLabel_one": "", - "selectedSkillLabel_one": "", - "skillsErrors_one": "", - "skillsFound_one": "", - "skillsImported_one": "", - "skillsSelected_one": "", - "skillsSkipped_one": "" + "zoomOut": "縮小" }, "app": { "backendError": { @@ -1086,12 +1086,12 @@ }, "approval": { "dismissBanner": "關閉審批通知橫幅", + "needAttention_one": "", "needAttention_other": "", "openMailbox": "開啟郵箱", "requestPlural": "請求", "requests": "審批請求", - "requestSingular": "請求", - "needAttention_one": "" + "requestSingular": "請求" }, "auth": { "clearAndRetry": "清除令牌並重試", @@ -1117,8 +1117,11 @@ "confirmMessage": "此工作階段在另一個標籤頁中處於活躍狀態。仍然開啟?", "confirmTitle": "開啟活躍工作階段", "dismissButton": "關閉", + "pillLabel_one": "", "pillLabel_other": "", + "pillTitle_one": "", "pillTitle_other": "", + "pillTitleWithInput_one": "", "pillTitleWithInput_other": "", "popoverHeader": "背景任務", "status": { @@ -1133,10 +1136,7 @@ "planning": "規劃", "sliceInterview": "切片訪談", "subtask": "子任務分解" - }, - "pillLabel_one": "", - "pillTitle_one": "", - "pillTitleWithInput_one": "" + } }, "board": { "archived": "已歸檔", @@ -1249,9 +1249,12 @@ "openQuickChat": "開啟快速聊天", "queuedMessage": "已排隊:{{preview}}", "quickChatTitle": "快速聊天", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "剛才", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", "removeAttachment": "移除 {{name}}", "resizePanelBottom": "從底部調整面板大小", @@ -1265,6 +1268,7 @@ "resizeSidebar": "調整側邊欄大小", "responseCopied": "已複製回覆", "responseFailed": "回應失敗", + "roomMemberCount_one": "", "roomMemberCount_other": "", "roomsGroupLabel": "頻道", "scopeDirect": "直接", @@ -1293,16 +1297,12 @@ "thinkingLabel": "思考", "thinkingStatus": "思考中……", "toolCalls": "工具呼叫", + "toolCallsCount_one": "", "toolCallsCount_other": "", "typeMessage": "輸入訊息...", "unreadMessages": "未讀訊息", "untitledSession": "未命名", - "you": "你", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "roomMemberCount_one": "", - "toolCallsCount_one": "" + "you": "你" }, "chatRooms": { "error": { @@ -1349,8 +1349,10 @@ "actionsTitle": "欄操作", "archiveAllDoneAriaLabel": "存檔所有已完成的工作", "archiveAllDoneTitle": "存檔所有已完成的工作", + "archiveAllMessage_one": "", "archiveAllMessage_other": "", "archiveAllTitle": "全部存檔已完成", + "archivedTasks_one": "", "archivedTasks_other": "", "autoMerge": "自動合併", "autoMergeDisabled": "自動合併已停用", @@ -1362,19 +1364,25 @@ "expandArchivedTitle": "展開已存檔的工作", "failedToArchive": "存檔工作失敗", "keepProgress": "保留進度", + "loadMore_one": "", "loadMore_other": "", "moveAllToTodo": "全部移至待辦", + "moveAllToTodoMessage_one": "", "moveAllToTodoMessage_other": "", "moveAllToTodoTitle": "全部移至待辦", + "movedToPlanning_one": "", "movedToPlanning_other": "", + "movedToTodo_one": "", "movedToTodo_other": "", "movePartialFailure": "已移動 {{total}} 個工作中的 {{moved}} 個;{{failed}} 個失敗", + "moveToTodoHint_one": "", "moveToTodoHint_other": "", "moveToTodoPartialFailure": "已將 {{total}} 個工作中的 {{moved}} 個移至待辦;{{failed}} 個失敗", "newTask": "新工作", "noManuallyPausableTasks": "沒有可手動暫停的工作", "noTasks": "沒有工作", "noTasksInColumn": "此欄中沒有工作", + "pauseHint_one": "", "pauseHint_other": "", "preserveProgressMessage": "此工作已完成步驟。在移動前保留進度?", "preserveProgressMoveTodoMessage": "某些工作已完成步驟。在移至待辦前保留進度?", @@ -1382,7 +1390,9 @@ "promote": "", "promoting": "", "replanAll": "全部重新規劃", + "replanAllHint_one": "", "replanAllHint_other": "", + "replanAllMessage_one": "", "replanAllMessage_other": "", "replanAllTitle": "重新規劃所有工作", "resetProgress": "重設進度", @@ -1391,22 +1401,12 @@ "resetProgressMoveTodoMessage": "在移至待辦前重設工作的步驟進度?", "resetProgressTitle": "重設進度?", "stopAll": "全部停止", + "stopAllMessage_one": "", "stopAllMessage_other": "", "stopAllTitle": "停止所有工作", "stopPartialFailure": "已停止 {{total}} 個工作中的 {{paused}} 個;{{failed}} 個失敗", - "stoppedTasks_other": "", - "archiveAllMessage_one": "", - "archivedTasks_one": "", - "loadMore_one": "", - "moveAllToTodoMessage_one": "", - "movedToPlanning_one": "", - "movedToTodo_one": "", - "moveToTodoHint_one": "", - "pauseHint_one": "", - "replanAllHint_one": "", - "replanAllMessage_one": "", - "stopAllMessage_one": "", - "stoppedTasks_one": "" + "stoppedTasks_one": "", + "stoppedTasks_other": "" }, "comments": { "addButton": "新增評論", @@ -1421,8 +1421,8 @@ "updatedSuccess": "評論已更新" }, "commit": { - "filesChanged_other": "", - "filesChanged_one": "" + "filesChanged_one": "", + "filesChanged_other": "" }, "commitDiff": { "error": "載入提交差異出錯:{{error}}", @@ -1564,6 +1564,7 @@ "filterBySeverity": "按嚴重程度篩選日誌", "info": "資訊", "lines": "行", + "lines_one": "", "lines_other": "", "loading": "載入中...", "loadingConfig": "載入開發伺服器設定...", @@ -1573,6 +1574,7 @@ "logs": "日誌", "lostConnection": "日誌串流連線已斷開。", "manual": "手動", + "matchCount_one": "", "matchCount_other": "", "newLogs": "新日誌", "noLogsYet": "暫無日誌。啟動開發伺服器以查看輸出。", @@ -1621,9 +1623,7 @@ "started": "開發伺服器已啟動。", "stopped": "開發伺服器已停止。" }, - "warn": "警告", - "lines_one": "", - "matchCount_one": "" + "warn": "警告" }, "dirPicker": { "ariaLabel": "目錄瀏覽器", @@ -1742,6 +1742,7 @@ "clearSearch": "清除搜尋", "collapse": "摺疊", "collapseContent": "摺疊內容", + "docCount_one": "", "docCount_other": "", "documentsCreatedIn": "文件在工作詳細資訊標籤中建立。", "expand": "展開", @@ -1762,6 +1763,7 @@ "plain": "純文字", "projectFiles": "專案檔案", "projectFilesTab": "專案檔案", + "resultCount_one": "", "resultCount_other": "", "retry": "重試", "retryLoading": "重試載入文件", @@ -1778,9 +1780,7 @@ "taskDocuments": "工作文件", "taskDocumentsTab": "工作文件", "title": "文件", - "untitled": "未命名", - "docCount_one": "", - "resultCount_one": "" + "untitled": "未命名" }, "droidCli": { "active": "活躍", @@ -1843,20 +1843,25 @@ }, "executor": { "blocked": "已封鎖", + "daysAgo_one": "", "daysAgo_other": "", "escalated": "已升級", "escalatedSuffix": " (已升級)", "hideProjectDir": "隱藏專案目錄", + "hoursAgo_one": "", "hoursAgo_other": "", "inReview": "審查中", "justNow": "剛剛", "loading": "載入中...", + "minutesAgo_one": "", "minutesAgo_other": "", "noActivity": "無活動", + "overlapBottleneck_one": "", "overlapBottleneck_other": "", "overlapQueue": "重疊隊列", "queued": "已排隊", "running": "執行中", + "secondsAgo_one": "", "secondsAgo_other": "", "showProjectDir": "顯示專案目錄", "stateIdle": "閒置", @@ -1864,12 +1869,7 @@ "stateRunning": "執行中", "status": "執行器狀態", "stuck": "卡住", - "temporary": "暫時", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "", - "overlapBottleneck_one": "", - "secondsAgo_one": "" + "temporary": "暫時" }, "fileBrowser": { "back": "返回檔案清單", @@ -1943,7 +1943,9 @@ "advancesHelpItem2": "reachable / subsumed / orphaned / superseded — 已處理(包括等效內容已落地、原始 SHA 已消失或 HEAD 已與重寫的整合提示對齊的歷史重寫情況)。", "advancesHelpItem3": "pending + off / not run — 設定中停用了自動同步;分支參照已移動,但工作樹未跟進。", "advancesHelpItem4": "pending + stash-failed / would-conflict / 類似情況 — 自動同步嘗試了但無法調和(通常是本機編輯與新提交衝突)。", + "advancesNeedAction_one": "", "advancesNeedAction_other": "", + "aheadOfUpstream_one": "", "aheadOfUpstream_other": "", "aligned": "已對齊", "apply": "套用", @@ -1960,6 +1962,7 @@ "backToIssuesList": "返回 Issue 清單", "backToPullsList": "返回 PR 清單", "baseHead": "基於:HEAD", + "behindUpstream_one": "", "behindUpstream_other": "", "branchLabel": "分支:", "cancel": "取消", @@ -1975,10 +1978,14 @@ "commitMessagePlaceholder": "提交訊息……", "commitsOnBranch": "{{name}} 上的提交", "commitStagedChanges": "提交已暫存變更", + "commitsToPull_one": "", "commitsToPull_other": "", + "commitsToPush_one": "", "commitsToPush_other": "", + "commitsToPushHeader_one": "", "commitsToPushHeader_other": "", "committedHash": "已提交:{{hash}}", + "conflictedCount_one": "", "conflictedCount_other": "", "conflictReclaimFailed": "新增衝突修復任務失敗", "conflictReclaimQueued": "衝突修復任務已加入佇列", @@ -2009,8 +2016,10 @@ "deletedBranch": "已刪除分支 {{name}}", "detectingRemotes": "偵測中……", "diffColon": "差異:", + "discardChangesMessage_one": "", "discardChangesMessage_other": "", "discardChangesTitle": "捨棄變更", + "discardedFiles_one": "", "discardedFiles_other": "", "discardSelected": "捨棄選取", "dismiss": "忽略", @@ -2062,7 +2071,9 @@ "forceDeletedBranch": "已強制刪除分支 {{name}}", "fullShaAbbrev": "完整", "ghAuthLoginHint": "執行 {{code}} 以啟用 PR 建立。", + "headAheadOfIntegration_one": "", "headAheadOfIntegration_other": "", + "headAheadOfOriginIntegration_one": "", "headAheadOfOriginIntegration_other": "", "headVsIntegration": "HEAD 與 {{branch}} 比較", "headVsOriginIntegration": "HEAD 與 origin/{{branch}} 比較", @@ -2070,11 +2081,14 @@ "hideExplanation": "隱藏說明", "import": "匯入", "imported": "已匯入", + "importedCount_one": "", "importedCount_other": "", "importFromGitHub": "從 GitHub 匯入", "importSubtitle": "選擇偵測到的遠端,載入開放中的 Issue 或 PR,並匯入看板。", "importTypeAriaLabel": "匯入類型", + "integrationAheadOfHead_one": "", "integrationAheadOfHead_other": "", + "issueCount_one": "", "issueCount_other": "", "load": "載入", "loadFromRepoAriaLabel": "從儲存庫載入 {{tab}}", @@ -2088,7 +2102,9 @@ "loadingTitle": "載入中……", "loadMoreCommits": "載入更多提交", "loadTabTitle": "載入 {{tab}}", + "localAheadOfOriginIntegration_one": "", "localAheadOfOriginIntegration_other": "", + "localBehindOriginIntegration_one": "", "localBehindOriginIntegration_other": "", "localVsOrigin": "本地 {{branch}} 與 origin 比較", "manualPrFlowHint": "使用底部操作為此任務執行 PR 優先完成流程。", @@ -2104,6 +2120,7 @@ "mergingStatus": "合併中……", "modalTitle": "Git 管理員", "modified": "已修改", + "modifiedCount_one": "", "modifiedCount_other": "", "newBranchName": "新分支名稱", "noAheadCommitsFound": "未找到領先提交(可能需要先 Fetch)", @@ -2139,6 +2156,7 @@ "notOnIntegrationBranchTitle": "目前位於非整合分支", "noUnstagedChanges": "無未暫存變更", "openPullsFrom": "來自 {{remote}} 的開放 PR", + "originIntegrationAheadOfHead_one": "", "originIntegrationAheadOfHead_other": "", "pop": "彈出", "popStashTitle": "彈出儲藏(套用並刪除)", @@ -2163,6 +2181,7 @@ "prUnlinked": "已取消關聯 PR #{{number}}", "pull": "Pull", "pullCompleted": "Pull 完成", + "pullCount_one": "", "pullCount_other": "", "pullFailed": "Pull 失敗", "pullOptions": "Pull 選項", @@ -2170,6 +2189,7 @@ "pullRebase": "Pull --rebase", "pullRebaseCompleted": "Pull --rebase 完成", "pullRequestHeading": "Pull Request", + "pullRequestsCount_one": "", "pullRequestsCount_other": "", "push": "Push", "pushCompleted": "Push 完成", @@ -2222,10 +2242,14 @@ "stageAll": "全部暫存", "stageAllAndCommit": "全部暫存並提交", "stageAllAndCommitTitle": "全部暫存並提交", + "stageCount_one": "", "stageCount_other": "", "staged": "已暫存", + "stagedChanges_one": "", "stagedChanges_other": "", + "stagedCount_one": "", "stagedCount_other": "", + "stagedFiles_one": "", "stagedFiles_other": "", "stageFile": "暫存檔案", "stageSelected": "暫存選取", @@ -2274,13 +2298,17 @@ "unlinkButton": "取消關聯", "unresolvedMergeConflicts": "未解決的合併衝突", "unstageAll": "全部取消暫存", + "unstageCount_one": "", "unstageCount_other": "", "unstaged": "未暫存", + "unstagedChanges_one": "", "unstagedChanges_other": "", + "unstagedFiles_one": "", "unstagedFiles_other": "", "unstageFile": "取消暫存檔案", "unstageSelected": "取消暫存選取", "untracked": "未追蹤", + "untrackedCount_one": "", "untrackedCount_other": "", "upToDate": "已是最新", "view": "查看", @@ -2291,40 +2319,13 @@ "workingTreeModified": "已修改", "worktreeBadgeBare": "裸庫", "worktreeBadgeMain": "主", - "worktreesInUse_other": "", - "worktreesTotal_other": "", - "advancesNeedAction_one": "", - "aheadOfUpstream_one": "", - "behindUpstream_one": "", - "commitsToPull_one": "", - "commitsToPush_one": "", - "commitsToPushHeader_one": "", - "conflictedCount_one": "", - "discardChangesMessage_one": "", - "discardedFiles_one": "", - "headAheadOfIntegration_one": "", - "headAheadOfOriginIntegration_one": "", - "importedCount_one": "", - "integrationAheadOfHead_one": "", - "issueCount_one": "", - "localAheadOfOriginIntegration_one": "", - "localBehindOriginIntegration_one": "", - "modifiedCount_one": "", - "originIntegrationAheadOfHead_one": "", - "pullCount_one": "", - "pullRequestsCount_one": "", - "stageCount_one": "", - "stagedChanges_one": "", - "stagedCount_one": "", - "stagedFiles_one": "", - "unstageCount_one": "", - "unstagedChanges_one": "", - "unstagedFiles_one": "", - "untrackedCount_one": "", "worktreesInUse_one": "", - "worktreesTotal_one": "" + "worktreesInUse_other": "", + "worktreesTotal_one": "", + "worktreesTotal_other": "" }, "goals": { + "activeCount_one": "", "activeCount_other": "", "addGoal": "新增目標", "archive": "封存", @@ -2343,8 +2344,7 @@ "title": "目標", "titleRequired": "標題為必需。", "unarchive": "取消封存", - "updateError": "現在無法更新目標狀態。請重試。", - "activeCount_one": "" + "updateError": "現在無法更新目標狀態。請重試。" }, "groupTask": { "abandonGroup": "", @@ -2365,6 +2365,7 @@ "unavailable": "分支群組不可用" }, "header": { + "activePlanningSessions_one": "", "activePlanningSessions_other": "", "addFirstScript": "新增第一個指令碼", "additionalHeaderActions": "更多頁首動作", @@ -2391,6 +2392,7 @@ "localNode": "本機", "mailbox": "信箱", "mailboxView": "信箱檢視", + "mailboxWithCount_one": "", "mailboxWithCount_other": "", "manageProjects": "管理專案", "manageScripts": "管理指令碼…", @@ -2413,6 +2415,7 @@ "reliabilityView": "可靠性", "researchView": "研究", "resumePlanningSession": "恢復規劃工作階段", + "resumePlanningSessionCount_one": "", "resumePlanningSessionCount_other": "", "resumeScheduling": "恢復排程", "scripts": "指令碼", @@ -2434,16 +2437,13 @@ "terminal": "終端機", "todosView": "待辦事項", "unreadChatResponse": "未讀聊天回覆", + "unreadMessages_one": "", "unreadMessages_other": "", "viewActivityLog": "查看活動記錄", "viewProjects": "查看專案", "viewUsage": "查看用量", "workflowSteps": "工作流程步驟", - "workingBranch": "工作分支", - "activePlanningSessions_one": "", - "mailboxWithCount_one": "", - "resumePlanningSessionCount_one": "", - "unreadMessages_one": "" + "workingBranch": "工作分支" }, "health": { "activeTasks": "活躍任務", @@ -2515,6 +2515,7 @@ "expandTaskOptions": "展開進階工作選項", "hintEnterEsc": "按 Enter 建立 · Esc 取消", "loadingAgents": "正在加載代理...", + "model_one": "", "model_other": "", "models": "模型", "noAgentsAvailable": "沒有可用的代理", @@ -2533,8 +2534,7 @@ "selectExecutionNode": "選擇執行節點", "subtask": "子工作", "useDefault": "使用預設值", - "whatNeedsToBeDone": "需要做什麼?", - "model_one": "" + "whatNeedsToBeDone": "需要做什麼?" }, "insights": { "allInsights": "所有洞察", @@ -2580,6 +2580,7 @@ "runCompleted": "已建立 {{created}} 個,已更新 {{updated}} 個", "showAllInsights": "顯示所有洞察", "showArchived": "顯示已存檔的洞察", + "showArchivedLabel_one": "", "showArchivedLabel_other": "", "showBacklogHealth": "僅顯示待辦事項健康狀況洞察", "taskCreated": "從\"{{title}}\"建立的任務", @@ -2591,8 +2592,7 @@ "unarchiveLabel": "取消存檔此洞察", "unarchiveTitle": "取消存檔此洞察", "unarchiving": "正在取消存檔\"{{title}}\"...", - "usePlanningDefault": "使用規劃預設值", - "showArchivedLabel_one": "" + "usePlanningDefault": "使用規劃預設值" }, "interview": { "addContextDirection": "添加任何額外的上下文或方向...", @@ -2647,13 +2647,16 @@ "archiveSelectedTitle": "封存選取的已完成任務", "archiveUnavailable": "封存操作無法使用", "archiveViaButton": "任務只能透過封存按鈕封存", + "bulkArchiveDone_one": "", "bulkArchiveDone_other": "", + "bulkArchiveMessage_one": "", "bulkArchiveMessage_other": "", "bulkArchiveNoTasks": "沒有可以封存的選取任務(只有已完成的任務)", "bulkArchiveSummary": "已封存 {{archived}} · {{skipped}} 已略過 · {{failed}} 失敗", "bulkArchiveTitle": "封存選取的任務", "bulkDeleteAll": "全部刪除", "bulkDeleteArchiveSummary": "已封存 {{archived}},已刪除 {{deleted}},失敗 {{failed}}", + "bulkDeleteMessage_one": "", "bulkDeleteMessage_other": "", "bulkDeleteNoTasks": "沒有可刪除的選取任務(已封存的任務除外)", "bulkDeleteSummary_one": "已刪除 {{count}} 個任務 · 跳過 {{skipped}} 個已封存 · {{failed}} 個失敗", @@ -2669,6 +2672,7 @@ "bulkUnpauseSummary": "已恢復 {{unpaused}} · {{skipped}} 已略過 · {{failed}} 失敗", "bulkUpdateFailed": "更新模型失敗", "bulkUpdateNoTasks": "沒有可更新的有效任務(已封存的任務無法修改)", + "bulkUpdateSuccess_one": "", "bulkUpdateSuccess_other": "", "cancelMove": "取消移動", "clear": "清除", @@ -2689,6 +2693,7 @@ "filterChip": "篩選:{{column}}", "forceDelete": "強制刪除", "forceDeleteTitle": "強制刪除任務", + "hidden_one": "", "hidden_other": "", "hideDone": "隱藏已完成", "hideDoneTitle": "隱藏已完成的任務", @@ -2719,6 +2724,7 @@ "resizeSidebar": "調整任務清單側邊欄大小", "reviewerModel": "審查器模型", "selectAll": "選取所有可見任務", + "selectedCount_one": "", "selectedCount_other": "", "selectTask": "選取 {{taskId}}", "selectTaskPrompt": "選取一個任務以查看詳情", @@ -2730,7 +2736,9 @@ "staleOnlyTitle": "僅顯示過期任務", "stalePausedReview": "過期暫停審核", "stalePausedReviewTitle": "僅顯示過期暫停審核任務", + "stats_one": "", "stats_other": "", + "statsInColumn_one": "", "statsInColumn_other": "", "statusMergingFix": "合併修復中…", "stuck": "卡住", @@ -2739,15 +2747,7 @@ "unpauseSelectedTitle": "恢復目前已暫停的選取任務", "unpauseUnavailable": "恢復操作無法使用", "useProjectDefault": "使用專案預設", - "viewOptions": "檢視選項", - "bulkArchiveDone_one": "", - "bulkArchiveMessage_one": "", - "bulkDeleteMessage_one": "", - "bulkUpdateSuccess_one": "", - "hidden_one": "", - "selectedCount_one": "", - "stats_one": "", - "statsInColumn_one": "" + "viewOptions": "檢視選項" }, "mailbox": { "agent": "代理", @@ -2791,6 +2791,7 @@ "markAllRead": "全部已讀", "markAllReadButton": "全部標記為已讀", "markAllReadTitle": "全部標記為已讀", + "markedAsRead_one": "", "markedAsRead_other": "", "markReadFailed": "無法將訊息標記為已讀", "messageDeleted": "訊息已刪除", @@ -2817,9 +2818,12 @@ "replyLoadFailed": "載入回覆訊息失敗。點擊重試。", "selectMessageToRead": "選擇要閱讀的訊息", "system": "系統", + "timeDaysAgo_one": "", "timeDaysAgo_other": "", + "timeHoursAgo_one": "", "timeHoursAgo_other": "", "timeJustNow": "剛剛", + "timeMinsAgo_one": "", "timeMinsAgo_other": "", "title": "郵箱", "to": "至", @@ -2830,11 +2834,7 @@ "typeSystem": "系統", "typeUserToAgent": "你 → 代理", "user": "使用者", - "you": "你", - "markedAsRead_one": "", - "timeDaysAgo_one": "", - "timeHoursAgo_one": "", - "timeMinsAgo_one": "" + "you": "你" }, "memory": { "auditChecksTitle": "稽核檢查", @@ -2851,6 +2851,7 @@ "capReadable": "可讀", "capWritable": "可寫", "categories": "分類", + "charCount_one": "", "charCount_other": "", "compactFailed": "壓縮記憶失敗", "compacting": "正在壓縮…", @@ -2886,7 +2887,9 @@ "healthIssues": "發現問題", "healthStatusTitle": "健康狀態", "healthWarning": "警告", + "insightCount_one": "", "insightCount_other": "", + "insightsExtracted_one": "", "insightsExtracted_other": "", "insightsMemoryLabel": "洞察記憶", "insightsSaved": "洞察已儲存", @@ -2937,6 +2940,7 @@ "saveSettingsFailed": "儲存記憶設定失敗", "saving": "正在儲存…", "searchPlaceholder": "使用 qmd 搜尋記憶", + "sectionCount_one": "", "sectionCount_other": "", "settingsNote": "注意:在以下位置變更後端類型:", "settingsNoteLink": "設定 → 記憶", @@ -2948,18 +2952,14 @@ "tabWorking": "工作記憶", "testing": "正在測試…", "testMemorySearchTitle": "測試記憶搜尋", + "testResultCount_one": "", "testResultCount_other": "", "testResultStatus": "qmd {{qmdStatus}} · {{fallbackStatus}}", "testRetrieval": "測試檢索", "testSearchHint": "執行與代理使用的相同 qmd 支援的 memory_search 路徑。", "title": "記憶", "totalInsights": "洞察總數", - "workingMemoryLabel": "工作記憶", - "charCount_one": "", - "insightCount_one": "", - "insightsExtracted_one": "", - "sectionCount_one": "", - "testResultCount_one": "" + "workingMemoryLabel": "工作記憶" }, "merge": { "advanced": "進階", @@ -2980,6 +2980,7 @@ "pr": "PR", "pulling": "拉取中…", "pushForceWithLease": "推送 (force-with-lease)", + "pushHeading_one": "", "pushHeading_other": "", "pushing": "推送中…", "pushSuccess": "已推送到 origin/{{branch}} @ {{sha}}。", @@ -2988,8 +2989,7 @@ "shortstatTitle": "最終提交簡統計;如需查看所有工作提交的完整著陸差異,請參閱「變更」分頁。", "smartPull": "智慧拉取", "status": "狀態", - "title": "合併詳情", - "pushHeading_one": "" + "title": "合併詳情" }, "mesh": { "ariaLabel": "節點網格拓撲可視化", @@ -3030,6 +3030,7 @@ "assertionTitlePlaceholder": "斷言標題", "assertionUpdated": "斷言已更新", "assertionUpdateFailed": "更新斷言失敗", + "attemptRetries_one": "", "attemptRetries_other": "", "autopilotActivatingSlice": "正在啟動切片", "autopilotCompleting": "完成中", @@ -3116,6 +3117,7 @@ "featureLinkFailed": "連結功能失敗", "featureLinkTaskFailed": "將功能連結到任務失敗", "featureSaveFailed": "儲存功能失敗", + "featuresCount_one": "", "featuresCount_other": "", "featureTitlePlaceholder": "功能標題", "featureTitleRequired": "功能標題不能為空", @@ -3153,7 +3155,9 @@ "lastValidatorStatus": "最近 {{status}}", "linkAFeature": "關聯功能", "linkButton": "連結", + "linkedCount_one": "", "linkedCount_other": "", + "linkedFeaturesCount_one": "", "linkedFeaturesCount_other": "", "linkedFeaturesLabel": "關聯功能", "linkedGoals": "關聯目標", @@ -3175,6 +3179,7 @@ "milestoneDeleteFailed": "刪除里程碑失敗", "milestoneDescriptionPlaceholder": "里程碑描述...", "milestoneSaveFailed": "儲存里程碑失敗", + "milestonesCount_one": "", "milestonesCount_other": "", "milestoneTitlePlaceholder": "里程碑標題", "milestoneTitleRequired": "里程碑標題不能為空", @@ -3211,11 +3216,15 @@ "planStatePlanned": "已規劃", "planTitle": "用 AI 規劃任務", "prepareQuestion": "準備下一個問題...", + "progressText_one": "", "progressText_other": "", "reconnecting": "正在重新連接…", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "剛剛", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", "removeFeature": "刪除功能", "removeMilestone": "刪除里程碑", @@ -3250,9 +3259,11 @@ "sliceDeleted": "切片已刪除", "sliceDeleteFailed": "刪除切片失敗", "sliceSaveFailed": "儲存切片失敗", + "slicesCount_one": "", "slicesCount_other": "", "sliceTitlePlaceholder": "切片標題", "sliceTitleRequired": "切片標題不能為空", + "sliceTriaged_one": "", "sliceTriaged_other": "", "sliceTriageFailed": "分類切片功能失敗", "sliceUpdated": "切片已更新", @@ -3277,8 +3288,10 @@ "statusTriaged": "已分類", "stopFailed": "停止任務失敗", "stopMission": "停止任務", + "stopped_one": "", "stopped_other": "", "summaryStats": "{{milestones}} 個里程碑,{{features}} 個功能。批准前請審查和編輯。", + "tabActivity_one": "", "tabActivity_other": "", "tabStructure": "結構", "takeControl": "接管", @@ -3287,6 +3300,7 @@ "targetBranchPlaceholder": "例如 main", "taskIdPlaceholder": "任務 ID(例如 FN-001)", "taskIdRequired": "任務 ID 不能為空", + "tasksFailed_one": "", "tasksFailed_other": "", "title": "任務", "titleLabel": "任務標題", @@ -3304,7 +3318,9 @@ "updateButton": "更新", "updated": "任務已更新", "validateFeature": "驗證功能", + "validationRoundsCount_one": "", "validationRoundsCount_other": "", + "validationRoundsLabel_one": "", "validationRoundsLabel_other": "", "validationRuns": "驗證執行", "validationState": "驗證狀態", @@ -3315,23 +3331,7 @@ "verification": "驗證:", "verificationCriteria": "驗證標準", "viewMissionFailures": "查看任務失敗", - "whatToBuild": "您想要建置什麼?", - "attemptRetries_one": "", - "featuresCount_one": "", - "linkedCount_one": "", - "linkedFeaturesCount_one": "", - "milestonesCount_one": "", - "progressText_one": "", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "slicesCount_one": "", - "sliceTriaged_one": "", - "stopped_one": "", - "tabActivity_one": "", - "tasksFailed_one": "", - "validationRoundsCount_one": "", - "validationRoundsLabel_one": "" + "whatToBuild": "您想要建置什麼?" }, "modalManager": { "createdFromPlanning": "在規劃模式中創建了 {{id}}", @@ -3347,6 +3347,7 @@ "addToFavorites": "添加到收藏", "addToFavoritesAriaLabel": "將 {{name}} 添加到收藏", "clearFilter": "清除篩選", + "count_one": "", "count_other": "", "descriptions": { "executor": "用於實現此任務的 AI 模型。", @@ -3401,8 +3402,7 @@ "titles": { "configuration": "模型設定" }, - "useDefault": "使用預設值", - "count_one": "" + "useDefault": "使用預設值" }, "modelSelection": { "choose": "為此工作選擇模型。如果未選擇,將使用預設模型。", @@ -3477,11 +3477,11 @@ "noAvailableTasks": "沒有可用的任務", "searchTasks": "搜尋任務…", "selectAgent": "選擇代理", + "selectedCount_one": "", "selectedCount_other": "", "taskCreated": "已建立 {{taskId}}", "title": "新任務", - "unsavedChanges": "您有未保存的變更。要放棄嗎?", - "selectedCount_one": "" + "unsavedChanges": "您有未保存的變更。要放棄嗎?" }, "nodes": { "actions": { @@ -3555,6 +3555,7 @@ "containerLogs": "容器日誌", "description": "通過提供連線詳情和並行設定來註冊現有的Fusion節點。", "discoverBeforeAdding": "在新增此節點之前探索遠端專案。", + "discoveredCount_one": "", "discoveredCount_other": "", "discovering": "正在探索...", "discoverRemoteProjects": "探索遠端專案", @@ -3694,6 +3695,7 @@ "refreshing": "重新整理中…", "refreshStatus": "重新整理狀態", "registered": "節點「{{name}}」已註冊", + "registeredCount_one": "", "registeredCount_other": "", "registerFailed": "無法註冊節點", "remote": "遠端", @@ -3746,9 +3748,7 @@ "portRange": "埠必須在1到65535之間" }, "viewLogsButton": "查看日誌", - "yes": "是", - "discoveredCount_one": "", - "registeredCount_one": "" + "yes": "是" }, "nodeStatus": { "local": "本機" @@ -4007,10 +4007,14 @@ "questionsLabel": "問題數量", "reconnecting": "重新連線中…", "refineFurther": "進一步精煉", + "relativeTimeDays_one": "", "relativeTimeDays_other": "", + "relativeTimeHours_one": "", "relativeTimeHours_other": "", "relativeTimeJustNow": "剛剛", + "relativeTimeMinutes_one": "", "relativeTimeMinutes_other": "", + "relativeTimeWeeks_one": "", "relativeTimeWeeks_other": "", "remove": "移除", "retryFailed": "重試失敗,請再試一次。", @@ -4050,11 +4054,7 @@ "untitledSession": "未命名工作階段", "usingDefault": "使用預設", "whatToBuild": "您想建構什麼?", - "whatToBuildPlaceholder": "例如,建構一個包含登入、註冊和密碼重設的使用者驗證系統...", - "relativeTimeDays_one": "", - "relativeTimeHours_one": "", - "relativeTimeMinutes_one": "", - "relativeTimeWeeks_one": "" + "whatToBuildPlaceholder": "例如,建構一個包含登入、註冊和密碼重設的使用者驗證系統..." }, "plugins": { "addItem": "新增項目", @@ -4089,6 +4089,7 @@ "enablePlugin": "啟用 {{name}}", "enablePluginFailed": "啟用插件失敗:{{error}}", "experimental": "實驗性", + "findings_one": "", "findings_other": "", "homepage": "首頁:", "install": "安裝", @@ -4145,8 +4146,7 @@ "uninstallTitle": "全域解除安裝插件", "unknownError": "未知錯誤", "updateFailed": "更新插件失敗:{{error}}", - "version": "版本:", - "findings_one": "" + "version": "版本:" }, "pr": { "authFail": "執行 gh auth login 並重試。", @@ -4193,11 +4193,15 @@ "confirm": "確認", "confirmRemove": "確認移除", "confirmRemoveProject": "確認移除專案", + "daysAgo_one": "", "daysAgo_other": "", + "hoursAgo_one": "", "hoursAgo_other": "", "justNow": "剛才", "lastActivity": "最後活動:", + "minutesAgo_one": "", "minutesAgo_other": "", + "moreItems_one": "", "moreItems_other": "", "never": "從未", "nodeAvailability": "專案節點可用性", @@ -4208,11 +4212,7 @@ "pauseProject": "暫停專案", "removeProject": "移除專案", "resume": "恢復", - "resumeProject": "恢復專案", - "daysAgo_one": "", - "hoursAgo_one": "", - "minutesAgo_one": "", - "moreItems_one": "" + "resumeProject": "恢復專案" }, "projectDetection": { "editName": "編輯名稱", @@ -4221,12 +4221,12 @@ "noDbWarning": "未找到 fn 資料庫 - 將初始化", "registerAll": "全部註冊", "registering": "註冊中...", - "registerSelected_other": "", - "selectAll_other": "", - "selectedCount_other": "", "registerSelected_one": "", + "registerSelected_other": "", "selectAll_one": "", - "selectedCount_one": "" + "selectAll_other": "", + "selectedCount_one": "", + "selectedCount_other": "" }, "projects": { "actions": { @@ -4284,10 +4284,10 @@ "detecting": "偵測中…", "detectModels": "偵測模型", "detectModelsTitle": "呼叫提供者的/models端點來探索可用模型", + "removeModel_one": "", "removeModel_other": "", "save": "儲存提供者", - "saving": "儲存中...", - "removeModel_one": "" + "saving": "儲存中..." }, "addCustom": "添加自訂提供者", "apiKeyLabel": "API 密鑰", @@ -4386,10 +4386,10 @@ "p95": "P95", "p95Raw": "P95 原始: {{value}} ms", "reason": "原因: {{reason}}", - "sampleCount_other": "", - "samples_other": "", "sampleCount_one": "", - "samples_one": "" + "sampleCount_other": "", + "samples_one": "", + "samples_other": "" }, "failureRate": "失敗率: {{rate}}", "heading": "可靠性", @@ -4398,14 +4398,14 @@ "insufficientData": "資料不足 — {{reason}}", "mergeAttempts": { "heading": "合併嘗試", + "histogramTotal_one": "", "histogramTotal_other": "", "max": "最大值", "mean": "平均值", "moreStats": "更多統計", "reason": "原因: {{reason}}", - "tasksCounted_other": "", - "histogramTotal_one": "", - "tasksCounted_one": "" + "tasksCounted_one": "", + "tasksCounted_other": "" }, "reason": "原因: {{reason}}", "resetBaseline": "重設基線: {{date}}", @@ -4486,6 +4486,7 @@ "viewLabel": "研究檢視" }, "routine": { + "andMore_one": "", "andMore_other": "", "delete": "刪除", "deleteMessage": "刪除例程 {{name}}?此操作無法復原。", @@ -4499,14 +4500,13 @@ "enableName": "啟用 {{name}}", "resultFailed": "失敗", "resultSuccess": "成功", + "runHistory_one": "", "runHistory_other": "", "runNameNow": "立即執行 {{name}}", "running": "執行中…", "runNow": "立即執行", - "stepCount_other": "", - "andMore_one": "", - "runHistory_one": "", - "stepCount_one": "" + "stepCount_one": "", + "stepCount_other": "" }, "routing": { "cannotChangeWhileActive": "工作為作用中時無法更改節點覆寫。", @@ -4555,10 +4555,12 @@ "advancedMode": "多步驟", "advancedModeHelp": "依序執行多個步驟(命令和 AI 提示)", "aiPromptType": "AI 提示詞", + "andMore_one": "", "andMore_other": "", "apiEndpointHint": "觸發此例行程序的 API 端點路徑", "apiEndpointLabel": "API 端點", "apiEndpointPlaceholder": "/api/routine/my-routine", + "automationCount_one": "", "automationCount_other": "", "cancelButton": "取消", "catchUpPolicyHint": "當計劃執行被錯過時的處理方式", @@ -4698,6 +4700,7 @@ "routineSuccess": "{{name}} 已成功完成", "routineUpdated": "例行程序已更新", "runError": "執行例行程序失敗", + "runHistory_one": "", "runHistory_other": "", "runNameNow": "立即執行 {{name}}", "running": "執行中…", @@ -4718,6 +4721,7 @@ "simpleMode": "簡單", "simpleModeHelp": "執行單一 shell 命令或 AI 提示", "stepCommandRequired": "步驟 {{index}}:命令為必填項", + "stepCount_one": "", "stepCount_other": "", "stepName": "步驟名稱", "stepNamePlaceholder": "例如:執行測試", @@ -4778,11 +4782,7 @@ "webhookPathPlaceholder": "/trigger/my-routine", "webhookSecretHint": "用於簽章驗證的 HMAC 密鑰。無需驗證的 webhook 請留空。", "webhookSecretLabel": "Webhook 密鑰(可選)", - "webhookSecretPlaceholder": "可選——無需驗證的 webhook 請留空", - "andMore_one": "", - "automationCount_one": "", - "runHistory_one": "", - "stepCount_one": "" + "webhookSecretPlaceholder": "可選——無需驗證的 webhook 請留空" }, "scriptsModal": { "addScript": "新增指令碼", @@ -4807,6 +4807,7 @@ "saving": "正在保存...", "scriptAlreadyExists": "已經存在同名指令碼", "scriptCommandRequired": "需要指令碼命令", + "scriptCount_one": "", "scriptCount_other": "", "scriptCreated": "指令碼已建立", "scriptDeleted": "指令碼已刪除", @@ -4814,8 +4815,7 @@ "scriptNamePlaceholder": "例如,build、test、lint", "scriptNameRequired": "需要指令碼名稱", "scriptUpdated": "指令碼已更新", - "title": "指令碼", - "scriptCount_one": "" + "title": "指令碼" }, "secrets": { "accessPolicyAuto": "自動", @@ -4880,17 +4880,17 @@ "failed": "失敗", "headerAwaitingAndErrorPlural": "{{awaitingCount}} 個 AI 工作階段需要您的輸入,{{errorCount}} 個失敗", "headerAwaitingAndErrorSingular": "{{awaitingCount}} 個 AI 工作階段需要您的輸入,{{errorCount}} 個失敗", + "headerAwaitingPlural_one": "", "headerAwaitingPlural_other": "", + "headerAwaitingSingular_one": "", "headerAwaitingSingular_other": "", + "headerErrorPlural_one": "", "headerErrorPlural_other": "", + "headerErrorSingular_one": "", "headerErrorSingular_other": "", "regionLabel": "需要輸入或已失敗的 AI 工作階段", "resume": "繼續", - "retry": "重試", - "headerAwaitingPlural_one": "", - "headerAwaitingSingular_one": "", - "headerErrorPlural_one": "", - "headerErrorSingular_one": "" + "retry": "重試" }, "settings": { "actions": { @@ -5253,7 +5253,9 @@ "projectSelected": "已選擇專案——任務建立和匯入功能已可用。", "projectSetupDescription": "在建立或匯入任務之前,請選擇您的第一個專案。您可以註冊現有的本機目錄,或透過設定精靈複製 GitHub 儲存庫 URL。", "providersConnectedSummary": "✓ {{total}} 個提供商中已連接 {{connected}} 個", + "providersSkippedSummary_one_one": "", "providersSkippedSummary_one_other": "", + "providersSkippedSummary_other_one": "", "providersSkippedSummary_other_other": "", "quickStartProviders": "快速啟動提供商", "readinessAiProviderConnected": "{{name}} 已連接——AI 代理可以處理任務", @@ -5360,9 +5362,7 @@ "withoutGitHub1": "手動建立任務", "withoutGitHub2": "為 AI 代理描述工作", "withoutGitHub3": "在看板上追蹤進度", - "withoutGitHubHeading": "不使用 GitHub(現在可用):", - "providersSkippedSummary_one_one": "", - "providersSkippedSummary_other_one": "" + "withoutGitHubHeading": "不使用 GitHub(現在可用):" }, "shell": { "activePill": "作用中", @@ -5396,6 +5396,7 @@ "disabled": "技能已停用", "disableSkill": "停用 {{name}}", "discovered": "已發現", + "discoveredCount_one": "", "discoveredCount_other": "", "discoveredSection": "已發現的技能", "enabled": "技能已啟用", @@ -5427,8 +5428,7 @@ "title": "技能", "toggleError": "切換技能失敗", "toggleFailed": "切換技能失敗: {{message}}", - "viewDetails": "查看 {{name}} 的詳情", - "discoveredCount_one": "" + "viewDetails": "查看 {{name}} 的詳情" }, "specEditor": { "edit": "編輯", @@ -5459,17 +5459,17 @@ "dropTitle": "刪除孤立的隱藏?", "failedToLoadDiff": "載入差異失敗", "failedToLoadOrphans": "載入孤立記錄失敗", + "fileCount_one": "", "fileCount_other": "", "inspectDiff": "檢查差異", "loadingDiff": "正在加載差異…", "noDiffOutput": "沒有可用的差異輸出。", "noOrphans": "未發現孤立的合併自動隱藏。", + "orphanCount_one": "", "orphanCount_other": "", "shaLabel": "SHA", "title": "貯存恢復", - "unknownSource": "未知來源", - "fileCount_one": "", - "orphanCount_one": "" + "unknownSource": "未知來源" }, "stepType": { "aiPrompt": "AI 提示", @@ -5539,6 +5539,7 @@ "untitled": "無標題" }, "syncLog": { + "entryCount_one": "", "entryCount_other": "", "filterAll": "全部", "filterAllNodes": "全部節點", @@ -5550,8 +5551,7 @@ "noHistory": "沒有同步歷史可用", "resultConflict": "衝突", "resultError": "錯誤", - "resultSuccess": "成功", - "entryCount_one": "" + "resultSuccess": "成功" }, "systemStats": { "agentActive": "活躍", @@ -5572,6 +5572,7 @@ "errorLoadVitestSettings": "載入 vitest 設定失敗", "errorSaveVitestSettings": "儲存 vitest 設定失敗", "footerRefreshFailed": "最新重新整理失敗:{{error}}", + "killedProcesses_one": "", "killedProcesses_other": "", "killThresholdInputAriaLabel": "終止閾值 (%)", "killThresholdLabel": "終止閾值 (%)", @@ -5615,8 +5616,7 @@ "title": "系統統計", "updatedAt": "已更新 {{time}}", "vitestProcesses": "Vitest 程序", - "waitingFirstUpdate": "等待首次更新", - "killedProcesses_one": "" + "waitingFirstUpdate": "等待首次更新" }, "taskChanges": { "attributionFailed": "已落地檔案集可能包含外來提交(歸因不可用)。", @@ -5625,6 +5625,7 @@ "error": "載入變更出錯: {{error}}", "expandDiff": "擴展為全螢幕差異視圖", "expandDiffView": "擴展差異視圖", + "filesChangedHeading_one": "", "filesChangedHeading_other": "", "loadError": "載入任務變更失敗", "loading": "正在載入變更...", @@ -5640,8 +5641,7 @@ "previousFile": "上一個檔案", "summaryHint": "最終提交摘要: {{files}} 個檔案{{plural}}已變更, +{{additions}} 次新增, -{{deletions}} 次刪除。僅計算已記錄的合併/壓縮提交,不計算完整的工作血統。", "toggleWordWrap": "切換自動換行", - "unavailable": "詳細文件變更無法使用。", - "filesChangedHeading_one": "" + "unavailable": "詳細文件變更無法使用。" }, "taskDetail": { "actions": { @@ -5693,11 +5693,11 @@ "reattachBtn": "重新綁定分支", "reattached": "已為 {{id}} 重新綁定分支 ({{branch}})", "reattachedResult": "已重新綁定 {{branch}}(領先 {{base}} {{count}} 次提交)。", + "reattachedResult_one": "", "reattachedResult_other": "", "reattaching": "正在重新綁定…", "skipped": "{{id}} 的分支重新綁定已跳過:{{reason}}", - "skippedResult": "重新綁定已跳過:{{reason}}", - "reattachedResult_one": "" + "skippedResult": "重新綁定已跳過:{{reason}}" }, "cacheBreakdown": "(讀取 {{read}} / 寫入 {{write}} / 輸入 {{input}})", "cacheHitRatio": "快取命中率:", @@ -5838,8 +5838,8 @@ "activityHeading": "活動", "agentLog": "代理日誌", "noActivity": "(無活動)", - "truncated_other": "", - "truncated_one": "" + "truncated_one": "", + "truncated_other": "" }, "longestTimingEvent": "最長計時事件", "longestWorkflowStep": "最長工作流程步驟", @@ -5930,8 +5930,8 @@ "progress": { "heading": "進度", "noSteps": "(未定義步驟)", - "stepCount_other": "", - "stepCount_one": "" + "stepCount_one": "", + "stepCount_other": "" }, "provenance": { "createdBy": "創建者:", @@ -5940,6 +5940,7 @@ "recoveryState": "恢復狀態", "refine": { "btn": "精化", + "charCount_one": "", "charCount_other": "", "createBtn": "建立精化任務", "creating": "正在建立...", @@ -5948,8 +5949,7 @@ "help": "描述需要精化或改善的內容...", "modalTitle": "精化", "placeholder": "在此輸入您的反饋...", - "taskCreated": "精化任務已建立:{{id}}", - "charCount_one": "" + "taskCreated": "精化任務已建立:{{id}}" }, "reset": { "btn": "重置", @@ -6112,6 +6112,12 @@ "switchToPlainText": "切換為純文字", "yes": "是" }, + "taskFields": { + "moreFields": "其他欄位", + "orphaned": "孤立欄位", + "saveFailed": "儲存欄位失敗", + "unset": "—" + }, "taskForm": { "addDependencies": "新增相依項", "attachHint": "您也可以貼上圖片或拖放", @@ -6139,6 +6145,7 @@ "branchStrategyLabel": "分支策略", "collapseDescription": "收合描述", "dependenciesLabel": "相依關係", + "dependenciesSelected_one": "", "dependenciesSelected_other": "", "descriptionLabel": "描述", "descriptionPlaceholder": "需要完成什麼?", @@ -6212,8 +6219,7 @@ "usingPreset": "使用預設:{{name}}", "workflowStepsDescription": "選擇任務實作完成後要執行的步驟", "workflowStepsLabel": "工作流程步驟", - "workingBranchLabel": "工作分支", - "dependenciesSelected_one": "" + "workingBranchLabel": "工作分支" }, "taskHandlers": { "githubImported": "從 GitHub 導入了 {{id}}" @@ -6236,6 +6242,7 @@ "noReviewItems": "尚無評審項目。", "perTaskAutoMerge": "按工作自動合併", "plain": "純文字", + "prSummaryLine_one": "", "prSummaryLine_other": "", "queueing": "加入隊列中…", "refresh": "重新整理", @@ -6245,6 +6252,7 @@ "refreshing": "重新整理中…", "refreshStatusLine": "{{status}} · 最後重新整理:{{timestamp}} · {{source}}", "requestRevision": "請求修訂", + "reviewerSummaryLine_one": "", "reviewerSummaryLine_other": "", "revisionQueueFailed": "無法將修訂加入隊列", "revisionStarted": "從選定的評審回饋開始了同工作人工智慧修訂", @@ -6253,9 +6261,7 @@ "showRawText": "顯示原始文字", "startedAtSep": " · 已開始:{{timestamp}}", "updateFailed": "更新 {{taskId}} 失敗:{{error}}", - "upToDate": "最新", - "prSummaryLine_one": "", - "reviewerSummaryLine_one": "" + "upToDate": "最新" }, "tasks": { "addTaskPlaceholder": "新增任務……", @@ -6269,6 +6275,7 @@ "archiveTask": "封存任務", "assignedTo": "已指派給 {{name}}", "attach": "附件", + "attachCount_one": "", "attachCount_other": "", "attachedFile": "已將 {{fileName}} 附加至 {{taskId}}", "attachFileFailed": "附加 {{fileName}} 失敗:{{error}}", @@ -6306,6 +6313,7 @@ "deleteTitle": "刪除任務", "dependencyConflict": "{{taskId}} 是 {{dependentList}} 的相依項目。\n\n仍要先移除這些相依參照並刪除嗎?", "deps": "依賴", + "depsCount_one": "", "depsCount_other": "", "descriptionPlaceholder": "任務描述", "descriptionRefined": "已用 AI 優化說明", @@ -6326,10 +6334,13 @@ "fanoutEscalated": "升級的重疊", "fanoutEscalationSuffix": " · 在阻擋欄中 {{minutes}} 分鐘後升級", "fanoutHighFanoutSuffix": "(重疊瓶頸閾值:{{threshold}})", + "fanoutStale_one": "", "fanoutStale_other": "", + "fanoutTooltip_one": "", "fanoutTooltip_other": "", "fast": "快速", "fastMode": "快速模式", + "filesChanged_one": "", "filesChanged_other": "", "forceDeleteTitle": "強制刪除任務", "githubTrackingDefaultOff": "關", @@ -6365,6 +6376,7 @@ "modelPlan": "規劃", "modelReviewer": "審閱者", "models": "模型", + "modelsCount_one": "", "modelsCount_other": "", "moreOptions": "更多選項", "move": "移動", @@ -6403,6 +6415,7 @@ "resetProgress": "重設進度", "resetProgressMessage": "移動此任務前重設所有步驟進度?", "resetProgressTitle": "重設進度?", + "retriesAriaLabel_one": "", "retriesAriaLabel_other": "", "retry": "重試", "retryFailed": "重試 {{taskId}} 失敗:{{error}}", @@ -6419,6 +6432,7 @@ "showSteps": "顯示步驟", "stalled": "停滯", "statusMergingFix": "正在合併修正…", + "stepCount_one": "", "stepCount_other": "", "stuck": "卡住", "subtask": "子任務", @@ -6434,15 +6448,7 @@ "usingDefault": "使用預設", "viewDependency": "點擊查看 {{depId}}", "workflow": "工作流程", - "workflowCheck": "工作流程檢查", - "attachCount_one": "", - "depsCount_one": "", - "fanoutStale_one": "", - "fanoutTooltip_one": "", - "filesChanged_one": "", - "modelsCount_one": "", - "retriesAriaLabel_one": "", - "stepCount_one": "" + "workflowCheck": "工作流程檢查" }, "terminal": { "clear": "清空", @@ -6560,14 +6566,14 @@ "resetsInDaysHours": "在 {{days}} 天 {{hours}} 小時後重置", "resetsInHours": "在 {{hours}} 小時後重置", "resetsInMinutes": "在 {{mins}} 分鐘後重置", + "showHidden_one": "", "showHidden_other": "", "statusError": "錯誤", "statusNotConfigured": "未設定", "title": "使用情況", "viewModeLabel": "使用情況檢視模式", "viewModeRemaining": "剩餘", - "viewModeUsed": "已使用", - "showHidden_one": "" + "viewModeUsed": "已使用" }, "workflow": { "add": "新增", @@ -6668,6 +6674,7 @@ "selectStepsDescription": "選擇任務實作完成後要執行的步驟", "showOutput": "顯示輸出", "started": "開始於:", + "stepCount_one": "", "stepCount_other": "", "stepCreated": "工作流程步驟已建立", "stepDefinitionNotFound": "找不到步驟定義。", @@ -6675,28 +6682,27 @@ "steps": "工作流程步驟", "stepsExplanation": "合併前步驟在實作後、合併前執行。合併後步驟在合併成功後執行。", "stepUpdated": "工作流程步驟已更新", + "summaryAdvisory_one": "", "summaryAdvisory_other": "", + "summaryFailed_one": "", "summaryFailed_other": "", + "summaryPassed_one": "", "summaryPassed_other": "", + "summaryRunning_one": "", "summaryRunning_other": "", "summarySeparator": " · ", + "summarySkipped_one": "", "summarySkipped_other": "", + "summaryStepCount_one": "", "summaryStepCount_other": "", "switchToMarkdown": "切換為 Markdown", "switchToPlain": "切換為純文字", + "tabMySteps_one": "", "tabMySteps_other": "", + "tabTemplates_one": "", "tabTemplates_other": "", "templateAdded": "已新增工作流程步驟「{{name}}」", - "useDefault": "使用預設", - "stepCount_one": "", - "summaryAdvisory_one": "", - "summaryFailed_one": "", - "summaryPassed_one": "", - "summaryRunning_one": "", - "summarySkipped_one": "", - "summaryStepCount_one": "", - "tabMySteps_one": "", - "tabTemplates_one": "" + "useDefault": "使用預設" }, "workflowColumns": { "add": "", @@ -6712,14 +6718,50 @@ "title": "", "traits": "", "traitsLoadFailed": "", - "unplacedCount_other": "", - "unplacedCount_one": "" + "unplacedCount_one": "", + "unplacedCount_other": "" + }, + "workflowFields": { + "add": "新增欄位", + "addOption": "新增選項", + "badge": "顯示為徽章", + "default": "預設", + "defaultLabel": "預設值", + "defaultTrue": "預設開啟", + "duplicateId": "已存在使用該 id 的欄位", + "editId": "編輯 id", + "empty": "尚無自訂欄位。新增欄位以擴充工作表單與卡片。", + "idLabel": "欄位 id", + "idWarn": "變更 id 會捨棄以舊 id 儲存的值(移除 + 新增)。", + "nameLabel": "欄位名稱", + "newFieldName": "新欄位", + "newOptionLabel": "選項 1", + "noDefault": "— 無 —", + "optionColor": "選項顏色", + "optionLabel": "選項標籤", + "optionN": "選項 {{n}}", + "options": "選項", + "optionValue": "選項值", + "placement": "放置位置", + "placementCard": "卡片徽章", + "placementDetail": "詳細資料(內嵌)", + "placementSection": "詳細資料區段", + "readOnlyHint": "內建工作流程為唯讀 — 複製以進行編輯", + "remove": "移除欄位", + "removeOption": "移除選項", + "required": "必填", + "title": "欄位", + "typeLabel": "類型", + "widget": "控制項", + "widgetDefault": "預設" }, "workflowNodes": { "advisory": "", "codeNote": "在沙箱中執行 TypeScript。語法會在儲存時驗證。", "codeSource": "原始碼(TypeScript)", "codeTimeout": "逾時(毫秒)", + "cycleBlocked": "", + "edgeCondition": "", "edgeConditionLabel": "條件:{{condition}}", "edgeInspector": "連線", "edgeNoVerdict": "— 成功(無裁定)—", @@ -6741,6 +6783,7 @@ "foreachWorktree": "每步驟工作樹", "gateBlocks": "關卡(阻擋)", "gateMode": "關卡模式", + "interpreterOnly": "", "joinAll": "所有分支", "joinAny": "任一分支", "joinMode": "合併模式", @@ -6761,14 +6804,7 @@ "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "分支從此節點並行執行。分支內不允許執行與合併接縫。", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "", - "summaryCodeDefault": "", - "summaryGateAdvisory": "", - "summaryGateBlocks": "", - "summaryHoldRelease": "", - "summaryNotConfigured": "", - "summaryReviewType": "" + "stepExecuteLabel": "Step execute" }, "workflows": { "duplicateToCustomize": "", @@ -6799,45 +6835,5 @@ "installRequestTitle": "Worktrunk 安裝請求", "sha256": "SHA-256", "version": "版本" - }, - "taskFields": { - "unset": "—", - "moreFields": "其他欄位", - "orphaned": "孤立欄位", - "saveFailed": "儲存欄位失敗" - }, - "workflowFields": { - "add": "新增欄位", - "addOption": "新增選項", - "badge": "顯示為徽章", - "default": "預設", - "defaultLabel": "預設值", - "defaultTrue": "預設開啟", - "duplicateId": "已存在使用該 id 的欄位", - "editId": "編輯 id", - "empty": "尚無自訂欄位。新增欄位以擴充工作表單與卡片。", - "idLabel": "欄位 id", - "idWarn": "變更 id 會捨棄以舊 id 儲存的值(移除 + 新增)。", - "nameLabel": "欄位名稱", - "newFieldName": "新欄位", - "newOptionLabel": "選項 1", - "noDefault": "— 無 —", - "optionColor": "選項顏色", - "optionLabel": "選項標籤", - "optionN": "選項 {{n}}", - "optionValue": "選項值", - "options": "選項", - "placement": "放置位置", - "placementCard": "卡片徽章", - "placementDetail": "詳細資料(內嵌)", - "placementSection": "詳細資料區段", - "readOnlyHint": "內建工作流程為唯讀 — 複製以進行編輯", - "remove": "移除欄位", - "removeOption": "移除選項", - "required": "必填", - "title": "欄位", - "typeLabel": "類型", - "widget": "控制項", - "widgetDefault": "預設" } } diff --git a/packages/i18n/locales/zh-TW/cli.json b/packages/i18n/locales/zh-TW/cli.json index 4c68317b36..dcf4eee88f 100644 --- a/packages/i18n/locales/zh-TW/cli.json +++ b/packages/i18n/locales/zh-TW/cli.json @@ -21,6 +21,7 @@ "agentRunLogsBackHint": "[Esc/q] 返回執行列表", "agentRunLogsTitle": "執行日誌({{index}})", "agentsFooterHints": "[s] 啟動 [x] 停止 [D] 刪除 [r] 重新整理 [Tab] 焦點 ↑↓ 選擇", + "agentsListTitle_one": "", "agentsListTitle_other": "", "agentsNoAgents": "找不到代理。", "agentStarted": "代理已啟動", @@ -44,6 +45,7 @@ "filesEmpty": "(空)", "filesEmptyFile": "(空檔案)", "filesFooterHints": "[Tab] 切換面板 [↑↓/jk] 移動 [Enter] 開啟 [←/→] 折疊/展開 [.] 隱藏檔案 [w] 換行 [p] 專案 [r] 重新載入", + "filesMoreLines_one": "", "filesMoreLines_other": "", "filesSelectProject": "選擇專案", "filesSelectToPreview": "選擇檔案以預覽", @@ -151,6 +153,7 @@ "settingsFooterHints": "[Tab] 切換面板 ↑↓ 選擇設定 [Space] 切換布林 [+/-] 調整數值 [←/→] 循環枚舉 [C/V/X/P/L/U/K/R] 遠端操作", "settingsInteractivePanelTitle": "設定", "settingsLoadingSettings": "正在載入設定…", + "settingsMoreModels_one": "", "settingsMoreModels_other": "", "settingsPanelTitle": "設定", "settingsPersistentTokenRegenerated": "持久金鑰已重新產生", @@ -218,9 +221,6 @@ "utilitiesKillVitest": "終止 Vitest 行程", "utilitiesPanelTitle": "工具", "utilitiesRefreshStats": "重新整理統計", - "utilitiesToggleEnginePause": "切換引擎暫停", - "agentsListTitle_one": "", - "filesMoreLines_one": "", - "settingsMoreModels_one": "" + "utilitiesToggleEnginePause": "切換引擎暫停" } } diff --git a/packages/i18n/locales/zh-TW/common.json b/packages/i18n/locales/zh-TW/common.json index 3d99717b89..f9fb7e049a 100644 --- a/packages/i18n/locales/zh-TW/common.json +++ b/packages/i18n/locales/zh-TW/common.json @@ -1,9 +1,4 @@ { - "actions": { - "cancel": "取消", - "close": "關閉", - "save": "儲存" - }, "agents": { "ratings": { "trendDeclining": "", @@ -34,7 +29,6 @@ "minutesAgo_other": "" } }, - "archive": "封存", "board": { "rejection": { "capacityExhausted": "", @@ -44,7 +38,6 @@ "workflowMismatch": "" } }, - "cancel": "取消", "chat": { "failedToGetResponse": "", "failureReferenceId": "", @@ -54,25 +47,15 @@ "openMailboxMessage": "", "toolCallArgsPrefix": "", "toolCallResultPrefix": "", + "toolCallsCount_one": "", + "toolCallsCount_other": "", + "toolCallsHeader": "", "toolCallStatusCompleted": "", "toolCallStatusError": "", "toolCallStatusErrors": "", "toolCallStatusRunning": "", - "toolCallsCount_one": "", - "toolCallsCount_other": "", - "toolCallsHeader": "", "viewFailureDetails": "" }, - "close": "關閉", - "columns": { - "archived": "已封存", - "done": "已完成", - "in-progress": "進行中", - "in-review": "審查中", - "todo": "待辦", - "triage": "規劃" - }, - "delete": "刪除", "health": { "anomaly": { "duplicateActiveId": "", @@ -110,13 +93,6 @@ "modelSetToDefault": "" } }, - "nodeStatus": { - "connecting": "", - "error": "", - "offline": "", - "online": "", - "unknown": "" - }, "nodes": { "auth": { "differ": "", @@ -137,7 +113,13 @@ "stopped": "" } }, - "refresh": "重新整理", + "nodeStatus": { + "connecting": "", + "error": "", + "offline": "", + "online": "", + "unknown": "" + }, "research": { "providerGitHub": "", "providerLlmSynthesis": "", @@ -145,7 +127,6 @@ "providerPageFetch": "", "providerWebSearch": "" }, - "retry": "重試", "routing": { "policyLabel": { "block": "", @@ -205,7 +186,6 @@ "zai": "" } }, - "skip": "略過", "taskForm": { "nodeStatusConnecting": "", "nodeStatusError": "", @@ -220,7 +200,6 @@ "refreshSourceInitialLoad": "", "refreshSourceManual": "" }, - "tryAgain": "重試", "workflow": { "postMerge": "", "preMerge": "", @@ -230,5 +209,14 @@ "statusRunning": "", "statusSkipped": "", "waitingForOutput": "" + }, + "workflowNodes": { + "summaryAwaitInput": "", + "summaryCodeDefault": "", + "summaryGateAdvisory": "", + "summaryGateBlocks": "", + "summaryHoldRelease": "", + "summaryNotConfigured": "", + "summaryReviewType": "" } } diff --git a/packages/i18n/src/resources.d.ts b/packages/i18n/src/resources.d.ts index bfd0013167..651ef0dbb2 100644 --- a/packages/i18n/src/resources.d.ts +++ b/packages/i18n/src/resources.d.ts @@ -6762,6 +6762,8 @@ export default interface Resources { "codeNote": "Runs sandboxed TypeScript. Syntax is validated at save.", "codeSource": "Source (TypeScript)", "codeTimeout": "Timeout (ms)", + "cycleBlocked": "That connection would create a cycle — only rework edges inside a for-each template may loop back", + "edgeCondition": "Condition", "edgeConditionLabel": "Condition: {{condition}}", "edgeInspector": "Edge", "edgeNoVerdict": "— success (no verdict) —", @@ -6783,6 +6785,7 @@ export default interface Resources { "foreachWorktree": "Per-step worktree", "gateBlocks": "Gate (blocks)", "gateMode": "Gate mode", + "interpreterOnly": "This workflow branches, so it runs on the graph interpreter — it can't compile to the linear step engine, but it will still run.", "joinAll": "All branches", "joinAny": "Any branch", "joinMode": "Join mode", @@ -6803,14 +6806,7 @@ export default interface Resources { "reviewPlan": "Plan review", "reviewType": "Review type", "splitNote": "Branches run concurrently from this node. Execute and merge seams are not allowed inside a branch.", - "stepExecuteLabel": "Step execute", - "summaryAwaitInput": "Waits for user input", - "summaryCodeDefault": "TypeScript", - "summaryGateAdvisory": "Advisory", - "summaryGateBlocks": "Gate (blocks)", - "summaryHoldRelease": "Release: {{release}}", - "summaryNotConfigured": "Not configured", - "summaryReviewType": "{{type}} review" + "stepExecuteLabel": "Step execute" }, "workflowSelector": { "switchActiveMessage": "This task has an active session. Switching workflows aborts it and re-homes the card into the new workflow's entry column. Continue?", @@ -7070,11 +7066,6 @@ export default interface Resources { } }, "common": { - "actions": { - "cancel": "Cancel", - "close": "Close", - "save": "Save" - }, "agents": { "ratings": { "trendDeclining": "↓ Declining", @@ -7105,7 +7096,6 @@ export default interface Resources { "minutesAgo_other": "{{count}}m ago" } }, - "archive": "Archive", "board": { "rejection": { "capacityExhausted": "That column is at capacity. Try again when a slot frees up.", @@ -7115,7 +7105,6 @@ export default interface Resources { "workflowMismatch": "Drag can't move a card between workflows. Use the workflow switcher instead." } }, - "cancel": "Cancel", "chat": { "failedToGetResponse": "Failed to get response", "failureReferenceId": "ID", @@ -7134,16 +7123,6 @@ export default interface Resources { "toolCallsHeader": "Tool calls", "viewFailureDetails": "View failure details" }, - "close": "Close", - "columns": { - "archived": "Archived", - "done": "Done", - "in-progress": "In Progress", - "in-review": "In Review", - "todo": "Todo", - "triage": "Planning" - }, - "delete": "Delete", "health": { "anomaly": { "duplicateActiveId": "Duplicate active task ID", @@ -7208,7 +7187,6 @@ export default interface Resources { "stopped": "Stopped" } }, - "refresh": "Refresh", "research": { "providerGitHub": "GitHub", "providerLlmSynthesis": "LLM Synthesis", @@ -7216,7 +7194,6 @@ export default interface Resources { "providerPageFetch": "Page Fetch", "providerWebSearch": "Web Search" }, - "retry": "Retry", "routing": { "policyLabel": { "block": "Block execution", @@ -7276,7 +7253,6 @@ export default interface Resources { "zai": "GLM models by Zhipu AI — strong multilingual support" } }, - "skip": "Skip", "taskForm": { "nodeStatusConnecting": "Connecting", "nodeStatusError": "Error", @@ -7291,7 +7267,6 @@ export default interface Resources { "refreshSourceInitialLoad": "Initial load", "refreshSourceManual": "Manual" }, - "tryAgain": "Try Again", "workflow": { "postMerge": "Post-merge", "preMerge": "Pre-merge", @@ -7301,6 +7276,15 @@ export default interface Resources { "statusRunning": "Running…", "statusSkipped": "Skipped", "waitingForOutput": "Waiting for agent output…" + }, + "workflowNodes": { + "summaryAwaitInput": "Waits for user input", + "summaryCodeDefault": "TypeScript", + "summaryGateAdvisory": "Advisory", + "summaryGateBlocks": "Gate (blocks)", + "summaryHoldRelease": "Release: {{release}}", + "summaryNotConfigured": "Not configured", + "summaryReviewType": "{{type}} review" } }, "errors": { From f67a2542b9009ac892b23d142d569e1f1f878874 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 4 Jun 2026 19:45:44 -0700 Subject: [PATCH 006/112] feat(dashboard): node/edge deletion with safe cascade semantics --- .../app/components/WorkflowNodeEditor.css | 6 + .../app/components/WorkflowNodeEditor.tsx | 91 ++++++++++- .../__tests__/WorkflowNodeEditor.test.tsx | 36 +++++ .../__tests__/workflow-flow-mapping.test.ts | 150 ++++++++++++++++++ .../app/components/workflow-flow-mapping.ts | 69 ++++++++ packages/i18n/locales/en/app.json | 2 + packages/i18n/locales/es/app.json | 2 + packages/i18n/locales/fr/app.json | 2 + packages/i18n/locales/ko/app.json | 2 + packages/i18n/locales/zh-CN/app.json | 2 + packages/i18n/locales/zh-TW/app.json | 2 + packages/i18n/src/resources.d.ts | 2 + 12 files changed, 365 insertions(+), 1 deletion(-) diff --git a/packages/dashboard/app/components/WorkflowNodeEditor.css b/packages/dashboard/app/components/WorkflowNodeEditor.css index 08612bedac..2fb92fe56c 100644 --- a/packages/dashboard/app/components/WorkflowNodeEditor.css +++ b/packages/dashboard/app/components/WorkflowNodeEditor.css @@ -194,6 +194,12 @@ color: var(--ws-error); } +/* Inspector delete buttons (U3): sit below the field group, sized to the panel. */ +.wf-inspector-delete { + margin-top: var(--space-sm); + justify-content: center; +} + .wf-editor-banner { padding: var(--space-sm) var(--space-md); background: var(--bg-secondary); diff --git a/packages/dashboard/app/components/WorkflowNodeEditor.tsx b/packages/dashboard/app/components/WorkflowNodeEditor.tsx index 2460ce241c..327d036aa3 100644 --- a/packages/dashboard/app/components/WorkflowNodeEditor.tsx +++ b/packages/dashboard/app/components/WorkflowNodeEditor.tsx @@ -53,6 +53,7 @@ import { edgeClassName, edgeConditionEditability, buildConnectionEdge, + cascadeDelete, WF_EDGE_INTERACTION_WIDTH, FOREACH_GROUP_WIDTH, FOREACH_GROUP_HEIGHT, @@ -152,6 +153,9 @@ function InnerEditor({ // built-in pair so the select is never empty; replaced by the live catalog // (built-ins + plugin parsers) once GET /api/step-parsers resolves. const [stepParsers, setStepParsers] = useState([...BUILTIN_STEP_PARSERS]); + // Wrapper around so keyboard deletion can return focus to the + // canvas container (R6) instead of leaving it on a now-removed node. + const canvasRef = useRef(null); const activeWorkflow = useMemo(() => workflows.find((w) => w.id === activeId), [workflows, activeId]); const isBuiltin = !!activeWorkflow && isBuiltinWorkflowId(activeWorkflow.id); @@ -403,6 +407,61 @@ function InnerEditor({ [selectedEdgeId, setEdges], ); + // ── Deletion (U3, R6) ────────────────────────────────────────────────────── + // Apply cascadeDelete to the current graph for the given node/edge ids, + // clearing any selection that pointed at a removed element. Shared by the + // inspector delete buttons and the keyboard-delete path. + const applyDelete = useCallback( + (ids: Iterable) => { + const idSet = new Set(ids); + let next: { nodes: FlowNode[]; edges: FlowEdge[] } | null = null; + setNodes((ns) => { + next = cascadeDelete(ns, edges, idSet); + return next.nodes; + }); + if (next) setEdges((next as { edges: FlowEdge[] }).edges); + if (selectedNodeId !== null && idSet.has(selectedNodeId)) setSelectedNodeId(null); + if (selectedEdgeId !== null && idSet.has(selectedEdgeId)) setSelectedEdgeId(null); + }, + [edges, setNodes, setEdges, selectedNodeId, selectedEdgeId], + ); + + // Keyboard delete (Backspace/Delete) flows through React Flow's onBeforeDelete: + // it hands us the nodes/edges it intends to remove, and we return the + // cascadeDelete-expanded set (foreach children + incident edges, protected + // nodes filtered out) so React Flow deletes exactly the right elements. After + // deletion, focus returns to the canvas container (R6). Built-ins never reach + // here (deleteKeyCode is null and selection is read-only), but the protection + // in cascadeDelete is the backstop. + const onBeforeDelete = useCallback( + async ({ nodes: delNodes, edges: delEdges }: { nodes: FlowNode[]; edges: FlowEdge[] }) => { + if (isBuiltin) return false; + const ids = new Set([...delNodes.map((n) => n.id), ...delEdges.map((e) => e.id)]); + const result = cascadeDelete(nodes, edges, ids); + const removedNodeIds = new Set(nodes.map((n) => n.id)); + for (const n of result.nodes) removedNodeIds.delete(n.id); + const removedEdgeIds = new Set(edges.map((e) => e.id)); + for (const e of result.edges) removedEdgeIds.delete(e.id); + if (removedNodeIds.size === 0 && removedEdgeIds.size === 0) return false; + return { + nodes: nodes.filter((n) => removedNodeIds.has(n.id)), + edges: edges.filter((e) => removedEdgeIds.has(e.id)), + }; + }, + [isBuiltin, nodes, edges], + ); + + // After React Flow removes the elements, drop any dangling selection and move + // focus to the canvas so keyboard nav continues from a live element (R6). + const onNodesDelete = useCallback(() => { + setSelectedNodeId(null); + canvasRef.current?.focus(); + }, []); + const onEdgesDelete = useCallback(() => { + setSelectedEdgeId(null); + canvasRef.current?.focus(); + }, []); + const handleCreateWorkflow = useCallback(async () => { const name = window.prompt("New workflow name"); if (!name?.trim()) return; @@ -766,7 +825,7 @@ function InnerEditor({ )} -

+
{ setSelectedNodeId(node.id); setSelectedEdgeId(null); @@ -1391,6 +1454,19 @@ function InnerEditor({

) : null} + {!isBuiltin && ( + + )} )} @@ -1459,6 +1535,19 @@ function InnerEditor({

)} + {!isBuiltin && ( + + )} )}
diff --git a/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx b/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx index 53f752aea5..b4c587b0d8 100644 --- a/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx +++ b/packages/dashboard/app/components/__tests__/WorkflowNodeEditor.test.tsx @@ -292,6 +292,42 @@ describe("WorkflowNodeEditor — U10 columns/traits/holds", () => { }); }); +// ── U3: deletion UX (delete buttons + cascade) ────────────────────────────── + +describe("WorkflowNodeEditor — U3 deletion", () => { + beforeEach(() => { + vi.mocked(fetchTraits).mockResolvedValue(TRAIT_CATALOG); + vi.mocked(fetchStepParsers).mockResolvedValue(["step-headings", "json-steps"]); + vi.mocked(fetchModels).mockResolvedValue({ models: [] }); + }); + afterEach(() => cleanup()); + + it("shows a Delete node button when a node is selected and removes the node on click", async () => { + vi.mocked(fetchWorkflows).mockResolvedValue([def()]); + render( {}} addToast={() => {}} />); + const gate = await screen.findByTestId("wf-node-gate"); + fireEvent.click(gate); + const delBtn = await screen.findByTestId("wf-delete-node"); + fireEvent.click(delBtn); + // The gate node is removed from the canvas. + await waitFor(() => expect(screen.queryByTestId("wf-node-gate")).not.toBeInTheDocument()); + // Selecting nothing → the delete button is gone too. + expect(screen.queryByTestId("wf-delete-node")).not.toBeInTheDocument(); + }); + + it("does not render a Delete node button for built-in workflows", async () => { + vi.mocked(fetchWorkflows).mockResolvedValue([ + { ...def(), id: "builtin:coding", name: "Built-in" }, + ]); + render( {}} addToast={() => {}} />); + const gate = await screen.findByTestId("wf-node-gate"); + fireEvent.click(gate); + // Inspector renders (read-only note) but no delete button. + await screen.findByTestId("wf-readonly-banner"); + expect(screen.queryByTestId("wf-delete-node")).not.toBeInTheDocument(); + }); +}); + // ── U8: step-inversion authoring (foreach/step-review/parse-steps/code) ────── /** A custom v2 workflow with a foreach (one step-execute child + a step-review) diff --git a/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts b/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts index fba698414a..c70b8f74cd 100644 --- a/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts +++ b/packages/dashboard/app/components/__tests__/workflow-flow-mapping.test.ts @@ -18,6 +18,7 @@ import { edgeConditionEditability, wouldCreateCycle, buildConnectionEdge, + cascadeDelete, COLUMN_BAND_HEIGHT, WF_CARD_WIDTH, WF_CARD_MAX_WIDTH, @@ -601,3 +602,152 @@ describe("edge-condition authoring (U2)", () => { expect("edge" in res).toBe(true); }); }); + +describe("cascadeDelete (U3, R6)", () => { + // start → a → b → c → end (a/b/c are prompt nodes), so deleting a mid-chain + // node must drop its two incident edges with no bridge created. + const chainDef = (): WorkflowDefinition => + makeDef({ + version: "v1", + name: "chain", + nodes: [ + { id: "start", kind: "start" }, + { id: "a", kind: "prompt", config: { prompt: "a" } }, + { id: "b", kind: "prompt", config: { prompt: "b" } }, + { id: "c", kind: "prompt", config: { prompt: "c" } }, + { id: "end", kind: "end" }, + ], + edges: [ + { from: "start", to: "a", condition: "success" }, + { from: "a", to: "b", condition: "success" }, + { from: "b", to: "c", condition: "success" }, + { from: "c", to: "end", condition: "success" }, + ], + }); + + it("deletes a mid-chain node + both incident edges, with NO bridge edge", () => { + const { nodes, edges } = irToFlow(chainDef()); + const bEdge = edges.find((e) => e.source === "a" && e.target === "b")!; + const result = cascadeDelete(nodes, edges, [/* node */ "b"]); + expect(result.nodes.find((n) => n.id === "b")).toBeUndefined(); + // Both incident edges (a→b and b→c) are gone. + expect(result.edges.find((e) => e.source === "a" && e.target === "b")).toBeUndefined(); + expect(result.edges.find((e) => e.source === "b" && e.target === "c")).toBeUndefined(); + // No auto-bridge a→c. + expect(result.edges.find((e) => e.source === "a" && e.target === "c")).toBeUndefined(); + // Untouched edges survive. + expect(result.edges.find((e) => e.source === "start" && e.target === "a")).toBeTruthy(); + expect(result.edges.find((e) => e.source === "c" && e.target === "end")).toBeTruthy(); + void bEdge; + }); + + // A foreach group with two template children (exec → review, review → exec + // rework), plus top-level edges parse→loop→end. + const foreachDef = (): WorkflowDefinition => + makeDef({ + version: "v1", + name: "loopwf", + nodes: [ + { id: "start", kind: "start" }, + { + id: "loop", + kind: "foreach", + config: { + source: "task-steps", + template: { + nodes: [ + { id: "exec", kind: "prompt", config: { seam: "step-execute", prompt: "do" } }, + { id: "review", kind: "step-review", config: { type: "code" } }, + ], + edges: [ + { from: "exec", to: "review", condition: "success" }, + { from: "review", to: "exec", condition: "outcome:revise", kind: "rework" }, + ], + }, + }, + }, + { id: "end", kind: "end" }, + ], + edges: [ + { from: "start", to: "loop", condition: "success" }, + { from: "loop", to: "end", condition: "success" }, + ], + }); + + it("deleting a foreach group removes the group + children + template edges + incident edges", () => { + const { nodes, edges } = irToFlow(foreachDef()); + const execId = foreachChildFlowId("loop", "exec"); + const reviewId = foreachChildFlowId("loop", "review"); + // Sanity: children + their template edges exist before delete. + expect(nodes.find((n) => n.id === execId)).toBeTruthy(); + expect(edges.some((e) => e.source === execId && e.target === reviewId)).toBe(true); + + const result = cascadeDelete(nodes, edges, ["loop"]); + // Group + both children gone. + expect(result.nodes.find((n) => n.id === "loop")).toBeUndefined(); + expect(result.nodes.find((n) => n.id === execId)).toBeUndefined(); + expect(result.nodes.find((n) => n.id === reviewId)).toBeUndefined(); + // Intra-template edges gone. + expect(result.edges.some((e) => e.source === execId || e.target === execId)).toBe(false); + expect(result.edges.some((e) => e.source === reviewId || e.target === reviewId)).toBe(false); + // The group's own incident edges (start→loop, loop→end) gone. + expect(result.edges.some((e) => e.source === "loop" || e.target === "loop")).toBe(false); + // start and end nodes survive. + expect(result.nodes.find((n) => n.id === "start")).toBeTruthy(); + expect(result.nodes.find((n) => n.id === "end")).toBeTruthy(); + }); + + it("deleting only a template child removes the child + its edges, leaving the group", () => { + const { nodes, edges } = irToFlow(foreachDef()); + const execId = foreachChildFlowId("loop", "exec"); + const reviewId = foreachChildFlowId("loop", "review"); + + const result = cascadeDelete(nodes, edges, [execId]); + // The exec child is gone; the group + sibling remain. + expect(result.nodes.find((n) => n.id === execId)).toBeUndefined(); + expect(result.nodes.find((n) => n.id === "loop")).toBeTruthy(); + expect(result.nodes.find((n) => n.id === reviewId)).toBeTruthy(); + // Edges touching exec (both directions) are gone. + expect(result.edges.some((e) => e.source === execId || e.target === execId)).toBe(false); + }); + + it("never deletes start/end nodes (and preserves their edges)", () => { + const { nodes, edges } = irToFlow(chainDef()); + const result = cascadeDelete(nodes, edges, ["start", "end"]); + expect(result.nodes.find((n) => n.id === "start")).toBeTruthy(); + expect(result.nodes.find((n) => n.id === "end")).toBeTruthy(); + // Their incident edges survive too (start→a, c→end). + expect(result.edges.some((e) => e.source === "start")).toBe(true); + expect(result.edges.some((e) => e.target === "end")).toBe(true); + // Nothing was removed at all. + expect(result.nodes).toHaveLength(nodes.length); + expect(result.edges).toHaveLength(edges.length); + }); + + it("never deletes column band nodes", () => { + const v2: WorkflowDefinition["ir"] = { + version: "v2", + name: "wf", + columns: [{ id: "col1", name: "Col 1", traits: [] }], + nodes: [ + { id: "start", kind: "start", column: "col1" }, + { id: "end", kind: "end", column: "col1" }, + ], + edges: [{ from: "start", to: "end", condition: "success" }], + }; + const { nodes, edges } = irToFlow(makeDef(v2)); + const bandId = nodes.find((n) => isColumnBandNode(n.id))!.id; + const result = cascadeDelete(nodes, edges, [bandId]); + expect(result.nodes.find((n) => n.id === bandId)).toBeTruthy(); + }); + + it("deletes an edge id directly, removing just that edge", () => { + const { nodes, edges } = irToFlow(chainDef()); + const target = edges.find((e) => e.source === "b" && e.target === "c")!; + const result = cascadeDelete(nodes, edges, [target.id]); + expect(result.edges.find((e) => e.id === target.id)).toBeUndefined(); + // No nodes removed, all other edges intact. + expect(result.nodes).toHaveLength(nodes.length); + expect(result.edges).toHaveLength(edges.length - 1); + }); +}); diff --git a/packages/dashboard/app/components/workflow-flow-mapping.ts b/packages/dashboard/app/components/workflow-flow-mapping.ts index 84c15b0795..ec20ac9aa9 100644 --- a/packages/dashboard/app/components/workflow-flow-mapping.ts +++ b/packages/dashboard/app/components/workflow-flow-mapping.ts @@ -415,6 +415,75 @@ function flowEdgeToIr(edge: FlowEdge, groupId?: string): WorkflowIrEdge { return { from, to, condition, ...(isRework ? { kind: "rework" as const } : {}) }; } +// ── Deletion with cascade semantics (U3, R6) ───────────────────────────────── +// +// Pure node/edge transformation for deleting nodes and/or edges. React Flow's +// built-in deletion removes incident edges but does NOT cascade group children +// (deleting a foreach group leaves its `parentId` children orphaned), so the +// editor routes all deletions through this helper for explicit, testable +// behavior. + +/** Node kinds that may never be deleted (start/end are structural). */ +const PROTECTED_NODE_KINDS = new Set(["start", "end"]); + +/** True when a flow node is protected from deletion: start/end kinds and column + * band group nodes are never removable, regardless of the requested ids. */ +function isProtectedFromDelete(node: FlowNode): boolean { + return isColumnBandNode(node.id) || PROTECTED_NODE_KINDS.has(node.data.kind); +} + +/** + * Delete the requested node and/or edge ids from the flow graph, applying R6's + * cascade rules: + * - Deleting a node removes ALL edges incident to it (no auto-bridging). + * - Deleting a `foreach` group node also deletes its template children + * (nodes with `parentId === groupId`) and every edge incident to those + * children (React Flow does not cascade parents — handled explicitly). + * - `start`/`end` nodes and column band nodes are never deleted: they are + * filtered out of the requested ids up front (and their incident edges are + * therefore preserved). + * - Edge ids in `ids` are removed directly. + * + * Pure and order-independent: the same `ids` set always yields the same result. + */ +export function cascadeDelete( + nodes: FlowNode[], + edges: FlowEdge[], + ids: Iterable, +): { nodes: FlowNode[]; edges: FlowEdge[] } { + const requested = new Set(ids); + const nodeById = new Map(nodes.map((n) => [n.id, n])); + + // Resolve which node ids are actually deletable, expanding foreach groups to + // their template children. Protected nodes are dropped from the request. + const deleteNodeIds = new Set(); + for (const id of requested) { + const node = nodeById.get(id); + if (!node || isProtectedFromDelete(node)) continue; + deleteNodeIds.add(id); + if (node.data.kind === "foreach") { + for (const child of nodes) { + if (child.parentId === id) deleteNodeIds.add(child.id); + } + } + } + + // Edge ids requested directly (only ones that exist as edges). + const deleteEdgeIds = new Set(); + for (const e of edges) { + if (requested.has(e.id)) deleteEdgeIds.add(e.id); + } + + const nextNodes = nodes.filter((n) => !deleteNodeIds.has(n.id)); + const nextEdges = edges.filter( + (e) => + !deleteEdgeIds.has(e.id) && + !deleteNodeIds.has(e.source) && + !deleteNodeIds.has(e.target), + ); + return { nodes: nextNodes, edges: nextEdges }; +} + // ── Edge-condition authoring (U2) ──────────────────────────────────────────── /** Editor node kinds whose edges expose a success/failure condition select diff --git a/packages/i18n/locales/en/app.json b/packages/i18n/locales/en/app.json index b3abf434ca..a9dbb929e6 100644 --- a/packages/i18n/locales/en/app.json +++ b/packages/i18n/locales/en/app.json @@ -6761,6 +6761,8 @@ "codeSource": "Source (TypeScript)", "codeTimeout": "Timeout (ms)", "cycleBlocked": "That connection would create a cycle — only rework edges inside a for-each template may loop back", + "deleteEdge": "Delete edge", + "deleteNode": "Delete node", "edgeCondition": "Condition", "edgeConditionLabel": "Condition: {{condition}}", "edgeInspector": "Edge", diff --git a/packages/i18n/locales/es/app.json b/packages/i18n/locales/es/app.json index abeb62cc89..5be4d4ee30 100644 --- a/packages/i18n/locales/es/app.json +++ b/packages/i18n/locales/es/app.json @@ -6761,6 +6761,8 @@ "codeSource": "Origen (TypeScript)", "codeTimeout": "Tiempo de espera (ms)", "cycleBlocked": "", + "deleteEdge": "", + "deleteNode": "", "edgeCondition": "", "edgeConditionLabel": "Condición: {{condition}}", "edgeInspector": "Conexión", diff --git a/packages/i18n/locales/fr/app.json b/packages/i18n/locales/fr/app.json index 562e0af93f..cdcacf9465 100644 --- a/packages/i18n/locales/fr/app.json +++ b/packages/i18n/locales/fr/app.json @@ -6761,6 +6761,8 @@ "codeSource": "Source (TypeScript)", "codeTimeout": "Délai d’expiration (ms)", "cycleBlocked": "", + "deleteEdge": "", + "deleteNode": "", "edgeCondition": "", "edgeConditionLabel": "Condition : {{condition}}", "edgeInspector": "Lien", diff --git a/packages/i18n/locales/ko/app.json b/packages/i18n/locales/ko/app.json index 7e45c6f55a..2e2ee82d14 100644 --- a/packages/i18n/locales/ko/app.json +++ b/packages/i18n/locales/ko/app.json @@ -6761,6 +6761,8 @@ "codeSource": "소스(TypeScript)", "codeTimeout": "제한 시간(ms)", "cycleBlocked": "", + "deleteEdge": "", + "deleteNode": "", "edgeCondition": "", "edgeConditionLabel": "조건: {{condition}}", "edgeInspector": "에지", diff --git a/packages/i18n/locales/zh-CN/app.json b/packages/i18n/locales/zh-CN/app.json index 8b6d98c993..0c66e13717 100644 --- a/packages/i18n/locales/zh-CN/app.json +++ b/packages/i18n/locales/zh-CN/app.json @@ -6761,6 +6761,8 @@ "codeSource": "源代码(TypeScript)", "codeTimeout": "超时(毫秒)", "cycleBlocked": "", + "deleteEdge": "", + "deleteNode": "", "edgeCondition": "", "edgeConditionLabel": "条件:{{condition}}", "edgeInspector": "连线", diff --git a/packages/i18n/locales/zh-TW/app.json b/packages/i18n/locales/zh-TW/app.json index ffb98650ec..8af8ded56b 100644 --- a/packages/i18n/locales/zh-TW/app.json +++ b/packages/i18n/locales/zh-TW/app.json @@ -6761,6 +6761,8 @@ "codeSource": "原始碼(TypeScript)", "codeTimeout": "逾時(毫秒)", "cycleBlocked": "", + "deleteEdge": "", + "deleteNode": "", "edgeCondition": "", "edgeConditionLabel": "條件:{{condition}}", "edgeInspector": "連線", diff --git a/packages/i18n/src/resources.d.ts b/packages/i18n/src/resources.d.ts index 651ef0dbb2..aeb63bb853 100644 --- a/packages/i18n/src/resources.d.ts +++ b/packages/i18n/src/resources.d.ts @@ -6763,6 +6763,8 @@ export default interface Resources { "codeSource": "Source (TypeScript)", "codeTimeout": "Timeout (ms)", "cycleBlocked": "That connection would create a cycle — only rework edges inside a for-each template may loop back", + "deleteEdge": "Delete edge", + "deleteNode": "Delete node", "edgeCondition": "Condition", "edgeConditionLabel": "Condition: {{condition}}", "edgeInspector": "Edge", From 5a499ea21277fa0e10b15f35ced6a68312645eb8 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 4 Jun 2026 20:51:24 -0700 Subject: [PATCH 007/112] feat(dashboard): workflow editor dialogs, inline rename, and dirty-state guard --- .../app/components/WorkflowNodeEditor.css | 78 ++++ .../app/components/WorkflowNodeEditor.tsx | 439 +++++++++++++++++- .../__tests__/WorkflowNodeEditor.test.tsx | 221 ++++++++- packages/i18n/locales/en/app.json | 20 + packages/i18n/locales/es/app.json | 20 + packages/i18n/locales/fr/app.json | 20 + packages/i18n/locales/ko/app.json | 20 + packages/i18n/locales/zh-CN/app.json | 20 + packages/i18n/locales/zh-TW/app.json | 20 + packages/i18n/src/resources.d.ts | 20 + 10 files changed, 852 insertions(+), 26 deletions(-) diff --git a/packages/dashboard/app/components/WorkflowNodeEditor.css b/packages/dashboard/app/components/WorkflowNodeEditor.css index 2fb92fe56c..efb2c06f24 100644 --- a/packages/dashboard/app/components/WorkflowNodeEditor.css +++ b/packages/dashboard/app/components/WorkflowNodeEditor.css @@ -533,6 +533,84 @@ color: var(--bg); } +/* Inline name + description strip (KTD-10). */ +.wf-name-strip { + display: flex; + align-items: baseline; + gap: var(--space-sm); + padding: var(--space-xs) var(--space-sm); + border-bottom: 1px solid var(--border); + flex-wrap: wrap; +} + +.wf-workflow-name, +.wf-workflow-name--readonly { + font-size: 0.95rem; + font-weight: 600; + color: var(--text); + background: none; + border: 1px solid transparent; + border-radius: var(--radius-sm); + padding: 2px var(--space-xs); + cursor: pointer; + text-align: left; +} + +.wf-workflow-name:hover { + background: var(--bg-tertiary); +} + +.wf-workflow-name--readonly { + cursor: default; +} + +.wf-workflow-name-input { + font-size: 0.95rem; + font-weight: 600; + color: var(--text); + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 2px var(--space-xs); +} + +.wf-workflow-description, +.wf-workflow-description--readonly { + font-size: 0.78rem; + color: var(--text-tertiary); + background: none; + border: 1px solid transparent; + border-radius: var(--radius-sm); + padding: 2px var(--space-xs); + cursor: pointer; + text-align: left; +} + +.wf-workflow-description:hover { + background: var(--bg-tertiary); +} + +.wf-workflow-description--readonly { + cursor: default; +} + +.wf-workflow-description-input { + font-size: 0.78rem; + color: var(--text); + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 2px var(--space-xs); + min-width: 220px; +} + +/* Create-workflow dialog (KTD-7). */ +.wf-create-error { + margin: var(--space-xs) 0 0; + font-size: 0.8rem; + color: var(--ws-error); +} + .wf-column-panel { display: flex; flex-direction: column; diff --git a/packages/dashboard/app/components/WorkflowNodeEditor.tsx b/packages/dashboard/app/components/WorkflowNodeEditor.tsx index 327d036aa3..262386195e 100644 --- a/packages/dashboard/app/components/WorkflowNodeEditor.tsx +++ b/packages/dashboard/app/components/WorkflowNodeEditor.tsx @@ -32,6 +32,7 @@ import type { Agent } from "../api"; import type { DiscoveredSkill } from "../api"; import type { ToastType } from "../hooks/useToast"; import { useOverlayDismiss } from "../hooks/useOverlayDismiss"; +import { useConfirm } from "../hooks/useConfirm"; import { useModalResizePersist } from "../hooks/useModalResizePersist"; import { workflowNodeTypes, type WorkflowFlowNodeData, type WorkflowEditorNodeKind } from "./nodes/WorkflowNodeTypes"; import { WorkflowEditorCatalogContext } from "./nodes/WorkflowEditorCatalogContext"; @@ -86,6 +87,29 @@ function parseModelDropdownValue(value: string): { provider: string; modelId: st return { provider: value.slice(0, slashIndex), modelId: value.slice(slashIndex + 1) }; } +/** Normalized serialization of the editor's authoring state for dirty tracking + * (U4). Serializes nodes/edges through flowToIr (so mapping-layer defaults are + * materialized identically on the loaded and live sides) plus the editor-owned + * name/description and the resulting layout (auto-layout/drag position changes + * count as dirty). Returns a stable JSON string for cheap equality. */ +function serializeGraph( + name: string, + description: string, + nodes: FlowNode[], + edges: FlowEdge[], + columns: WorkflowIrColumn[], + fields: WorkflowFieldDefinition[], +): string { + const { ir, layout } = flowToIr( + name, + nodes, + edges, + columns.length ? columns : undefined, + fields.length ? fields : undefined, + ); + return JSON.stringify({ name, description, ir, layout }); +} + interface WorkflowNodeEditorProps { isOpen: boolean; onClose: () => void; @@ -124,6 +148,128 @@ const PALETTE: Array<{ kind: WorkflowEditorNodeKind; label: string; icon: typeof { kind: "code", label: "Code", icon: Code2, presetConfig: { source: "" } }, ]; +/** Local create-workflow dialog (KTD-7). Built on the shared `.modal` primitives + * (precedent: NewTaskModal). Owns its own name/description/error state; the + * parent supplies an async `onCreate` that performs the createWorkflow call and + * throws on failure so the dialog can surface server rejections inline without + * losing the typed input. Escape/overlay close (no dirty state of its own). */ +function CreateWorkflowDialog({ + onCreate, + onClose, +}: { + onCreate: (name: string, description: string) => Promise; + onClose: () => void; +}) { + const { t } = useTranslation("app"); + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [error, setError] = useState(null); + const [submitting, setSubmitting] = useState(false); + const nameRef = useRef(null); + + useEffect(() => { + nameRef.current?.focus(); + }, []); + + const overlayProps = useOverlayDismiss(onClose); + + const handleSubmit = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + const trimmed = name.trim(); + if (!trimmed) { + setError(t("workflows.createNameRequired", "Enter a workflow name")); + return; + } + setSubmitting(true); + setError(null); + try { + await onCreate(trimmed, description.trim()); + // Success path closes the dialog from the parent. + } catch (err) { + setError(getErrorMessage(err) || t("workflows.createFailed", "Failed to create workflow")); + setSubmitting(false); + } + }, + [name, description, onCreate, t], + ); + + return ( +
+
e.stopPropagation()} + onKeyDown={(e) => { + if (e.key === "Escape") { + e.stopPropagation(); + onClose(); + } + }} + > +
+

{t("workflows.createTitle", "New workflow")}

+ +
+
+
+ +