Compare commits

..
Author SHA1 Message Date
CodeWhale BotandClaude Opus 5.5 0eac11fa2c ci: read main's sccache on every run, write it only from main
The sccache install step now runs on every event in ci.yml and
ci-test-suite.yml, and each Enable sccache step sets
SCCACHE_GHA_RW_MODE to READ_WRITE only on refs/heads/main and READ_ONLY
everywhere else (sccache docs/GHA.md; the action installs the latest
release, v0.19.0). Pull request and branch-dispatch runs, which now run
the full sharded suite, get main's compiler cache hits without writing
the refs/pull/N entries that once pushed the repo past its 10 GiB cache
cap. rust-cache save-if stays main-only and the Windows RUSTC_WRAPPER
guard from MAIN-GREEN is unchanged.

release-workflows.test.js now checks, per file, that every sccache
enable carries the off-main read-only switch and that no sccache install
is gated on main; both checks were confirmed to fail on a mutated copy.

Windows test legs keep debug 0: no test asserts on backtrace content
(only RUST_BACKTRACE pass-through lists and compile-time
Location::caller, which debug info does not affect).

Checks: node .github/scripts/release-workflows.test.js passed (211
paths, 11 wrapper cases x 12 steps, 15 hermetic checks, workflow
contracts); actionlint 1.7.12 with the repo's CI args (-ignore SC2129
-ignore SC2221 -ignore SC2222) clean on all workflows;
scripts/test_ci_migration_wiring.py 19 tests OK.

First drafted by a duplicate agent run in this worktree; reviewed and
tightened here.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-12 16:58:47 -08:00
CodeWhale BotandClaude Sonnet 5.5 4321aecea3 wip(ci): sharded full suite on pull requests, scoped dispatch, cancel superseded runs
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 16:53:54 -08:00
CodeWhale BotandClaude Sonnet 5.5 d0da1d2c5e fix(ci): guard npm wrapper smoke sccache with matrix.os
The wrapper-guard contract test evaluates step conditions without a runner
context, so use matrix.os, which it supplies.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 16:02:33 -08:00
CodeWhale BotandClaude Sonnet 5.5 199ab3179d fix(ci): drop unused engine arboard and keep sccache off Windows legs
Cargo 1.100 lays build artifacts out per unit, so a rustc call for
codewhale-runtime carries about 330 search-path arguments (45K characters).
sccache expands the argument file and spawns rustc with the full line, which
Windows refuses past 32767 characters. The release-artifacts, nightly and npm
wrapper smoke Windows legs no longer enable sccache. codewhale-engine declared
arboard but never uses it; the TUI keeps its own.

Picked from ci/rc-fix b97e38645f (without its terminal.rs hunk).

Co-Authored-By: CodeWhale Bot <[email protected]>
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 15:53:00 -08:00
CodeWhale BotandClaude Sonnet 5.5 094747fb59 fix(tui): satisfy clippy 1.100 needless_range_loop and unreachable_code
Iterate with enumerate in the context menu rows and two transcript tests, and
match the uninhabited backend error in the probe test instead of formatting it.
Behaviour unchanged.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 15:50:48 -08:00
CodeWhale BotandClaude Sonnet 5.5 b59c9ab725 chore(web): regenerate agent docs for the CONTRIBUTORS entry and RUNTIME_API
npm run prebuild; the generated snapshot was stale for RUNTIME_API.md on main
and now also carries the CONTRIBUTORS.md change.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 15:28:32 -08:00
CodeWhale BotandClaude Sonnet 5.5 6ba531722b chore(credit): credit MannXo for the Qwen Code registry change and cite the issue number
Map the commit author's name and email to the MannXo account, list them in
CONTRIBUTORS and the website release credits, and write the existing Qwen Code
line as (#7293) so the feature release-note receipt check finds it. check-
contributor-credit.py and check-versions.sh --range-audit-advisory pass.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 15:08:18 -08:00
CodeWhale BotandClaude Sonnet 5.5 74ee30e6da fix(engine): collapse four needless_bool tails flagged by clippy 1.100
Return the condition directly in auto_review tag-like check, fleet start_leased
result, DSH overlay_granted (cfg split) and ledger contract overlap. Behaviour
unchanged.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-12 15:08:14 -08:00
191 changed files with 7329 additions and 6303 deletions

No files matched your search

+222 -33
View File
@@ -32,6 +32,7 @@ function namedStep(source, name) {
}
const ci = read(".github/workflows/ci.yml");
const ciSuite = read(".github/workflows/ci-test-suite.yml");
const nightly = read(".github/workflows/nightly.yml");
const candidate = read(".github/workflows/release-candidate.yml");
const artifacts = read(".github/workflows/release-artifacts.yml");
@@ -46,28 +47,212 @@ const archiveInstaller = read("scripts/release/install.sh");
const cliDispatcher = read("crates/cli/src/lib.rs");
const runbook = read("docs/RELEASE_RUNBOOK.md");
const ciTestJob = ci.slice(ci.indexOf("\n test:\n"));
assert.match(
ciTestJob,
/matrix\.os == 'ubuntu-latest'.*github\.event_name == 'pull_request'/,
"heavy pull requests must select the real Ubuntu test lane",
);
assert.match(
ciTestJob,
/cargo nextest run --workspace --all-features --locked --profile ci/,
"the Ubuntu pull-request lane must run workspace nextest",
);
assert.match(
ciTestJob,
/name: Linux test location \(CNB\)/,
"the non-PR CNB fallback must be named explicitly",
);
function jobBlock(source, job) {
const match = source.match(new RegExp(`^ ${job}:\\n([\\s\\S]*?)(?=^ \\S|(?![\\s\\S]))`, "m"));
assert.ok(match, `missing job: ${job}`);
return match[1];
}
function jobIf(source, job) {
const lines = jobBlock(source, job).split("\n");
const at = lines.findIndex((line) => /^ if:/.test(line));
assert.notEqual(at, -1, `${job} must declare an if`);
const first = lines[at].replace(/^ if:\s*/, "");
if (first !== ">-") return first.replace(/^'(.*)'$/, "$1");
const folded = [];
for (let i = at + 1; i < lines.length && /^ \S/.test(lines[i]); i += 1) folded.push(lines[i].trim());
return folded.join(" ");
}
function evaluate(expression, context) {
return Boolean(vm.runInNewContext(expression, context));
}
// The sharded suite: one archive per OS, partitions of it in parallel shards,
// doctests once, and a check that the shards add up to the archive's list.
assert.match(
namedStep(ciTestJob, "Build canonical executable for acceptance tests"),
namedStep(ciSuite, "Archive test binaries"),
/cargo nextest archive --workspace --all-features --locked --profile ci/,
"the suite must archive the same workspace, features and profile the old single run used",
);
assert.match(
namedStep(ciSuite, "Build canonical executable for acceptance tests"),
/cargo build -p codewhale-cli --bin codewhale --all-features --locked/,
"Engine acceptance must build the canonical executable first",
);
assert.match(
namedStep(ciSuite, "Run doctests"),
/cargo test --workspace --all-features --locked --doc/,
"nextest does not run doctests; the suite must run them once per OS",
);
const shardRun = namedStep(ciSuite, "Run tests");
assert.match(shardRun, /--partition "count:\$\{\{ matrix\.shard \}\}\/\$\{\{ inputs\.shards \}\}"/);
assert.match(shardRun, /-E "not \(\$NATIVE_FILTER\)"/, "every shard must exclude the native tests that shard 1 runs apart");
assert.match(namedStep(ciSuite, "Run native containment tests"), /-E "\$NATIVE_FILTER"/);
assert.match(ciSuite, /nextest-shard-count\.py check counts/, "the suite must prove the shards add up to the archive's list");
for (const name of ["Run tests", "Run native containment tests", "Run doctests"]) {
const step = namedStep(ciSuite, name);
assert.match(step, /shell: bash/, `${name} must invoke the POSIX helper on Windows too`);
}
assert.match(ciSuite, /RUST_MIN_STACK: '16777216'/);
// The native receipt script requires its tests in one JUnit report, so the
// shard that runs them must select exactly the script's list.
const receiptScript = read("scripts/compiled-host-native-receipt.py");
const receiptNames = [
receiptScript.match(/^COMPILED = "([^"]+)"$/m)[1],
receiptScript.match(/^MEMORY = "([^"]+)"$/m)[1],
...[...receiptScript.match(/^WINDOWS = \[([\s\S]*?)^\]/m)[1].matchAll(/"([^"]+)"/g)].map((m) => m[1]),
];
const nativeFilter = ciSuite.match(/NATIVE_FILTER: >-\n([\s\S]*?)\n steps:/)[1];
assert.deepEqual(
[...nativeFilter.matchAll(/test\(=([^)]+)\)/g)].map((m) => m[1]).sort(),
receiptNames.sort(),
"NATIVE_FILTER must list exactly the tests scripts/compiled-host-native-receipt.py requires",
);
// Shard counts: each caller's shards equals the length of its shard_list, the
// suite's own list agrees with it, and every OS keeps a pipeline.
const suiteCallers = {};
for (const job of ["test-ubuntu", "test-macos", "test-windows"]) {
const block = jobBlock(ci, job);
const os = block.match(/^ os: (\S+)$/m)[1];
const shards = Number(block.match(/^ shards: (\d+)$/m)[1]);
const list = JSON.parse(block.match(/^ shard_list: '(.+)'$/m)[1]);
assert.deepEqual(list, Array.from({ length: shards }, (_, i) => i + 1), `${job} shard_list must be 1..shards`);
assert.match(block, /uses: \.\/\.github\/workflows\/ci-test-suite\.yml/);
assert.equal(jobIf(ci, job), jobIf(ci, "test-ubuntu"), `${job} must share the suite condition`);
suiteCallers[os] = shards;
}
assert.deepEqual(Object.keys(suiteCallers).sort(), ["macos-latest", "ubuntu-latest", "windows-latest"]);
// Required contexts. The ruleset requires exactly "Lint" and "Test
// (windows-latest)". Only Lint and the compile-only test-windows-pr job may
// produce them; a shard, build or suite check must never share a name.
const jobNames = (source) => [...source.matchAll(/^ [A-Za-z0-9_-]+:\n name: (.+)$/gm)].map((m) => m[1]);
assert.deepEqual(
[...jobNames(ci), ...jobNames(ciSuite)].filter((name) => /^Test \(/.test(name) || name === "Lint"),
["Lint", "Test (windows-latest)"],
"only Lint and the compile-only Windows leg may use the required context names",
);
assert.match(jobBlock(ci, "test-windows-pr"), /^ name: Test \(windows-latest\)$/m);
assert.equal(jobIf(ci, "test-windows-pr"), "github.event_name == 'pull_request'");
assert.match(jobBlock(ci, "test-windows-pr"), /cargo check --workspace --all-features --all-targets|cargo check --workspace --all-targets --all-features --locked/);
// Each gate that pull requests lost on 2026-11-07 (99cb5a0f4f) runs on a heavy
// pull request again, plus on dispatch; a docs-only pull request keeps skipping
// them; a scoped dispatch skips all of them.
const gates = ["safety-gate", "msrv", "test-ubuntu", "test-macos", "test-windows", "portable-boundaries", "npm-wrapper-smoke", "mobile-smoke"];
for (const job of gates) {
const guard = jobIf(ci, job);
const base = { inputs: { workspace_test_mode: "nextest" } };
const run = (event, heavy, extra = {}) =>
evaluate(guard, {
github: { event_name: event },
needs: { changes: { outputs: { heavy: String(heavy), mobile: "true", scoped: "false", ...extra } } },
...base,
});
assert.equal(run("pull_request", true), true, `${job} must run on a heavy pull request`);
if (job !== "npm-wrapper-smoke") {
assert.equal(run("pull_request", false), false, `${job} must skip a docs-only pull request`);
}
assert.equal(run("workflow_dispatch", true), true, `${job} must run on a full dispatch`);
assert.equal(run("workflow_dispatch", true, { scoped: "true" }), false, `${job} must skip a scoped dispatch`);
}
assert.equal(
evaluate(jobIf(ci, "mobile-smoke"), {
github: { event_name: "pull_request" },
needs: { changes: { outputs: { heavy: "true", mobile: "false", scoped: "false" } } },
}),
false,
"mobile smoke keeps its path filter on pull requests",
);
for (const job of ["test-ubuntu", "test-macos", "test-windows"]) {
assert.equal(
evaluate(jobIf(ci, job), {
github: { event_name: "workflow_dispatch" },
inputs: { workspace_test_mode: "shared-process-twice" },
needs: { changes: { outputs: { heavy: "true", scoped: "false" } } },
}),
false,
`${job} must yield to the shared-process qualification`,
);
}
const sharedGuard = jobIf(ci, "test");
for (const [event, mode, scoped, expected] of [
["workflow_dispatch", "shared-process-twice", "false", true],
["workflow_dispatch", "nextest", "false", false],
["workflow_dispatch", "shared-process-twice", "true", false],
["pull_request", "nextest", "false", false],
]) {
assert.equal(
evaluate(sharedGuard, {
github: { event_name: event },
inputs: { workspace_test_mode: mode },
needs: { changes: { outputs: { heavy: "true", scoped } } },
}),
expected,
`shared-process job: ${event} ${mode} scoped=${scoped}`,
);
}
assert.equal(
evaluate(jobIf(ci, "scoped-test"), { needs: { changes: { outputs: { scoped: "true" } } } }),
true,
);
assert.equal(
evaluate(jobIf(ci, "scoped-test"), { needs: { changes: { outputs: { scoped: "false" } } } }),
false,
);
assert.match(ci, /^ expected_sha:\n description: .*\n required: true\n type: string$/m, "expected_sha stays required");
for (const input of ["crate", "filter", "os"]) {
assert.match(ci, new RegExp(`^ ${input}:\\n description: .*\\n required: false\\n`, "m"), `scoped dispatch input ${input}`);
}
// Concurrency: a new push to the same pull request or non-main branch cancels
// the older run; runs on main and scoped dispatches never cancel anything.
const concurrency = ci.match(/^concurrency:\n group: (.+)\n cancel-in-progress: (.+)$/m);
assert.ok(concurrency, "ci.yml must declare its concurrency");
const strip = (value) => value.replace(/^\$\{\{ /, "").replace(/ \}\}$/, "");
const format = (template, ...args) => template.replace(/\{(\d)\}/g, (_, i) => args[Number(i)]);
const groupOf = (context) =>
vm.runInNewContext(strip(concurrency[1]), { ...context, format });
const cancelOf = (context) => vm.runInNewContext(strip(concurrency[2]), context);
const dispatch = (ref, sha, inputs = {}) => ({
github: { event_name: "workflow_dispatch", ref, sha, workflow: "CI", run_id: `run-${sha}` },
inputs: { crate: "", filter: "", ...inputs },
});
const pr = (number, sha) => ({
github: { event_name: "pull_request", ref: `refs/pull/${number}/merge`, sha, workflow: "CI", event: { pull_request: { number } }, run_id: `run-${sha}` },
inputs: {},
});
assert.equal(groupOf(pr(7, "a")), groupOf(pr(7, "b")), "a new push to a pull request shares its group");
assert.notEqual(groupOf(pr(7, "a")), groupOf(pr(8, "a")));
assert.equal(cancelOf(pr(7, "a")), true);
assert.equal(groupOf(dispatch("refs/heads/ci/x", "a")), groupOf(dispatch("refs/heads/ci/x", "b")), "a new dispatch on the same ci branch shares its group");
assert.notEqual(groupOf(dispatch("refs/heads/ci/x", "a")), groupOf(dispatch("refs/heads/ci/y", "a")));
assert.equal(cancelOf(dispatch("refs/heads/ci/x", "a")), true);
assert.notEqual(groupOf(dispatch("refs/heads/main", "a")), groupOf(dispatch("refs/heads/main", "b")), "runs on main never share a group");
assert.equal(cancelOf(dispatch("refs/heads/main", "a")), false, "runs on main never cancel");
assert.notEqual(
groupOf(dispatch("refs/heads/ci/x", "a", { crate: "codewhale-tui" })),
groupOf(dispatch("refs/heads/ci/x", "a")),
"a scoped dispatch never shares the full run's group",
);
assert.equal(cancelOf(dispatch("refs/heads/ci/x", "a", { filter: "test(x)" })), false, "a scoped dispatch cancels nothing");
// Security for pull requests from forks: the workflows use pull_request (no
// pull_request_target), read-only permissions, no secrets, and write caches
// only from main.
for (const [name, source] of [["ci.yml", ci], ["ci-test-suite.yml", ciSuite]]) {
assert.doesNotMatch(source, /pull_request_target/, `${name} must not use pull_request_target`);
assert.doesNotMatch(source, /\$\{\{\s*secrets\./, `${name} must not read secrets`);
assert.match(source, /^permissions:\n contents: read\n/m, `${name} must keep read-only default permissions`);
assert.doesNotMatch(source.replace(/^permissions:\n contents: read\n/m, ""), /^\s+(?:contents|actions|id-token|pull-requests|packages):\s*write/m, `${name} must not grant write permissions`);
for (const match of source.matchAll(/Swatinem\/rust-cache@[^\n]*\n(?:\s+(?:with|cache-bin):[^\n]*\n)*\s+save-if: ([^\n]+)/g)) {
assert.match(match[1], /refs\/heads\/main|false/, `${name}: rust-cache must save only on main`);
}
assert.doesNotMatch(source, /actions\/cache(?:\/save)?@/, `${name} must not write caches outside rust-cache and sccache`);
}
const npmSmokeJob = ci.match(/^ npm-wrapper-smoke:\n([\s\S]*?)(?=^ \S)/m)?.[1];
assert.ok(npmSmokeJob, "CI must retain the npm-wrapper job");
assert.match(
@@ -79,13 +264,13 @@ assert.match(
/run: node scripts\/release\/npm-wrapper-smoke\.js/,
);
const npmSmokeSteps = npmSmokeJob.split(/(?=^ - )/m).slice(1);
// Exercise the workflow's actual Boolean guards. The smoke is manual-only
// (workflow_dispatch); pull requests, pushes and schedules skip the job.
// Exercise the workflow's actual Boolean guards. The smoke runs on pull
// requests and dispatches (§180); pushes and schedules skip the job.
const npmSmokeCases = [
// name, event, heavy, OS, trusted, cache success, execute, Linux deps, CNB
["own PR", "pull_request", true, "ubuntu-latest", true, true, false, false, false],
["fork PR", "pull_request", true, "ubuntu-latest", false, true, false, false, false],
["PR cache failure", "pull_request", true, "ubuntu-latest", false, false, false, false, false],
["own PR", "pull_request", true, "ubuntu-latest", true, true, true, true, false],
["fork PR", "pull_request", true, "ubuntu-latest", false, true, true, true, false],
["PR cache failure", "pull_request", true, "ubuntu-latest", false, false, true, true, false],
["light PR", "pull_request", false, "ubuntu-latest", true, true, false, false, false],
["manual Ubuntu", "workflow_dispatch", true, "ubuntu-latest", true, true, true, true, false],
["main Ubuntu", "push", true, "ubuntu-latest", true, true, false, false, false],
@@ -95,15 +280,22 @@ const npmSmokeCases = [
["light main", "push", false, "ubuntu-latest", true, true, false, false, false],
["schedule", "schedule", true, "ubuntu-latest", true, true, false, false, false],
];
// The sccache GitHub Actions backend is main-only, mirroring rust-cache's
// save-if: pull requests never install or enable it (cache bloat, PLAN D).
// The sccache GitHub Actions backend is read-only off main: every run reads
// main's cache, and only main writes it (SCCACHE_GHA_RW_MODE), mirroring
// rust-cache's save-if (cache bloat, PLAN D).
for (const [name, source] of [["ci.yml", ci], ["ci-test-suite.yml", ciSuite]]) {
const enabled = source.match(/SCCACHE_GHA_ENABLED=true/g) ?? [];
const modes = source.match(/if \[ "\$\{GITHUB_REF\}" = refs\/heads\/main \]; then rw=READ_WRITE; else rw=READ_ONLY; fi\n\s+echo "SCCACHE_GHA_RW_MODE=\$\{rw\}"/g) ?? [];
assert.ok(enabled.length > 0, `${name} must enable sccache`);
assert.equal(modes.length, enabled.length, `${name}: every sccache enable must be read-only off main`);
assert.doesNotMatch(source, /sccache-action[^\n]*\n(?:[^\n]*\n){0,4}\s+if: [^\n]*github\.ref == 'refs\/heads\/main'/, `${name}: sccache must install on every run`);
}
const sccacheInstallStep = "mozilla-actions/[email protected]";
for (const [label, event, heavy, os, trusted, cache, execute, linuxDeps, cnb] of npmSmokeCases) {
const ref = event === "pull_request" ? "refs/pull/1/merge" : "refs/heads/main";
const onMain = ref === "refs/heads/main";
const installed = execute && onMain;
const installed = execute;
const context = {
needs: { changes: { outputs: { heavy: String(heavy), trusted: String(trusted) } } },
needs: { changes: { outputs: { heavy: String(heavy), trusted: String(trusted), scoped: "false" } } },
github: { event_name: event, ref },
matrix: { os },
steps: { sccache: { outcome: installed ? (cache ? "success" : "failure") : "skipped" } },
@@ -688,7 +880,8 @@ assert.doesNotMatch(
// itself runs none: its parity job calls release-parity.yml.
let hermeticInvocations = 0;
for (const [label, workflow, expected] of [
["CI", ci, 6],
["CI", ci, 5],
["CI test suite", ciSuite, 3],
["release", release, 0],
["release parity", parityWorkflow, 4],
["CNB", cnb, 3],
@@ -707,11 +900,6 @@ for (const [label, workflow, expected] of [
}
hermeticInvocations += commands.length;
}
for (const name of ["Run tests", "Run doctests"]) {
const step = namedStep(ciTestJob, name);
assert.match(step, /shell: bash/, `${name} must invoke the POSIX helper on Windows too`);
assert.match(step, /RUST_MIN_STACK: '16777216'/);
}
console.log(`Hermetic Rust workflow invocations OK: ${hermeticInvocations} checks passed.`);
const nextest = read(".config/nextest.toml");
@@ -853,6 +1041,7 @@ for (const [name, source] of [
["release-parity.yml", parityWorkflow],
["release-republish.yml", republish],
["ci.yml", ci],
["ci-test-suite.yml", ciSuite],
["nightly.yml", nightly],
]) {
assert.deepEqual(
+388
View File
@@ -0,0 +1,388 @@
name: CI test suite
# Called by ci.yml, once per operating system, so each OS is its own pipeline:
# one build of the whole workspace's test binaries, parallel shards that run
# partitions of that one nextest archive, and a check that the shards together
# ran exactly the tests the archive lists. Running per OS means Linux reports
# as soon as Linux is done instead of waiting for the slowest build.
#
# Trust boundary: this runs with the caller's event. For a pull request from a
# fork that is the read-only token and no secrets; nothing here writes a cache
# (rust-cache and sccache save only on main) or uses a write permission. The
# artifacts passed between jobs live inside one run.
on:
workflow_call:
inputs:
os:
description: Hosted runner label
required: true
type: string
shards:
description: Number of shards, equal to the length of shard_list
required: true
type: number
shard_list:
description: JSON array of shard numbers, for example [1,2,3,4]
required: true
type: string
build_jobs:
description: CARGO_BUILD_JOBS for the test build
required: true
type: string
debug:
description: Debug-table level for the test build (CARGO_PROFILE_*_DEBUG)
required: true
type: string
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUSTFLAGS: -Dwarnings
RUST_MIN_STACK: 8388608
jobs:
build:
name: Build
# A cold hosted Mac compiled for 65 minutes with one Cargo job (run
# 43216596942) and the old one-job cap was 210; this job only compiles, so
# it keeps real margin without the test run in it.
timeout-minutes: 150
runs-on: ${{ inputs.os }}
env:
# Test builds compile all features of the whole workspace. One Cargo job
# kept hosted runners inside memory (exit 143 on 2026-10-19 with four);
# trimmed debug tables shrink compiler and linker memory so Linux and
# Windows can run two. Assertions and every test are unchanged.
CARGO_BUILD_JOBS: ${{ inputs.build_jobs }}
CARGO_PROFILE_DEV_DEBUG: ${{ inputs.debug }}
CARGO_PROFILE_TEST_DEBUG: ${{ inputs.debug }}
steps:
- uses: actions/checkout@v7
- name: Test Windows installer PATH helper
if: inputs.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/update-user-path.tests.ps1
- name: Install NSIS for Windows installer regression
if: inputs.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/install-nsis.ps1
- name: Test Windows installer PATH regression
if: inputs.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/installer-path-regression.tests.ps1 -AllowUserPathMutation
- uses: dtolnay/rust-toolchain@stable
- name: Install macOS LLVM tools
if: inputs.os == 'macos-latest'
run: rustup component add llvm-tools --toolchain stable
- uses: mozilla-actions/[email protected]
id: sccache
continue-on-error: true
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
if: inputs.os == 'ubuntu-latest'
run: |
bash scripts/ci-apt-install.sh libdbus-1-dev pkg-config bubblewrap apparmor-profiles
sh scripts/prepare-linux-test-sandbox.sh
- name: Ubuntu build headroom
# Reuse the same fixed hosted-runner provisioning as Safety and Lint.
# Exit 143 is a shutdown observation, not proof of OOM or timeout.
if: inputs.os == 'ubuntu-latest'
shell: bash
run: bash scripts/prepare-ubuntu-build-headroom.sh
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- uses: taiki-e/install-action@nextest
- uses: actions/[email protected]
with:
node-version: 22
- name: Build canonical executable for acceptance tests
shell: bash
run: cargo build -p codewhale-cli --bin codewhale --all-features --locked
env:
RUSTC_WRAPPER: ${{ inputs.os != 'windows-latest' && env.RUSTC_WRAPPER || '' }}
- name: Windows Terminal clipboard-to-draft acceptance
if: inputs.os == 'windows-latest'
timeout-minutes: 5
shell: pwsh
run: node scripts/release/windows-terminal-clipboard.mjs target/debug/codewhale.exe "${{ runner.temp }}/windows-clipboard"
- name: Retain Windows Terminal clipboard-to-draft evidence
if: ${{ !cancelled() && inputs.os == 'windows-latest' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: windows-clipboard-${{ github.sha }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/windows-clipboard/
if-no-files-found: error
retention-days: 7
- name: Archive test binaries
# One compile per OS. Shards run this archive with
# `cargo nextest run --archive-file`, so the suite is the same test
# binaries, built once. Doctests are not in the archive; they run
# below, once, while the library artifacts are still warm.
shell: bash
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/test-archive" "$RUNNER_TEMP/test-expected"
cargo nextest archive --workspace --all-features --locked --profile ci \
--archive-file "$RUNNER_TEMP/test-archive/nextest-archive.tar.zst"
exe=codewhale
if [ "$RUNNER_OS" = Windows ]; then exe=codewhale.exe; fi
cp "target/debug/$exe" "$RUNNER_TEMP/test-archive/$exe"
env:
RUSTC_WRAPPER: ${{ inputs.os != 'windows-latest' && env.RUSTC_WRAPPER || '' }}
- name: Count the tests the archive selects
shell: bash
run: |
set -euo pipefail
cargo nextest list --archive-file "$RUNNER_TEMP/test-archive/nextest-archive.tar.zst" \
--workspace-remap . --profile ci --message-format json > "$RUNNER_TEMP/test-listing.json"
tests="$(python3 -I scripts/ci/nextest-shard-count.py list "$RUNNER_TEMP/test-listing.json")"
printf '{"os": "%s", "tests": %s, "shards": %s}\n' "${{ inputs.os }}" "$tests" "${{ inputs.shards }}" \
> "$RUNNER_TEMP/test-expected/expected-${{ inputs.os }}.json"
cat "$RUNNER_TEMP/test-expected/expected-${{ inputs.os }}.json"
- name: Run doctests
# nextest does not run doctests; this keeps them once per OS.
shell: bash
run: sh scripts/with-hermetic-test-home.sh cargo test --workspace --all-features --locked --doc
env:
RUSTC_WRAPPER: ${{ inputs.os != 'windows-latest' && env.RUSTC_WRAPPER || '' }}
RUST_MIN_STACK: '16777216'
- name: Lockfile drift guard
run: git diff --exit-code -- Cargo.lock
- name: sccache stats
if: steps.sccache.outcome == 'success'
continue-on-error: true
shell: bash
run: sccache --show-stats
- name: Retain test archive for the shards
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: test-archive-${{ inputs.os }}
path: ${{ runner.temp }}/test-archive/
if-no-files-found: error
retention-days: 1
compression-level: 0
- name: Retain expected test count
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: test-expected-${{ inputs.os }}
path: ${{ runner.temp }}/test-expected/
if-no-files-found: error
retention-days: 7
shard:
name: Shard ${{ matrix.shard }}/${{ inputs.shards }}
needs: build
timeout-minutes: 60
runs-on: ${{ inputs.os }}
strategy:
# A failure in one shard must not erase the others' results; the suite
# gate needs every conclusion.
fail-fast: false
matrix:
shard: ${{ fromJSON(inputs.shard_list) }}
env:
CODEWHALE_EXT_HOST_TESTS: '1'
CODEWHALE_EXT_HOST_BUN_TESTS: '1'
# Give test threads the stack the product gives itself; the reasoning is
# on the shared-process step above and in scripts/dev-cargo.sh.
RUST_MIN_STACK: '16777216'
# The exact-image Native containment tests (and, on Windows, the LPAC
# owner and profile tests) that scripts/compiled-host-native-receipt.py
# requires in ONE JUnit report. Shard 1 runs them in their own nextest
# invocation and every shard excludes them from its partition, so each
# still runs exactly once. release-workflows.test.js keeps this list equal
# to the script's.
NATIVE_FILTER: >-
package(codewhale-engine) & kind(lib) & (
test(=extension_host::tests::compiled_native_host_cannot_read_secrets_or_write_outside_its_data_dir) |
test(=extension_host::tests::compiled_native_host_memory_cap_is_enforced) |
test(=extension_host::windows::tests::windows_native_lpac_node_owner_boundary) |
test(=extension_host::windows::tests::windows_native_lpac_bun_owner_boundary) |
test(=extension_host::windows::tests::windows_native_lpac_compiled_owner_boundary) |
test(=extension_host::windows::tests::windows_native_profiles_are_distinct_and_acl_grant_refuses_junctions) |
test(=extension_host::windows::tests::windows_argv_and_environment_keep_exact_values_and_reject_nul) |
test(=extension_host::windows::tests::windows_profile_retirement_removes_only_its_grants_and_inherited_data_on_restarts) |
test(=extension_host::windows::tests::windows_profile_directory_budget_and_recorded_identity_refuse_before_overwrite))
steps:
- uses: actions/checkout@v7
- name: Point terminal failure diagnostics at the runner temp directory
shell: bash
run: echo "QA_PTY_DIAGNOSTICS_DIR=${RUNNER_TEMP}/pty-failures" >> "${GITHUB_ENV}"
- uses: dtolnay/rust-toolchain@stable
- name: Install Linux system dependencies
if: inputs.os == 'ubuntu-latest'
run: |
bash scripts/ci-apt-install.sh libdbus-1-dev pkg-config bubblewrap apparmor-profiles
sh scripts/prepare-linux-test-sandbox.sh
- uses: taiki-e/install-action@nextest
- uses: actions/[email protected]
# The extension-host integration tests spawn the real bundle under
# Node >= 22.19; CODEWHALE_EXT_HOST_TESTS makes a missing Node a
# failure instead of a silent skip.
with:
node-version: 22
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2
with:
bun-version: 1.4.0
- name: Build matching compiled-host input for required Native containment receipts
shell: bash
run: bash scripts/ci/compiled-host-test-input.sh
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
with:
name: test-archive-${{ inputs.os }}
path: ${{ runner.temp }}/test-archive
- name: Place the canonical executable for acceptance tests
shell: bash
run: |
set -euo pipefail
mkdir -p target/debug
cp "$RUNNER_TEMP"/test-archive/codewhale* target/debug/
if [ "$RUNNER_OS" != Windows ]; then chmod +x target/debug/codewhale; fi
- name: Run native containment tests
if: matrix.shard == 1
shell: bash
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/test-count" "$RUNNER_TEMP/nextest-extract"
sh scripts/with-hermetic-test-home.sh cargo nextest run \
--archive-file "$RUNNER_TEMP/test-archive/nextest-archive.tar.zst" \
--extract-to "$RUNNER_TEMP/nextest-extract" --extract-overwrite \
--workspace-remap . --profile ci -E "$NATIVE_FILTER"
cp target/nextest/ci/junit.xml "$RUNNER_TEMP/native-junit.xml"
python3 -I scripts/ci/nextest-shard-count.py junit "$RUNNER_TEMP/native-junit.xml" > "$RUNNER_TEMP/native-count.txt"
- name: Run tests
# Same test binaries as `cargo test`, run by cargo-nextest: one
# process per test, all runner cores busy, slow tests named instead
# of stalling the binary. `.config/nextest.toml` serializes the PTY
# binary and bounds the integration binary that spawns the real
# executable; retries are off, so a flake is a red run, not a hidden
# one. This shard runs partition k of N of everything except the
# native containment tests; test-suite proves the shards add up to the
# archive's full list.
shell: bash
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/test-count" "$RUNNER_TEMP/nextest-extract"
monitor=
if [ "$RUNNER_OS" = Linux ]; then
# Headroom trace: if the runner is terminated again, the last lines
# say whether memory or disk ran out.
( while sleep 30; do
echo "[headroom] $(free -m | awk '/^Mem:/{print "mem used " $3 "/" $2 " MiB"} /^Swap:/{print "swap used " $3 "/" $2 " MiB"}' | paste -sd ' ') disk free $(df -h / | awk 'NR==2{print $4}')"
done ) &
monitor=$!
fi
status=0
sh scripts/with-hermetic-test-home.sh cargo nextest run \
--archive-file "$RUNNER_TEMP/test-archive/nextest-archive.tar.zst" \
--extract-to "$RUNNER_TEMP/nextest-extract" --extract-overwrite \
--workspace-remap . --profile ci \
--partition "count:${{ matrix.shard }}/${{ inputs.shards }}" \
-E "not ($NATIVE_FILTER)" || status=$?
if [ -n "$monitor" ]; then kill "$monitor" 2>/dev/null || true; fi
if [ "$status" -ne 0 ]; then exit "$status"; fi
tests="$(python3 -I scripts/ci/nextest-shard-count.py junit target/nextest/ci/junit.xml)"
if [ -f "$RUNNER_TEMP/native-count.txt" ]; then tests=$((tests + $(cat "$RUNNER_TEMP/native-count.txt"))); fi
printf '{"os": "%s", "shard": %s, "tests": %s}\n' "${{ inputs.os }}" "${{ matrix.shard }}" "$tests" \
> "$RUNNER_TEMP/test-count/shard-${{ inputs.os }}-${{ matrix.shard }}.json"
cat "$RUNNER_TEMP/test-count/shard-${{ inputs.os }}-${{ matrix.shard }}.json"
- name: Retain sealed terminal failure diagnostics
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: terminal-failures-${{ runner.os }}-${{ matrix.shard }}-${{ github.sha }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/pty-failures/
include-hidden-files: true
if-no-files-found: ignore
retention-days: 7
- name: Export exact compiled-image Native containment receipt
# JUnit is from the same archive's native invocation: no second
# compile. The official entire CI run must be green before release can
# consume this artifact. Missing/changed inputs or silent test skips
# are red.
if: matrix.shard == 1
shell: bash
run: |
set -euo pipefail
test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
git diff --exit-code
git diff --cached --exit-code
python3 scripts/compiled-host-native-receipt.py \
--junit "$RUNNER_TEMP/native-junit.xml" \
--compiled-image "$CODEWHALE_COMPILED_HOST_TEST_BINARY" \
--bundle crates/engine/extension-host/dist/codewhale-extension-host.mjs \
--bun "$CODEWHALE_COMPILED_HOST_TEST_BUN" --source-sha "$GITHUB_SHA" \
--image-platform "$CODEWHALE_COMPILED_HOST_TEST_PLATFORM" --image-arch "$CODEWHALE_COMPILED_HOST_TEST_ARCH" \
--host-sha256 "$CODEWHALE_COMPILED_HOST_TEST_SHA256" \
--runtime-sha256 "$CODEWHALE_COMPILED_HOST_TEST_RUNTIME_SHA256" \
--bundle-sha256 "$CODEWHALE_COMPILED_HOST_TEST_BUNDLE_SHA256" \
--output "$RUNNER_TEMP/native-compiled-host"
- name: Retain exact compiled image and Native receipt
if: matrix.shard == 1
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: native-compiled-host-${{ runner.os }}-${{ runner.arch }}
path: ${{ runner.temp }}/native-compiled-host/
if-no-files-found: error
retention-days: 30
- name: Lockfile drift guard
run: git diff --exit-code -- Cargo.lock
- name: Retain shard test count
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: test-count-${{ inputs.os }}-${{ matrix.shard }}
path: ${{ runner.temp }}/test-count/
if-no-files-found: error
retention-days: 7
check:
# The job that answers "did this OS's whole suite pass": the build and every
# shard succeeded, and the shards together ran exactly the tests the archive
# lists. Not a required check (§180).
name: Suite check
needs: [build, shard]
if: '!cancelled()'
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
sparse-checkout: scripts/ci
- name: Every build and shard succeeded
shell: bash
env:
BUILD_RESULT: ${{ needs.build.result }}
SHARD_RESULT: ${{ needs.shard.result }}
run: |
echo "build: ${BUILD_RESULT}"
echo "shard: ${SHARD_RESULT}"
if [ "${BUILD_RESULT}" != success ] || [ "${SHARD_RESULT}" != success ]; then
echo "::error::The sharded suite did not complete successfully."
exit 1
fi
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
with:
name: test-expected-${{ inputs.os }}
path: counts
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
with:
pattern: test-count-${{ inputs.os }}-*
path: counts
merge-multiple: true
- name: Shards ran every listed test exactly once
run: python3 -I scripts/ci/nextest-shard-count.py check counts
+316 -315
View File
@@ -16,13 +16,32 @@ on:
options:
- nextest
- shared-process-twice
crate:
description: Scoped run, in a few minutes. One workspace package (for example codewhale-tui); with crate or filter set only the scoped test runs, not the full suite
required: false
default: ''
type: string
filter:
description: Scoped run, in a few minutes. A nextest filterset (for example 'test(auto_review)'), alone or with crate; with crate or filter set only the scoped test runs
required: false
default: ''
type: string
os:
description: Operating systems for a scoped run, comma separated (ubuntu-latest, macos-latest, windows-latest, or all); ignored by a full run
required: false
default: ubuntu-latest
type: string
permissions:
contents: read
# A new push to a pull request, or a new dispatch on the same non-main branch
# (an agent's ci/<task> branch), cancels the older run still in progress.
# Runs on main are keyed by SHA and never cancel each other, and a scoped
# dispatch gets its own group so it cannot cancel a full run on the same branch.
concurrency:
group: ${{ github.event_name == 'pull_request' && format('ci-pr-{0}', github.event.pull_request.number) || format('ci-{0}-{1}', github.workflow, github.sha) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
group: ${{ github.event_name == 'pull_request' && format('ci-pr-{0}', github.event.pull_request.number) || (github.event_name == 'workflow_dispatch' && (inputs.crate != '' || inputs.filter != '') && format('ci-scoped-{0}', github.run_id)) || (github.ref != 'refs/heads/main' && format('ci-ref-{0}', github.ref)) || format('ci-{0}-{1}', github.workflow, github.sha) }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !(github.event_name == 'workflow_dispatch' && (inputs.crate != '' || inputs.filter != '')) }}
env:
CARGO_TERM_COLOR: always
@@ -45,6 +64,8 @@ jobs:
mobile: ${{ steps.detect.outputs.mobile }}
actions: ${{ steps.detect.outputs.actions }}
trusted: ${{ steps.trust.outputs.trusted }}
scoped: ${{ steps.scope.outputs.scoped }}
scoped_os: ${{ steps.scope.outputs.scoped_os }}
steps:
- name: Classify event trust
id: trust
@@ -64,6 +85,48 @@ jobs:
else
echo "trusted=false" >> "$GITHUB_OUTPUT"
fi
- name: Classify scoped dispatch
id: scope
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
SCOPE_CRATE: ${{ inputs.crate }}
SCOPE_FILTER: ${{ inputs.filter }}
SCOPE_OS: ${{ inputs.os }}
run: |
set -euo pipefail
# A dispatch with a crate or a filter runs only the scoped test job.
# Inputs reach the shell only through env, and the crate and OS
# names are validated before anything uses them.
scoped=false
scoped_os='["ubuntu-latest"]'
if [[ "${EVENT_NAME}" == "workflow_dispatch" && ( -n "${SCOPE_CRATE}" || -n "${SCOPE_FILTER}" ) ]]; then
scoped=true
if [[ -n "${SCOPE_CRATE}" && ! "${SCOPE_CRATE}" =~ ^[A-Za-z0-9_-]+$ ]]; then
echo "::error::crate must be a package name (letters, digits, - and _)." >&2
exit 1
fi
oses=()
IFS=',' read -r -a requested <<< "${SCOPE_OS:-ubuntu-latest}"
for name in "${requested[@]}"; do
name="${name//[[:space:]]/}"
case "${name}" in
ubuntu|ubuntu-latest|linux) oses+=("ubuntu-latest") ;;
macos|macos-latest) oses+=("macos-latest") ;;
windows|windows-latest) oses+=("windows-latest") ;;
all) oses+=("ubuntu-latest" "macos-latest" "windows-latest") ;;
"") ;;
*)
echo "::error::os entries must be ubuntu-latest, macos-latest, windows-latest or all." >&2
exit 1
;;
esac
done
if [[ "${#oses[@]}" -eq 0 ]]; then oses=("ubuntu-latest"); fi
scoped_os="$(printf '%s\n' "${oses[@]}" | sort -u | jq -R . | jq -sc .)"
fi
echo "scoped=${scoped}" >> "${GITHUB_OUTPUT}"
echo "scoped_os=${scoped_os}" >> "${GITHUB_OUTPUT}"
- uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -197,6 +260,8 @@ jobs:
versions:
name: Version drift
needs: changes
if: needs.changes.outputs.scoped != 'true'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
@@ -274,6 +339,8 @@ jobs:
plugin-conversion:
name: Plugin conversion
needs: changes
if: needs.changes.outputs.scoped != 'true'
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
@@ -293,6 +360,8 @@ jobs:
integrations:
name: Integrations
needs: changes
if: needs.changes.outputs.scoped != 'true'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
@@ -349,7 +418,7 @@ jobs:
extension-host-runtimes:
name: Extension host runtimes (${{ matrix.os }})
needs: changes
if: needs.changes.outputs.heavy == 'true'
if: needs.changes.outputs.heavy == 'true' && needs.changes.outputs.scoped != 'true'
timeout-minutes: 15
strategy:
fail-fast: false
@@ -388,6 +457,8 @@ jobs:
vscode-extension:
name: VS Code extension
needs: changes
if: needs.changes.outputs.scoped != 'true'
timeout-minutes: 15
runs-on: ubuntu-latest
defaults:
@@ -421,7 +492,7 @@ jobs:
safety-gate:
name: Safety gate
needs: changes
if: github.event_name == 'workflow_dispatch' && needs.changes.outputs.heavy == 'true'
if: needs.changes.outputs.heavy == 'true' && needs.changes.outputs.scoped != 'true'
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
@@ -431,16 +502,18 @@ jobs:
toolchain: stable
- uses: mozilla-actions/[email protected]
id: sccache
# The GitHub Actions cache backend is main-only, mirroring
# rust-cache's save-if: PR runs wrote thousands of refs/pull/N
# entries that pushed the repo past its 10 GiB cache cap.
if: github.ref == 'refs/heads/main'
# Every run reads the cache main wrote; only main writes it
# (SCCACHE_GHA_RW_MODE in Enable sccache), mirroring rust-cache's
# save-if. PR runs once wrote thousands of refs/pull/N entries that
# pushed the repo past its 10 GiB cache cap.
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
@@ -475,6 +548,7 @@ jobs:
lint:
name: Lint
needs: changes
if: needs.changes.outputs.scoped != 'true'
# Measured on 89ee629e with runner headroom: clippy 10 min, runtime-contract
# budget 16 min, and persistence-backlog still running at the old 45-minute
# cancellation. Commands, filters and budgets are unchanged.
@@ -494,13 +568,15 @@ jobs:
# Cache bootstrap failures (e.g. GitHub 504s fetching the sccache
# binary) degrade to an uncached build instead of failing product CI.
continue-on-error: true
# Main-only GitHub Actions cache backend; see the Safety gate job.
if: needs.changes.outputs.heavy == 'true' && github.ref == 'refs/heads/main'
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
if: needs.changes.outputs.heavy == 'true'
- name: Enable sccache
if: needs.changes.outputs.heavy == 'true' && steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
@@ -725,7 +801,7 @@ jobs:
# fail the build there while stable stays green (#6543).
name: MSRV check (1.89)
needs: changes
if: github.event_name == 'workflow_dispatch' && needs.changes.outputs.heavy == 'true'
if: needs.changes.outputs.heavy == 'true' && needs.changes.outputs.scoped != 'true'
timeout-minutes: 45
runs-on: ubuntu-latest
steps:
@@ -746,7 +822,7 @@ jobs:
workflow-rlm-cache:
name: Workflow RLM cache
needs: changes
if: needs.changes.outputs.workflow == 'true'
if: needs.changes.outputs.workflow == 'true' && needs.changes.outputs.scoped != 'true'
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
@@ -754,14 +830,15 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/[email protected]
id: sccache
# Main-only GitHub Actions cache backend; see the Safety gate job.
if: github.ref == 'refs/heads/main'
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- uses: Swatinem/rust-cache@v2
@@ -772,261 +849,64 @@ jobs:
run: sh scripts/with-hermetic-test-home.sh cargo test -p codewhale-workflow --locked
test:
name: Test
# Manual shared-process qualification only (workspace_test_mode =
# shared-process-twice): the GH6698 evidence of two libtest passes at one
# exact revision on one hosted Ubuntu runner. Every other run executes the
# suite through test-build, test-shard and test-suite below.
name: Shared-process tests
needs: changes
if: github.event_name == 'workflow_dispatch'
# Contexts "Test (ubuntu-latest)" / "Test (macos-latest)" /
# "Test (windows-latest)" derive from job name + matrix.os and are
# independent of runs-on. For light changes the macOS/Windows legs only
# echo a skip line, so run them on ubuntu instead of queueing for scarce
# macOS/Windows runners. Pull requests run only the Linux leg here; the
# required "Test (windows-latest)" context comes from test-windows-pr.
# The ternary is safe: matrix.os is always a non-empty literal, so
# runs-on can never evaluate to empty.
# A cold GitHub-hosted Mac spent 77-80 minutes in Test on 2026-09-23
# (fork PRs #6431, #6417), too close to the old 90-minute limit.
# On 2026-10-04 a PR leg spent 111 minutes compiling with no cache and
# was cancelled at 120 with 12,356 tests passed and none failed. The
# limit stays a literal (release-workflows.test.js, #5496); 210 bounds
# cold compilation and the complete suite without disabling test deadlines.
if: github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice' && needs.changes.outputs.heavy == 'true' && needs.changes.outputs.scoped != 'true'
# A cold GitHub-hosted runner spent 111 minutes compiling with no cache on
# 2026-10-04. The limit stays a literal (release-workflows.test.js, #5496);
# 210 bounds cold compilation and both complete passes.
timeout-minutes: 210
# macOS legs go to the self-hosted Mac ONLY when all three hold: the
# change is heavy, the event is trusted (not a fork PR), and the
# CW_SELF_HOSTED_MAC repo variable is 'true'. That variable is the kill
# switch: unset it and every leg falls back to GitHub-hosted runners
# immediately, with no commit — important because an offline
# self-hosted runner queues jobs forever, which is worse than a slow one.
runs-on: ${{ needs.changes.outputs.heavy != 'true' && 'ubuntu-latest' || (matrix.os == 'macos-latest' && needs.changes.outputs.trusted == 'true' && vars.CW_SELF_HOSTED_MAC == 'true' && fromJSON('["self-hosted","macOS","ARM64","codewhale-mac"]')) || matrix.os }}
strategy:
# A failure on one desktop platform must not erase evidence from the
# other one. We need both conclusions to diagnose and release safely.
fail-fast: false
matrix:
# Pull requests run the Linux workspace suite only; the macOS and
# Windows suites run in final validation. The explicit manual
# libtest qualification uses one hosted Ubuntu job, never a fork PR or
# self-hosted runner; normal dispatches keep all three legs.
os: ${{ fromJSON((github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')) && '["ubuntu-latest"]' || '["ubuntu-latest","macos-latest","windows-latest"]') }}
runs-on: ubuntu-latest
steps:
- name: Skip tests for light change
if: needs.changes.outputs.heavy != 'true'
run: echo "No executable Rust changes detected; preserving required Test context."
- uses: actions/checkout@v7
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Test Windows installer PATH helper
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/update-user-path.tests.ps1
- name: Install NSIS for Windows installer regression
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/install-nsis.ps1
- name: Test Windows installer PATH regression
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
shell: pwsh
run: ./scripts/installer/installer-path-regression.tests.ps1 -AllowUserPathMutation
- uses: dtolnay/rust-toolchain@stable
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Install macOS LLVM tools
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'macos-latest'
run: rustup component add llvm-tools --toolchain stable
- name: Omit macOS build debug metadata
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'macos-latest'
shell: bash
# Match the existing full-workspace CNB gate. Keep debug assertions and
# every test; only disposable build debug tables change on this lane.
run: printf '%s\n' 'CARGO_PROFILE_DEV_DEBUG=0' 'CARGO_PROFILE_TEST_DEBUG=0' >> "$GITHUB_ENV"
- uses: mozilla-actions/[email protected]
id: sccache
continue-on-error: true
# Main-only GitHub Actions cache backend; see the Safety gate job.
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && github.ref == 'refs/heads/main'
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
- name: Enable sccache
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success'
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && (github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: |
bash scripts/ci-apt-install.sh libdbus-1-dev pkg-config bubblewrap apparmor-profiles
sh scripts/prepare-linux-test-sandbox.sh
- name: Ubuntu build headroom
# Reuse the same fixed hosted-runner provisioning as Safety and Lint.
# Exit 143 is a shutdown observation, not proof of OOM or timeout.
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && (github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
shell: bash
run: bash scripts/prepare-ubuntu-build-headroom.sh
- uses: Swatinem/rust-cache@v2
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- uses: taiki-e/install-action@nextest
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Check portable config policy boundary
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && (github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
shell: bash
run: |
python3 -B scripts/test_check_command_config_proof.py
sh scripts/check-portable-config.sh
- name: Check portable core navigation boundary
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && (github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
shell: bash
run: |
python3 -B scripts/test_check_command_core_navigation_proof.py
sh scripts/check-portable-core-navigation.sh
- uses: actions/[email protected]
# The extension-host integration tests spawn the real bundle under
# Node >= 22.19; CODEWHALE_EXT_HOST_TESTS below makes a missing Node a
# failure instead of a silent skip.
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
with:
node-version: 22
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
with:
bun-version: 1.4.0
- name: Build matching compiled-host input for required Native containment receipts
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
shell: bash
run: |
set -euo pipefail
bun_binary="$(bun -p 'process.execPath')"
host_binary="$(node -p "require('path').join(process.env.RUNNER_TEMP, 'codewhale-extension-host' + (process.platform === 'win32' ? '.exe' : ''))")"
compiled_info="$(node crates/engine/extension-host/compile-host.mjs --bun "$bun_binary" --output "$host_binary")"
printf 'CODEWHALE_COMPILED_HOST_TEST_BINARY=%s\n' "$host_binary" >> "$GITHUB_ENV"
node - "$host_binary" "$bun_binary" "$compiled_info" >> "$GITHUB_ENV" <<'JS'
const fs = require('node:fs'), crypto = require('node:crypto');
const digest = (file) => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
const info = JSON.parse(process.argv[4]);
if (!info.platform || !info.arch || info.platform !== info.compiler?.platform || info.arch !== info.compiler?.arch) throw new Error('image/compiler identity mismatch');
console.log('CODEWHALE_COMPILED_HOST_TEST_PLATFORM=' + info.platform);
console.log('CODEWHALE_COMPILED_HOST_TEST_ARCH=' + info.arch);
console.log('CODEWHALE_COMPILED_HOST_TEST_SHA256=' + digest(process.argv[2]));
console.log('CODEWHALE_COMPILED_HOST_TEST_BUN=' + process.argv[3]);
console.log('CODEWHALE_COMPILED_HOST_TEST_RUNTIME_SHA256=' + digest(process.argv[3]));
console.log('CODEWHALE_COMPILED_HOST_TEST_BUNDLE_SHA256=' + digest('crates/engine/extension-host/dist/codewhale-extension-host.mjs'));
JS
# The required hermetic full invocation executes the shared actual
# compiled Native secret/history/write scenario on each OS; Windows
# additionally requires Node/Bun/compiled LPAC owner/reparse probes.
# Missing requested compiled input or a failed sandbox is red.
- name: Hold this machine's build lock (self-hosted)
# The self-hosted Mac is also a developer machine: local agents build
# through scripts/dev-cargo.sh, which holds this lock, and two Cargo
# builds at once exhaust its memory. Opt-in: the runner's `.env` names
# the same file as CODEWHALE_BUILD_LOCK_FILE. The holder is a
# background process; the runner kills orphans when the job ends, so a
# cancelled or crashed job cannot leave the lock held.
# (`env.*` in `if:` cannot see the runner's `.env`, so the opt-in is
# checked in the script.)
if: needs.changes.outputs.heavy == 'true' && runner.environment == 'self-hosted'
shell: bash
run: |
if [ -z "${CODEWHALE_BUILD_LOCK_FILE:-}" ]; then
echo "CODEWHALE_BUILD_LOCK_FILE is not set on this runner; building without the machine lock."
exit 0
fi
hold="$RUNNER_TEMP/cw-build-lock.hold"
ready="$RUNNER_TEMP/cw-build-lock.ready"
log="$RUNNER_TEMP/cw-build-lock.log"
touch "$hold"
rm -f "$ready"
# The single quotes are deliberate: the inner sh expands $1/$2.
# shellcheck disable=SC2016
nohup python3 scripts/build-lock.py "$CODEWHALE_BUILD_LOCK_FILE" -- \
sh -c 'touch "$1"; while [ -e "$2" ]; do sleep 2; done' _ "$ready" "$hold" \
>"$log" 2>&1 &
shown=0
until [ -e "$ready" ]; do
if [ "$shown" -eq 0 ] && [ -s "$log" ]; then cat "$log"; shown=1; fi
sleep 2
done
cat "$log"
# Scripts inside this job already run under the lock.
echo "CODEWHALE_BUILD_LOCK_HELD=1" >> "$GITHUB_ENV"
run: bash scripts/ci/compiled-host-test-input.sh
- name: Build canonical executable for acceptance tests
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
shell: bash
run: cargo build -p codewhale-cli --bin codewhale --all-features --locked
env:
RUSTC_WRAPPER: ${{ matrix.os != 'windows-latest' && env.RUSTC_WRAPPER || '' }}
- name: Windows Terminal clipboard-to-draft acceptance
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'windows-latest'
timeout-minutes: 5
shell: pwsh
run: node scripts/release/windows-terminal-clipboard.mjs target/debug/codewhale.exe "${{ runner.temp }}/windows-clipboard"
- name: Retain Windows Terminal clipboard-to-draft evidence
if: ${{ !cancelled() && matrix.os == 'windows-latest' && needs.changes.outputs.heavy == 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: windows-clipboard-${{ github.sha }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/windows-clipboard/
if-no-files-found: error
retention-days: 7
- name: Run tests
# Same test binaries as `cargo test`, run by cargo-nextest: one
# process per test, all runner cores busy, slow tests named instead
# of stalling the binary. `.config/nextest.toml` serializes the PTY
# binary and bounds the integration binary that spawns the real
# executable; retries are off, so a flake is a red run, not a hidden
# one. nextest does not run doctests — the next step keeps them.
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && !(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
shell: bash
run: |
monitor=
if [ "$RUNNER_OS" = Linux ]; then
# Headroom trace: if the runner is terminated again, the last lines
# say whether memory or disk ran out.
( while sleep 30; do
echo "[headroom] $(free -m | awk '/^Mem:/{print "mem used " $3 "/" $2 " MiB"} /^Swap:/{print "swap used " $3 "/" $2 " MiB"}' | paste -sd ' ') disk free $(df -h / | awk 'NR==2{print $4}')"
done ) &
monitor=$!
fi
status=0
sh scripts/with-hermetic-test-home.sh cargo nextest run --workspace --all-features --locked --profile ci || status=$?
if [ -n "$monitor" ]; then kill "$monitor" 2>/dev/null || true; fi
exit "$status"
env:
CARGO_BUILD_JOBS: '1'
QA_PTY_DIAGNOSTICS_DIR: ${{ runner.temp }}/pty-failures
CODEWHALE_EXT_HOST_TESTS: '1'
CODEWHALE_EXT_HOST_BUN_TESTS: '1'
# sccache 0.17 panics resolving its config directory under the
# isolated Windows home before Cargo can compile or run any test.
# Bypass only that optional cache; keep the full suite and isolation.
RUSTC_WRAPPER: ${{ matrix.os != 'windows-latest' && env.RUSTC_WRAPPER || '' }}
# Give test threads the stack the product gives itself. main.rs runs
# the owner thread and every tokio worker at
# CODEWHALE_MAIN_STACK_BYTES (32 MiB) because the engine and
# runtime-thread futures are genuinely deep. `#[tokio::test]` builds
# its own runtime and never sees that, so tests ran the same code on
# ~2 MiB (~1 MiB on Windows) — a configuration that never ships.
# That gap is what aborted the whole Windows test binary with
# STATUS_STACK_OVERFLOW in start_turn_accepts_dynamic_tools_and_
# environment_id, masking every other Windows result (78afd8d3d4
# Box::pin'd that one frame; the mismatch itself remained). std reads
# this for any thread spawned without an explicit size, which covers
# both libtest's per-test threads and tokio's workers. Test threads
# hold 16 MiB: the engine-only chains they run measured a ~2.5 MiB
# debug high-water, while the full ~16.5 MiB UI-loop chain that
# forced 32 MiB lives in spawned binaries, which size their own
# stacks explicitly and never read this variable.
RUST_MIN_STACK: '16777216'
- name: Retain sealed terminal failure diagnostics
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: terminal-failures-${{ runner.os }}-${{ github.sha }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/pty-failures/
include-hidden-files: true
if-no-files-found: ignore
retention-days: 7
- name: Shared-process workspace qualification
if: github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice' && matrix.os == 'ubuntu-latest'
if: github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice'
shell: bash
env:
CARGO_BUILD_JOBS: '1'
@@ -1128,83 +1008,193 @@ jobs:
cat "$evidence/results.txt"
exit "$failed"
- name: Retain shared-process qualification evidence
if: always() && github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice' && matrix.os == 'ubuntu-latest'
if: always() && github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice'
uses: actions/upload-artifact@v7
with:
name: shared-process-workspace-${{ github.sha }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/shared-process-workspace/
if-no-files-found: error
retention-days: 30
- name: Export exact compiled-image Native containment receipt
# JUnit is from the same full invocation: no second compile/test run.
# The official entire CI run must be green before release can consume
# this artifact. Missing/changed inputs or silent test skips are red.
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && !(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
# One sharded pipeline per OS (ci-test-suite.yml). Shard counts follow the
# measured serial test time of each OS (2026-11-12, run 43216596942: Linux 19
# min, macOS 24 min, Windows 25 min of test execution, on top of 30 to 65
# minutes of single-job compilation), so a shard is five to eight minutes of
# tests plus setup. Hosted macOS is the scarce pool, so it gets three shards.
# The caller names ("Sharded tests (...)") never equal the required
# "Test (windows-latest)" context, which test-windows-pr still produces on
# every pull request.
test-ubuntu:
name: Sharded tests (ubuntu-latest)
needs: changes
if: >-
needs.changes.outputs.heavy == 'true' &&
needs.changes.outputs.scoped != 'true' &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') &&
!(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
uses: ./.github/workflows/ci-test-suite.yml
with:
os: ubuntu-latest
shards: 4
shard_list: '[1,2,3,4]'
build_jobs: '2'
debug: line-tables-only
test-macos:
name: Sharded tests (macos-latest)
needs: changes
if: >-
needs.changes.outputs.heavy == 'true' &&
needs.changes.outputs.scoped != 'true' &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') &&
!(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
uses: ./.github/workflows/ci-test-suite.yml
with:
os: macos-latest
shards: 3
shard_list: '[1,2,3]'
build_jobs: '1'
debug: '0'
test-windows:
name: Sharded tests (windows-latest)
needs: changes
if: >-
needs.changes.outputs.heavy == 'true' &&
needs.changes.outputs.scoped != 'true' &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') &&
!(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
uses: ./.github/workflows/ci-test-suite.yml
with:
os: windows-latest
shards: 4
shard_list: '[1,2,3,4]'
build_jobs: '2'
debug: '0'
portable-boundaries:
name: Portable boundaries
needs: changes
if: >-
needs.changes.outputs.heavy == 'true' &&
needs.changes.outputs.scoped != 'true' &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
timeout-minutes: 45
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/[email protected]
id: sccache
continue-on-error: true
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
run: |
bash scripts/ci-apt-install.sh libdbus-1-dev pkg-config bubblewrap apparmor-profiles
sh scripts/prepare-linux-test-sandbox.sh
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- uses: taiki-e/install-action@nextest
- uses: actions/[email protected]
with:
node-version: 22
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2
with:
bun-version: 1.4.0
- name: Check portable config policy boundary
shell: bash
run: |
python3 -B scripts/test_check_command_config_proof.py
sh scripts/check-portable-config.sh
- name: Check portable core navigation boundary
shell: bash
run: |
python3 -B scripts/test_check_command_core_navigation_proof.py
sh scripts/check-portable-core-navigation.sh
scoped-test:
# workflow_dispatch with `crate` and/or `filter`: one package or one nextest
# filterset on the chosen OSes (default ubuntu-latest) instead of the full
# suite. `changes` skips every other job for such a run. The build uses the
# same flags as the full build; only `-p` and `-E` narrow what runs.
name: Scoped test (${{ matrix.os }})
needs: changes
if: needs.changes.outputs.scoped == 'true'
timeout-minutes: 90
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ${{ fromJSON(needs.changes.outputs.scoped_os) }}
env:
CARGO_BUILD_JOBS: ${{ matrix.os == 'macos-latest' && '1' || '2' }}
CARGO_PROFILE_DEV_DEBUG: ${{ matrix.os == 'ubuntu-latest' && 'line-tables-only' || '0' }}
CARGO_PROFILE_TEST_DEBUG: ${{ matrix.os == 'ubuntu-latest' && 'line-tables-only' || '0' }}
CODEWHALE_EXT_HOST_TESTS: '1'
CODEWHALE_EXT_HOST_BUN_TESTS: '1'
RUST_MIN_STACK: '16777216'
SCOPE_CRATE: ${{ inputs.crate }}
SCOPE_FILTER: ${{ inputs.filter }}
steps:
- uses: actions/checkout@v7
- name: Point terminal failure diagnostics at the runner temp directory
shell: bash
run: echo "QA_PTY_DIAGNOSTICS_DIR=${RUNNER_TEMP}/pty-failures" >> "${GITHUB_ENV}"
- uses: dtolnay/rust-toolchain@stable
- name: Install Linux system dependencies
if: matrix.os == 'ubuntu-latest'
run: |
bash scripts/ci-apt-install.sh libdbus-1-dev pkg-config bubblewrap apparmor-profiles
sh scripts/prepare-linux-test-sandbox.sh
- uses: Swatinem/rust-cache@v2
with:
cache-bin: false
save-if: false
- uses: taiki-e/install-action@nextest
- uses: actions/[email protected]
with:
node-version: 22
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2
with:
bun-version: 1.4.0
- name: Build matching compiled-host input for required Native containment receipts
shell: bash
run: bash scripts/ci/compiled-host-test-input.sh
- name: Build canonical executable for acceptance tests
# Acceptance tests in the TUI, engine and CLI crates, and any run that
# names no crate, look for the codewhale binary next to the test
# binaries; a narrow run on another crate does not need it.
if: env.SCOPE_CRATE == '' || env.SCOPE_CRATE == 'codewhale-tui' || env.SCOPE_CRATE == 'codewhale-engine' || env.SCOPE_CRATE == 'codewhale-cli'
shell: bash
run: cargo build -p codewhale-cli --bin codewhale --all-features --locked
- name: Run the scoped tests
shell: bash
run: |
set -euo pipefail
test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
git diff --exit-code
git diff --cached --exit-code
python3 scripts/compiled-host-native-receipt.py \
--junit target/nextest/ci/junit.xml \
--compiled-image "$CODEWHALE_COMPILED_HOST_TEST_BINARY" \
--bundle crates/engine/extension-host/dist/codewhale-extension-host.mjs \
--bun "$CODEWHALE_COMPILED_HOST_TEST_BUN" --source-sha "$GITHUB_SHA" \
--image-platform "$CODEWHALE_COMPILED_HOST_TEST_PLATFORM" --image-arch "$CODEWHALE_COMPILED_HOST_TEST_ARCH" \
--host-sha256 "$CODEWHALE_COMPILED_HOST_TEST_SHA256" \
--runtime-sha256 "$CODEWHALE_COMPILED_HOST_TEST_RUNTIME_SHA256" \
--bundle-sha256 "$CODEWHALE_COMPILED_HOST_TEST_BUNDLE_SHA256" \
--output "$RUNNER_TEMP/native-compiled-host"
- name: Retain exact compiled image and Native receipt
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && !(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
args=(--all-features --locked --profile ci --no-tests=fail)
if [ -n "${SCOPE_CRATE}" ]; then args+=(-p "${SCOPE_CRATE}"); else args+=(--workspace); fi
if [ -n "${SCOPE_FILTER}" ]; then args+=(-E "${SCOPE_FILTER}"); fi
sh scripts/with-hermetic-test-home.sh cargo nextest run "${args[@]}"
- name: Retain sealed terminal failure diagnostics
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: native-compiled-host-${{ runner.os }}-${{ runner.arch }}
path: ${{ runner.temp }}/native-compiled-host/
if-no-files-found: error
retention-days: 30
- name: Run doctests
# The shared-process command already includes every workspace doctest.
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && !(github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice')
shell: bash
run: sh scripts/with-hermetic-test-home.sh cargo test --workspace --all-features --locked --doc
env:
RUSTC_WRAPPER: ${{ matrix.os != 'windows-latest' && env.RUSTC_WRAPPER || '' }}
RUST_MIN_STACK: '16777216'
# The Ubuntu lint lane validates non-RSS backlog fields. Run the same
# source-bound measurement on macOS so loss or growth of RSS evidence
# fails closed instead of becoming an unsupported-field skip.
# Only on the self-hosted Mac: there it reuses the warm build. Every
# hosted Mac leg (fork PRs, or any PR with CW_SELF_HOSTED_MAC off) runs
# it in the separate `macos-budget` job with its own timeout, because
# on a cold hosted Mac it pushed Test past 90 minutes.
- name: Check persistence-backlog RSS budget
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'macos-latest' && needs.changes.outputs.trusted == 'true' && vars.CW_SELF_HOSTED_MAC == 'true'
run: python3 scripts/check-persistence-backlog-budget.py
- name: Lockfile drift guard
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
run: git diff --exit-code -- Cargo.lock
- name: Run Offline Eval Harness
# The eval harness is OS-independent prompt/composition checking;
# running it once (on the faster macOS leg, warm from the test build)
# instead of once per desktop OS keeps the coverage while taking
# ~2min off the Windows critical path. Self-hosted Mac only; hosted
# Mac legs run it in `macos-budget` (see the RSS step above).
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'macos-latest' && needs.changes.outputs.trusted == 'true' && vars.CW_SELF_HOSTED_MAC == 'true'
run: cargo run -p codewhale-cli --bin codewhale --all-features -- eval
- name: sccache stats
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success'
continue-on-error: true
shell: bash
run: sccache --show-stats
- name: Linux test location (CNB)
if: needs.changes.outputs.heavy == 'true' && matrix.os == 'ubuntu-latest' && github.event_name != 'workflow_dispatch' && github.event_name != 'pull_request'
run: echo "Linux workspace tests run on CNB for non-PR release/main pushes; pull requests run directly on Ubuntu."
- name: Release this machine's build lock (self-hosted)
if: always() && runner.environment == 'self-hosted'
shell: bash
run: rm -f "$RUNNER_TEMP/cw-build-lock.hold"
name: terminal-failures-scoped-${{ runner.os }}-${{ github.sha }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/pty-failures/
include-hidden-files: true
if-no-files-found: ignore
retention-days: 7
test-windows-pr:
name: Test (windows-latest)
@@ -1239,7 +1229,7 @@ jobs:
echo "## Test (windows-latest) on a pull request"
echo
echo "Compiled every workspace target for Windows with warnings denied and ran the installer PATH helper tests."
echo "The Windows and macOS test suites run in final validation, before a release, not on pull requests."
echo "The full Windows test suite runs beside this check as Sharded tests (windows-latest); it is not a required check."
} >> "$GITHUB_STEP_SUMMARY"
macos-budget:
@@ -1252,15 +1242,15 @@ jobs:
# macOS leg runs on the self-hosted Mac (trusted event and
# CW_SELF_HOSTED_MAC == 'true'), it runs these two steps on the warm
# build instead. The name keeps "(fork PR)" so check contexts stay stable.
# Hosted macOS allows only five concurrent jobs per account, and this job
# doubled every pull request's claim on them, queueing the required Test
# (macos-latest) leg for hours. So pull requests skip it and every push to
# main still runs it; a regression shows up on the merge that caused it.
# Hosted macOS allows only five concurrent jobs per account, and the macOS
# test build and shards already take most of them, so pull requests skip
# this job and every dispatch (main-landing issues one per push to main)
# still runs it; a regression shows up on the merge that caused it. The
# sharded macOS suite never runs on the self-hosted Mac, so these gates no
# longer depend on CW_SELF_HOSTED_MAC.
name: macOS budget and eval (fork PR)
needs: changes
# The explicit Ubuntu-only qualification has no warm Test macOS leg, so
# retain these gates on the hosted fallback even when self-hosting is on.
if: needs.changes.outputs.heavy == 'true' && github.event_name != 'pull_request' && ((github.event_name == 'workflow_dispatch' && inputs.workspace_test_mode == 'shared-process-twice') || !(needs.changes.outputs.trusted == 'true' && vars.CW_SELF_HOSTED_MAC == 'true'))
if: needs.changes.outputs.heavy == 'true' && needs.changes.outputs.scoped != 'true' && github.event_name != 'pull_request'
# Cold hosted builds consumed 73 minutes before eval could start (F run
# 37497498829). Match Test's compile allowance; RSS/eval limits stay intact.
timeout-minutes: 210
@@ -1282,9 +1272,10 @@ jobs:
npm-wrapper-smoke:
name: npm wrapper smoke
needs: changes
if: github.event_name == 'workflow_dispatch'
# Same ternary rationale as the Test job: light legs only echo, so keep
# them off macOS/Windows runners. On pull_request the matrix is
if: needs.changes.outputs.scoped != 'true' && (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
# Light legs only echo, so keep them off macOS/Windows runners. The
# ternary is safe: matrix.os is always a non-empty literal. On
# pull_request the matrix is
# ubuntu-only, so the required "npm wrapper smoke (ubuntu-latest)"
# context is unaffected. Heavy pull requests execute the Ubuntu smoke
# here; their branches may not be mirrored to CNB.
@@ -1310,13 +1301,15 @@ jobs:
- uses: mozilla-actions/[email protected]
id: sccache
continue-on-error: true
# Main-only GitHub Actions cache backend; see the Safety gate job.
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && github.ref == 'refs/heads/main'
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request')
- name: Enable sccache
if: needs.changes.outputs.heavy == 'true' && (matrix.os != 'ubuntu-latest' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && steps.sccache.outcome == 'success' && matrix.os != 'windows-latest'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- uses: actions/[email protected]
@@ -1358,8 +1351,14 @@ jobs:
mobile-smoke:
name: Mobile runtime smoke
needs: changes
# Manual (workflow_dispatch) only; the release candidate builds android-arm64.
if: github.event_name == 'workflow_dispatch' && needs.changes.outputs.heavy == 'true'
# Not a required PR context. Pull requests run it only when the mobile
# runtime surface changed (see the `mobile` filter above); every dispatch,
# which main-landing issues for each push to main, runs it unconditionally
# as the pre-release safety net.
if: >-
needs.changes.outputs.scoped != 'true' &&
needs.changes.outputs.heavy == 'true' &&
(github.event_name != 'pull_request' || needs.changes.outputs.mobile == 'true')
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
@@ -1367,14 +1366,15 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/[email protected]
id: sccache
# Main-only GitHub Actions cache backend; see the Safety gate job.
if: github.ref == 'refs/heads/main'
# Every run reads the GitHub Actions cache main wrote; only main writes (see Enable sccache).
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success'
shell: bash
run: |
echo "SCCACHE_GHA_ENABLED=true" >> "${GITHUB_ENV}"
if [ "${GITHUB_REF}" = refs/heads/main ]; then rw=READ_WRITE; else rw=READ_ONLY; fi
echo "SCCACHE_GHA_RW_MODE=${rw}" >> "${GITHUB_ENV}"
echo "RUSTC_WRAPPER=sccache" >> "${GITHUB_ENV}"
echo "SCCACHE_IGNORE_SERVER_IO_ERROR=1" >> "${GITHUB_ENV}"
- name: Install Linux system dependencies
@@ -1401,7 +1401,7 @@ jobs:
actionlint:
name: Workflow lint
needs: changes
if: needs.changes.outputs.actions == 'true'
if: needs.changes.outputs.actions == 'true' && needs.changes.outputs.scoped != 'true'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
@@ -1418,7 +1418,8 @@ jobs:
# Check documentation builds without warnings
docs:
name: Documentation
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
needs: changes
if: needs.changes.outputs.scoped != 'true' && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
@@ -1439,17 +1440,17 @@ jobs:
cargo-deny:
name: cargo-deny
needs: changes
if: github.event_name == 'workflow_dispatch'
if: github.event_name == 'workflow_dispatch' && needs.changes.outputs.scoped != 'true'
uses: ./.github/workflows/cargo-deny.yml
security-audit:
name: Security audit
needs: changes
if: github.event_name == 'workflow_dispatch'
if: github.event_name == 'workflow_dispatch' && needs.changes.outputs.scoped != 'true'
uses: ./.github/workflows/security-audit.yml
ohos:
name: OpenHarmony
needs: changes
if: github.event_name == 'workflow_dispatch'
if: github.event_name == 'workflow_dispatch' && needs.changes.outputs.scoped != 'true'
uses: ./.github/workflows/ohos.yml
+4 -3
View File
@@ -88,7 +88,9 @@ jobs:
build:
name: Build ${{ matrix.platform }}
timeout-minutes: ${{ startsWith(matrix.os, 'macos-') && 360 || 210 }}
# Both cold macOS artifact builds on 0.10.1 exhausted 90 minutes inside
# compilation. Keep the full CI build budget; packaging stays capped below.
timeout-minutes: 210
# FreeBSD is a source-build target with no prebuilt asset, no npm binary and no CI check
# (see packaging/freebsd/README.md and docs/INSTALL.md#freebsd).
strategy:
@@ -173,11 +175,10 @@ jobs:
toolchain: stable
targets: ${{ matrix.target }}
- uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
if: runner.os == 'Linux'
id: sccache
continue-on-error: true
- name: Enable sccache
if: steps.sccache.outcome == 'success' && runner.os == 'Linux'
if: steps.sccache.outcome == 'success' && runner.os != 'Windows'
shell: bash
run: |
{
-12
View File
@@ -7,25 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- **Removed (crate API):** the unwired `codewhale-hooks` dispatcher and its stdout, JSONL and Unix-socket sinks; `codewhale-core`'s `session`, `journal` and `ids` modules and the `hooks` argument of `Runtime::new`; `codewhale-runtime::resource_telemetry`; ten unreferenced public functions; and the duplicate `codewhale-agent` crate. `hook_sinks.unix_socket_path` still parses and is ignored. CLI, TUI and app-server behavior is unchanged.
- **Plugin index hooks:** hooks with the same name and event now have distinct row IDs, so clients can keep every configured hook visible.
- **Renaming sessions with Chinese titles:** the session picker no longer rejects a Chinese, Japanese, Korean or emoji title of more than about 33 characters as "Title must be 1–100 characters". It now counts characters, as the message says and as `/rename` and the Runtime API already did, so any title up to 100 characters is accepted. Thanks [@luochen211](https://github.com/luochen211) (PR 7322).
- **Non-ASCII file names:** `/diff`, the `@git` and `@diff` mentions and the Runtime API workspace diff now show paths with Chinese, emoji and other non-ASCII characters as written instead of as quoted octal escapes, and the turn context no longer lists the workspace root as an empty "Active paths" entry. Thanks [@luochen211](https://github.com/luochen211) (PR 7317).
- **Session names after a crash, and keep-forever snapshot retention:** a session name saved right after a crash that cut off the previous session-index line is no longer lost, because the new entry now starts on its own line; and a very large `[snapshots] max_age_days` (such as `9223372036854775807` for "keep forever") no longer wraps around and deletes every undo snapshot at session start. Thanks [@luochen211](https://github.com/luochen211) (PR 7316).
- **Blank environment variables:** exporting a variable empty (for example `CODEWHALE_MODEL=` from a compose `${VAR:-}` template) no longer hides its legacy alias. `DEEPSEEK_MODEL`, `DEEPSEEK_BASE_URL`, `KIMI_BASE_URL`, `DEEPSEEK_FORCE_HTTP1`, `DEEPSEEK_STREAM_OPEN_TIMEOUT_SECS` and the other provider alias variables now apply as they do when the primary is unset. Thanks [@luochen211](https://github.com/luochen211) (PR 7315).
- **MCP and language servers that send requests mid-call:** a tool call no longer fails with "neither a result nor an error" when an MCP server sends a `ping` or other request that reuses the call's id while the call is running, and a language server's `workspace/configuration` or similar request no longer ends a pending LSP request. Codewhale now answers `ping`, answers other server requests with "Method not found" (it never advertised them), keeps waiting for the real reply, and a refused answer over Streamable HTTP no longer drops the connection to legacy SSE. Thanks [@luochen211](https://github.com/luochen211) (PR 7319).
- **Qwen Code as an external agent:** Codewhale now finds an installed Qwen Code CLI (`qwen`, 0.6.1 or newer) and can run it as a session over ACP with `qwen --acp`. `GET /v1/agents/external` lists it, an older install is reported as needing `npm i -g @qwen-code/qwen-code@latest`, and sign-in stays inside Qwen Code (`/auth`). Thanks [@MannXo](https://github.com/MannXo) (#7293).
- **Qwen Code as an external agent:** Codewhale now finds an installed Qwen Code CLI (`qwen`, 0.6.1 or newer) and can run it as a session over ACP with `qwen --acp`. `GET /v1/agents/external` lists it, an older install is reported as needing `npm i -g @qwen-code/qwen-code@latest`, and sign-in stays inside Qwen Code (`/auth`). Thanks [@MannXo](https://github.com/MannXo) (PR 7293).
- **Telemetry setting default:** the settings schema API reports telemetry's default as on, matching what Codewhale does when you have not chosen.
- **Auto routing abstention:** when the decision model marks a tier, effort or shadow answer `abstained: true`, Auto no longer acts on it, even with `min_confidence = 0`: an abstained tier takes the local fallback, an abstained effort keeps the tier and drops only the effort, and the routing receipt lists the abstained questions.
- **Plugin index (Runtime API):** a new `GET /v1/apps/plugin-index` route lists plugins, skills, connectors, hooks and hand-written commands with kind, source and state, and `/v1/commands` rows say which plugin (`plugin_id`) added a command and whether a command came from the project (`workspace_sourced`) (CW-8092).
- **Model commands and routing:** `codewhale model list` now lists every custom endpoint you have configured, under its own name. `codewhale model resolve` no longer refuses a model on a custom endpoint, router or local server whose model list has not been fetched yet; once a list is fetched, a model missing from it is still refused. Automatic routing marks a context window as verified only when the route itself supplies it, and no longer reports a guessed output limit.
- **ACP:** when a plugin tool asks the core to run a tool that needs approval, the editor now gets a `session/request_permission` on the plugin tool's call that names the nested tool and its input; before, the prompt ended with an internal error (CW-8050).
- **README and contributor credit:** the repository front page now opens the way the website does: the line "The model can be anyone's. The agent should be yours.", one sentence on what Codewhale is, the install command and one picture, with reference detail moved into the linked guides; the 18 translated READMEs follow the same structure and say they are machine-drafted. The contributor wall and the website now count the same 433 people (407 GitHub accounts and the commit authors whose email is not linked to an account), where the website had counted accounts only. `DEPENDENCY_SECURITY.md` moved into `docs/dependency-maintenance.md`, and `.github/SUPPORT.md` says where to ask for help.
- **Website Plugins page:** The website's Plugins page now describes what the released version does, and a labelled section says what 0.10.3 adds: one Plugins place, Standard and Creator mode, and the Permissions control.
- **First-time guide on the website:** a new docs page, "Use Codewhale for the first time" (`/docs/first-time`, English and Simplified Chinese), walks someone who has never used a terminal through opening one, installing, choosing the folder Codewhale works in and when that choice matters, opening a terminal in a folder from Finder or File Explorer, connecting a model, a first task, and stopping, undoing and quitting. The install page gains a short "New to the terminal?" block for macOS and Windows that links to it, and `llms.txt` carries the same steps.
- **Plugin docs and plugin-creator:** Docs now say everything you add is a plugin. The bundled plugin-creator skill no longer tells an agent never to trust or enable a plugin (in Full Access it may, for one it wrote and installed from its project), points code and screen plugins at cordis-plugin-development, and an untouched copy from 0.10.2 now upgrades. The Chinese extension and Runtime API docs now say editor ACP sessions get plugin tools and configured MCP servers.
- **Model thinking:** New installs show model thinking by default: it streams live in the transcript and collapses under a "Thought for …" header when the answer starts. Existing installs keep their saved setting; turn it on under Model reasoning in chat in /config.
- **Footer clock:** The footer clock and phase now say "thinking", matching the transcript.
+16 -9
View File
@@ -165,7 +165,7 @@ before starting a change; preserve any local work when updating your branch.
- Write tests for new functionality
- Run the tests near your change (see [Fast local loop](#fast-local-loop));
your pull request runs the Linux workspace suite and a Windows build for
your pull request runs the full test suite on Linux, macOS and Windows for
you (see [What happens after you open a pull request](#what-happens-after-you-open-a-pull-request))
- Colocate unit tests beside the code they cover (standard Rust `#[cfg(test)]`
modules), and add integration tests under the owning crate's `tests/`
@@ -174,8 +174,8 @@ before starting a change; preserve any local work when updating your branch.
### Pre-push verification
These are the Rust commands your pull request runs on Linux (the `Lint` and
`Test (ubuntu-latest)` checks). You do not need all of them before every
These are the Rust commands your pull request runs on Linux (the `Lint` check
and the Linux shards of `Sharded tests (ubuntu-latest)`). You do not need all of them before every
push: run `cargo fmt`, then check and test the crates you touched (see
[Fast local loop](#fast-local-loop)). Run the full set locally when a change
spans many crates, or let the pull request run it for you:
@@ -215,7 +215,7 @@ cargo install cargo-nextest --locked # once
scripts/dev-test.sh tui
scripts/dev-cargo.sh nextest run --workspace --all-features --locked
# 4. The Linux suite your PR runs:
# 4. The suite your PR runs on Linux (hosted CI runs it as parallel shards):
cargo test --workspace --all-features --locked
```
@@ -340,6 +340,9 @@ maintainer to approve the first run for a brand-new GitHub account.
| --- | --- | --- |
| `Lint` (required) | `cargo fmt --check`, clippy on every target, and the fast drift checks (locales, READMEs, provider registry, dead-code and blocking-call budgets) | Run `cargo fmt --all` and the clippy command in [Pre-push verification](#pre-push-verification); the log names the file and the check |
| `Test (windows-latest)` (required) | Compiles every workspace target for Windows with warnings denied, and the installer PATH helper tests | Usually a `cfg(windows)` path or an import only Windows sees; the log has the compiler error |
| `Sharded tests (ubuntu-latest)`, `(macos-latest)`, `(windows-latest)` | The full workspace test suite, built once per OS and run as parallel shards of one nextest archive, plus the doctests; each OS ends with a `Suite check` that fails if the shards did not run every test exactly once | Open the failing `Shard k/N` job; the log names the test. The same test reproduces locally with `cargo nextest run -E 'test(name)'` |
| `Safety gate`, `MSRV check (1.89)`, `npm wrapper smoke`, `Portable boundaries` | The hermetic safety and authorization tests, a build on the minimum Rust version, the npm wrapper install smoke and the portable-core boundary checks | The log names the failing test or the compiler error |
| `Mobile runtime smoke` | The `codewhale serve --mobile` HTTP and event-stream smoke, only when the mobile runtime surface changed | The log shows the failing request |
| `Version drift` | Version files, the `feat:` release-note rule, release helper tests and contributor credit | The credit step only reports: a maintainer adds your credit when the PR merges |
Smaller checks cover the VS Code extension, integrations, the extension host
@@ -347,11 +350,15 @@ and plugin conversion, plus workflow lint when you change `.github/workflows`.
A documentation-only change skips the Rust builds but still reports the
required checks, so it can merge.
Your pull request does not run the test suites, the safety gate, MSRV, the npm
wrapper smoke, the slow runtime-contract and persistence-backlog measurements,
the dependency audits or the OpenHarmony build. Maintainers run those once per
release, on the exact commit being released. If that run finds a problem your
change introduced, we fix it on `main`; we will not ask you to chase it.
Only `Lint` and `Test (windows-latest)` are required. Every other job above is
informational for a contributor's pull request: a red one tells you and the
maintainers something, and never blocks the merge. Your pull request does not
run the slow runtime-contract and persistence-backlog measurements, the macOS
budget and eval job, the dependency audits or the OpenHarmony build; those run
on `main` and for each release, on the exact commit. If one of them finds a
problem your change introduced, we fix it on `main`; we will not ask you to
chase it. A newer push to your branch cancels the older run of the same pull
request, so the runners always work on your latest commit.
A red check that your change did not cause is not your job to fix. We rerun it
or fix it on `main`, and we never close a PR because CI is slow or flaky. Your
Generated
+26 -5
View File
@@ -912,6 +912,14 @@ dependencies = [
"zeroize",
]
[[package]]
name = "codewhale-agent"
version = "0.10.3"
dependencies = [
"codewhale-config",
"serde",
]
[[package]]
name = "codewhale-agent-contract"
version = "0.10.3"
@@ -935,6 +943,7 @@ dependencies = [
"chrono",
"clap",
"codewhale-account-cli",
"codewhale-agent",
"codewhale-agent-contract",
"codewhale-app-server-protocol",
"codewhale-build-support",
@@ -1040,7 +1049,6 @@ dependencies = [
"codewhale-paths",
"codewhale-release",
"codewhale-runtime",
"codewhale-sanitize",
"codewhale-secrets",
"codewhale-state",
"codewhale-telemetry",
@@ -1110,7 +1118,6 @@ dependencies = [
"codewhale-execpolicy",
"codewhale-paths",
"codewhale-protocol",
"codewhale-sanitize",
"codewhale-secrets",
"fd-lock",
"libc",
@@ -1134,6 +1141,7 @@ name = "codewhale-core"
version = "0.10.3"
dependencies = [
"codewhale-config",
"codewhale-hooks",
"codewhale-protocol",
"codewhale-state",
"regex",
@@ -1142,6 +1150,7 @@ dependencies = [
"sha2 0.11.1",
"tempfile",
"thiserror 2.0.21",
"tokio",
"uuid",
]
@@ -1176,6 +1185,7 @@ dependencies = [
"base64 0.23.1",
"chrono",
"clap",
"codewhale-agent",
"codewhale-agent-contract",
"codewhale-app-server-protocol",
"codewhale-build-support",
@@ -1210,6 +1220,7 @@ dependencies = [
"codewhale-util",
"codewhale-workflow",
"codewhale-workflow-js",
"cucumber",
"dirs 7.0.0",
"encoding_rs",
"fd-lock",
@@ -1228,10 +1239,12 @@ dependencies = [
"objc2-foundation",
"parking_lot",
"portable-pty",
"pretty_assertions",
"proc-macro2",
"regex",
"reqwest",
"ring",
"rio-vt",
"rmcp",
"rusqlite",
"rustls",
@@ -1247,7 +1260,9 @@ dependencies = [
"tar",
"tempfile",
"thiserror 2.0.21",
"tiny_http",
"tokio",
"tokio-tungstenite 0.30.0",
"tokio-util",
"toml 1.1.6+spec-1.1.0",
"toml_edit 0.25.15+spec-1.1.0",
@@ -1291,11 +1306,14 @@ name = "codewhale-hooks"
version = "0.10.3"
dependencies = [
"anyhow",
"async-trait",
"chrono",
"codewhale-app-server-protocol",
"codewhale-paths",
"codewhale-protocol",
"codewhale-release",
"reqwest",
"serde",
"serde_json",
"tempfile",
"tokio",
@@ -1415,7 +1433,7 @@ version = "0.10.3"
dependencies = [
"codewhale-config",
"codewhale-runtime",
"codewhale-sanitize",
"codewhale-secrets",
"dirs 7.0.0",
"regex",
"tempfile",
@@ -1592,12 +1610,12 @@ dependencies = [
"codewhale-paths",
"codewhale-protocol",
"codewhale-release",
"codewhale-sanitize",
"codewhale-secrets",
"codewhale-util",
"colored",
"dirs 7.0.0",
"fd-lock",
"futures-util",
"ignore",
"jsonwebtoken",
"libc",
@@ -1865,7 +1883,9 @@ dependencies = [
"reqwest",
"rio-vt",
"rquickjs",
"rusqlite",
"rustls",
"schemars 1.2.2",
"semver",
"serde",
"serde_json",
@@ -1875,6 +1895,7 @@ dependencies = [
"tempfile",
"tiny_http",
"tokio",
"tokio-tungstenite 0.30.0",
"tokio-util",
"toml 1.1.6+spec-1.1.0",
"toml_edit 0.25.15+spec-1.1.0",
@@ -1898,7 +1919,7 @@ version = "0.10.3"
dependencies = [
"codewhale-palette",
"codewhale-ratatui",
"codewhale-sanitize",
"codewhale-secrets",
"crossterm",
"ratatui",
"similar",
+1
View File
@@ -1,6 +1,7 @@
[workspace]
members = [
"crates/account-cli",
"crates/agent",
"crates/agent-contract",
"crates/app-server",
"crates/app-server-protocol",
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "codewhale-agent"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "Model/provider registry and fallback strategy for Codewhale"
[lints]
workspace = true
[dependencies]
codewhale-config = { path = "../config", version = "0.10.3" }
serde.workspace = true
File diff suppressed because it is too large. Load diff
+1
View File
@@ -32,6 +32,7 @@ codewhale-app-server-protocol = { path = "../app-server-protocol", version = "0.
anyhow.workspace = true
axum.workspace = true
chrono.workspace = true
codewhale-agent = { path = "../agent", version = "0.10.3" }
codewhale-config = { path = "../config", version = "0.10.3" }
codewhale-core = { path = "../core", version = "0.10.3" }
codewhale-hooks = { path = "../hooks", version = "0.10.3" }
+15 -50
View File
@@ -47,18 +47,6 @@ impl Drop for TurnClaim {
}
}
}
fn admitted_call<'a>(
calls: &'a HashMap<String, PendingToolCall>,
execution: &str,
) -> Option<(&'a str, &'a PendingToolCall)> {
let mut id = execution;
loop {
if let Some((key, call)) = calls.get_key_value(id) {
return Some((key.as_str(), call));
}
id = id.rsplit_once('.')?.0;
}
}
fn update(session: &str, update: acp::SessionUpdate) -> Outgoing {
Outgoing::Update(acp::SessionNotification::new(session.to_string(), update))
}
@@ -431,50 +419,27 @@ impl PromptRun {
&& pending.turn_id == turn
&& pending.tool_call_id.as_deref() == Some(execution)
}) {
let (shown, call) = admitted_call(calls, execution)
let call = calls
.get(execution)
.ok_or_else(|| anyhow!("Approval projection lacks admitted tool start"))?;
let id = uuid::Uuid::new_v4().to_string();
let nested = shown != execution;
let nested_call;
let shown_call = if nested {
nested_call = PendingToolCall {
execution_id: execution.to_string(),
name: p
.get("tool_name")
.and_then(Value::as_str)
.unwrap_or(&call.name)
.to_string(),
input: p.get("input").cloned().unwrap_or(Value::Null),
};
&nested_call
} else {
call
};
let title = tool_call_title(shown_call);
let description = p
let title = tool_call_title(call);
let text = p
.get("description")
.and_then(Value::as_str)
.filter(|text| !text.trim().is_empty());
let summary = p
.get("summary")
.and_then(Value::as_str)
.filter(|text| nested && !text.trim().is_empty());
let text = match (summary, description) {
(Some(summary), Some(description)) => format!("{summary}\n{description}"),
(Some(text), None) | (None, Some(text)) => text.to_string(),
(None, None) => title.clone(),
};
let mut fields = acp::ToolCallUpdateFields::new()
.title(title)
.kind(tool_call_kind(shown_call))
.raw_input((!shown_call.input.is_null()).then(|| shown_call.input.clone()))
.content(vec![acp::ToolCallContent::from(text)]);
if !nested {
fields = fields.status(acp::ToolCallStatus::Pending);
}
.filter(|text| !text.trim().is_empty())
.map_or_else(|| title.clone(), str::to_string);
let request = acp::RequestPermissionRequest::new(
session.to_string(),
acp::ToolCallUpdate::new(shown.to_string(), fields),
acp::ToolCallUpdate::new(
execution.to_string(),
acp::ToolCallUpdateFields::new()
.title(title)
.kind(tool_call_kind(call))
.status(acp::ToolCallStatus::Pending)
.raw_input((!call.input.is_null()).then(|| call.input.clone()))
.content(vec![acp::ToolCallContent::from(text)]),
),
vec![
acp::PermissionOption::new(
"allow-once",
+33 -2
View File
@@ -14,6 +14,7 @@ use crate::stdio::{BoundedLines, run_stdio_loop};
use anyhow::Context as _;
use anyhow::{Result, anyhow};
use axum::http::{Method, StatusCode};
use codewhale_agent::ModelRegistry;
use codewhale_app_server_protocol::rpc::{
RequestId, RpcCall, RpcErrorDetails, RpcErrorResponse, RpcResponse,
};
@@ -22,6 +23,7 @@ use codewhale_app_server_protocol::runtime::MAX_RUNTIME_IMAGE_BODY_BYTES;
use codewhale_app_server_protocol::runtime::RuntimeImageInput;
use codewhale_config::ConfigStore;
use codewhale_core::Runtime;
use codewhale_hooks::{HookDispatcher, JsonlHookSink, StdoutHookSink, UnixSocketHookSink};
use codewhale_protocol::EventFrame;
use codewhale_state::StateStore;
use serde::Deserialize;
@@ -362,6 +364,7 @@ pub struct AppState {
/// Bookkeeping config and read-only historical archive access.
/// Actual turns and transcript writes belong to the captured owner.
runtime: Arc<RwLock<Runtime>>,
registry: ModelRegistry,
auth_token: Option<String>,
#[cfg(test)]
runtime_bridge: Arc<Mutex<Option<SharedRuntimeBridge>>>,
@@ -794,19 +797,46 @@ async fn build_state_off_runtime(
fn build_state_with_transport(
config_path: Option<PathBuf>,
auth_token: Option<String>,
_transport: AppTransport,
transport: AppTransport,
) -> Result<AppState> {
let has_explicit_config_path = config_path.is_some();
let store = ConfigStore::load(config_path)?;
let config_path = has_explicit_config_path.then(|| store.path().to_path_buf());
let config = store.config.clone();
let registry = ModelRegistry::default();
let state_db_path = config_path
.as_ref()
.and_then(|p| p.parent().map(|parent| parent.join("state.db")));
let state_store = StateStore::open(state_db_path)?;
let runtime = Runtime::new(config.clone(), state_store);
let mut hooks = HookDispatcher::default();
// Stdio carries JSON-RPC on stdout: printing raw hook events there
// corrupts the protocol stream (#5165). HTTP mode keeps the stdout
// sink for local development visibility.
if transport == AppTransport::Http {
hooks.add_sink(Arc::new(StdoutHookSink));
}
// The hook log sits beside the state database: next to an explicit
// config, otherwise in the directory the state store resolved under the
// Codewhale home. Never relative to the process cwd (#6513).
let hook_log_path = state_store
.db_path()
.parent()
.unwrap_or_else(|| Path::new("."))
.join("events.jsonl");
hooks.add_sink(Arc::new(JsonlHookSink::new(hook_log_path)));
if let Some(socket_path) = config
.hook_sinks
.as_ref()
.and_then(|sinks| sinks.unix_socket_path.as_ref())
.filter(|path| !path.as_os_str().is_empty())
{
hooks.add_sink(Arc::new(UnixSocketHookSink::new(socket_path.clone())));
}
let runtime = Runtime::new(config.clone(), state_store, hooks);
Ok(AppState {
captured_owner: None,
@@ -816,6 +846,7 @@ fn build_state_with_transport(
config_path,
config: Arc::new(RwLock::new(config)),
runtime: Arc::new(RwLock::new(runtime)),
registry,
auth_token,
#[cfg(test)]
runtime_bridge: Arc::new(Mutex::new(None)),
+5 -12
View File
@@ -111,14 +111,7 @@ pub(crate) async fn runtime_app_models(state: &AppState) -> Result<Vec<Value>> {
providers.len() <= 256,
"Runtime provider catalog exceeds its limit"
);
let aliases = codewhale_config::catalog::reviewed::bundled_reviewed()
.selections
.iter()
.filter_map(|row| {
codewhale_config::ProviderKind::parse_config_identity(&row.provider)
.map(|provider| (provider, row))
})
.collect::<Vec<_>>();
let aliases = state.registry.list();
let mut models = Vec::new();
let mut routes = std::collections::HashSet::new();
for provider in providers {
@@ -156,13 +149,13 @@ pub(crate) async fn runtime_app_models(state: &AppState) -> Result<Vec<Value>> {
.context("Runtime model identity is invalid")?;
let compatibility_aliases = aliases
.iter()
.find(|(provider, row)| {
.find(|entry| {
parsed != codewhale_config::ProviderKind::Custom
&& provider_id.is_none_or(|identity| identity == kind)
&& *provider == parsed
&& row.id == id
&& entry.provider == parsed
&& entry.id == id
})
.map(|(_, row)| row.aliases.clone())
.map(|entry| entry.aliases.clone())
.unwrap_or_default();
let capabilities: codewhale_config::route::RouteCapabilities =
match model.pointer("/facts/capabilities") {
-12
View File
@@ -129,7 +129,6 @@ mod members;
mod memory_lens;
mod mobile;
mod plans;
mod plugin_index;
mod plugins;
pub(crate) mod review;
mod secrets;
@@ -3373,7 +3372,6 @@ pub fn build_router(state: RuntimeApiState) -> Router {
.route("/v1/skills/{name}/audit", get(audit_skill_api))
.route("/v1/apps/mcp/tools", get(list_mcp_tools))
.route("/v1/apps/plugins", get(plugins::list_plugins))
.route("/v1/apps/plugin-index", get(plugin_index::get_plugin_index))
.route("/v1/apps/avatars", get(avatars::list_avatars))
.route(
"/v1/apps/avatars/{handle}/atlases/{page}",
@@ -5877,10 +5875,6 @@ struct CommandCatalogEntry {
#[serde(skip_serializing_if = "Option::is_none")]
origin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
plugin_id: Option<String>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
workspace_sourced: bool,
#[serde(skip_serializing_if = "Option::is_none")]
registration_id: Option<String>,
}
@@ -5939,8 +5933,6 @@ fn command_catalog(
shadowed_by,
shadowed_aliases,
origin: None,
plugin_id: None,
workspace_sourced: false,
registration_id: None,
});
}
@@ -5964,8 +5956,6 @@ fn command_catalog(
shadowed_by: None,
shadowed_aliases: Vec::new(),
origin: None,
plugin_id: command.plugin_id.clone(),
workspace_sourced: command.workspace_sourced,
registration_id: None,
});
}
@@ -6048,8 +6038,6 @@ async fn list_commands(
shadowed_by: None,
shadowed_aliases: Vec::new(),
origin: Some(reference.origin.clone()),
plugin_id: Some(reference.plugin_id.clone()),
workspace_sourced: false,
registration_id: query
.thread_id
.as_deref()
@@ -1,489 +0,0 @@
use std::collections::{BTreeSet, HashMap};
use std::path::{Path as FsPath, PathBuf};
use axum::Json;
use axum::extract::{Query, State};
use serde::Serialize;
use serde_json::Value;
use super::plugins::{self, PluginSummaryEntry};
use super::{ApiError, CommandsQuery, HooksQuery, RuntimeApiState};
const MAX_ADDED_NAMES: usize = 512;
#[derive(Debug, Serialize)]
pub(super) struct PluginIndexResponse {
workspace: String,
items: Vec<IndexItem>,
unavailable: Vec<IndexNote>,
problems: Vec<IndexNote>,
}
#[derive(Debug, Serialize)]
struct IndexNote {
kind: &'static str,
message: String,
}
#[derive(Debug, Serialize)]
struct IndexItem {
id: String,
kind: &'static str,
name: String,
description: Option<String>,
source: &'static str,
state: &'static str,
labels: Vec<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
plugin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
adds: Option<PluginAdds>,
#[serde(skip_serializing_if = "Option::is_none")]
tier: Option<&'static str>,
owner: &'static str,
row: Value,
}
#[derive(Debug, Default, Serialize)]
struct PluginAdds {
skills: Vec<String>,
connectors: Vec<String>,
hooks: Vec<String>,
commands: Vec<String>,
profiles: Vec<String>,
}
impl PluginAdds {
fn labels(&self, entry: &PluginSummaryEntry) -> Vec<&'static str> {
[
("skill", !self.skills.is_empty()),
("connector", !self.connectors.is_empty()),
("hook", !self.hooks.is_empty()),
("command", !self.commands.is_empty()),
(
"tool",
entry.inventory.native > 0 || entry.inventory.lsp > 0,
),
("profile", !self.profiles.is_empty()),
]
.into_iter()
.filter_map(|(label, present)| present.then_some(label))
.collect()
}
}
fn row_value<T: Serialize>(row: &T) -> Value {
serde_json::to_value(row).unwrap_or(Value::Null)
}
fn note_failure(unavailable: &mut Vec<IndexNote>, kind: &'static str, error: &ApiError) {
unavailable.push(IndexNote {
kind,
message: error.message.clone(),
});
}
fn plugin_source(origin: &str) -> &'static str {
match origin {
"codewhale-builtin" => "built_in",
"workspace-codewhale" => "project",
_ => "user",
}
}
fn plugin_state(entry: &PluginSummaryEntry) -> &'static str {
if matches!(
entry.trust_status,
"content-changed" | "capabilities-changed"
) || entry.state == "enabled-untrusted"
{
return "needs_review";
}
match entry.state {
"active" => "enabled",
"disabled" => "disabled",
_ => "unavailable",
}
}
fn add_stem(names: &mut BTreeSet<String>, path: &FsPath, extension: Option<&str>, lowercase: bool) {
if let Some(wanted) = extension
&& path.extension().and_then(|value| value.to_str()) != Some(wanted)
{
return;
}
if let Some(stem) = path.file_stem().and_then(|value| value.to_str()) {
names.insert(if lowercase {
stem.to_lowercase()
} else {
stem.to_string()
});
}
}
async fn component_names(
paths: &[PathBuf],
extension: Option<&str>,
lowercase: bool,
omitted: &mut bool,
) -> Vec<String> {
let mut names = BTreeSet::new();
for path in paths {
let Ok(meta) = tokio::fs::symlink_metadata(path).await else {
continue;
};
if meta.is_file() {
add_stem(&mut names, path, extension, lowercase);
} else if meta.is_dir()
&& let Ok(mut entries) = tokio::fs::read_dir(path).await
{
let mut seen = 0;
while let Ok(Some(entry)) = entries.next_entry().await {
seen += 1;
if seen > MAX_ADDED_NAMES {
*omitted = true;
break;
}
if entry.file_type().await.is_ok_and(|kind| kind.is_file()) {
add_stem(&mut names, &entry.path(), extension, lowercase);
}
}
}
if names.len() >= MAX_ADDED_NAMES {
*omitted = true;
break;
}
}
if names.iter().any(|name| name.chars().any(char::is_control)) {
*omitted = true;
names.retain(|name| !name.chars().any(char::is_control));
}
names.into_iter().take(MAX_ADDED_NAMES).collect()
}
async fn plugin_adds(
plugin: &codewhale_plugins::types::LoadedPlugin,
omitted: &mut bool,
) -> PluginAdds {
let mut skills: Vec<String> = plugin
.skill_snapshots
.iter()
.map(|skill| skill.name.clone())
.collect();
skills.sort();
let mut connectors: Vec<String> = plugin
.manifest
.mcp_servers
.as_ref()
.map(|servers| servers.keys().cloned().collect())
.unwrap_or_default();
connectors.sort();
PluginAdds {
skills,
connectors,
hooks: component_names(&plugin.components.hooks, None, false, omitted).await,
commands: component_names(&plugin.components.commands, Some("md"), true, omitted).await,
profiles: component_names(&plugin.components.agents, Some("toml"), false, omitted).await,
}
}
async fn plugin_adds_by_id(
state: &RuntimeApiState,
omitted: &mut BTreeSet<String>,
) -> HashMap<String, PluginAdds> {
let registry = state
.plugin_discovery
.registry_for_workspace(&state.workspace);
let mut adds = HashMap::new();
for plugin in registry.list() {
let mut cut = false;
adds.insert(
plugin.id.as_str().to_string(),
plugin_adds(plugin, &mut cut).await,
);
if cut {
omitted.insert(plugin.name().to_string());
}
}
adds
}
fn skill_source(
path: Option<&PathBuf>,
is_bundled: bool,
skills_dir: &FsPath,
workspace: &FsPath,
) -> &'static str {
if is_bundled {
return "built_in";
}
match path {
Some(path) if path.starts_with(skills_dir) => "user",
Some(path) if path.starts_with(workspace) => "project",
Some(_) => "other_app",
None => "plugin",
}
}
pub(super) async fn get_plugin_index(
State(state): State<RuntimeApiState>,
) -> Result<Json<PluginIndexResponse>, ApiError> {
let mut items = Vec::new();
let mut unavailable = Vec::new();
let mut problems = Vec::new();
let commands = super::list_commands(
State(state.clone()),
Query(CommandsQuery { thread_id: None }),
)
.await;
let mut plugin_commands: HashMap<String, BTreeSet<String>> = HashMap::new();
if let Ok(Json(response)) = &commands {
for command in &response.commands {
if let (Some(plugin_id), "user") = (command.plugin_id.as_ref(), command.kind) {
plugin_commands
.entry(plugin_id.clone())
.or_default()
.insert(command.name.clone());
}
}
}
match plugins::list_plugins(State(state.clone())).await {
Ok(Json(response)) => {
let mut omitted = BTreeSet::new();
let mut adds_by_id = plugin_adds_by_id(&state, &mut omitted).await;
for name in &omitted {
problems.push(IndexNote {
kind: "plugin",
message: format!(
"plugin '{name}' adds more files than are listed, or a file name with control characters; some names are left out of `adds`"
),
});
}
for diagnostic in &response.registry_diagnostics {
problems.push(IndexNote {
kind: "plugin",
message: diagnostic.message.clone(),
});
}
for entry in &response.plugins {
let mut adds = adds_by_id.remove(&entry.id);
if entry.state == "active"
&& commands.is_ok()
&& let Some(adds) = adds.as_mut()
{
adds.commands = plugin_commands
.remove(&entry.id)
.map(|names| names.into_iter().collect())
.unwrap_or_default();
}
items.push(IndexItem {
id: format!("plugin:{}", entry.id),
kind: "plugin",
name: entry
.display_name
.clone()
.unwrap_or_else(|| entry.name.clone()),
description: entry.description.clone(),
source: plugin_source(entry.origin),
state: plugin_state(entry),
labels: adds
.as_ref()
.map(|adds| adds.labels(entry))
.unwrap_or_default(),
plugin: None,
adds,
tier: None,
owner: "/v1/apps/plugins",
row: row_value(entry),
});
}
}
Err(error) => note_failure(&mut unavailable, "plugin", &error),
}
match plugins::list_plugin_catalog(State(state.clone())).await {
Ok(Json(catalog)) => {
for (tier, rows) in [
("builtin", &catalog.builtin),
("experimental", &catalog.experimental),
("more", &catalog.more),
] {
for row in rows {
items.push(IndexItem {
id: format!("plugin:catalog:{}", row.id),
kind: "plugin",
name: row.title.clone(),
description: row.description.clone(),
source: "built_in",
state: if !row.available {
"unavailable"
} else if row.enabled {
"enabled"
} else {
"disabled"
},
labels: Vec::new(),
plugin: None,
adds: None,
tier: Some(tier),
owner: "/v1/apps/plugins/catalog",
row: row_value(row),
});
}
}
}
Err(error) => note_failure(&mut unavailable, "plugin", &error),
}
match super::list_skills(State(state.clone())).await {
Ok(Json(response)) => {
for warning in &response.warnings {
problems.push(IndexNote {
kind: "skill",
message: warning.clone(),
});
}
for skill in &response.skills {
if skill.plugin_id.is_some() {
continue;
}
items.push(IndexItem {
id: format!("skill:{}", skill.name),
kind: "skill",
name: skill.name.clone(),
description: Some(skill.description.clone()),
source: skill_source(
skill.path.as_ref(),
skill.is_bundled,
&response.directory,
&state.workspace,
),
state: if skill.enabled { "enabled" } else { "disabled" },
labels: vec!["skill"],
plugin: None,
adds: None,
tier: None,
owner: "/v1/skills",
row: row_value(skill),
});
}
}
Err(error) => note_failure(&mut unavailable, "skill", &error),
}
match super::list_mcp_servers(State(state.clone())).await {
Ok(Json(response)) => {
for server in &response.servers {
let source = match server.origin {
"plugin" => continue,
"project" => "project",
"runtime" => "runtime",
_ => "user",
};
items.push(IndexItem {
id: format!("connector:{}", server.name),
kind: "connector",
name: server.name.clone(),
description: None,
source,
state: if !server.enabled {
"disabled"
} else if server.auth_required {
"needs_sign_in"
} else {
"enabled"
},
labels: vec!["connector"],
plugin: None,
adds: None,
tier: None,
owner: "/v1/apps/mcp/servers",
row: row_value(server),
});
}
}
Err(error) => note_failure(&mut unavailable, "connector", &error),
}
match super::list_hooks(State(state.clone()), Query(HooksQuery { thread_id: None })).await {
Ok(Json(response)) => {
for problem in &response.problems {
problems.push(IndexNote {
kind: "hook",
message: problem.clone(),
});
}
let mut ordinals: HashMap<&'static str, usize> = HashMap::new();
for hook in &response.hooks {
let ordinal = ordinals.entry(hook.event).or_default();
*ordinal += 1;
let source = match hook.source {
"plugin" => continue,
"project" => "project",
_ => "user",
};
let name = hook
.name
.clone()
.unwrap_or_else(|| format!("{} {}", hook.event, ordinal));
items.push(IndexItem {
id: format!("hook:{source}:{}:{ordinal}", hook.event),
kind: "hook",
name,
description: None,
source,
state: if response.enabled {
"enabled"
} else {
"disabled"
},
labels: vec!["hook"],
plugin: None,
adds: None,
tier: None,
owner: "/v1/hooks",
row: row_value(hook),
});
}
}
Err(error) => note_failure(&mut unavailable, "hook", &error),
}
match commands {
Ok(Json(response)) => {
for command in &response.commands {
let (source, plugin) = match (command.kind, command.plugin_id.as_ref()) {
("builtin", _) => continue,
("user", Some(_)) => continue,
("extension", plugin_id) => ("plugin", plugin_id.cloned()),
_ if command.workspace_sourced => ("project", None),
_ => ("user", None),
};
items.push(IndexItem {
id: format!("command:{}", command.name),
kind: "command",
name: command.name.clone(),
description: command.summary.clone(),
source,
state: "enabled",
labels: vec!["command"],
plugin,
adds: None,
tier: None,
owner: "/v1/commands",
row: row_value(command),
});
}
}
Err(error) => note_failure(&mut unavailable, "command", &error),
}
Ok(Json(PluginIndexResponse {
workspace: state.workspace.display().to_string(),
items,
unavailable,
problems,
}))
}
@@ -15,7 +15,6 @@ use tokio::sync::{Mutex, mpsc, oneshot};
use tokio::time::sleep;
use uuid::Uuid;
mod catalog_parity;
mod command_catalog;
#[cfg(unix)]
mod control_socket_selection;
@@ -29,7 +28,6 @@ mod headless_catalog;
mod member_operations;
#[cfg(unix)]
mod owner_bootstrap;
mod plugin_index;
mod plugin_ui;
mod profile_constitution;
#[cfg(any(unix, windows))]
@@ -1,600 +0,0 @@
use super::*;
use codewhale_config::catalog::{
CatalogOffering, CatalogSource, CatalogStatus, ProviderCatalogDelta, base_url_fingerprint,
now_unix,
};
use codewhale_engine::cost_status::EffectiveRouteEnvelope;
use codewhale_engine::model_inventory::ModelInventory;
use codewhale_runtime::config::ProviderIdentity;
use sha2::{Digest, Sha256};
use std::collections::BTreeMap;
const SINGULAR: &str = "model list / model resolve";
const PLURAL: &str = "models";
const RUNTIME: &str = "runtime api";
const ROUTING: &str = "routing inventory";
const COST: &str = "cost";
const UNKNOWN: &str = "unknown";
const ROSTER: &[&str] = &["claude-opus-5", "claude-haiku-4-5", "claude-parity-probe-1"];
type Readings = BTreeMap<(String, String, &'static str), BTreeMap<&'static str, String>>;
struct Route {
label: &'static str,
api_path: &'static str,
identity: ProviderIdentity,
base_url: String,
models: &'static [&'static str],
}
fn cold_process() {
codewhale_engine::provider_catalog_live::reset_cache_for_test();
codewhale_engine::provider_lake::clear_live_snapshot();
}
fn known<T: ToString>(value: Option<T>) -> String {
value.map_or_else(|| UNKNOWN.to_string(), |value| value.to_string())
}
fn rate(value: &Value) -> String {
let number = match value {
Value::Number(number) => number.as_f64(),
Value::String(text) => text.parse::<f64>().ok(),
_ => None,
};
known(number)
}
fn roster(mut models: Vec<String>) -> String {
models.sort();
models.dedup();
models.join(",")
}
fn read(
readings: &mut Readings,
route: &Route,
model: &str,
field: &'static str,
surface: &'static str,
value: String,
) {
readings
.entry((route.label.to_string(), model.to_string(), field))
.or_default()
.insert(surface, value);
}
fn persist_id_only_roster(identity: &ProviderIdentity, base_url: &str) {
let fingerprint = base_url_fingerprint(base_url);
let fetched_at = now_unix();
let ticket = codewhale_engine::provider_catalog_live::begin_refresh_for_identity(
identity.provider,
identity.key.as_str(),
base_url,
);
assert_eq!(
codewhale_engine::provider_catalog_live::record_success_if_current(
&ticket,
ProviderCatalogDelta {
provider: identity.key.to_string(),
base_url_fingerprint: fingerprint.clone(),
fetched_at,
offerings: ROSTER
.iter()
.map(|id| CatalogOffering {
provider: identity.key.to_string(),
wire_model_id: (*id).to_string(),
endpoint_key: "chat".into(),
source: CatalogSource::Live {
base_url_fingerprint: fingerprint.clone(),
fetched_at,
},
..Default::default()
})
.collect(),
},
),
Some(CatalogStatus::Fresh)
);
}
fn read_singular(readings: &mut Readings, config_path: &Path, route: &Route) -> Result<()> {
cold_process();
let store = codewhale_config::ConfigStore::load(Some(config_path.to_path_buf()))?;
let listed =
codewhale_engine::route_preferences::list_models(&store, Some(route.identity.provider))?
.into_iter()
.find(|(listed, _)| listed == route.identity.key.as_str())
.map(|(_, models)| roster(models));
read(
readings,
route,
"*",
"roster",
SINGULAR,
listed.unwrap_or_else(|| "route not listed".into()),
);
for model in route.models {
let limits = codewhale_engine::route_preferences::resolve_model(
config_path,
route.identity.key.as_str(),
&route.base_url,
Some(model),
)
.map(|candidate| candidate.limits());
let (context, output) = match limits {
Ok(limits) => (known(limits.context_tokens), known(limits.output_tokens)),
Err(error) => (format!("refused: {error}"), format!("refused: {error}")),
};
read(readings, route, model, "limit.context", SINGULAR, context);
read(readings, route, model, "limit.output", SINGULAR, output);
}
Ok(())
}
fn read_plural(readings: &mut Readings, config: &Config, route: &Route) -> Result<()> {
cold_process();
codewhale_engine::models_dev_live::maybe_load_persisted_cache();
let mut route_config = config.clone();
route_config
.scope_to_provider_identity(&route.identity)
.map_err(anyhow::Error::msg)?;
read(
readings,
route,
"*",
"roster",
PLURAL,
roster(codewhale_engine::provider_lake::listed_models_for_route(
&route_config,
&route.identity,
)),
);
Ok(())
}
async fn read_runtime(
readings: &mut Readings,
client: &reqwest::Client,
addr: &SocketAddr,
route: &Route,
) -> Result<()> {
let body: Value = client
.get(format!("http://{addr}/v1/providers/{}", route.api_path))
.send()
.await?
.error_for_status()?
.json()
.await?;
let models = body["models"].as_array().context("models array")?;
read(
readings,
route,
"*",
"roster",
RUNTIME,
roster(
models
.iter()
.filter_map(|model| model["id"].as_str().map(str::to_string))
.collect(),
),
);
for model in route.models {
let facts = models
.iter()
.find(|entry| entry["id"] == *model)
.map_or(&Value::Null, |entry| &entry["facts"]);
read(
readings,
route,
model,
"limit.context",
RUNTIME,
known(facts["effective_limits"]["context_tokens"].as_u64()),
);
read(
readings,
route,
model,
"limit.output",
RUNTIME,
known(facts["effective_limits"]["output_tokens"].as_u64()),
);
read(
readings,
route,
model,
"window",
RUNTIME,
known(facts["effective_context"]["tokens"].as_u64()),
);
read(
readings,
route,
model,
"window.source",
RUNTIME,
known(facts["effective_context"]["source"].as_str()),
);
read(
readings,
route,
model,
"price.input",
RUNTIME,
rate(&facts["pricing"]["input_per_million"]),
);
read(
readings,
route,
model,
"price.output",
RUNTIME,
rate(&facts["pricing"]["output_per_million"]),
);
read(
readings,
route,
model,
"price.basis",
RUNTIME,
format!(
"provenance={} status={} source={}",
facts["pricing"]["provenance"], facts["pricing_status"], facts["source"]
),
);
}
Ok(())
}
fn read_routing(readings: &mut Readings, config: &Config, route: &Route) -> Result<()> {
let inventory = ModelInventory::from_config(config).map_err(anyhow::Error::msg)?;
let candidates: Vec<_> = inventory
.candidates
.iter()
.filter(|candidate| candidate.identity == route.identity)
.collect();
read(
readings,
route,
"*",
"roster",
ROUTING,
roster(
candidates
.iter()
.map(|candidate| candidate.model.clone())
.collect(),
),
);
for model in route.models {
let candidate = candidates
.iter()
.find(|candidate| candidate.model == *model);
read(
readings,
route,
model,
"window",
ROUTING,
known(candidate.map(|candidate| candidate.context_window)),
);
read(
readings,
route,
model,
"window.source",
ROUTING,
known(candidate.map(|candidate| {
if candidate.context_window_unverified {
"unverified"
} else {
"verified"
}
})),
);
read(
readings,
route,
model,
"limit.output",
ROUTING,
known(candidate.and_then(|candidate| candidate.max_output)),
);
}
Ok(())
}
fn read_cost(readings: &mut Readings, config: &Config, route: &Route) {
let usage = Usage {
input_tokens: 100_000,
output_tokens: 10_000,
..Default::default()
};
for model in route.models {
let envelope = EffectiveRouteEnvelope::from_admitted(
Some(config),
&route.identity,
*model,
Some(&route.base_url),
chrono::Utc::now(),
);
let quote = envelope.provider_live_pricing.as_ref();
let audit = envelope.audit(&usage);
read(
readings,
route,
model,
"price.input",
COST,
quote
.and_then(|quote| quote.input_per_million.as_deref())
.map_or_else(|| UNKNOWN.to_string(), |text| rate(&json!(text))),
);
read(
readings,
route,
model,
"price.output",
COST,
quote
.and_then(|quote| quote.output_per_million.as_deref())
.map_or_else(|| UNKNOWN.to_string(), |text| rate(&json!(text))),
);
read(
readings,
route,
model,
"price.basis",
COST,
format!(
"provenance={:?} billing={:?} charge_usd={} unpriced={:?}",
quote.map(|quote| quote.provenance.clone()),
envelope.billing_mode,
known(audit.exact_usd.as_deref()),
audit.unpriced_reason,
),
);
}
}
#[tokio::test]
async fn one_captured_catalog_reads_the_same_on_every_model_surface() -> Result<()> {
let _env = lock_test_env();
let _live = codewhale_engine::provider_lake::lock_live_snapshot();
let root = tempfile::tempdir()?;
let captured = codewhale_config::catalog::BUNDLED_MODELS_DEV_JSON;
let catalog_path = root.path().join("captured-models-dev.json");
fs::write(&catalog_path, captured)?;
let _catalog = EnvVarGuard::set("CODEWHALE_MODELS_DEV_PATH", &catalog_path);
let _home = EnvVarGuard::set("CODEWHALE_HOME", root.path());
let _config_path = EnvVarGuard::remove("CODEWHALE_CONFIG_PATH");
let _legacy_config_path = EnvVarGuard::remove("DEEPSEEK_CONFIG_PATH");
let _cli = EnvVarGuard::remove(codewhale_config::CLI_API_KEY_ENV);
cold_process();
let config_path = root.path().join("config.toml");
fs::write(
&config_path,
r#"provider = "anthropic"
[providers.anthropic]
api_key = "parity-fixture-key"
model = "claude-opus-5"
[providers.zai]
api_key = "parity-fixture-key"
model = "GLM-5.3"
[providers.lab]
kind = "openai-compatible"
base_url = "http://127.0.0.1:9/v1"
api_key = "parity-fixture-key"
model = "claude-haiku-4-5"
"#,
)?;
let config = Config::load(Some(config_path.clone()), None)?;
let route = |label: &'static str,
api_path: &'static str,
key: &str,
models: &'static [&'static str]|
-> Result<Route> {
let identity = config
.resolve_provider_pin_identity(key)
.map_err(anyhow::Error::msg)?;
Ok(Route {
label,
api_path,
base_url: config.base_url_for_route(&identity),
identity,
models,
})
};
let routes = [
route(
"anthropic (official, id-only roster)",
"anthropic/models",
"anthropic",
ROSTER,
)?,
route(
"lab (custom endpoint, same spelling)",
"custom/models?model_provider_id=lab",
"lab",
&["claude-haiku-4-5"],
)?,
route(
"zai (plan endpoint)",
"zai/models",
"zai",
&["GLM-5.3", "GLM-5.2"],
)?,
];
assert!(
codewhale_engine::models_dev_live::refresh(false)
.await
.map_err(|error| anyhow::anyhow!("{error}"))?
> 0
);
persist_id_only_roster(&routes[0].identity, &routes[0].base_url);
let mut readings = Readings::new();
for route in &routes {
read_singular(&mut readings, &config_path, route)?;
read_plural(&mut readings, &config, route)?;
}
cold_process();
let (addr, _, handle) = spawn_test_server_with_config_path(config_path.clone())
.await?
.expect("loopback server required");
let client = codewhale_release::tls::reqwest_client();
for route in &routes {
read_runtime(&mut readings, &client, &addr, route).await?;
read_routing(&mut readings, &config, route)?;
read_cost(&mut readings, &config, route);
}
handle.abort();
cold_process();
println!(
"PARITY captured_catalog sha256={} bytes={}",
Sha256::digest(captured.as_bytes())
.iter()
.map(|byte| format!("{byte:02x}"))
.collect::<String>(),
captured.len()
);
let mut differing = Vec::new();
let mut known_differences: Vec<String> = Vec::new();
for ((route, model, field), surfaces) in &readings {
let mut values: Vec<String> = surfaces
.values()
.map(|value| {
if *field == "roster" {
roster(
value
.to_ascii_lowercase()
.split(',')
.map(str::to_string)
.collect(),
)
} else {
value.clone()
}
})
.collect();
values.sort();
values.dedup();
let compared = !matches!(*field, "price.basis" | "window.source");
let borrowed_window = *field == "window"
&& surfaces.get(RUNTIME).map(String::as_str) == Some(UNKNOWN)
&& readings
.get(&(route.clone(), model.clone(), "window.source"))
.and_then(|sources| sources.get(ROUTING))
.map(String::as_str)
== Some("unverified");
let verdict = if !compared {
"info"
} else if borrowed_window {
known_differences.push(format!("{route} | {model} | {surfaces:?}"));
"KNOWN-DIFFERENCE"
} else if values.len() == 1 {
"agree"
} else {
differing.push(format!("{route} | {model} | {field} | {surfaces:?}"));
"DIFFER"
};
println!("PARITY {verdict} | {route} | {model} | {field} | {surfaces:?}");
}
let value = |route: &Route, model: &str, field: &'static str, surface: &'static str| {
readings
.get(&(route.label.to_string(), model.to_string(), field))
.and_then(|surfaces| surfaces.get(surface))
.cloned()
.unwrap_or_default()
};
assert_eq!(
value(&routes[0], "*", "roster", SINGULAR),
"claude-haiku-4-5,claude-opus-5,claude-parity-probe-1",
"the singular command lists the route's own roster, not every bundled row"
);
assert_eq!(
value(&routes[0], "claude-opus-5", "limit.context", RUNTIME),
"1000000"
);
assert_eq!(
value(&routes[0], "claude-haiku-4-5", "limit.context", RUNTIME),
"200000"
);
assert_eq!(value(&routes[0], "claude-opus-5", "price.input", COST), "5");
assert_eq!(
value(&routes[0], "claude-haiku-4-5", "price.output", COST),
"5"
);
for field in ["limit.context", "limit.output", "price.input"] {
assert_eq!(
value(&routes[1], "claude-haiku-4-5", field, RUNTIME),
UNKNOWN,
"a custom endpoint borrows no fact from a same-named model: {field}"
);
}
assert_eq!(
value(&routes[1], "claude-haiku-4-5", "window.source", ROUTING),
"unverified",
"routing never presents a same-named model's window as this endpoint's"
);
assert_eq!(
value(&routes[1], "claude-haiku-4-5", "limit.output", ROUTING),
UNKNOWN
);
for model in ["GLM-5.3", "GLM-5.2"] {
let basis = value(&routes[2], model, "price.basis", COST);
assert!(
basis.contains("NotMoneyMetered") && basis.contains("charge_usd=unknown"),
"a plan route is never billed per token: {model}: {basis}"
);
}
for (model, rate) in [("GLM-5.3", UNKNOWN), ("GLM-5.2", "1.4")] {
for surface in [COST, RUNTIME] {
assert_eq!(
value(&routes[2], model, "price.input", surface),
rate,
"the list rate is shown the same everywhere and never turned into a charge: {model} {surface}"
);
}
}
let basis = value(&routes[1], "claude-haiku-4-5", "price.basis", COST);
assert!(
basis.contains("UnknownBillingBasis") && basis.contains("charge_usd=unknown"),
"a custom endpoint is never given a charge: {basis}"
);
for surface in [COST, RUNTIME] {
assert_eq!(
value(&routes[0], "claude-parity-probe-1", "price.input", surface),
UNKNOWN,
"a metered first-party model with no price row reads unknown: {surface}"
);
}
let basis = value(&routes[0], "claude-parity-probe-1", "price.basis", COST);
assert!(
basis.contains("charge_usd=unknown") && !basis.contains("unpriced=None"),
"an unpriced model produces no charge and says why: {basis}"
);
assert_eq!(
known_differences,
vec![
"lab (custom endpoint, same spelling) | claude-haiku-4-5 | {\"routing inventory\": \"200000\", \"runtime api\": \"unknown\"}"
],
"the only named difference is the custom endpoint's borrowed routing window"
);
assert!(
differing.is_empty(),
"surfaces disagree on the same captured catalog:\n{}",
differing.join("\n")
);
Ok(())
}
@@ -28,8 +28,6 @@ fn user(name: &str) -> UserCommand {
takes_arguments: false,
hidden: false,
extension: false,
plugin_id: None,
workspace_sourced: false,
builtin_bindings: vec![name.to_string()],
}
}
@@ -1,219 +0,0 @@
use super::*;
use codewhale_engine::command_catalog::{BuiltinCommand, CommandCatalog, UserCommand};
struct Catalog(Arc<std::sync::Mutex<Option<String>>>);
impl CommandCatalog for Catalog {
fn answers_to(&self, _name: &str) -> bool {
false
}
fn builtins(&self) -> Vec<BuiltinCommand> {
Vec::new()
}
fn user_commands(&self, _workspace: &Path) -> Vec<UserCommand> {
let plugin_id = self.0.lock().expect("plugin id").clone();
let command = |name: &str, plugin: Option<String>| UserCommand {
name: name.to_string(),
aliases: Vec::new(),
description: Some("A command.".to_string()),
usage: None,
takes_arguments: false,
hidden: false,
extension: false,
plugin_id: plugin,
workspace_sourced: false,
builtin_bindings: Vec::new(),
};
vec![command("mine", None), command("ship", plugin_id)]
}
}
#[tokio::test]
async fn the_index_lists_every_kind_once_and_a_plugin_carries_what_it_adds() -> Result<()> {
let _env = lock_test_env();
let temp = tempfile::tempdir()?;
let root = temp.path().join("index-route");
let workspace = root.join("workspace");
fs::create_dir_all(&workspace)?;
let plugin_id = Arc::new(std::sync::Mutex::new(None));
let _catalog = codewhale_engine::command_catalog::CatalogGuard::install(Arc::new(Catalog(
plugin_id.clone(),
)));
let sources = root.join("sources");
fs::create_dir_all(&sources)?;
let bundle = write_plugin_source_bundle(&sources, "indexed")?;
fs::create_dir_all(bundle.join("commands"))?;
fs::write(bundle.join("commands/ship.md"), "Ship it.\n")?;
fs::create_dir_all(bundle.join("agents"))?;
fs::write(bundle.join("agents/reviewer.toml"), "name = \"reviewer\"\n")?;
fs::write(
bundle.join("plugin.toml"),
"schema_version = 1\n[plugin]\nname = \"indexed\"\nversion = \"1.0.0\"\n\
description = \"test bundle\"\n\n[skills]\npath = \"skills\"\n\
[commands]\npath = \"commands\"\n[agents]\npath = \"agents\"\n",
)?;
let Some((addr, handle)) = spawn_plugin_api_server(root, workspace).await? else {
return Ok(());
};
let client = codewhale_release::tls::reqwest_client();
plugin_ui::install_active(
&client,
&format!("http://{addr}/v1/apps/plugins"),
bundle.display().to_string(),
)
.await?;
let listed: Value = client
.get(format!("http://{addr}/v1/apps/plugins"))
.send()
.await?
.error_for_status()?
.json()
.await?;
let id = listed["plugins"]
.as_array()
.and_then(|plugins| plugins.iter().find(|plugin| plugin["name"] == "indexed"))
.and_then(|plugin| plugin["id"].as_str())
.expect("installed plugin id")
.to_string();
*plugin_id.lock().expect("plugin id") = Some(id.clone());
let commands: Value = client
.get(format!("http://{addr}/v1/commands"))
.send()
.await?
.error_for_status()?
.json()
.await?;
let ship = commands["commands"]
.as_array()
.and_then(|rows| rows.iter().find(|row| row["name"] == "ship"))
.expect("ship row");
assert_eq!(ship["plugin_id"], id.as_str());
let index: Value = client
.get(format!("http://{addr}/v1/apps/plugin-index"))
.send()
.await?
.error_for_status()?
.json()
.await?;
let items = index["items"].as_array().expect("items");
let find = |id: &str| items.iter().find(|item| item["id"] == id);
let plugin = items
.iter()
.find(|item| item["kind"] == "plugin" && item["row"]["name"] == "indexed")
.unwrap_or_else(|| panic!("plugin row in {index}"));
assert_eq!(plugin["kind"], "plugin");
assert_eq!(plugin["state"], "enabled");
assert_eq!(plugin["adds"]["skills"], serde_json::json!(["greet"]));
assert_eq!(plugin["adds"]["commands"], serde_json::json!(["ship"]));
assert_eq!(plugin["adds"]["profiles"], serde_json::json!(["reviewer"]));
assert_eq!(
plugin["labels"],
serde_json::json!(["skill", "command", "profile"])
);
assert_eq!(plugin["row"]["name"], "indexed");
assert!(find("skill:greet").is_none());
assert!(find("command:ship").is_none());
let mine = find("command:mine").expect("a hand-written command is a row");
assert_eq!(mine["source"], "user");
assert_eq!(mine["labels"], serde_json::json!(["command"]));
assert!(
items
.iter()
.any(|item| item["kind"] == "plugin" && item["tier"] == "builtin"),
"built-in switches are rows"
);
assert_eq!(
index["unavailable"].as_array().map(Vec::len),
Some(0),
"{index}"
);
handle.abort();
Ok(())
}
#[tokio::test]
async fn the_index_keeps_same_name_hooks_distinct() -> Result<()> {
let _env = lock_test_env();
let temp = tempfile::tempdir()?;
let root = temp.path().join("hook-index-route");
let workspace = root.join("workspace");
let mut config = Config::default();
config.hooks = Some(codewhale_config::hooks::HooksConfig {
hooks: vec![
codewhale_config::hooks::Hook::new(
codewhale_config::hooks::HookEvent::SessionStart,
"echo first",
)
.with_name("gate"),
codewhale_config::hooks::Hook::new(
codewhale_config::hooks::HookEvent::SessionStart,
"echo second",
)
.with_name("gate"),
codewhale_config::hooks::Hook::new(
codewhale_config::hooks::HookEvent::SessionStart,
"echo third",
),
codewhale_config::hooks::Hook::new(
codewhale_config::hooks::HookEvent::SessionStart,
"echo fourth",
)
.with_name("session_start 3"),
],
enabled: true,
..Default::default()
});
let (addr, _runtime_threads, handle) =
spawn_test_server_with_root_token_mobile_workspace_and_overrides(
root.clone(),
root.join("sessions"),
None,
false,
workspace.clone(),
TestServerOverrides {
config: Some(config),
plugin_discovery: Some(isolated_plugin_discovery(&root, &workspace)),
..TestServerOverrides::default()
},
)
.await?
.expect("hook index test server");
let client = codewhale_release::tls::reqwest_client();
let index: Value = client
.get(format!("http://{addr}/v1/apps/plugin-index"))
.send()
.await?
.error_for_status()?
.json()
.await?;
let hooks: Vec<_> = index["items"]
.as_array()
.expect("items")
.iter()
.filter(|item| item["kind"] == "hook")
.collect();
assert_eq!(hooks.len(), 4, "{index}");
for (ordinal, hook) in hooks.iter().enumerate() {
assert_eq!(
hook["id"],
format!("hook:user:session_start:{}", ordinal + 1)
);
assert_eq!(hook["state"], "enabled");
}
assert_eq!(hooks[0]["name"], "gate");
assert_eq!(hooks[1]["name"], "gate");
assert_eq!(hooks[2]["name"], "session_start 3");
assert_eq!(hooks[3]["name"], "session_start 3");
assert_eq!(hooks[3]["row"]["command"], "echo fourth");
assert_eq!(hooks[0]["row"]["command"], "echo first");
assert_eq!(hooks[1]["row"]["command"], "echo second");
handle.abort();
Ok(())
}
@@ -79,7 +79,7 @@ fn write_native_ui_bundle(dir: &Path, name: &str) -> Result<PathBuf> {
Ok(bundle)
}
pub(super) async fn install_active(
async fn install_active(
client: &reqwest::Client,
base: &str,
source: String,
+75
View File
@@ -367,6 +367,81 @@ fn build_state_keeps_resolved_explicit_config_path() {
);
}
#[tokio::test]
async fn stdio_transport_never_registers_the_stdout_hook_sink() {
let tmp = tempfile::tempdir().expect("tempdir");
let config_path = tmp.path().join("config.toml");
fs::write(&config_path, "api_key = \"sk-deepseek-secret\"\n").expect("write config");
let http_state =
build_state_with_transport(Some(config_path.clone()), None, AppTransport::Http)
.expect("http state");
let stdio_state = build_state_with_transport(Some(config_path), None, AppTransport::Stdio)
.expect("stdio state");
let http_sinks = http_state.runtime.read().await.hooks.sink_count();
let stdio_sinks = stdio_state.runtime.read().await.hooks.sink_count();
assert_eq!(
http_sinks,
stdio_sinks + 1,
"HTTP mode keeps StdoutHookSink + JsonlHookSink; stdio must drop the stdout sink (#5165)"
);
}
// Points CODEWHALE_HOME at a temp dir for one test and restores it after.
// The variable is process-global, so these tests hold a lock.
static CODEWHALE_HOME_TEST_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
struct CodewhaleHomeGuard {
prior: Option<std::ffi::OsString>,
_lock: std::sync::MutexGuard<'static, ()>,
}
impl CodewhaleHomeGuard {
fn set(value: &Path) -> Self {
let lock = CODEWHALE_HOME_TEST_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let prior = std::env::var_os("CODEWHALE_HOME");
// SAFETY: serialised by CODEWHALE_HOME_TEST_LOCK.
unsafe { std::env::set_var("CODEWHALE_HOME", value) };
Self { prior, _lock: lock }
}
}
impl Drop for CodewhaleHomeGuard {
fn drop(&mut self) {
// SAFETY: serialised by CODEWHALE_HOME_TEST_LOCK.
unsafe {
match &self.prior {
Some(value) => std::env::set_var("CODEWHALE_HOME", value),
None => std::env::remove_var("CODEWHALE_HOME"),
}
}
}
}
#[tokio::test]
async fn hook_log_without_config_path_goes_beside_state_db_not_cwd() {
let home = tempfile::tempdir().expect("tempdir");
let _home = CodewhaleHomeGuard::set(home.path());
let state = build_state_with_transport(None, None, AppTransport::Stdio).expect("state");
state
.runtime
.read()
.await
.hooks
.emit(codewhale_hooks::HookEvent::ResponseStart {
response_id: "resp-6513".to_string(),
})
.await;
let log = fs::read_to_string(home.path().join("events.jsonl"))
.expect("hook log beside state.db in CODEWHALE_HOME");
assert!(log.contains("resp-6513"), "{log}");
}
async fn response_body_json(response: Response) -> Value {
let bytes = to_bytes(response.into_body(), usize::MAX)
.await
+2 -345
View File
@@ -3,13 +3,13 @@ mod acp_support;
use acp_support::{Client, fixture_config, text_of, updates};
use anyhow::{Result, anyhow};
use codewhale_app_server::acp_server::capture_frontend;
use codewhale_engine::llm_client::mock::{CannedTurn, MockLlmClient, canned};
use codewhale_engine::llm_client::mock::{MockLlmClient, canned};
use codewhale_engine::runtime_threads::RuntimeTurnStatus;
use codewhale_engine::runtime_threads::manager::{
RuntimeThreadManager, RuntimeThreadManagerConfig,
};
use serde_json::{Value, json};
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use tokio::io::{AsyncWriteExt, BufReader};
@@ -497,346 +497,3 @@ async fn extension_journey() -> Result<()> {
host.shutdown().await;
Ok(())
}
const GATES_MCP_FIXTURE: &str = r#"import readline from 'node:readline';
readline.createInterface({input:process.stdin}).on('line', line => {
const r = JSON.parse(line); if (r.id === undefined) return;
let result = {};
if (r.method === 'initialize') result = {protocolVersion:'2024-11-05',capabilities:{tools:{}},serverInfo:{name:'fixture',version:'1'}};
if (r.method === 'tools/list') result = {tools:['echo','hidden'].map(name => ({name,description:'Echo text',inputSchema:{type:'object',properties:{text:{type:'string'}},required:['text']}}))};
if (r.method === 'tools/call') result = {content:[{type:'text',text:'mcp-ran:' + r.params.name + ':' + r.params.arguments.text}]};
process.stdout.write(JSON.stringify({jsonrpc:'2.0',id:r.id,result}) + '\n');
});
"#;
struct Outcome {
response: Value,
frames: Vec<Value>,
asked: Vec<Value>,
}
impl Outcome {
fn rendered(&self) -> String {
serde_json::to_string(&self.frames).unwrap_or_default()
}
fn completed(&self) -> usize {
updates(&self.frames, "tool_call_update")
.iter()
.filter(|frame| frame.pointer("/params/update/status") == Some(&json!("completed")))
.count()
}
fn titles(&self) -> Vec<String> {
self.asked
.iter()
.map(|frame| {
frame["params"]["toolCall"]["title"]
.as_str()
.unwrap_or_default()
.to_string()
})
.collect()
}
fn announced_ids(&self) -> Vec<String> {
updates(&self.frames, "tool_call")
.iter()
.filter_map(|frame| frame.pointer("/params/update/toolCallId")?.as_str())
.map(str::to_string)
.collect()
}
}
async fn run_prompt(
client: &mut Client,
session: &str,
allow: &dyn Fn(usize) -> bool,
) -> Result<Outcome> {
client.next_id += 1;
let prompt_id = client.next_id;
client
.send(
json!({"jsonrpc":"2.0","id":prompt_id,"method":"session/prompt","params":{
"sessionId":session,"prompt":[{"type":"text","text":"go"}]}}),
)
.await?;
let mut frames = Vec::new();
let mut asked = Vec::new();
let response = loop {
let frame = client.recv().await?;
if frame["method"] == "session/request_permission" {
let option = if allow(asked.len()) {
"allow-once"
} else {
"reject-once"
};
client
.send(json!({"jsonrpc":"2.0","id":frame["id"],
"result":{"outcome":{"outcome":"selected","optionId":option}}}))
.await?;
asked.push(frame);
} else if frame["id"] == json!(prompt_id) && frame.get("method").is_none() {
break frame;
} else {
frames.push(frame);
}
};
Ok(Outcome {
response,
frames,
asked,
})
}
async fn new_session(
client: &mut Client,
manager: &RuntimeThreadManager,
workspace: &Path,
turns: Vec<CannedTurn>,
plan: bool,
) -> Result<String> {
manager.set_test_model_client(Arc::new(MockLlmClient::new(turns)));
let (created, _) = client
.request("session/new", json!({"cwd":workspace}))
.await?;
let session = created["result"]["sessionId"]
.as_str()
.ok_or_else(|| anyhow!("session/new returned no sessionId: {created}"))?
.to_string();
if plan {
let (set, _) = client
.request(
"session/set_mode",
json!({"sessionId":session,"modeId":"plan"}),
)
.await?;
assert!(set.get("error").is_none(), "{set}");
}
Ok(session)
}
#[test]
fn extension_tools_keep_the_permission_boundary_in_an_acp_session() -> Result<()> {
std::thread::Builder::new()
.stack_size(64 << 20)
.spawn(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?
.block_on(async {
tokio::time::timeout(Duration::from_secs(180), gates())
.await
.map_err(|_| anyhow!("extension gates exceeded 180s"))?
})
})?
.join()
.map_err(|_| anyhow!("extension gates thread panicked"))?
}
async fn gates() -> Result<()> {
use codewhale_engine::extension_host::test_support::{FixturePlugins, node_for_tests};
let Some(node) = node_for_tests("extension_tools_keep_the_permission_boundary") else {
return Ok(());
};
let _policy = codewhale_plugins::activation::TestPolicyGuard::extension_host(true);
let fixture = FixturePlugins::new(&["plugin-context", "core-call"]).await;
let host = fixture.manager(node.clone());
let _host = codewhale_engine::extension_host::TestManagerGuard::install(Arc::clone(&host));
let dir = tempfile::tempdir()?;
let _home = codewhale_engine::test_support::SealedHome::at(dir.path());
let workspace = fixture.workspace().to_path_buf();
std::fs::write(workspace.join("seed.txt"), "seed-content-xyz")?;
let server = dir.path().join("fixture-mcp.mjs");
std::fs::write(&server, GATES_MCP_FIXTURE)?;
let mcp_config = dir.path().join("mcp.json");
std::fs::write(
&mcp_config,
serde_json::to_vec(&json!({"servers":{
"fixture":{"command":node,"args":[server],"disabled_tools":["hidden"]},
"off":{"command":node,"args":[server],"disabled":true}
}}))?,
)?;
let runtime_dir = dir.path().join("runtime");
let mut config = fixture_config();
config.set_feature("mcp", true).unwrap();
config.set_feature("extension_host", true).unwrap();
config.mcp_config_path = Some(mcp_config.to_string_lossy().into_owned());
let manager = Arc::new(RuntimeThreadManager::open_host(
config.clone(),
workspace.clone(),
RuntimeThreadManagerConfig {
mcp_auth_context: Default::default(),
data_dir: runtime_dir.clone(),
task_data_dir: runtime_dir,
sessions_dir: None,
max_active_threads: 16,
},
fixture.registry(),
codewhale_engine::core::engine::EngineHostProfile::Acp,
None,
None,
)?);
let frontend = capture_frontend(
config,
"fixture-model".into(),
workspace.clone(),
Arc::clone(&manager),
codewhale_engine::session_manager::default_sessions_dir()?,
None,
None,
)?;
let (mut client, agent_read, agent_write) = Client::connect(false);
let connection = frontend.serve(Box::new(BufReader::new(agent_read)), Box::new(agent_write));
let manager_for_script = Arc::clone(&manager);
let script =
async {
let manager = manager_for_script;
let result = async {
client
.request(
"initialize",
json!({"protocolVersion":1,"clientCapabilities":{}}),
)
.await?;
let session = new_session(
&mut client,
&manager,
&workspace,
vec![
canned::tool_call_turn(
"n1",
"cc_call",
r#"{"name":"write","input":{"path":"nested.txt","content":"via-plugin"}}"#,
),
canned::simple_text_turn("nested allowed"),
],
false,
)
.await?;
let allowed = run_prompt(&mut client, &session, &|_| true).await?;
assert!(allowed.response.get("error").is_none(), "{}", allowed.response);
assert_eq!(allowed.response["result"]["stopReason"], "end_turn");
assert_eq!(allowed.asked.len(), 2, "{:?}", allowed.titles());
assert!(allowed.titles()[0].starts_with("cc_call"));
let announced = allowed.announced_ids();
for request in &allowed.asked {
let id = request["params"]["toolCall"]["toolCallId"]
.as_str()
.unwrap_or_default();
assert!(
announced.iter().any(|known| known == id),
"a nested approval is shown on a tool call the editor knows: {id} {announced:?}"
);
}
let nested = &allowed.asked[1]["params"]["toolCall"];
assert_eq!(nested["title"], "write: nested.txt", "{nested}");
assert_eq!(nested["kind"], "edit", "{nested}");
assert_eq!(nested["rawInput"]["path"], "nested.txt", "{nested}");
assert!(nested.get("status").is_none(), "{nested}");
assert_eq!(
std::fs::read_to_string(workspace.join("nested.txt"))?,
"via-plugin"
);
std::fs::remove_file(workspace.join("nested.txt"))?;
let session = new_session(
&mut client,
&manager,
&workspace,
vec![
canned::tool_call_turn(
"n2",
"cc_call",
r#"{"name":"write","input":{"path":"nested.txt","content":"via-plugin"}}"#,
),
canned::simple_text_turn("nested denied"),
],
false,
)
.await?;
let denied = run_prompt(&mut client, &session, &|index| index == 0).await?;
assert!(denied.response.get("error").is_none(), "{}", denied.response);
assert_eq!(denied.response["result"]["stopReason"], "end_turn");
assert_eq!(denied.asked.len(), 2, "{:?}", denied.titles());
assert!(
!workspace.join("nested.txt").exists(),
"a rejected nested write must not run"
);
let session = new_session(
&mut client,
&manager,
&workspace,
vec![
canned::tool_call_turn("r1", "ctx_probe", "{}"),
canned::tool_call_turn("r2", "mcp_fixture_echo", r#"{"text":"control"}"#),
canned::tool_call_turn("r3", "ctx_note", r#"{"text":"must-not-be-written"}"#),
canned::tool_call_turn("r4", "mcp_fixture_echo", r#"{"text":"rejected"}"#),
canned::simple_text_turn("rejections done"),
],
false,
)
.await?;
let rejected = run_prompt(&mut client, &session, &|index| index < 2).await?;
assert_eq!(rejected.asked.len(), 4, "{:?}", rejected.titles());
let rendered = rejected.rendered();
assert!(rendered.contains("mcp-ran:echo:control"), "{rendered}");
assert!(!rendered.contains("mcp-ran:echo:rejected"), "{rendered}");
assert!(!rendered.contains("note.txt"), "{rendered}");
let session = new_session(
&mut client,
&manager,
&workspace,
vec![
canned::tool_call_turn("p1", "ctx_probe", "{}"),
canned::tool_call_turn("p2", "mcp_fixture_echo", r#"{"text":"plan"}"#),
canned::simple_text_turn("plan done"),
],
true,
)
.await?;
let plan = run_prompt(&mut client, &session, &|_| true).await?;
assert!(plan.asked.is_empty(), "{:?}", plan.titles());
assert_eq!(plan.completed(), 0, "{}", plan.rendered());
assert!(!plan.rendered().contains("mcp-ran:"));
let session = new_session(
&mut client,
&manager,
&workspace,
vec![
canned::tool_call_turn("f1", "mcp_fixture_hidden", r#"{"text":"hid"}"#),
canned::tool_call_turn("f2", "mcp_off_echo", r#"{"text":"off"}"#),
canned::tool_call_turn("f3", "mcp_evil_echo", r#"{"text":"evil"}"#),
canned::tool_call_turn(
"f4",
"start_mcp_server",
r#"{"name":"evil","command":"node","args":["-e","0"]}"#,
),
canned::tool_call_turn("f5", "agent", r#"{"action":"start","prompt":"p"}"#),
canned::simple_text_turn("fabricated done"),
],
false,
)
.await?;
let fabricated = run_prompt(&mut client, &session, &|_| true).await?;
assert!(fabricated.asked.is_empty(), "{:?}", fabricated.titles());
assert_eq!(fabricated.completed(), 0, "{}", fabricated.rendered());
assert!(!fabricated.rendered().contains("mcp-ran:"));
client.request("shutdown", json!({})).await?;
Ok::<_, anyhow::Error>(())
}
.await;
if result.is_err() {
let _ = client.write.shutdown().await;
}
result
};
let (served, scripted) = tokio::join!(connection, script);
served?;
scripted?;
manager.shutdown_and_wait().await?;
host.shutdown().await;
Ok(())
}
-1
View File
@@ -38,7 +38,6 @@ codewhale-workflow = { path = "../workflow", version = "0.10.3" }
codewhale-execpolicy = { path = "../execpolicy", version = "0.10.3" }
codewhale-paths = { path = "../paths", version = "0.10.3" }
codewhale-release = { path = "../release", version = "0.10.3" }
codewhale-sanitize = { path = "../sanitize", version = "0.10.3" }
codewhale-secrets = { path = "../secrets", version = "0.10.3" }
codewhale-state = { path = "../state", version = "0.10.3" }
codewhale-telemetry = { path = "../telemetry", version = "0.10.3" }
+1 -1
View File
@@ -379,7 +379,7 @@ fn url_carries_credential(text: &str) -> bool {
// `***`; count masks rather than compare bytes, because it re-encodes the
// query and would otherwise flag benign URLs.
let masks = |value: &str| value.matches("***").count();
if masks(&codewhale_sanitize::sanitize::redact_url_for_display(text)) > masks(text) {
if masks(&codewhale_secrets::sanitize::redact_url_for_display(text)) > masks(text) {
return true;
}
let host = url.host_str().unwrap_or_default().to_ascii_lowercase();
-1
View File
@@ -25,7 +25,6 @@ semver.workspace = true
schemars = { version = "1.2.1", optional = true, features = ["derive", "preserve_order"] }
codewhale-execpolicy = { path = "../execpolicy", version = "0.10.3" }
codewhale-paths = { path = "../paths", version = "0.10.3" }
codewhale-sanitize = { path = "../sanitize", version = "0.10.3" }
codewhale-secrets = { path = "../secrets", version = "0.10.3" }
fd-lock = "4.0.4"
libc = "0.2"
+2 -2
View File
@@ -300,7 +300,7 @@ pub(crate) fn remove_plaintext_api_keys_in_array(array: &mut toml_edit::Array) {
pub(crate) fn backup_value_carries_secret(value: &toml_edit::Value) -> bool {
value
.as_str()
.is_some_and(codewhale_sanitize::sanitize::contains_secret)
.is_some_and(codewhale_secrets::sanitize::contains_secret)
}
pub(crate) fn scrub_backup_decor(decor: &mut toml_edit::Decor) {
@@ -331,7 +331,7 @@ pub(crate) fn scrub_backup_comments(text: &str) -> String {
comment
.split_once('=')
.is_some_and(|(key, _)| is_sensitive_config_key(key))
|| codewhale_sanitize::sanitize::contains_secret(comment)
|| codewhale_secrets::sanitize::contains_secret(comment)
})
})
.collect()
+1 -1
View File
@@ -99,7 +99,7 @@ pub fn toml_error_location(source: Option<&str>, err: &toml::de::Error) -> Strin
.and_then(|rest| rest.strip_prefix("\nin `"))
.and_then(|rest| rest.strip_suffix("`\n"))
.filter(|keys| !keys.is_empty())
.map(|keys| format!("in `{}`", codewhale_sanitize::redact::redact_secrets(keys)));
.map(|keys| format!("in `{}`", codewhale_secrets::redact::redact_secrets(keys)));
match (position, key_path) {
(Some(position), Some(keys)) => format!("{position}, {keys}"),
(Some(position), None) => position,
+1 -1
View File
@@ -128,7 +128,7 @@ pub(crate) fn redact_secret(secret: &str) -> String {
pub fn is_sensitive_config_key(key: &str) -> bool {
key.rsplit('.')
.next()
.is_some_and(codewhale_sanitize::sanitize::is_sensitive_key_name)
.is_some_and(codewhale_secrets::sanitize::is_sensitive_key_name)
}
/// Resolve dotted paths without treating a dotted key as a top-level literal.
+7
View File
@@ -5,6 +5,13 @@ use std::path::PathBuf;
/// On-disk schema for the `[hook_sinks]` table.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct HookSinksToml {
/// Unix domain socket path used by the app-server event sink.
///
/// Known limitation: only `codewhale app-server` reads this table; the
/// TUI and the Runtime API do not dispatch hook events to it.
///
/// When unset, no Unix socket sink is registered. There is deliberately no
/// shared `/tmp` default because socket ownership should be explicit.
#[serde(default)]
pub unix_socket_path: Option<PathBuf>,
}
+2 -2
View File
@@ -314,10 +314,10 @@ fn rollback(snapshots: &[Snapshot]) {
}
// FEAT-025 D4: the pure secret-redaction primitives moved to
// `codewhale-sanitize::redact` so portable command helpers can share one
// `codewhale-secrets::redact` so portable command helpers can share one
// implementation without depending on this crate. Re-exported here to keep
// the existing `codewhale_config::persistence::*` public API stable.
pub use codewhale_sanitize::redact::{
pub use codewhale_secrets::redact::{
REDACTED, RedactionPolicy, redact_json_model_bound_secrets, redact_json_secrets,
redact_model_bound_secrets, redact_secrets, redact_secrets_with,
};
+2 -2
View File
@@ -59,7 +59,7 @@ pub fn check_config_toml_choice(key: &str, value: &str) -> Result<()> {
} else {
""
};
let value = codewhale_sanitize::redact::redact_secrets(value);
let value = codewhale_secrets::redact::redact_secrets(value);
bail!(
"invalid value '{value}' for '{key}': config.toml accepts {}.{settings_note} \
No value was changed.\nfix: codewhale config set {key} {}",
@@ -205,7 +205,7 @@ pub fn load_project_config_outcome(workspace: &Path) -> ProjectConfigOutcome {
// echoed; an ordinary typo stays readable.
Some(name) => format!(
"unknown provider '{}'",
codewhale_sanitize::redact::redact_secrets(&name)
codewhale_secrets::redact::redact_secrets(&name)
),
None => "unknown provider".to_string(),
},
+1 -1
View File
@@ -1313,7 +1313,7 @@ pub const SETTINGS_SCHEMA: &[SettingDef] = &[
def(
"telemetry",
SettingKind::Bool(TELEMETRY),
"true",
"false",
ui(
TAB_TRUST,
"network",
+2
View File
@@ -14,6 +14,7 @@ workspace = true
serde.workspace = true
thiserror.workspace = true
codewhale-config = { path = "../config", version = "0.10.3" }
codewhale-hooks = { path = "../hooks", version = "0.10.3" }
codewhale-protocol = { path = "../protocol", version = "0.10.3" }
codewhale-state = { path = "../state", version = "0.10.3" }
regex = "1.11"
@@ -23,3 +24,4 @@ serde_json = { workspace = true, features = ["preserve_order"] }
[dev-dependencies]
tempfile.workspace = true
uuid.workspace = true
tokio = { workspace = true, features = ["macros", "rt", "time"] }
+9
View File
@@ -0,0 +1,9 @@
//! `ThreadId` / `SessionId` for the `crates/core` boundary (issue #5261).
//!
//! Re-exports the protocol ids so every crate that depends on `core` (the
//! TUI, CLI, app-server) speaks the same typed ids without depending on
//! `protocol` directly. The persisted JSON shape stays a plain string
//! (`"thread-…"` / `"session-…"`) so existing `state.json` / `threads/`
//! files need no migration.
pub use codewhale_protocol::ids::{SessionId, ThreadId};
+78
View File
@@ -0,0 +1,78 @@
//! Session tree journal placeholder (issue #5262).
//!
//! The journal is append-only with an in-memory tree projection:
//! every non-header entry carries `id` + `parentId`, the active position is
//! a `leafId`, appending creates a child of the leaf, and branching only
//! moves the leaf — it never rewrites history. This file lands the entry
//! shape that #5262's tree operations hang off of; compaction and
//! branch-summary entry kinds are included as first-class kinds but their
//! *strategies* are deferred.
//!
//! Re-exports the protocol journal as the canonical shape so `protocol` and
//! `core` agree on the wire. `core` adds the `SessionJournal` wrapper that
//! owns the `current_leaf_id` column in `state.threads`.
pub use codewhale_protocol::journal::{Journal, JournalEntry};
use serde::{Deserialize, Serialize};
/// Persisted thread metadata extension for the tree. This is the
/// `current_leaf_id` column added to `state.threads`; `None` before the
/// first turn, `Some(id)` after. The existing `threads` JSON shape is
/// otherwise unchanged (back-compat: old rows read as `None` and the next
/// append mints the header leaf).
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ThreadLeafState {
pub thread_id: String,
pub leaf_id: Option<String>,
}
/// First-class journal entry kinds (data shape lands now; strategies later).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JournalKind {
Header,
User,
Assistant,
ToolResult,
Compaction,
BranchSummary,
}
impl JournalKind {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Header => "header",
Self::User => "user",
Self::Assistant => "assistant",
Self::ToolResult => "tool_result",
Self::Compaction => "compaction",
Self::BranchSummary => "branch_summary",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn leaf_state_roundtrip() {
let s = ThreadLeafState {
thread_id: "thread-1".into(),
leaf_id: Some("entry-abc".into()),
};
let j = serde_json::to_string(&s).unwrap();
let back: ThreadLeafState = serde_json::from_str(&j).unwrap();
assert_eq!(back, s);
}
#[test]
fn journal_append_is_child_of_leaf() {
let mut j = Journal::new();
let a = j.append("header", json!({}));
let b = j.append("user", json!("hi"));
assert_eq!(j.get(&b).unwrap().parent_id.as_deref(), Some(a.as_str()));
}
}
+18 -5
View File
@@ -1,9 +1,12 @@
pub mod context_reference;
pub mod fragments;
pub mod ids;
pub mod journal;
pub mod prefix_cache;
pub mod request;
pub mod role;
pub mod secret_eq;
pub mod session;
pub mod tool_parser;
pub use context_reference::{
@@ -12,9 +15,10 @@ pub use context_reference::{
};
use codewhale_config::{ConfigToml, ProviderKind};
use codewhale_hooks::HookDispatcher;
use codewhale_state::StateStore;
/// Compatibility configuration.
/// Compatibility configuration and hooks.
///
/// Conversation execution and durable history belong to the held canonical
/// RuntimeThreadManager/Engine. Legacy State data is retained for read-only
@@ -22,11 +26,16 @@ use codewhale_state::StateStore;
pub struct Runtime {
pub config: ConfigToml,
state: StateStore,
pub hooks: HookDispatcher,
}
impl Runtime {
pub fn new(config: ConfigToml, state: StateStore) -> Self {
Self { config, state }
pub fn new(config: ConfigToml, state: StateStore, hooks: HookDispatcher) -> Self {
Self {
config,
state,
hooks,
}
}
/// Existing compatibility data and receipts; no transcript controller.
@@ -94,7 +103,7 @@ mod tests {
fn runtime_bookkeeping_keeps_the_legacy_store_read_only() {
let store = temp_core_state("read-only-runtime");
let before = store.list_threads(Default::default()).unwrap();
let mut runtime = Runtime::new(ConfigToml::default(), store);
let mut runtime = Runtime::new(ConfigToml::default(), store, HookDispatcher::default());
runtime.update_config(ConfigToml::default());
assert_eq!(
runtime
@@ -104,7 +113,11 @@ mod tests {
.len(),
before.len()
);
let reopened = Runtime::new(runtime.config.clone(), runtime.state_store().clone());
let reopened = Runtime::new(
runtime.config.clone(),
runtime.state_store().clone(),
HookDispatcher::default(),
);
assert!(
reopened
.state_store()
+135
View File
@@ -0,0 +1,135 @@
//! `Thread` / `Session` split (issue #5261).
//!
//! `codewhale`'s `Session` was really a thread. The new split is:
//! - `Thread` — durable, persisted, owns the append-only `Journal` and the
//! `leafId` cursor. One row in `state.threads`, one directory on disk.
//! - `Session` — ephemeral, per-turn / per-engine-lifetime, owns the
//! in-memory `TurnContext` plus the live approval/sandbox posture for this
//! `SessionId`. Many sessions can attach to one thread over time, but only
//! one `Session` drives a turn for a given `ThreadId` at a time.
//!
//! The canonical RuntimeThreadManager creates sessions without a TUI and drives
//! the same Engine turn loop used by mounted clients. These types preserve the
//! shared model, append log, prefix stability and message revision state; the
//! compatibility Core Runtime owns only configuration, hooks and job bookkeeping.
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::ids::{SessionId, ThreadId};
use crate::journal::Journal;
/// Durable thread (the former `Session`). One per conversation, persisted in
/// `state.threads`. The only new field vs the old `Session` is `leaf_id` — the
/// journal cursor — plus the typed `ThreadId`. All other fields keep their
/// persisted JSON shape unchanged.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Thread {
pub thread_id: ThreadId,
/// Active branch tip. `None` before the first journal header.
#[serde(skip_serializing_if = "Option::is_none")]
pub leaf_id: Option<String>,
/// Journal (append-only). In-memory projection of the persisted
/// `threads/turns/items/events` layout is derived root→leaf.
#[serde(default)]
pub journal: Journal,
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<String>,
pub workspace: PathBuf,
#[serde(default)]
pub ephemeral: bool,
}
impl Thread {
#[must_use]
pub fn new(thread_id: ThreadId, workspace: PathBuf, model: impl Into<String>) -> Self {
Self {
thread_id,
leaf_id: None,
journal: Journal::new(),
model: model.into(),
reasoning_effort: None,
workspace,
ephemeral: false,
}
}
#[must_use]
pub fn leaf_id(&self) -> Option<&str> {
self.leaf_id.as_deref()
}
pub fn set_leaf(&mut self, leaf: Option<String>) {
self.leaf_id = leaf;
}
}
/// Ephemeral session within a thread (one engine lifetime / one turn's
/// live posture). The TUI's `EngineHandle` and the headless `exec` both
/// hold a `Session` that points at the same `ThreadId` but with different
/// `SessionId`s.
#[derive(Debug, Clone)]
pub struct Session {
pub session_id: SessionId,
pub thread_id: ThreadId,
/// Model for this session's next turn (may differ from thread default).
pub model: String,
pub workspace: PathBuf,
/// Monotonic `messages_revision` for prefix-cache memoization (carried
/// from the former `Session::messages_revision`).
pub messages_revision: u64,
}
impl Session {
#[must_use]
pub fn new(thread_id: ThreadId, workspace: PathBuf, model: impl Into<String>) -> Self {
Self {
session_id: SessionId::new(),
thread_id,
model: model.into(),
workspace,
messages_revision: 0,
}
}
pub fn bump_revision(&mut self) {
self.messages_revision = self.messages_revision.wrapping_add(1);
}
}
/// Split helper: derive a `Session` from an existing `Thread` without
/// cloning the journal. Headless and TUI call the same constructor so
/// the request shape stays identical.
#[must_use]
pub fn session_for_thread(thread: &Thread, workspace: PathBuf) -> Session {
Session::new(thread.thread_id.clone(), workspace, thread.model.clone())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn thread_and_session_ids_are_distinct_scopes() {
let t = Thread::new(ThreadId::new(), PathBuf::from("/tmp"), "deepseek-v4-flash");
let s1 = Session::new(t.thread_id.clone(), PathBuf::from("/tmp"), &t.model);
let s2 = Session::new(t.thread_id.clone(), PathBuf::from("/tmp"), &t.model);
assert_eq!(s1.thread_id, s2.thread_id);
assert_ne!(s1.session_id, s2.session_id);
}
#[test]
fn leaf_is_moved_not_rewritten() {
let mut t = Thread::new(ThreadId::new(), PathBuf::from("/tmp"), "m");
let a = t.journal.append("header", serde_json::json!({}));
let b = t.journal.append("user", serde_json::json!("b"));
t.leaf_id = t.journal.leaf_id.clone();
assert_eq!(t.leaf_id.as_deref(), Some(b.as_str()));
assert!(t.journal.branch_to(&a));
t.leaf_id = t.journal.leaf_id.clone();
assert_eq!(t.leaf_id.as_deref(), Some(a.as_str()));
assert_eq!(t.journal.len(), 2); // history never rewritten; branching only moved the leaf
}
}
+6
View File
@@ -79,6 +79,7 @@ codewhale-app-server-protocol = { path = "../app-server-protocol", version = "0.
codewhale-sanitize = { path = "../sanitize", version = "0.10.3" }
codewhale-memory = { path = "../memory", version = "0.10.3" }
anyhow.workspace = true
codewhale-agent = { path = "../agent", version = "0.10.3" }
codewhale-agent-contract = { path = "../agent-contract", version = "0.10.3" }
codewhale-config = { path = "../config", version = "0.10.3" }
codewhale-command-contract = { path = "../command-contract", version = "0.10.3" }
@@ -202,9 +203,14 @@ codewhale-util = { path = "../util", version = "0.10.3", features = ["test-suppo
codewhale-models = { path = "../models", version = "0.10.3", features = [
"test-support",
] }
cucumber = "0.23.0"
wiremock = "0.6"
tiny_http = "0.12"
pretty_assertions = "1.4"
rio-vt = "0.5.1"
rusqlite.workspace = true
schemars = { version = "1.2.1", features = ["derive", "preserve_order"] }
tokio-tungstenite = "0.30"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
+1 -1
View File
@@ -56,7 +56,7 @@ use codewhale_models::{
ContentBlock, Message, MessageRequest, MessageResponse, SystemPrompt, Usage,
};
use codewhale_runtime::logging;
use codewhale_sanitize::sanitize::redact_url_for_display;
use codewhale_secrets::sanitize::redact_url_for_display;
/// Every provider request that can feed the interactive TUI's attached CWC run
/// takes a shared permit at this lowest common dispatch seam. Runtime Chat holds
+1 -1
View File
@@ -115,7 +115,7 @@ impl RouteShape {
/// Which endpoint this request would be POSTed to, as typed facts.
///
/// `url` is the real, unredacted target: production needs it to send. Every
/// display surface must go through [`codewhale_sanitize::sanitize::redact_url_for_display`] rather
/// display surface must go through [`codewhale_secrets::sanitize::redact_url_for_display`] rather
/// than printing it, and the manifest only ever publishes the redacted
/// scheme/host and a fingerprint — never the path, which can itself carry a
/// deployment secret.
-12
View File
@@ -138,16 +138,6 @@ pub struct SystemOneResponse {
pub answers_validated: Option<bool>,
}
impl SystemOneResponse {
pub fn abstained_questions(&self, names: &[&str]) -> Vec<String> {
names
.iter()
.filter(|name| self.answers.get(**name).is_some_and(|a| a.abstained))
.map(|name| (*name).to_string())
.collect()
}
}
impl<'de> Deserialize<'de> for SystemOneResponse {
fn deserialize<D: serde::Deserializer<'de>>(
deserializer: D,
@@ -211,8 +201,6 @@ pub struct SystemOneAnswer {
pub probabilities: BTreeMap<String, Option<f64>>,
#[serde(default)]
pub confidence: Option<f64>,
#[serde(default)]
pub abstained: bool,
}
/// Provider usage. OpenRouter adds `cost`; the token-count casing differs
-2
View File
@@ -29,8 +29,6 @@ pub struct UserCommand {
pub takes_arguments: bool,
pub hidden: bool,
pub extension: bool,
pub plugin_id: Option<String>,
pub workspace_sourced: bool,
pub builtin_bindings: Vec<String>,
}
@@ -1130,7 +1130,7 @@ pub fn build_reviewer_context(
held_reason: &str,
tool_input: &Value,
) -> String {
use codewhale_sanitize::redact::{redact_json_model_bound_secrets, redact_model_bound_secrets};
use codewhale_secrets::redact::{redact_json_model_bound_secrets, redact_model_bound_secrets};
let mut input = redact_json_model_bound_secrets(tool_input);
let tool = redact_model_bound_secrets(ctx.tool_name.as_ref());
+14 -32
View File
@@ -456,7 +456,7 @@ async fn captured_identity_cancel_and_task_bounds_refuse_before_any_provider() {
#[tokio::test]
async fn dropping_an_actual_dispatched_core_call_keeps_unknown_usage_without_retaining_authority() {
struct Pending(Arc<tokio::sync::Notify>);
struct Pending;
impl Replies for Pending {
fn effective_route_envelope(
&self,
@@ -478,42 +478,24 @@ async fn dropping_an_actual_dispatched_core_call_keeps_unknown_usage_without_ret
&self,
_: MessageRequest,
) -> Pin<Box<dyn Future<Output = anyhow::Result<MessageResponse>> + Send + '_>> {
self.0.notify_one();
Box::pin(std::future::pending())
}
}
let entered = Arc::new(tokio::sync::Notify::new());
let caller = Arc::new(caller_for(
Arc::new(Pending(entered.clone())),
"captured-model",
));
let caller = Arc::new(caller_for(Arc::new(Pending), "captured-model"));
let weak_caller = Arc::downgrade(&caller);
let usage = RlmUsageAccumulator::new();
let mut dispatch = caller.dispatch(RlmInvocation {
prompt: "pending".into(),
mode: RlmMode::Completion,
max_tokens: None,
task_instructions: None,
deadline: Some(tokio::time::Instant::now() + Duration::from_secs(600)),
gate: None,
events: None,
usage: usage.clone(),
});
tokio::time::timeout(Duration::from_secs(10), async {
tokio::select! {
biased;
() = entered.notified() => {}
result = &mut dispatch => panic!(
"dropped dispatch never reached the client: {:?}",
result.error
),
}
})
.await
.expect("the dispatched call must reach the client");
tokio::time::pause();
tokio::time::advance(Duration::from_secs(601)).await;
let result = dispatch.await;
let result = caller
.dispatch(RlmInvocation {
prompt: "pending".into(),
mode: RlmMode::Completion,
max_tokens: None,
task_instructions: None,
deadline: Some(tokio::time::Instant::now() + Duration::from_millis(100)),
gate: None,
events: None,
usage: usage.clone(),
})
.await;
assert!(
result
.error
@@ -30,13 +30,18 @@ use std::hash::{Hash, Hasher};
use crate::compaction::estimate_input_tokens_for_pressure;
use codewhale_models::{Message, SystemPrompt};
/// Default capacity for the rolling audit ring. Sized so a 64-entry window
/// covers a full capacity controller observation cycle without unbounded
/// growth on long-running sessions.
const AUDIT_RING_CAPACITY: usize = 64;
/// Process-local memoization for `estimate_input_tokens_for_pressure`.
///
/// The cache is keyed on the `(messages_revision, system_fingerprint)`
/// pair, both of which the engine bumps on every content change. On a hit
/// the previously stored token estimate is returned without re-walking the
/// message list. On a miss, the estimator runs and the result is stored
/// for the next lookup.
/// alongside the audit ring entry.
#[derive(Debug, Default, Clone)]
pub struct TokenEstimateCache {
/// Monotonic counter bumped by the engine on every message mutation.
@@ -46,6 +51,10 @@ pub struct TokenEstimateCache {
system_fingerprint: u64,
/// Cached token count, valid iff both keys match the current inputs.
cached_tokens: Option<usize>,
/// Audit ring of recent (revision, tokens) pairs. The most recent entry
/// is the tail; the oldest is dropped when capacity is exceeded. Used by
/// observability to surface cache effectiveness to `/status`.
audit_ring: Vec<(u64, usize)>,
/// Number of cache hits since the cache was last cleared. Saturates at
/// `u64::MAX` (effectively never in practice).
hits: u64,
@@ -88,6 +97,7 @@ impl TokenEstimateCache {
self.system_fingerprint = system_fingerprint;
self.cached_tokens = Some(tokens);
self.misses = self.misses.saturating_add(1);
self.push_audit(messages_revision, tokens);
tokens
}
@@ -105,6 +115,7 @@ impl TokenEstimateCache {
pub fn invalidate(&mut self) {
self.cached_tokens = None;
self.system_fingerprint = 0;
self.audit_ring.clear();
self.hits = 0;
self.misses = 0;
}
@@ -114,6 +125,20 @@ impl TokenEstimateCache {
pub fn stats(&self) -> (u64, u64) {
(self.hits, self.misses)
}
/// Returns the most recent `(revision, tokens)` audit entries, newest
/// first. Bounded by [`AUDIT_RING_CAPACITY`].
#[must_use]
pub fn recent_audit(&self) -> &[(u64, usize)] {
&self.audit_ring
}
fn push_audit(&mut self, revision: u64, tokens: usize) {
if self.audit_ring.len() >= AUDIT_RING_CAPACITY {
self.audit_ring.remove(0);
}
self.audit_ring.push((revision, tokens));
}
}
/// Stable 64-bit hash of the system prompt text. Walks the same shape the
@@ -263,4 +288,29 @@ mod tests {
assert_eq!(hits, 0);
assert_eq!(misses, 2);
}
#[test]
fn audit_ring_records_recent_pairs() {
let mut cache = TokenEstimateCache::new();
let messages = vec![user_text("hi")];
for rev in 1..=5 {
let _ = cache.lookup_or_compute(rev, None, &messages);
}
let ring = cache.recent_audit();
assert_eq!(ring.len(), 5);
assert_eq!(ring.last().copied(), Some((5, ring.last().unwrap().1)));
}
#[test]
fn audit_ring_bounded_by_capacity() {
let mut cache = TokenEstimateCache::new();
let messages = vec![user_text("hi")];
for rev in 1..=(AUDIT_RING_CAPACITY + 10) as u64 {
let _ = cache.lookup_or_compute(rev, None, &messages);
}
let ring = cache.recent_audit();
assert_eq!(ring.len(), AUDIT_RING_CAPACITY);
// newest entry should be the most recent revision we asked for
assert_eq!(ring.last().unwrap().0, (AUDIT_RING_CAPACITY + 10) as u64);
}
}
+2 -2
View File
@@ -301,7 +301,7 @@ fn mcp_snapshot_to_wire(snapshot: &McpManagerSnapshot) -> wire::McpManagerSnapsh
/// `EventMsg::McpSessionBoot`, which every SSE and stream-JSON consumer
/// receives and any frame-retaining log keeps.
///
/// URLs reuse the existing masking in `codewhale_sanitize::sanitize::redact_url_for_display`. Stdio
/// URLs reuse the existing masking in `codewhale_secrets::sanitize::redact_url_for_display`. Stdio
/// keeps the program name and elides the arguments, because a secret there can
/// be positional and is not reliably recognizable by key.
fn redacted_command_or_url(raw: &str) -> String {
@@ -315,7 +315,7 @@ fn redacted_command_or_url(raw: &str) -> String {
// mentions a URL — `docker run -e TOKEN=… img --url https://…` — would
// reach the wire with its positional secret intact.
if !trimmed.is_empty() && !trimmed.contains(char::is_whitespace) && trimmed.contains("://") {
return codewhale_sanitize::sanitize::redact_url_for_display(trimmed);
return codewhale_secrets::sanitize::redact_url_for_display(trimmed);
}
if let Some((program, rest)) = trimmed.split_once(char::is_whitespace)
&& !rest.trim().is_empty()
-1
View File
@@ -2643,7 +2643,6 @@ pub fn decision_receipt_fixture(source_id: &str) -> RuntimeDecisionReceipt {
probabilities_bp: Default::default(),
confidence_bp: 0,
min_confidence_bp: 5_000,
abstained_questions: Vec::new(),
cost_saving_kept_fast: false,
thinking: None,
provider_reported_cost_usd: Some("0.000012054".to_string()),
+1 -1
View File
@@ -204,7 +204,7 @@ pub enum CommandOutcome {
fn strip_escapes(text: &str) -> String {
let mut clean = String::with_capacity(text.len());
codewhale_sanitize::sanitize::strip_ansi_into(text, &mut clean);
codewhale_secrets::sanitize::strip_ansi_into(text, &mut clean);
clean
}
+3 -1
View File
@@ -18,6 +18,8 @@
//! never render a child session, which is what keeps the orchestrator light at
//! high fanout.
#![allow(dead_code)]
use anyhow::Result;
use codewhale_config::FleetExecConfig;
use codewhale_protocol::fleet::{
@@ -527,7 +529,7 @@ fn parse_exec_terminal_route(value: &serde_json::Value) -> ParsedTerminalRoute {
route.map_or(ParsedTerminalRoute::Invalid, ParsedTerminalRoute::Valid)
}
#[cfg(test)]
#[cfg(any(test, feature = "test-support"))]
fn map_exec_terminal_route(line: &str) -> Option<FleetWorkerReportedRoute> {
let value: serde_json::Value = serde_json::from_str(line).ok()?;
match parse_exec_terminal_route(&value) {
+5 -3
View File
@@ -4,6 +4,8 @@
//! observe work through this trait without knowing whether the worker is a
//! local child process or an SSH-backed remote command.
#![allow(dead_code)]
use std::collections::{BTreeMap, BTreeSet};
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
@@ -216,7 +218,7 @@ struct LocalWorkerProcess {
#[cfg(unix)]
session_id: libc::pid_t,
#[cfg(unix)]
_parent_death_writer: Option<std::io::PipeWriter>,
parent_death_writer: Option<std::io::PipeWriter>,
#[cfg(windows)]
windows_job: FleetWindowsJob,
host_kind: FleetHostKind,
@@ -385,7 +387,7 @@ impl LocalProcessFleetHostAdapter {
#[cfg(unix)]
session_id: pid as libc::pid_t,
#[cfg(unix)]
_parent_death_writer: parent_death_writer,
parent_death_writer,
#[cfg(windows)]
windows_job,
host_kind,
@@ -1518,7 +1520,7 @@ fn signal_unix_session(
Ok(errors)
}
#[cfg(all(unix, test))]
#[cfg(unix)]
fn unix_pid_is_running(pid: libc::pid_t) -> bool {
if !unix_pid_exists(pid) {
return false;
+2
View File
@@ -5,6 +5,8 @@
//! Artifacts are referenced by bounded metadata; large payloads live on disk
//! and are never embedded in the ledger.
#![allow(dead_code)]
use std::collections::BTreeMap;
use std::collections::HashMap;
#[cfg(test)]
+2 -1
View File
@@ -4,6 +4,8 @@
//! foreground and coordinate logical local workers while later host adapters
//! add real process and SSH execution behind the same records.
#![allow(dead_code)]
use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};
use std::time::Duration;
@@ -2358,7 +2360,6 @@ impl FleetManager {
}
}
#[cfg(test)]
fn append_worker_event(
&self,
run_id: &FleetRunId,
+3
View File
@@ -1,5 +1,7 @@
//! Fleet profile vocabulary, local profile discovery, and config-facing aliases.
#![allow(dead_code)]
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
@@ -8,6 +10,7 @@ use serde::{Deserialize, Serialize};
use crate::reasoning_preference::ReasoningEffort;
#[allow(unused_imports)]
pub use codewhale_config::{
FleetDelegationHints, FleetLoadout, FleetProfile, FleetProfilePermissions, FleetRole, FleetSlot,
};
+5 -16
View File
@@ -1,16 +1,14 @@
//! Fleet scheduler policy: leases, heartbeats, backpressure, and recovery.
#[cfg(test)]
#![allow(dead_code)]
use std::collections::{BTreeMap, BTreeSet};
use std::path::Path;
use std::time::Duration;
#[cfg(test)]
use anyhow::anyhow;
use anyhow::{Context, Result};
use anyhow::{Context, Result, anyhow};
use chrono::{DateTime, SecondsFormat, Utc};
use codewhale_protocol::fleet::*;
#[cfg(test)]
use serde_json::Value;
use super::ledger::{FleetLedger, FleetLedgerState, FleetTaskLedgerStatus, FleetTaskState};
@@ -67,7 +65,7 @@ impl FleetScheduler {
self.now = now;
}
#[cfg(test)]
#[cfg(any(test, feature = "test-support"))]
pub fn tick_run(&self, run_id: &FleetRunId) -> Result<FleetSchedulerReport> {
let mut report = FleetSchedulerReport::default();
self.recover_unhealthy_work(run_id, &mut report, &mut |_, _, _, _| Ok(()))?;
@@ -85,7 +83,7 @@ impl FleetScheduler {
/// and idempotent to call on a fresh process: a task re-leased by an
/// earlier resume is no longer stale at the same instant, and a terminally
/// failed task is never failed or escalated twice.
#[cfg(test)]
#[cfg(any(test, feature = "test-support"))]
pub fn resume_run(&self, run_id: &FleetRunId) -> Result<FleetSchedulerReport> {
self.resume_run_with_restart_callback(run_id, |_, _, _, _| Ok(()))
}
@@ -136,7 +134,6 @@ impl FleetScheduler {
Ok(report)
}
#[cfg(test)]
fn recover_unhealthy_work(
&self,
run_id: &FleetRunId,
@@ -397,7 +394,6 @@ impl FleetScheduler {
Ok(())
}
#[cfg(test)]
fn launch_queued_work(
&self,
run_id: &FleetRunId,
@@ -454,7 +450,6 @@ impl FleetScheduler {
}
}
#[cfg(test)]
fn next_launch(
&self,
run: &FleetRun,
@@ -599,7 +594,6 @@ impl FleetScheduler {
.update_run_status(run_id, status, &self.timestamp())
}
#[cfg(test)]
fn append_worker_event(
&self,
run_id: &FleetRunId,
@@ -621,14 +615,12 @@ impl FleetScheduler {
}
}
#[cfg(test)]
#[derive(Debug, Default)]
struct ActiveCounts {
by_host: BTreeMap<String, usize>,
by_task_class: BTreeMap<String, usize>,
}
#[cfg(test)]
fn active_counts(state: &FleetLedgerState, run: &FleetRun) -> ActiveCounts {
let mut counts = ActiveCounts::default();
for task in active_tasks_for_run(state, &run.id) {
@@ -654,7 +646,6 @@ fn active_counts(state: &FleetLedgerState, run: &FleetRun) -> ActiveCounts {
counts
}
#[cfg(test)]
fn active_tasks_for_run(state: &FleetLedgerState, run_id: &FleetRunId) -> Vec<FleetTaskState> {
state
.tasks
@@ -676,7 +667,6 @@ fn task_spec_for(state: &FleetLedgerState, task: &FleetTaskState) -> Option<Flee
.cloned()
}
#[cfg(test)]
fn host_key(worker: &FleetWorkerSpec) -> String {
match &worker.host {
FleetHostSpec::Local => "local".to_string(),
@@ -686,7 +676,6 @@ fn host_key(worker: &FleetWorkerSpec) -> String {
}
}
#[cfg(test)]
fn task_class(task: &FleetTaskSpec) -> String {
task.metadata
.get("class")
@@ -11,6 +11,8 @@
//! - Mailbox events stream into the Fleet ledger as `FleetWorkerEventPayload`
//! - `FleetWorkerInspection` reads both ledger state and sub-agent worker records
#![allow(dead_code)]
use std::borrow::Cow;
use std::path::PathBuf;
+17 -44
View File
@@ -1669,10 +1669,6 @@ pub trait McpTransport: Send + Sync {
async fn recv(&mut self) -> Result<Vec<u8>>;
async fn send_reply(&mut self, msg: Vec<u8>) -> Result<()> {
self.send(msg).await
}
/// Record the protocol revision negotiated at `initialize`. Only the
/// Streamable HTTP transport uses it (the `MCP-Protocol-Version` header on
/// subsequent requests); stdio and legacy SSE have no header channel, so
@@ -3129,30 +3125,6 @@ impl McpConnection {
result
}
async fn answer_server_request(&mut self, reply: &serde_json::Value) {
let result = match serde_json::to_vec(reply) {
Ok(bytes) => {
let cancel_token = self.cancel_token.clone();
tokio::select! {
biased;
_ = cancel_token.cancelled() => {
Err(anyhow::anyhow!("MCP connection was cancelled"))
}
result = self.transport.send_reply(bytes) => result,
}
}
Err(err) => Err(err.into()),
};
if let Err(err) = result {
tracing::debug!(
target: "mcp",
server = %self.name,
error = %err,
"could not answer an MCP server request"
);
}
}
/// Handshake and discovery receive: each frame wait is bounded by the read
/// knob, and a server that stays silent past it is treated as dead.
async fn recv(&mut self, expected_id: String) -> Result<serde_json::Value> {
@@ -3230,22 +3202,6 @@ impl McpConnection {
{
self.catalog_stale = true;
}
if let Some(method) = value.get("method") {
if let Some(id) = value.get("id") {
let method = method.as_str().unwrap_or_default();
let reply = if method == "ping" {
serde_json::json!({"jsonrpc": "2.0", "id": id, "result": {}})
} else {
serde_json::json!({
"jsonrpc": "2.0",
"id": id,
"error": {"code": -32601, "message": format!("Method not found: {method}")}
})
};
self.answer_server_request(&reply).await;
}
continue;
}
if response_id_matches(value.get("id"), &expected_id) {
// Marks the connection stale so it is rebuilt, but this is a
// reply to the request, so it never qualifies for a replay.
@@ -3736,6 +3692,23 @@ impl McpPool {
Ok(pool)
}
/// Construct a source-aware empty pool after the initial config load
/// failed. Keeping the source paths means a later edit or explicit
/// `/mcp reload` can recover in-process instead of pinning the session to
/// an ad-hoc pool that has no files to re-read.
pub fn empty_with_workspace_config_sources(
path: &std::path::Path,
workspace: &Path,
plugins: Arc<codewhale_plugins::PluginRegistry>,
) -> Result<Self> {
Self::empty_with_workspace_config_sources_and_auth_context(
path,
workspace,
plugins,
process_mcp_auth_context(),
)
}
pub fn empty_with_workspace_config_sources_and_auth_context(
path: &std::path::Path,
workspace: &Path,
+68 -1
View File
@@ -404,6 +404,30 @@ pub fn persist_decisions(
})
}
/// Filter candidates that still need a user decision for this content hash.
#[allow(dead_code)] // used by future selector UI + unit tests
pub fn candidates_needing_consent(
candidates: &[ImportCandidate],
store: &ImportConsentStore,
) -> Vec<ImportCandidate> {
candidates
.iter()
.filter(|c| {
let key = consent_key(&c.source_path, &c.content_hash);
match store.entries.get(&key) {
Some(entry) if entry.decision == ImportDecision::Decline => false,
Some(entry) if entry.decision == ImportDecision::Approve => {
// Re-prompt only when the specific server was not part of
// the prior approval list (partial approval).
!entry.servers.iter().any(|s| s == &c.name)
}
_ => true,
}
})
.cloned()
.collect()
}
/// Apply approvals: returns servers to merge into user mcp.json.
/// Hard-blocked candidates are never returned even if decision is Approve.
#[cfg(any(test, feature = "test-support"))]
@@ -1069,7 +1093,7 @@ mod tests {
}
#[test]
fn unrelated_source_rewrites_keep_review_tokens() {
fn unrelated_source_rewrites_keep_review_tokens_and_declines() {
with_import_context(|context| {
let source = write_claude_json(
&context.home,
@@ -1092,6 +1116,23 @@ mod tests {
)
.unwrap();
assert!(receipt.imported);
let candidates = discover_from_json_file(&source, ExternalMcpSourceKind::ClaudeJson);
let mut store = ImportConsentStore::default();
let decisions = HashMap::from([("y".to_string(), ImportDecision::Decline)]);
record_decisions(&mut store, &candidates, &decisions, 1);
fs::write(
&source,
r#"{"numStartups":3,"mcpServers":{"x":{"command":"echo"},"y":{"command":"echo"}}}"#,
)
.unwrap();
let refreshed = discover_from_json_file(&source, ExternalMcpSourceKind::ClaudeJson);
let needing: Vec<_> = candidates_needing_consent(&refreshed, &store)
.into_iter()
.map(|c| c.name)
.collect();
// `y` stays declined; `x` was never decided in this store.
assert_eq!(needing, ["x"]);
});
}
@@ -1167,6 +1208,32 @@ mod tests {
assert!(!config.servers["ok"].is_enabled());
}
#[test]
fn declined_consent_skips_reprompt_until_hash_changes() {
let dir = tempdir().unwrap();
let path = write_claude_json(
dir.path(),
r#"{"mcpServers":{"x":{"command":"echo","enabled":true}}}"#,
);
let candidates = discover_from_json_file(&path, ExternalMcpSourceKind::ClaudeJson);
let mut store = ImportConsentStore::default();
let mut decisions = HashMap::new();
decisions.insert("x".into(), ImportDecision::Decline);
record_decisions(&mut store, &candidates, &decisions, 1);
let needing = candidates_needing_consent(&candidates, &store);
assert!(needing.is_empty(), "declined should not re-prompt");
// Content change → new hash → re-prompt.
fs::write(
&path,
r#"{"mcpServers":{"x":{"command":"echo","args":["changed"],"enabled":true}}}"#,
)
.unwrap();
let refreshed = discover_from_json_file(&path, ExternalMcpSourceKind::ClaudeJson);
let needing = candidates_needing_consent(&refreshed, &store);
assert_eq!(needing.len(), 1);
}
#[test]
fn provenance_display_includes_source_and_hash() {
let dir = tempdir().unwrap();
-15
View File
@@ -177,21 +177,6 @@ impl McpTransport for HttpTransport {
}
}
async fn send_reply(&mut self, msg: Vec<u8>) -> Result<()> {
match &mut self.mode {
HttpTransportMode::Streamable(transport) => {
transport.send(msg).await.map_err(|err| match err {
StreamableSendError::Incompatible(detail)
| StreamableSendError::StaleSession(detail) => anyhow::anyhow!(
"MCP Streamable HTTP refused a reply to a server request: {detail}"
),
StreamableSendError::Other(err) => err,
})
}
HttpTransportMode::Sse(transport) => transport.send(msg).await,
}
}
async fn recv(&mut self) -> Result<Vec<u8>> {
match &mut self.mode {
HttpTransportMode::Streamable(transport) => transport.recv().await,
+17
View File
@@ -1607,6 +1607,23 @@ pub fn server_supports_oauth_login(server: &McpServerConfig) -> bool {
&& !server_has_manual_authorization(server)
}
/// Whether the shared token store already holds a usable credential for this
/// server, with its binding revalidated against discovery. Used by the
/// authenticate tool's already-authorized branch.
pub async fn has_usable_stored_tokens(
name: &str,
server: &McpServerConfig,
network_policy: Option<&NetworkPolicyDecider>,
) -> Result<bool> {
has_usable_stored_tokens_with_auth_context(
name,
server,
network_policy,
super::process_mcp_auth_context(),
)
.await
}
pub async fn has_usable_stored_tokens_with_auth_context(
name: &str,
server: &McpServerConfig,
-128
View File
@@ -3314,80 +3314,6 @@ async fn call_method_skips_notifications_and_unmatched_responses() {
assert_eq!(sent[0]["method"], "tools/call");
}
#[tokio::test]
async fn call_method_answers_server_requests_instead_of_taking_them_as_the_reply() {
let sent = Arc::new(Mutex::new(Vec::new()));
let transport = ScriptedValueTransport {
sent: Arc::clone(&sent),
responses: VecDeque::from([
json_frame(serde_json::json!({"jsonrpc": "2.0", "id": 1, "method": "ping"})),
json_frame(serde_json::json!({"jsonrpc": "2.0", "id": "1", "method": "roots/list"})),
json_frame(serde_json::json!({"jsonrpc": "2.0", "id": 1, "result": {"ok": true}})),
]),
};
let mut conn = test_connection(Box::new(transport));
let result = conn
.call_method("tools/call", serde_json::json!({"name": "echo"}), 1)
.await
.unwrap();
assert_eq!(result, serde_json::json!({"ok": true}));
let sent = sent.lock().unwrap();
assert_eq!(sent.len(), 3);
assert_eq!(
sent[1],
serde_json::json!({"jsonrpc": "2.0", "id": 1, "result": {}})
);
assert_eq!(sent[2]["id"], "1");
assert_eq!(sent[2]["error"]["code"], -32601);
}
struct ReplyRefusingTransport {
sent: Arc<Mutex<Vec<serde_json::Value>>>,
responses: VecDeque<Vec<u8>>,
}
#[async_trait::async_trait]
impl McpTransport for ReplyRefusingTransport {
async fn send(&mut self, msg: Vec<u8>) -> Result<()> {
let msg: serde_json::Value = serde_json::from_slice(&msg)?;
anyhow::ensure!(msg.get("method").is_some(), "status=405 Method Not Allowed");
self.sent.lock().unwrap().push(msg);
Ok(())
}
async fn recv(&mut self) -> Result<Vec<u8>> {
self.responses
.pop_front()
.context("scripted transport exhausted")
}
}
#[tokio::test]
async fn call_method_keeps_its_reply_when_answering_a_server_request_fails() {
let sent = Arc::new(Mutex::new(Vec::new()));
let transport = ReplyRefusingTransport {
sent: Arc::clone(&sent),
responses: VecDeque::from([
json_frame(serde_json::json!({"jsonrpc": "2.0", "id": 1, "method": "ping"})),
json_frame(serde_json::json!({"jsonrpc": "2.0", "id": 1, "result": {"ok": true}})),
]),
};
let mut conn = test_connection(Box::new(transport));
let result = conn
.call_method("tools/call", serde_json::json!({"name": "echo"}), 1)
.await
.unwrap();
assert_eq!(result, serde_json::json!({"ok": true}));
assert_eq!(conn.state, ConnectionState::Ready);
let sent = sent.lock().unwrap();
assert_eq!(sent.len(), 1);
assert_eq!(sent[0]["method"], "tools/call");
}
#[tokio::test]
async fn call_method_invalid_json_includes_server_output_preview() {
let sent = Arc::new(Mutex::new(Vec::new()));
@@ -6844,60 +6770,6 @@ async fn custom_headers_applied_to_get_preflight() {
);
}
#[tokio::test]
async fn refused_reply_to_a_server_request_does_not_fall_back_to_sse() {
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
let _env = crate::test_support::lock_test_env();
let _lock = lock_mcp_loopback_tests().await;
let _no_proxy = crate::test_support::EnvVarGuard::set("NO_PROXY", "*,127.0.0.1");
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let requests = Arc::new(Mutex::new(Vec::new()));
let requests_srv = Arc::clone(&requests);
let server = tokio::spawn(async move {
loop {
let (mut socket, _) = listener.accept().await.unwrap();
let mut buf = [0u8; 4096];
let n = socket.read(&mut buf).await.unwrap();
let request_line = String::from_utf8_lossy(&buf[..n])
.lines()
.next()
.unwrap_or_default()
.to_string();
requests_srv.lock().unwrap().push(request_line);
socket
.write_all(
b"HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\nContent-Length: 0\r\n\r\n",
)
.await
.unwrap();
}
});
let url = format!("http://{addr}/mcp");
let mut transport = HttpTransport::new(
test_mcp_http_client(&url),
url,
tokio_util::sync::CancellationToken::new(),
Duration::from_secs(2),
);
let result = transport
.send_reply(json_frame(
serde_json::json!({"jsonrpc": "2.0", "id": 1, "result": {}}),
))
.await;
server.abort();
assert!(result.is_err(), "a refused reply reports the refusal");
let requests = requests.lock().unwrap();
assert_eq!(requests.len(), 1, "requests seen: {requests:?}");
assert!(requests[0].starts_with("POST "), "{requests:?}");
}
// === add_runtime_server_config conflict tests ===
#[test]
+23 -5
View File
@@ -282,20 +282,31 @@ impl ModelInventory {
// vendor-family heuristic) carries the number *and* the fact
// that nobody verified it — the auto-router must not read a
// guessed window as a route capability.
let mut context_window_unverified = true;
let mut context_window_unverified =
codewhale_config::catalog::reviewed::intrinsic_model(&model)
.and_then(|row| row.context_window)
.is_none();
if let Ok(route) = crate::route_runtime::resolve_runtime_route_for_identity(
config,
&identity,
Some(&model),
) {
capability.context_window = route.context_window.tokens;
context_window_unverified = !route.context_window.source.is_verified();
capability.max_output = route
if let Some(context_window) = route.candidate.limits().context_tokens {
capability.context_window = context_window.min(u64::from(u32::MAX)) as u32;
context_window_unverified = !route.context_window.source.is_verified();
}
// A concrete offering maximum is a stronger fact than the
// static compatibility matrix — and is the only way a
// membership route (no static cap) gets a known ceiling.
if let Some(max_output) = route
.candidate
.limits()
.output_tokens
.and_then(|tokens| u32::try_from(tokens).ok())
.filter(|tokens| *tokens > 0);
.filter(|tokens| *tokens > 0)
{
capability.max_output = Some(max_output);
}
user_declared = route
.candidate
.applied_limit_overrides()
@@ -305,6 +316,13 @@ impl ModelInventory {
== codewhale_config::route::OverrideSource::UserModelMetadata
});
if user_declared {
context_window_unverified = !route.context_window.source.is_verified();
capability.context_window = route.context_window.tokens;
capability.max_output = route
.candidate
.limits()
.output_tokens
.and_then(|value| u32::try_from(value).ok());
capability.thinking_supported = route.candidate.capabilities().reasoning
== codewhale_config::route::CapabilityState::Supported;
}
+2 -60
View File
@@ -1852,7 +1852,6 @@ pub struct ValidChoice {
pub choice: String,
pub probabilities_bp: BTreeMap<String, u16>,
pub confidence_bp: u16,
pub abstained: bool,
}
/// Validate one `choice` answer against the offered options. Any violation
@@ -1895,7 +1894,6 @@ pub fn validated_choice(answer: Option<&SystemOneAnswer>, options: &[&str]) -> O
choice: choice.to_string(),
probabilities_bp,
confidence_bp: probability_bp(confidence),
abstained: answer.abstained,
})
}
@@ -1984,7 +1982,6 @@ fn decision_attempt_from_response(
probabilities_bp: Default::default(),
confidence_bp: 0,
min_confidence_bp: inventory.router_min_confidence_bp,
abstained_questions: response.abstained_questions(&["tier", "thinking"]),
cost_saving_kept_fast: false,
thinking: None,
provider_reported_cost_usd: response
@@ -2008,18 +2005,17 @@ fn decision_attempt_from_response(
let min_confidence_bp = inventory.router_min_confidence_bp;
// An invalid or unsure `thinking` answer drops only the effort.
let thinking = validated_choice(response.answers.get("thinking"), &DECISION_THINKING_OPTIONS)
.filter(|thinking| !thinking.abstained && thinking.confidence_bp >= min_confidence_bp)
.filter(|thinking| thinking.confidence_bp >= min_confidence_bp)
.map(|thinking| thinking.choice);
let strong_bp = tier.probabilities_bp.get("strong").copied().unwrap_or(0);
let cost_saving_kept_fast =
cost_saving && tier.choice == "strong" && strong_bp < COST_SAVING_STRONG_MIN_BP;
let acted = !tier.abstained && tier.confidence_bp >= min_confidence_bp;
let acted = tier.confidence_bp >= min_confidence_bp;
attempt.decision = Some(AutoRouteDecisionEvidence {
choice: tier.choice.clone(),
probabilities_bp: tier.probabilities_bp,
confidence_bp: tier.confidence_bp,
min_confidence_bp,
abstained_questions: response.abstained_questions(&["tier", "thinking"]),
cost_saving_kept_fast: acted && cost_saving_kept_fast,
thinking: thinking.clone().filter(|_| acted),
provider_reported_cost_usd: response
@@ -4191,60 +4187,6 @@ mod decision_router_tests {
);
}
#[test]
fn explicit_abstention_survives_decode_and_never_authorizes_auto_at_floor_zero() {
let _env = hermetic_env();
let mut config = decision_config("https://openrouter.invalid/api/v1", false, 2);
config
.auto
.as_mut()
.unwrap()
.router
.as_mut()
.unwrap()
.min_confidence = Some(0.0);
let inventory = ModelInventory::from_config(&config).unwrap();
let attempt = |body: serde_json::Value| {
decision_attempt_from_response(false, &inventory, &pair(), None, &parsed(body), 120)
};
let mut body = answer_body(0.1, 0.9);
body["answers"]["thinking"]["abstained"] = true.into();
let effort_abstained = attempt(body.clone());
let recommendation = effort_abstained
.recommendation
.expect("valid tier survives effort abstention");
assert_eq!(recommendation.model, "deepseek-v4-flash");
assert_eq!(recommendation.reasoning_effort, None);
assert_eq!(
effort_abstained.decision.unwrap().abstained_questions,
vec!["thinking"]
);
body["answers"]["tier"]["abstained"] = true.into();
let tier_abstained = attempt(body);
assert!(tier_abstained.recommendation.is_none());
assert_eq!(
tier_abstained.fallback_reason,
Some(AutoRouteHeuristicReason::LowConfidence)
);
assert_eq!(tier_abstained.failure, None);
let decision = tier_abstained.decision.unwrap();
assert_eq!(decision.abstained_questions, vec!["tier", "thinking"]);
assert_eq!(decision.choice, "fast");
assert_eq!(
decision.provider_reported_cost_usd.as_deref(),
Some("0.000019992")
);
}
#[test]
fn non_boolean_abstention_is_refused_not_ignored() {
let mut body = answer_body(0.1, 0.9);
body["answers"]["tier"]["abstained"] = "yes".into();
let attempt = policy(false, &parsed(body));
assert!(attempt.recommendation.is_none());
assert_eq!(attempt.failure, Some(AutoRouterFailure::InvalidAnswer));
}
#[test]
fn invalid_answers_are_rejected_not_repaired() {
let mut outside = answer_body(0.8, 0.6);
+1
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
//! System prompt composition.
//!
//! Prompts are assembled from composable layers loaded at compile time from
+16 -19
View File
@@ -1455,24 +1455,6 @@ pub fn configured_catalog_models_for_route(
ids
}
pub fn listed_models_for_route(route_config: &Config, identity: &ProviderIdentity) -> Vec<String> {
let mut models = configured_catalog_models_for_route(
route_config,
identity.provider,
identity.key.as_str(),
&route_config.active_route_base_url(),
);
if identity.provider != ProviderKind::OpenaiCodex {
let default_model = route_config.default_model();
if !default_model.is_empty() && !default_model.eq_ignore_ascii_case("auto") {
push_unique_model(&mut models, &default_model);
}
models.sort();
models.dedup();
}
models
}
/// Look up the **bundled-snapshot** offering for `(provider, wire_model_id)`,
/// ignoring any live rows merged over it.
///
@@ -2237,8 +2219,23 @@ pub async fn run_models(
route_config
.scope_to_provider_identity(identity)
.map_err(anyhow::Error::msg)?;
let models = listed_models_for_route(&route_config, identity);
let mut models = configured_catalog_models_for_route(
&route_config,
identity.provider,
identity.key.as_str(),
&route_config.active_route_base_url(),
);
let default_model = route_config.default_model();
if identity.provider != ProviderKind::OpenaiCodex
&& !default_model.is_empty()
&& !default_model.eq_ignore_ascii_case("auto")
{
push_unique_model(&mut models, &default_model);
}
if identity.provider != ProviderKind::OpenaiCodex {
models.sort();
models.dedup();
}
if json {
// Preserve the existing array + AvailableModel field shape.
let chatgpt_roster = (identity.provider == ProviderKind::OpenaiCodex)
+1 -1
View File
@@ -1715,7 +1715,7 @@ fn number(value: Option<&Value>, keys: &[&str]) -> Option<i64> {
}
fn redact(text: &str) -> String {
codewhale_sanitize::redact::redact_secrets(text)
codewhale_secrets::redact::redact_secrets(text)
}
use codewhale_commands::diagnostics_reports::receipts::{bounded, plural};
+42 -136
View File
@@ -325,7 +325,7 @@ pub fn selected_route(path: &Path) -> Result<(String, String, codewhale_config::
pub fn list_models(
store: &codewhale_config::ConfigStore,
filter: Option<ProviderKind>,
) -> Result<Vec<(String, Vec<String>)>> {
) -> Result<Vec<(ProviderKind, Vec<String>)>> {
crate::models_dev_live::maybe_load_persisted_cache();
let mut config = saved_config(store)?;
config.base_url_env_receipt = config
@@ -333,33 +333,42 @@ pub fn list_models(
.map_or(BaseUrlEnvReceipt::NoOwner, |identity| {
BaseUrlEnvReceipt::Route(identity.provider, identity.key.to_string())
});
let mut custom_routes: Vec<String> = config
.providers
.as_ref()
.map(|providers| providers.custom.keys().cloned().collect())
.unwrap_or_default();
custom_routes.sort();
let providers = filter
.as_ref()
.map_or(ProviderKind::all(), std::slice::from_ref);
let mut catalogs = Vec::with_capacity(providers.len());
for provider in providers {
let routes = if *provider == ProviderKind::Custom {
custom_routes.clone()
} else {
vec![provider.as_str().to_string()]
};
for route in routes {
let identity = config
.legacy_selection_identity(&route)
.map_err(anyhow::Error::msg)?;
let mut route_config = config.clone();
route_config
.scope_to_provider_identity(&identity)
.map_err(anyhow::Error::msg)?;
let models = crate::provider_lake::listed_models_for_route(&route_config, &identity);
catalogs.push((route, models));
if *provider == ProviderKind::Custom
&& config
.providers
.as_ref()
.and_then(|providers| providers.custom_provider_config(provider.as_str()))
.is_none()
{
continue;
}
let identity = config
.legacy_selection_identity(provider.as_str())
.map_err(anyhow::Error::msg)?;
let mut route_config = config.clone();
route_config
.scope_to_provider_identity(&identity)
.map_err(anyhow::Error::msg)?;
let mut models = crate::provider_lake::configured_catalog_models_for_route(
&route_config,
identity.provider,
identity.key.as_str(),
&route_config.active_route_base_url(),
);
if identity.provider != ProviderKind::OpenaiCodex {
let default_model = route_config.default_model();
if !default_model.is_empty() && !default_model.eq_ignore_ascii_case("auto") {
models.push(default_model);
}
models.sort();
models.dedup();
}
catalogs.push((*provider, models));
}
Ok(catalogs)
}
@@ -401,82 +410,20 @@ pub fn resolve_model(
)?
.is_some_and(|entry| entry.fetched_at > 0)
{
return Err(model_not_available(
identity.provider,
model.unwrap_or("auto"),
));
}
if !crate::provider_catalog_live::provider_owns_live_catalog(identity.provider, base_url) {
admit_reviewed_selection(identity.provider, model.filter(|model| *model != "auto"))?;
}
}
Ok(route?.candidate)
}
fn model_not_available(provider: ProviderKind, requested: &str) -> anyhow::Error {
anyhow::anyhow!(
"model '{requested}' is not available from provider '{}'",
provider.as_str()
)
}
fn admit_reviewed_selection(provider: ProviderKind, requested: Option<&str>) -> Result<()> {
let selections = &codewhale_config::catalog::reviewed::bundled_reviewed().selections;
let rows = || {
selections
.iter()
.filter(move |row| ProviderKind::parse_config_identity(&row.provider) == Some(provider))
};
let normalize = |value: &str| value.trim().to_ascii_lowercase();
let row_matches = |row: &codewhale_config::catalog::reviewed::ModelSelection, wanted: &str| {
let wanted = normalize(wanted);
normalize(&row.id) == wanted || row.aliases.iter().any(|alias| normalize(alias) == wanted)
};
let default_model = provider.provider().default_model();
let requested = requested.filter(|name| !name.trim().is_empty());
let Some(name) = requested else {
if rows().any(|row| row_matches(row, default_model)) {
return Ok(());
}
if !default_model.trim().is_empty() && provider != ProviderKind::Ollama {
return Ok(());
}
if rows().next().is_none() {
anyhow::bail!(
"provider '{}' has no registered default model",
provider.as_str()
return Err(
codewhale_agent::ModelResolutionError::ModelNotAvailableForProvider {
provider: identity.provider,
requested: model.unwrap_or("auto").to_string(),
}
.into(),
);
}
anyhow::bail!(
"provider '{}' declares default model '{default_model}', but that model is not registered for the provider",
provider.as_str()
);
};
let trimmed = name.trim();
let admitted = match provider {
ProviderKind::Ollama | ProviderKind::OllamaCloud => true,
ProviderKind::OpencodeGo => codewhale_config::opencode_go_model_id(name)
.is_some_and(|canonical| rows().any(|row| row.id.eq_ignore_ascii_case(canonical))),
_ => rows().any(|row| row_matches(row, name)),
} || match provider {
ProviderKind::Atlascloud => !trimmed.is_empty() && trimmed.contains('/'),
ProviderKind::Arcee => !trimmed.is_empty(),
ProviderKind::XiaomiMimo => !trimmed.is_empty() && !trimmed.chars().any(char::is_control),
_ => false,
} || (!default_model.trim().is_empty()
&& trimmed.eq_ignore_ascii_case(default_model.trim()));
if admitted {
return Ok(());
codewhale_agent::ModelRegistry::default().resolve(
model.filter(|model| *model != "auto"),
Some(identity.provider),
)?;
}
if rows().next().is_none() {
anyhow::bail!(
"provider '{}' has no registered model for '{name}'",
provider.as_str()
);
}
Err(model_not_available(provider, name))
Ok(route?.candidate)
}
/// Save one explicit route preference after atomically adopting legacy choices.
@@ -1142,45 +1089,4 @@ model = "Other-X"
assert_eq!(loaded.default_model(), selected_route(&path)?.1);
Ok(())
}
#[test]
fn reviewed_admission_keeps_passthrough_and_default_contracts() {
for (provider, model) in [
(ProviderKind::Atlascloud, Some("Qwen/Qwen3-Coder")),
(ProviderKind::Arcee, Some("trinity-future-thinking")),
(ProviderKind::XiaomiMimo, Some("mimo-custom-id")),
(ProviderKind::Ollama, Some("qwen2.5-coder:7b")),
(ProviderKind::OpencodeGo, Some("deepseek-v4-pro")),
(ProviderKind::OllamaCloud, None),
(ProviderKind::Deepseek, None),
] {
admit_reviewed_selection(provider, model)
.unwrap_or_else(|error| panic!("{provider:?} {model:?}: {error}"));
}
for kind in ProviderKind::all() {
let default = kind.provider().default_model();
if default.trim().is_empty() {
continue;
}
admit_reviewed_selection(*kind, Some(default))
.unwrap_or_else(|error| panic!("default of {kind:?}: {error}"));
}
}
#[test]
fn reviewed_admission_fails_closed_without_borrowing_another_provider() {
let error = admit_reviewed_selection(ProviderKind::Atlascloud, Some("not-in-atlas"))
.expect_err("unknown model must not become the provider default");
assert_eq!(
error.to_string(),
"model 'not-in-atlas' is not available from provider 'atlascloud'"
);
let error = admit_reviewed_selection(ProviderKind::Ollama, None)
.expect_err("the placeholder default must not resolve");
assert!(
error.to_string().contains("default model 'unknown'"),
"{error}"
);
assert!(admit_reviewed_selection(ProviderKind::Moonshot, Some("glm-5.2")).is_err());
}
}
+2 -2
View File
@@ -11,7 +11,7 @@
//! - the provider enum and the non-secret configured route key,
//! - the canonical wire model id,
//! - a **normalized, redacted** endpoint identity (URL userinfo and sensitive
//! query values masked by [`codewhale_sanitize::sanitize::redact_url_for_display`]),
//! query values masked by [`codewhale_secrets::sanitize::redact_url_for_display`]),
//! - a one-way credential *generation* digest that is never rendered.
//!
//! The credential generation is deliberately taken over the endpoint **and** the
@@ -47,7 +47,7 @@ pub fn endpoint_identity(base_url: &str) -> String {
if reqwest::Url::parse(trimmed).is_err() {
return OPAQUE_ENDPOINT.to_string();
}
codewhale_sanitize::sanitize::redact_url_for_display(trimmed)
codewhale_secrets::sanitize::redact_url_for_display(trimmed)
.trim_end_matches('/')
.to_string()
}
+18 -1
View File
@@ -2009,7 +2009,7 @@ impl SavedTurnOutcome {
/// Build the persisted record for a failed turn. Redacts before bounding
/// so a cut can never leave half a secret behind.
pub fn failed(error: &str, after_message_count: usize) -> Self {
let redacted = codewhale_sanitize::redact::redact_secrets(error.trim());
let redacted = codewhale_secrets::redact::redact_secrets(error.trim());
let error = if redacted.chars().count() > MAX_SAVED_TURN_OUTCOME_ERROR_CHARS {
let mut cut: String = redacted
.chars()
@@ -4309,6 +4309,23 @@ impl SessionManager {
self.save_session_inner(session, JournalPrune::Excess, true)
}
#[cfg(any(test, feature = "test-support"))]
pub fn commit_completed_session(&self, session: SavedSession) -> io::Result<io::Result<()>> {
let session_id = session.metadata.id.clone();
let exec_mode = session.metadata.mode.as_deref() == Some("exec");
let clear = self
.with_session_write_admission(&session_id, || {
let persisted = self.load_session_write_metadata(&session_id)?;
self.write_session_admitted(session, JournalPrune::Excess, true, &persisted)?;
Ok(self.clear_session_checkpoint_admitted(&session_id))
})?
.ok_or_else(Self::retired_session_write_error)?;
if let Err(error) = self.cleanup_old_sessions_for_mode(None, Some(exec_mode)) {
tracing::warn!(session_id = %session_id, %error, "completion was committed but retention could not be inspected");
}
Ok(clear)
}
/// Make a saved document whose file exceeds the full-history transport
/// bound readable under it. The bound counts what a canonical handoff
/// carries: compact JSON without the journal-derived `messages` copy
+2 -2
View File
@@ -203,7 +203,7 @@ pub const REDACTED_PLACEHOLDER: &str = "[redacted]";
/// Mask credential-shaped substrings.
///
/// The shared export sanitizer ([`codewhale_sanitize::sanitize::sanitize_text`],
/// The shared export sanitizer ([`codewhale_secrets::sanitize::sanitize_text`],
/// also used by `/export`) runs first: it covers `Bearer <token>`, JWTs,
/// URL credentials, PEM blocks, and quoted JSON/TOML keyed secrets. A
/// token-level pass then masks the extra bare prefixes (AWS, Google, Hugging
@@ -211,7 +211,7 @@ pub const REDACTED_PLACEHOLDER: &str = "[redacted]";
/// peek line is cheap; leaking a key over a LAN is not.
#[must_use]
pub fn redact(text: &str) -> (String, bool) {
let sanitized = codewhale_sanitize::sanitize::sanitize_text(text);
let sanitized = codewhale_secrets::sanitize::sanitize_text(text);
// The sanitizer also strips control bytes and normalises URLs, so compare
// placeholder counts rather than bytes to decide whether it redacted.
let mut redacted = redaction_marks(&sanitized) > redaction_marks(text);
+2 -26
View File
@@ -451,11 +451,6 @@ async fn evaluate(
.map_or_else(Default::default, |v| v.probabilities_bp.clone()),
confidence_bp: intent.as_ref().map_or(0, |v| v.confidence_bp),
min_confidence_bp: 5_000,
abstained_questions: response.abstained_questions(&[
"intent",
"needs_tool",
"answerable_from_context",
]),
cost_saving_kept_fast: false,
thinking: None,
provider_reported_cost_usd: response
@@ -526,7 +521,7 @@ fn unit_interval(value: Option<f64>) -> Option<f64> {
/// fast route.
fn read_noul(response: &SystemOneResponse, key: &str) -> Option<f64> {
let answer = response.answers.get(key)?;
(answer.kind == "noul" && !answer.abstained)
(answer.kind == "noul")
.then_some(answer.noul)
.and_then(unit_interval)
}
@@ -553,9 +548,7 @@ fn derive_route(response: &SystemOneResponse) -> Route {
response.answers.get("intent"),
&["code_change", "code_question", "command", "chat", "other"],
)
.is_some_and(|intent| {
!intent.abstained && intent.choice == "chat" && intent.confidence_bp >= 5_000
});
.is_some_and(|intent| intent.choice == "chat" && intent.confidence_bp >= 5_000);
if intent_is_calibrated_chat && needs_tool.is_some_and(|nt| nt <= 0.2) {
return Route::PlainChat;
}
@@ -571,23 +564,6 @@ mod tests {
const TYPESAFE_TEST_KEY: &str = "sf-typesafe-test-key-0123456789";
#[test]
fn explicit_abstention_never_authorizes_a_shadow_route() {
let mut value = json!({"answers":{
"intent":{"type":"choice","choice":"chat","confidence":0.9,
"probabilities":{"chat":0.9,"code_change":0.1,"code_question":0.0,"command":0.0,"other":0.0}},
"needs_tool":{"type":"noul","noul":0.1},
"answerable_from_context":{"type":"noul","noul":0.1}}});
let decoded =
|value: Value| serde_json::from_value::<SystemOneResponse>(value).expect("response");
assert_eq!(derive_route(&decoded(value.clone())), Route::PlainChat);
value["answers"]["intent"]["abstained"] = true.into();
assert_eq!(derive_route(&decoded(value.clone())), Route::Unknown);
value["answers"]["needs_tool"]["noul"] = 0.95.into();
value["answers"]["needs_tool"]["abstained"] = true.into();
assert_eq!(derive_route(&decoded(value)), Route::Unknown);
}
/// Fields drop in declaration order: restore the environment before the
/// lock is released, or another test observes our overrides.
struct Env {
+1 -1
View File
@@ -288,7 +288,7 @@ fn strip_plan_provenance(content: &str) -> (String, Option<u32>) {
)
}
#[cfg(test)]
#[cfg(any(test, feature = "test-support"))]
fn plan_provenance_marker(index: u32) -> String {
format!("{PLAN_PROVENANCE_PREFIX}{index}{PLAN_PROVENANCE_SUFFIX}")
}
+2
View File
@@ -16,6 +16,8 @@
//! Session persistence, legacy import, UI projections, and liveness adapters
//! are wired: `session_manager` stores a snapshot, `tools/shell` and
//! `tools/tasks` observe operations, and the engine records owner liveness.
#![allow(dead_code)]
#![allow(unused_imports)]
mod compat;
mod digest;
+2 -2
View File
@@ -23,8 +23,8 @@ use super::events::{
};
use super::ids::{ChangeId, WorkEdgeId, WorkNodeId};
use super::model::{
EdgeKind, EvidenceRef, NodeKind, NodeState, Provenance, WorkActivityEvent, WorkEdge,
WorkGraphSnapshot, WorkNode,
EdgeKind, EvidenceRef, NodeKind, NodeState, OperationBinding, Provenance, WorkActivityEvent,
WorkEdge, WorkGraphSnapshot, WorkNode,
};
use super::validate::{ValidationCode, ValidationReport, validate};
+2 -2
View File
@@ -9,8 +9,8 @@ use crate::tools::todo::{SharedTodoList, TodoList, TodoListSnapshot, TodoStatus}
use codewhale_lane::LaneRegistry;
use super::{
BindingId, ChangeCtx, CompatPlanMetadata, CompatTodoBinding, EdgeKind, IdempotencyKey,
NodeKind, NodeState, OperationBinding, OperationIntent, OperationObservation,
BindingId, ChangeCtx, CompatPlanMetadata, CompatProjectionState, CompatTodoBinding, EdgeKind,
IdempotencyKey, NodeKind, NodeState, OperationBinding, OperationIntent, OperationObservation,
OperationOwnerSnapshot, Provenance, WorkActivityEvent, WorkEdge, WorkEdgeId, WorkGraph,
WorkGraphChange, WorkGraphSnapshot, WorkNode, WorkNodeId, WorkNodePatch,
external_identity_is_well_formed, fleet_task_owner_snapshot, import_legacy,
+19
View File
@@ -43,6 +43,16 @@ pub struct Ruleset {
}
impl Ruleset {
/// Creates an empty ruleset at the builtin default priority layer.
pub fn builtin_default() -> Self {
Self {
layer: RulesetLayer::BuiltinDefault,
trusted_prefixes: vec![],
denied_prefixes: vec![],
ask_rules: vec![],
}
}
/// Creates an agent-layer ruleset with the given trusted and denied prefixes.
pub fn agent(trusted: Vec<String>, denied: Vec<String>) -> Self {
Self {
@@ -358,6 +368,15 @@ impl ExecPolicyEngine {
}
}
/// Add a ruleset layer (re-sorts internally).
pub fn add_ruleset(&mut self, ruleset: Ruleset) {
let mut guard = Self::lock_rulesets(&self.rulesets);
let mut updated = guard.clone();
updated.push(ruleset);
updated.sort_by_key(|r| r.layer);
*guard = updated;
}
/// Replace the ruleset at one priority layer without clearing approvals
/// remembered for the current session.
pub fn set_ruleset(&mut self, ruleset: Ruleset) {
+4 -1
View File
@@ -5,7 +5,7 @@ edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "Webhook and notification delivery support for Codewhale"
description = "Hook dispatch and notifications support for Codewhale"
[lints]
workspace = true
@@ -13,10 +13,13 @@ workspace = true
[dependencies]
codewhale-app-server-protocol = { path = "../app-server-protocol", version = "0.10.3" }
anyhow.workspace = true
async-trait.workspace = true
chrono.workspace = true
codewhale-paths = { path = "../paths", version = "0.10.3" }
codewhale-protocol = { path = "../protocol", version = "0.10.3" }
codewhale-release = { path = "../release", version = "0.10.3" }
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
tracing.workspace = true
+655 -23
View File
@@ -1,6 +1,15 @@
use std::path::{Path, PathBuf};
use std::sync::Arc;
#[cfg(unix)]
use std::time::Duration;
use anyhow::{Context, Result};
use async_trait::async_trait;
use chrono::Utc;
use codewhale_protocol::EventFrame;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use tokio::io::AsyncWriteExt;
mod lifecycle_outbox;
@@ -9,6 +18,151 @@ pub use lifecycle_outbox::{
OUTBOX_PREVIEW_MAX_CHARS, OUTBOX_TRUNCATION_MARKER, bounded_text,
};
/// All events that can be emitted through the hook system.
///
/// Each variant represents a distinct lifecycle or streaming event. The enum is
/// serialised with a `"type"` discriminator using `snake_case` naming (e.g.
/// `"response_start"`, `"tool_lifecycle"`), making it easy to consume from
/// JSON-based log files or webhook receivers.
#[allow(clippy::large_enum_variant)] // Keep the public HookEvent shape stable for 0.8.x.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum HookEvent {
/// A new response stream has started.
ResponseStart {
/// Unique identifier for the response being streamed.
response_id: String,
},
/// A chunk of text has been received for an in-progress response.
ResponseDelta {
/// Unique identifier for the response being streamed.
response_id: String,
/// The incremental text content of this chunk.
delta: String,
},
/// A response stream has finished.
ResponseEnd {
/// Unique identifier for the response that completed.
response_id: String,
},
/// A tool invocation has transitioned to a new phase (e.g. start, end, error).
ToolLifecycle {
/// Identifier of the response under which the tool was invoked.
response_id: String,
/// Name of the tool (e.g. `"shell"`, `"read_file"`).
tool_name: String,
/// Current phase of the tool execution (e.g. `"start"`, `"end"`).
phase: String,
/// Arbitrary structured payload associated with this phase.
payload: Value,
},
/// A background job has transitioned to a new phase.
JobLifecycle {
/// Unique identifier of the job.
job_id: String,
/// Current phase of the job (e.g. `"queued"`, `"running"`, `"done"`).
phase: String,
/// Optional progress percentage (0-100).
progress: Option<u8>,
/// Optional human-readable detail about the current phase.
detail: Option<String>,
},
/// An approval request has transitioned to a new phase.
ApprovalLifecycle {
/// Unique identifier of the approval request.
approval_id: String,
/// Current phase (e.g. `"requested"`, `"approved"`, `"denied"`).
phase: String,
/// Optional reason explaining the current phase.
reason: Option<String>,
},
/// A catch-all variant that wraps an arbitrary [`EventFrame`].
///
/// Use this when you need to forward a protocol-level event frame without
/// mapping it to a more specific variant.
GenericEventFrame {
/// The raw event frame to forward.
frame: Box<EventFrame>,
},
}
impl HookEvent {
/// Serialise this event into a [`serde_json::Value`].
///
/// Returns a JSON object with the `"type"` discriminator and all variant
/// fields. If serialisation fails (which should be extremely rare), a
/// fallback `{"type":"serialization_error"}` value is returned instead of
/// panicking.
pub fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or_else(|_| json!({"type":"serialization_error"}))
}
}
/// A destination that can receive [`HookEvent`]s.
///
/// Implementors handle the transport-specific details of delivering events
/// (writing to stdout, appending to a file, POSTing to a webhook, etc.).
/// The [`HookDispatcher`] fans out every event to all registered sinks, so a
/// single process can log to multiple destinations simultaneously.
///
/// Sinks are expected to be **best-effort**: implementations should avoid
/// panicking and should return an [`anyhow::Error`] only for truly unexpected
/// failures. [`HookDispatcher::emit`] discards individual sink errors so hook
/// delivery failures do not abort the application.
#[async_trait]
pub trait HookSink: Send + Sync {
/// Deliver a single event to this sink.
///
/// Implementations should be resilient to transient failures (e.g. a
/// missing listener) and should not block the caller for extended periods.
async fn emit(&self, event: &HookEvent) -> Result<()>;
}
/// A [`HookSink`] that prints each event as a single JSON line to stdout.
///
/// Useful for local development and debugging. Events are printed via
/// [`println!`] so they appear interleaved with other program output.
#[derive(Default)]
pub struct StdoutHookSink;
#[async_trait]
impl HookSink for StdoutHookSink {
async fn emit(&self, event: &HookEvent) -> Result<()> {
println!("{}", event.to_json());
Ok(())
}
}
/// A [`HookSink`] that appends each event as a JSON line to a file.
///
/// The file is created (along with any missing parent directories) on the
/// first emitted event. Each line is a JSON object of the form
/// `{"at": "<ISO 8601 timestamp>", "event": {...}}`.
///
/// Concurrent [`emit`](HookSink::emit) calls serialize on an internal mutex so
/// that each JSON event is written and flushed as a complete line; without that
/// lock, overlapping `write_all` calls can interleave partial lines and corrupt
/// the JSONL log (see issue #4739).
pub struct JsonlHookSink {
path: PathBuf,
/// Serializes open+append+flush so concurrent tool-call emits cannot
/// interleave bytes mid-line.
write_lock: tokio::sync::Mutex<()>,
}
impl JsonlHookSink {
/// Create a new sink that writes to the file at `path`.
///
/// A leading `~` is expanded against the user home. Parent directories
/// are created lazily on the first [`HookSink::emit`] call.
pub fn new(path: PathBuf) -> Self {
Self {
path: expand_home(path),
write_lock: tokio::sync::Mutex::new(()),
}
}
}
/// Expand a leading `~` in a configured sink path, reusing the one expansion
/// rule global path overrides use. Documented examples write
/// `~/.codewhale/...`; taken literally that created a directory named `~` in
@@ -45,9 +199,38 @@ pub(crate) async fn open_private_append(path: &Path) -> Result<tokio::fs::File>
.with_context(|| format!("failed to open sink file {}", path.display()))
}
/// HTTP transport for lifecycle outbox webhooks: POSTs a JSON payload to a
/// remote endpoint. Failed requests are retried up to 2 times with exponential
/// back-off (200 ms, 400 ms). After exhausting retries the error is propagated.
#[async_trait]
impl HookSink for JsonlHookSink {
async fn emit(&self, event: &HookEvent) -> Result<()> {
// Encode outside the lock so only I/O is serialized.
let payload = json!({
"at": Utc::now().to_rfc3339(),
"event": event
});
let encoded = serde_json::to_string(&payload).context("failed to encode hook event")?;
let _guard = self.write_lock.lock().await;
let mut file = open_private_append(&self.path).await?;
file.write_all(encoded.as_bytes())
.await
.context("failed to write hook event")?;
file.write_all(b"\n")
.await
.context("failed to write hook event newline")?;
// Flush before drop so sequential emits (and tests that read the
// file immediately after) observe every completed line. Holding the
// mutex through flush guarantees concurrent writers never observe a
// partial line at EOF.
file.flush().await.context("failed to flush hook event")?;
Ok(())
}
}
/// A [`HookSink`] that POSTs each event as JSON to a remote HTTP endpoint.
///
/// The request body is `{"at": "<ISO 8601 timestamp>", "event": {...}}`.
/// Failed requests are retried up to 2 times with exponential back-off
/// (200 ms, 400 ms). After exhausting retries the error is propagated.
#[derive(Clone)]
pub struct WebhookHookSink {
url: String,
@@ -57,6 +240,11 @@ pub struct WebhookHookSink {
}
impl WebhookHookSink {
/// Create a new sink that sends events to the given `url`.
pub fn new(url: String) -> Self {
Self::new_with_token(url, None)
}
/// Create a new sink that sends events to the given `url`, attaching
/// `Authorization: Bearer <token>` when a token is provided.
pub fn new_with_token(url: String, bearer_token: Option<String>) -> Self {
@@ -76,7 +264,10 @@ impl WebhookHookSink {
/// POST an arbitrary JSON payload to the configured endpoint.
///
/// This is the delivery path behind the lifecycle outbox fan-out.
/// This is the shared delivery path behind both [`HookSink::emit`] and
/// the lifecycle outbox fan-out. It is deliberately not part of the
/// [`HookSink`] trait: outbox events are runtime event envelopes, not
/// [`HookEvent`]s, and only the transport needs to be shared.
pub async fn post_payload(&self, payload: serde_json::Value) -> Result<()> {
let mut retries = 0usize;
loop {
@@ -104,12 +295,406 @@ impl WebhookHookSink {
}
}
#[async_trait]
impl HookSink for WebhookHookSink {
async fn emit(&self, event: &HookEvent) -> Result<()> {
self.post_payload(json!({
"at": Utc::now().to_rfc3339(),
"event": event,
}))
.await
}
}
/// A [`HookSink`] that sends events over a Unix domain socket.
///
/// Each event is serialized as a single JSON line (`{"at": "...", "event": {...}}\n`)
/// and written to the socket. If the socket is not available (listener not running),
/// the event is silently dropped - hook sinks are best-effort observability, not
/// control flow.
///
/// On non-Unix platforms this struct exists but its [`HookSink::emit`] is a no-op.
#[derive(Debug, Clone)]
pub struct UnixSocketHookSink {
#[cfg(unix)]
path: PathBuf,
}
impl UnixSocketHookSink {
/// Create a sink that connects to the Unix domain socket at `path`.
pub fn new(path: PathBuf) -> Self {
#[cfg(unix)]
{
Self { path }
}
#[cfg(not(unix))]
{
let _ = path;
Self {}
}
}
}
/// Longest one Unix-socket delivery (connect + write) may take. The
/// dispatcher awaits its sinks in order, so a listener that accepts and never
/// reads would otherwise stall every later sink, and the emitting turn, as
/// soon as the socket buffer filled.
#[cfg(unix)]
const UNIX_SOCKET_SINK_TIMEOUT: Duration = Duration::from_secs(2);
#[async_trait]
impl HookSink for UnixSocketHookSink {
#[cfg(unix)]
async fn emit(&self, event: &HookEvent) -> Result<()> {
let payload = json!({
"at": Utc::now().to_rfc3339(),
"event": event
});
let mut line = serde_json::to_string(&payload).context("failed to encode hook event")?;
line.push('\n');
let deliver = async {
let mut stream = match tokio::net::UnixStream::connect(&self.path).await {
Ok(s) => s,
Err(_) => return Ok(()), // listener not running, skip silently
};
stream
.write_all(line.as_bytes())
.await
.context("failed to write to unix socket")
};
tokio::time::timeout(UNIX_SOCKET_SINK_TIMEOUT, deliver)
.await
.map_err(|_| {
anyhow::anyhow!(
"unix socket hook sink {} did not accept the event within {:?}",
self.path.display(),
UNIX_SOCKET_SINK_TIMEOUT
)
})?
}
#[cfg(not(unix))]
async fn emit(&self, _event: &HookEvent) -> Result<()> {
// Unix sockets are not available on this platform.
Ok(())
}
}
/// Fans out [`HookEvent`]s to a collection of [`HookSink`]s.
///
/// Register one or more sinks via [`add_sink`](HookDispatcher::add_sink),
/// then call [`emit`](HookDispatcher::emit) to broadcast an event to all of
/// them. If a sink returns an error it is silently ignored so that a failing
/// sink does not prevent remaining sinks from receiving the event.
#[derive(Default, Clone)]
pub struct HookDispatcher {
sinks: Vec<Arc<dyn HookSink>>,
}
impl HookDispatcher {
/// Register a new sink that will receive all subsequently emitted events.
pub fn add_sink(&mut self, sink: Arc<dyn HookSink>) {
self.sinks.push(sink);
}
/// Number of registered sinks. Exposed so transport setup can assert
/// exactly which sinks were wired (e.g. no stdout sink in stdio mode).
#[must_use]
pub fn sink_count(&self) -> usize {
self.sinks.len()
}
/// Broadcast an event to every registered sink.
///
/// Errors from individual sinks are silently discarded so that one failing
/// sink does not block the others.
pub async fn emit(&self, event: HookEvent) {
for sink in &self.sinks {
let _ = sink.emit(&event).await;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Mutex;
#[cfg(unix)]
use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(unix)]
use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(unix)]
static SOCKET_PATH_NONCE: AtomicU64 = AtomicU64::new(0);
#[test]
fn expand_home_expands_tilde_and_leaves_other_paths() {
fn hook_event_serializes_with_snake_case_type_and_payload() {
let event = HookEvent::ToolLifecycle {
response_id: "resp-1".to_string(),
tool_name: "shell".to_string(),
phase: "end".to_string(),
payload: json!({ "exit_code": 0 }),
};
let encoded = event.to_json();
assert_eq!(encoded["type"], "tool_lifecycle");
assert_eq!(encoded["response_id"], "resp-1");
assert_eq!(encoded["tool_name"], "shell");
assert_eq!(encoded["phase"], "end");
assert_eq!(encoded["payload"]["exit_code"], 0);
}
#[test]
fn generic_event_frame_serialization_is_unchanged_by_boxing() {
let event = HookEvent::GenericEventFrame {
frame: Box::new(EventFrame::ResponseStart {
response_id: "resp-1".to_string(),
}),
};
let encoded = event.to_json();
assert_eq!(encoded["type"], "generic_event_frame");
assert_eq!(encoded["frame"]["event"], "response_start");
assert_eq!(encoded["frame"]["response_id"], "resp-1");
}
#[tokio::test]
async fn jsonl_sink_creates_parent_dir_and_appends_events() {
let root = unique_temp_dir("jsonl_sink");
let path = root.join("nested").join("hooks.jsonl");
let sink = JsonlHookSink::new(path.clone());
sink.emit(&HookEvent::ResponseStart {
response_id: "resp-1".to_string(),
})
.await
.unwrap();
sink.emit(&HookEvent::ResponseEnd {
response_id: "resp-1".to_string(),
})
.await
.unwrap();
let raw = std::fs::read_to_string(&path).unwrap();
let lines = raw.lines().collect::<Vec<_>>();
assert_eq!(lines.len(), 2);
let first: Value = serde_json::from_str(lines[0]).unwrap();
let second: Value = serde_json::from_str(lines[1]).unwrap();
assert!(first["at"].as_str().is_some());
assert_eq!(first["event"]["type"], "response_start");
assert_eq!(first["event"]["response_id"], "resp-1");
assert_eq!(second["event"]["type"], "response_end");
assert_eq!(second["event"]["response_id"], "resp-1");
let _ = std::fs::remove_dir_all(root);
}
/// Concurrent emits must not interleave partial lines (#4739).
///
/// Spawns many tasks writing through one shared [`JsonlHookSink`] and
/// asserts every line in the resulting file is complete, parseable JSON.
#[tokio::test(flavor = "multi_thread", worker_threads = 8)]
async fn jsonl_sink_concurrent_emits_write_atomic_json_lines() {
let root = unique_temp_dir("jsonl_sink_concurrent");
let path = root.join("hooks.jsonl");
let sink = Arc::new(JsonlHookSink::new(path.clone()));
const TASKS: usize = 32;
const EVENTS_PER_TASK: usize = 20;
let expected = TASKS * EVENTS_PER_TASK;
let mut handles = Vec::with_capacity(TASKS);
for task_id in 0..TASKS {
let sink = Arc::clone(&sink);
handles.push(tokio::spawn(async move {
for n in 0..EVENTS_PER_TASK {
let event = HookEvent::ToolLifecycle {
response_id: format!("resp-{task_id}"),
tool_name: "shell".to_string(),
phase: "end".to_string(),
payload: json!({ "n": n, "task": task_id }),
};
sink.emit(&event).await.expect("concurrent emit");
}
}));
}
for handle in handles {
handle.await.expect("join concurrent writer");
}
let raw = std::fs::read_to_string(&path).expect("read concurrent jsonl");
// Trailing newline yields an empty final split; keep non-empty lines only.
let lines: Vec<&str> = raw.lines().filter(|l| !l.is_empty()).collect();
assert_eq!(
lines.len(),
expected,
"expected {expected} complete lines, got {}; sample: {:?}",
lines.len(),
lines
.first()
.map(|s| s.chars().take(80).collect::<String>())
);
for (idx, line) in lines.iter().enumerate() {
let parsed: Value = serde_json::from_str(line).unwrap_or_else(|err| {
panic!("line {idx} is not complete JSON ({err}): {line:?}");
});
assert!(
parsed.get("at").and_then(|v| v.as_str()).is_some(),
"line {idx} missing at: {parsed}"
);
assert_eq!(
parsed["event"]["type"], "tool_lifecycle",
"line {idx} unexpected event type"
);
}
let _ = std::fs::remove_dir_all(root);
}
#[tokio::test]
async fn dispatcher_continues_after_sink_error() {
let mut dispatcher = HookDispatcher::default();
let first = Arc::new(RecordingSink::default());
let second = Arc::new(RecordingSink::default());
dispatcher.add_sink(first.clone());
dispatcher.add_sink(Arc::new(FailingSink));
dispatcher.add_sink(second.clone());
dispatcher
.emit(HookEvent::ApprovalLifecycle {
approval_id: "approval-1".to_string(),
phase: "requested".to_string(),
reason: Some("needs review".to_string()),
})
.await;
assert_eq!(
first.events(),
vec![json!({
"type": "approval_lifecycle",
"approval_id": "approval-1",
"phase": "requested",
"reason": "needs review",
})]
);
assert_eq!(second.events(), first.events());
}
#[cfg(unix)]
#[tokio::test]
async fn unix_socket_sink_skips_when_listener_absent() {
let (_root, socket_path) = unique_short_socket_path("missing");
let sink = UnixSocketHookSink::new(socket_path);
let result = sink
.emit(&HookEvent::ResponseStart {
response_id: "resp-1".to_string(),
})
.await;
assert!(result.is_ok());
}
#[cfg(unix)]
#[tokio::test]
async fn unix_socket_sink_sends_event_to_listener() {
use tokio::io::AsyncBufReadExt;
use tokio::net::UnixListener;
let (root, socket_path) = unique_short_socket_path("send");
std::fs::create_dir_all(&root).expect("mkdir");
let _ = std::fs::remove_file(&socket_path);
let listener = UnixListener::bind(&socket_path).expect("bind");
let sink = UnixSocketHookSink::new(socket_path.clone());
let cleanup = || {
let _ = std::fs::remove_file(&socket_path);
let _ = std::fs::remove_dir_all(&root);
};
let mut handle = tokio::spawn(async move {
let (stream, _) = listener.accept().await.expect("accept");
let mut reader = tokio::io::BufReader::new(stream);
let mut line = String::new();
reader.read_line(&mut line).await.expect("read_line");
line
});
let event = HookEvent::ResponseStart {
response_id: "resp-42".to_string(),
};
let emit = sink.emit(&event);
match tokio::time::timeout(Duration::from_secs(5), emit).await {
Ok(result) => result.expect("emit"),
Err(_) => {
handle.abort();
let _ = (&mut handle).await;
cleanup();
panic!("unix socket emit timed out");
}
}
let received = match tokio::time::timeout(Duration::from_secs(5), &mut handle).await {
Ok(result) => result.expect("join"),
Err(_) => {
handle.abort();
let _ = (&mut handle).await;
cleanup();
panic!("unix socket exchange timed out");
}
};
let parsed: Value = serde_json::from_str(&received).expect("parse");
assert_eq!(parsed["event"]["type"], "response_start");
assert_eq!(parsed["event"]["response_id"], "resp-42");
assert!(parsed["at"].as_str().is_some());
cleanup();
}
/// Audit R04-11: a listener that accepts and never reads must not stall
/// the sequential dispatcher past the sink's own bound.
#[cfg(unix)]
#[tokio::test]
async fn unix_socket_sink_gives_up_on_a_listener_that_never_reads() {
use tokio::net::UnixListener;
let (root, socket_path) = unique_short_socket_path("stall");
std::fs::create_dir_all(&root).expect("mkdir");
let listener = UnixListener::bind(&socket_path).expect("bind");
let held = tokio::spawn(async move {
let (stream, _) = listener.accept().await.expect("accept");
// Hold the connection open without ever reading from it.
tokio::time::sleep(Duration::from_secs(60)).await;
drop(stream);
});
let sink = UnixSocketHookSink::new(socket_path.clone());
// Far larger than any socket buffer, so `write_all` must block.
let event = HookEvent::ToolLifecycle {
response_id: "resp-stall".to_string(),
tool_name: "shell".to_string(),
phase: "end".to_string(),
payload: json!({ "output": "x".repeat(16 * 1024 * 1024) }),
};
let outcome = tokio::time::timeout(Duration::from_secs(10), sink.emit(&event)).await;
held.abort();
let _ = std::fs::remove_file(&socket_path);
let _ = std::fs::remove_dir_all(&root);
let result = outcome.expect("emit must return within its own bound");
assert!(result.is_err(), "a stalled delivery is reported, not faked");
}
/// Audit R04-10: `~` expands against the home, and a new JSONL sink is
/// private (dir 0700, file 0600) on Unix.
#[cfg(unix)]
#[tokio::test]
async fn jsonl_sink_expands_home_and_creates_private_files() {
use std::os::unix::fs::PermissionsExt;
let home = codewhale_paths::user_home().expect("test home");
assert_eq!(
expand_home(PathBuf::from("~/.codewhale/events.jsonl")),
@@ -119,24 +704,15 @@ mod tests {
expand_home(PathBuf::from("relative/events.jsonl")),
PathBuf::from("relative/events.jsonl")
);
}
#[cfg(unix)]
#[tokio::test]
async fn open_private_append_creates_private_files() {
use std::os::unix::fs::PermissionsExt;
use std::time::{SystemTime, UNIX_EPOCH};
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let root = std::env::temp_dir().join(format!(
"deepseek-hooks-private-{}-{nanos}",
std::process::id()
));
let root = unique_temp_dir("private");
let path = root.join("nested").join("events.jsonl");
open_private_append(&path).await.expect("open");
let sink = JsonlHookSink::new(path.clone());
sink.emit(&HookEvent::ResponseStart {
response_id: "resp-private".to_string(),
})
.await
.expect("emit");
let file_mode = std::fs::metadata(&path).unwrap().permissions().mode() & 0o777;
let dir_mode = std::fs::metadata(path.parent().unwrap())
.unwrap()
@@ -148,10 +724,66 @@ mod tests {
assert_eq!(dir_mode, 0o700);
}
#[derive(Default)]
struct RecordingSink {
events: Mutex<Vec<Value>>,
}
impl RecordingSink {
fn events(&self) -> Vec<Value> {
self.events.lock().unwrap().clone()
}
}
#[async_trait::async_trait]
impl HookSink for RecordingSink {
async fn emit(&self, event: &HookEvent) -> Result<()> {
self.events.lock().unwrap().push(event.to_json());
Ok(())
}
}
struct FailingSink;
#[async_trait::async_trait]
impl HookSink for FailingSink {
async fn emit(&self, _event: &HookEvent) -> Result<()> {
anyhow::bail!("sink failed")
}
}
fn unique_temp_dir(label: &str) -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
std::env::temp_dir().join(format!(
"deepseek-hooks-{label}-{}-{nanos}",
std::process::id()
))
}
#[cfg(unix)]
fn unique_short_socket_path(label: &str) -> (PathBuf, PathBuf) {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let nonce = SOCKET_PATH_NONCE.fetch_add(1, Ordering::Relaxed);
let root = PathBuf::from("/tmp").join(format!(
"cw-hk-{label}-{}-{nanos}-{nonce}",
std::process::id()
));
let path = root.join("hook.sock");
(root, path)
}
#[test]
fn webhook_sink_new_does_not_panic() {
let sink =
WebhookHookSink::new_with_token("https://example.invalid/webhook".to_string(), None);
// Construction must never panic: if the configured client builder
// fails, the code falls back to a default `reqwest::Client` instead of
// calling `.expect(...)`.
let sink = WebhookHookSink::new("https://example.invalid/webhook".to_string());
let _ = sink;
}
}
+1 -1
View File
@@ -411,7 +411,7 @@ impl WriterState {
append_result
}
/// Append complete JSONL lines:
/// Append complete JSONL lines, mirroring [`crate::JsonlHookSink`]:
/// lazy parent directories, append mode, flush before returning. The
/// writer task is the only appender for this outbox, so no extra lock is
/// needed here; the queue already serializes. The whole batch shares one
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "El Runtime ha tancat el flux d'esdeveniments d'aquesta conversa; torna a obrir-la",
"MobileStreamReconnecting": "Connexió perduda; reconnectant",
"MobileStreamConnected": "Connectat",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Un hàbitat compartit",
"PetHabitatHints": "{back} enrere · {sound} so · {browser} aparença · {window} finestra",
"PetHabitatQueued": "Enviat a l’hàbitat compartit. /pet on mostra la mascota i el quadre de missatge.",
"PetWatchSoundOn": "So activat",
"PetWatchSoundOff": "So desactivat",
"PetWatchSoundPaused": "So en pausa",
"PetWatchSoundUnavailable": "El so de Codewhale s’ha aturat. Comprova l’FFmpeg (ffplay) i la sortida d’àudio i torna a activar el so.",
"CmdPetDescription": "Fes servir la mascota animada com a vista principal de Codewhale",
"ConfigLabelPetMode": "Mode mascota",
"ConfigHintPetMode": "Mostra la mascota animada com a vista principal quan s’inicia Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "mode mascota desactivat",
"PetViewOpen": "hàbitat obert",
"PetViewClosed": "hàbitat tancat",
"PetWatchRestored": "/pet ha restaurat l’hàbitat d’aquesta sessió. S’espera telemetria nova.",
"PetWatchStorageUnavailable": "Watch no ha pogut restaurar ni desar aquest hàbitat. S’han conservat els fitxers existents. Fes servir {command} per exportar aquesta execució.",
"PetWatchExported": "Reproducció de Watch desada: {path}",
"PetWatchExportFailed": "No s’ha pogut desar la reproducció de Watch. L’enregistrament continua a la memòria.",
"PetWatchExportQueued": "S’està desant la reproducció de Watch…",
"PetWatchExportUnavailable": "Obre /pet en una sessió desada o espera que acabi l’exportació actual.",
"PetUnobserved": "sense observació",
"PetOffline": "fora de línia — codewhale pet serve el desperta",
"PetDozing": "endormiscat",
"PetWatchUnavailable": "La telemetria de la mascota està en pausa. /pet on ho torna a intentar.",
"ConversationChangedBeforeUndo": "La conversa ha canviat abans de completar l’acció de desfer. No s’ha desfet res ni s’ha enviat cap nou intent. Revisa la conversa actual abans de tornar-ho a provar.",
"SessionArchiveExported": "Sessió exportada",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Edita",
"ExtensionsHooksAddLabel": "Afegeix un ganxo",
"ExtensionsHooksAddDescription": "Obre el fitxer de ganxos d'aquest projecte al teu editor",
"ExtensionsActionReload": "torna a carregar",
"ExtensionsActionConnect": "connecta",
"ExtensionsActionReconnect": "torna a connectar",
"ExtensionsActionReauth": "reautentica",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "connectat",
"ExtensionsStateEnabled": "activat",
"ExtensionsStateError": "error",
"ExtensionsStateInactive": "inactiu",
"ExtensionsStateInapplicable": "no aplicable",
"ExtensionsStateInvalid": "no vàlid",
"ExtensionsStateNotInspected": "no inspeccionat",
"ExtensionsStateDisconnected": "desconnectat",
"ExtensionsStateRejected": "rebutjat",
"ExtensionsStateReviewedCandidate": "candidat revisat",
"ExtensionsStateUnderEvaluation": "en avaluació",
"ExtensionsStateUnstaged": "sense preparar",
"ExtensionsStateUnsupported": "no compatible",
"ExtensionsStateWarning": "avís",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ enviar a aquest torn",
"ComposerHintLongDraft": "{shortcut}: editor extern",
"PendingSendingIntoTurnPrefix": " ↳ S'està enviant a aquest torn: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ No s'ha pogut enviar a aquest torn: ",
"PendingEditingFollowUpPrefix": " ↳ S'està editant el seguiment: ",
"PendingQueuedOnePrefix": "A la cua #1: ",
"PendingQueuedManyPrefix": "A la cua {count} · següent: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Ha acabat de pensar",
"TranscriptThoughtFor": "Ha pensat durant {duration}",
"TelemetryNoticeDefaultOn": "Les estadístiques d’ús estan activades per defecte. Compartir totals de versió, plataforma, sessions, funcions i errors amb Codewhale i l’encarregat del tractament PostHog. També compta proveïdors, models del catàleg públic, totals de tokens i l’ús de les eines integrades. Sense contingut ni IP. docs/TELEMETRY.md Desactiva: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Estadístiques d’ús de Codewhale",
"TelemetryNoticeBody": "Codewhale compta: la versió que executes, el sistema operatiu i la família\nde CPU, la durada i el resultat de la sessió, i recomptes agregats de funcions\ni errors.\n\nTambé compta els proveïdors i els models del catàleg públic que fas servir, els seus totals de tokens i quantes vegades s’executa cada eina integrada.\n\nNo recopila mai les teves converses, codi, prompts, fitxers, noms de\nfitxers, repositoris o branques, contingut del model ni credencials — i mai no\nenvia una cronologia de l'activitat de l'agent per torn o eina.\n\nNomés t'identifica un identificador aleatori desat en aquesta màquina, que se\nsubstitueix cada 90 dies. Pots canviar d'opinió en qualsevol moment:\n codewhale config set telemetry false\n\nEsquema complet, camp per camp: docs/TELEMETRY.md\n\nLes estadístiques d’ús estan activades per defecte. Codewhale i PostHog tracten aquests totals quan l’enviament està configurat. No es recopila cap IP.",
"TelemetryNoticeCompactBody": "Compta: versió, SO/CPU, temps/resultat, funcions/errors.\nTambé: proveïdor/model, tokens, eines.\nID local rota/90d.\nMai: xats/codi/prompts/fitxers/noms; contingut del model/credencials; torns/eines.\nVegeu: docs/TELEMETRY.md\nDesact.: codewhale config set telemetry false\nLes estadístiques d’ús estan activades per defecte. Codewhale i PostHog tracten aquests totals quan l’enviament està configurat. No es recopila cap IP.",
"TelemetryNoticeChoiceKeep": "Sí, mantenir el recompte anònim",
"TelemetryNoticeChoiceDisable": "No, desactivar el seguiment",
"TelemetryNoticeActionChoose": "triar",
"TelemetryNoticeActionConfirm": "confirmar",
"TelemetryNoticeActionExit": "sortir",
"TelemetryNoticeReceiptEnabled": "El recompte anònim d'ús està activat. Mai es recullen converses ni codi. Canvia-ho a /settings; esquema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "El recompte anònim d'ús està desactivat. No t'ho tornarem a preguntar.",
"TelemetryNoticeReceiptEnabledUnsaved": "El recompte anònim d'ús està activat en aquesta sessió. Codewhale no ha pogut desar aquest avís i el tornarà a mostrar. Canvia-ho a /settings; esquema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "El recompte anònim d'ús està desactivat en aquesta sessió. Codewhale no ha pogut desar l'elecció i tornarà a preguntar al pròxim inici.",
"TelemetryPreferenceEnabledNextLaunch": "El recompte anònim d'ús s'activarà al pròxim inici. Mai es recullen converses ni codi.",
"TelemetryPreferenceDisabled": "El recompte anònim d'ús està desactivat. S'han esborrat les dades locals de telemetria.",
"TelemetryPreferenceDisabledWithWarning": "El recompte anònim d'ús està desactivat, però una part de la neteja requereix atenció: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "No hi ha accions de Hotbar disponibles.",
"HotbarSetupRecommended": "rec",
"HotbarSetupEmptySlot": "buida",
"HotbarSetupHelp": "Tab/Shift+Tab origen Amunt/Avall acció 1-8 ranura Enter assignar Space commutar Delete netejar s desar Esc cancel·lar",
"HotbarActionVoiceToggleName": "Entrada de veu",
"HotbarActionVoiceToggleDescription": "Commuta la captura de veu des del micròfon del terminal.",
"HotbarActionSessionCompactName": "Compactar la sessió",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Mode Work",
"HotbarActionModeAgentDescription": "Treballa directament a la sessió actual.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Compatibilitat: Work amb permisos de Full Access (no és un mode separat).",
"HotbarActionReasoningCycleName": "Canviar el raonament",
"HotbarActionReasoningCycleDescription": "Canvia l'esforç de raonament configurat per al proveïdor actiu.",
"HotbarActionReasoningCycleAutoDisabled": "L'esforç de raonament el controla l'encaminament automàtic del model.",
"HotbarActionSidebarToggleName": "Commutar la barra lateral",
"HotbarActionSidebarToggleDescription": "Mostra o amaga la barra lateral.",
"HotbarActionFileTreeToggleName": "Commutar l'arbre de fitxers",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " No hi ha configuració disponible.",
"ConfigNoMatchesPrefix": " Cap configuració coincideix amb ",
"ConfigFilteredSettings": " Configuració filtrada",
"ConfigShowing": " Es mostra",
"ConfigFooterDefault": " escriure=filtrar, Amunt/Avall=seleccionar, Enter=editar, Esc=tancar ",
"ConfigFooterScrollable": " escriure=filtrar, Amunt/Avall=seleccionar, Enter=editar, PgUp/PgDn=desplaçar, Esc=tancar ",
"ConfigFooterFiltered": " escriure=filtrar, Backspace=esborrar, Ctrl+U/Esc=netejar, Enter=editar ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; els suggeriments de text fantasma s’apliquen després dels torns següents)",
"ConfigNotificationsSetHint": "Defineix-ho amb /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; s’aplica als avisos següents)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs ha de ser un nombre enter",
"ConfigAuditSearchProvider": "Escriu [search] provider; les crides web_search següents continuen respectant les substitucions d’entorn.",
"ConfigAuditPromptSuggestion": "Escriu prompt_suggestion al nivell superior; els suggeriments de text fantasma continuen sent opcionals.",
"ConfigAuditNotifications": "Escriu valors escalars de [notifications] i els aplica als avisos de final de torn següents.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL de l'API del proveïdor",
"ConfigHintProviderUrl": "Endpoint actual del proveïdor; Xiaomi: pla de tokens | pagament per ús | URL personalitzat",
"ConfigLabelModel": "Model actiu del proveïdor",
"ConfigLabelFastModel": "Model ràpid (derivat)",
"ConfigLabelDefaultModel": "Model alternatiu heretat (només rutes DeepSeek)",
"ConfigLabelReasoningEffort": "Nivell de raonament",
"ConfigLabelApprovalMode": "Permís d'aquesta sessió",
"ConfigLabelPermissionPosture": "Permís de les sessions noves",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Totals de versió, sessions, funcions i errors a Codewhale i PostHog; mai contingut ni IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Activat",
"ConfigValueTelemetryOff": "Desactivat",
"ConfigLabelStreamTimeout": "Temps d'espera del flux",
"ConfigLabelTheme": "Tema",
"ConfigLabelLocale": "Idioma",
"ConfigLabelBackground": "Fons",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Ressaltat de fons del raonament",
"ConfigLabelShowToolDetails": "Nivell de detall de les eines",
"ConfigLabelInlineDiffs": "Canvis de fitxers en línia",
"ConfigLabelStatusIndicator": "Indicador d'estat",
"ConfigLabelSynchronizedOutput": "Ritme de la sortida",
"ConfigLabelCostCurrency": "Moneda dels costos",
"ConfigLabelTranscriptSpacing": "Espaiat de la transcripció",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "Densitat del redactor",
"ConfigLabelComposerBorder": "Vora del redactor",
"ConfigLabelComposerMultilineMode": "Mode multilínia del redactor",
"ConfigLabelComposerVimMode": "Mode Vim del redactor",
"ConfigLabelBracketedPaste": "Enganxada amb claudàtors",
"ConfigLabelPasteBurstDetection": "Detecció d'enganxades",
"ConfigLabelMentionMenuLimit": "Límit del menú de mencions",
"ConfigLabelMentionMenuBehavior": "Comportament del menú de mencions",
"ConfigLabelMentionWalkDepth": "Profunditat de mencions de fitxers",
"ConfigLabelWorkspaceFollowSymlinks": "Seguir enllaços simbòlics",
"ConfigLabelContextPanel": "Panell de context",
"ConfigLabelAutoCompact": "Compactació automàtica",
"ConfigLabelAutoCompactThreshold": "Llindar de compactació",
"ConfigLabelMaxHistory": "Historial d'entrada",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "Comanda d'objectiu",
"ConfigLabelWorkflow": "Flux de treball",
"ConfigLabelFeaturePrefix": "Funció: {name}",
"ConfigColumnSetting": "Configuració",
"ConfigColumnValue": "Valor",
"ConfigColumnScope": "Abast",
"ConfigActionOpenProvider": "Enter obre el selector de proveïdor",
"ConfigActionOpenModel": "Enter obre el selector de model",
"ConfigActionOpenMcp": "Enter obre el gestor MCP",
@@ -415,6 +456,7 @@
"HelpKeybindings": "Dreceres de teclat",
"HelpUserCommands": "Comandes d'usuari",
"HelpSkills": "Skills",
"HelpFooterTypeFilter": " escriure per filtrar ",
"HelpFooterMove": " Amunt/Avall moure ",
"HelpFooterJump": " PgUp/PgDn saltar ",
"HelpFooterClose": " Esc tancar ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "Connector suggerit: {name}",
"PluginCtaReview": "Revisa",
"PluginCtaInstall": "Instal·la",
"PluginCtaReviewTrust": "Revisa la confiança",
"PluginCtaEnable": "Activa",
"PluginCtaDismiss": "No ho tornis a suggerir",
"PluginCtaDismissSaveFailed": "Ocult durant aquesta sessió; no s'ha pogut desar la preferència del connector.",
"PluginSuggestionReason": "Coincideix amb «{trigger}»",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "L'acció del plugin ha fallat: {error}",
"CmdPluginNoneFound": "No s'han trobat eines de plugin executables heretades a {dir}",
"CmdPluginNotFound": "No s'ha trobat el plugin '{name}'",
"CmdPluginListHeader": "Eines de plugin executables heretades ({count}):",
"CmdPluginDetailDescription": "Descripció: {description}",
"CmdPluginDetailSchema": "Esquema:\n{schema}",
"CmdPluginDetailApproval": "Aprovació: {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "Catàleg en memòria cau; executa `codewhale models --update` per actualitzar els proveïdors configurats.",
"ModelsUpdateSummary": "Catàlegs de models: {updated} actualitzats, {loaded} carregats des de Codex, {failed} amb errors, {skipped} omesos.",
"ModelsUpdatePartial": "No s’han pogut actualitzar alguns catàlegs. Els models anteriors i configurats continuen disponibles.",
"ModelsCodexHint": "Els models de ChatGPT es carreguen a través de Codex. L’hora de consulta no confirma una actualització del catàleg del proveïdor.",
"ModelsSourceFallback": "Models inclosos o configurats; disponibilitat no verificada.",
"CmdModelDbDescription": "Explora la base de dades de models inclosa",
"CmdNetworkDescription": "Gestiona les regles de xarxa de permís i denegació",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "Mostra o edita els missatges en cua",
"CmdQueueUsage": "Ús: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "S'han restaurat {count} missatges en cua d'una sessió anterior. No s'envien automàticament: /queue send <n> n'envia un, /queue clear els descarta.",
"CmdQueueDraftHeader": "S'està editant el missatge en cua:",
"CmdQueueNoMessages": "No hi ha missatges en cua",
"CmdQueueListHeader": "Missatges en cua ({count}):",
"CmdQueueTip": "Consell: /queue send <n> per enviar ara, /queue drop <n> per eliminar",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} hit / {miss} miss",
"CmdTokensCacheHitOnly": "{hit} hit / miss no reportat",
"CmdTokensCacheMissOnly": "hit no reportat / {miss} miss",
"CmdTokensContextUnknownWindow": "~{estimated} / finestra desconeguda",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 agent",
"FooterAgentsPlural": "{count} agents",
"HeaderAgentsChip": "agents {count}",
"FooterPressCtrlCAgain": "Prem Ctrl+C de nou per sortir",
"FooterWorking": "treballant",
"FooterBalancePrefix": "saldo",
"HelpSectionActions": "Accions",
"HelpSectionClipboard": "Porta-retalls",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "no reportat",
"CmdTokensReport": "Ús de tokens:\n ─────────────────────────────\n Context actiu: {active}\n Última entrada d'API: {input} (telemetria del torn; pot comptar el prefix repetit entre rondes d'eines)\n Última sortida d'API: {output}\n Cache hit/miss: {cache} (només telemetria/cost)\n Tokens acumulats: {total} (telemetria d'ús de la sessió)\n Cost aprox. de sessió: {cost}\n Missatges d'API: {api_messages}\n Missatges del xat: {chat_messages}\n Model: {model}",
"KbScrollTranscript": "Desplaça la transcripció, navega per l'historial d'entrada o selecciona adjunts del redactor",
"KbNavigateHistory": "Navega per l'historial d'entrada",
"KbBrowseHistory": "Explora l'historial de la conversació",
"KbScrollTranscriptAlt": "Desplaça la transcripció",
"KbScrollPage": "Desplaça la transcripció per pàgines",
@@ -807,6 +858,7 @@
"KbCompactContext": "Compacta el contexte de la conversa",
"KbLastMessagePager": "Obre el paginador de l'últim missatge (quan l'entrada és buida)",
"KbSelectedDetails": "Mostra el detall en brut de l'eina o el missatge seleccionat; Ctrl+Alt+O obre la visió general de tot el torn",
"KbToolDetailsPager": "Mostra el detall en brut de l'element seleccionat (Alt+V)",
"KbExternalEditor": "Obre l'esborrany del redactor en un editor extern",
"KbLiveTranscript": "Obre la superposició de transcripció en viu (Ctrl+Shift+T; desplaçament automàtic fixat al final)",
"KbBacktrackMessage": "Torna enrere fins a un missatge anterior de l'usuari (Esquerra/Dreta per anar pas a pas, Enter per rebobinar)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "Obre aquesta superposició d'ajuda (quan l'entrada és buida)",
"KbCycleWorkDock": "Recorre el moll de treball (tasques, agents, feines, segon pla) o, en mode mascota, les vistes de la mascota",
"KbCycleWorkDockBack": "Recorre el moll de treball o les vistes de la mascota enrere",
"KbToggleHelp": "Commuta la superposició d'ajuda",
"KbToggleHelpSlash": "Commuta la superposició d'ajuda",
"HelpUsageLabel": "Ús:",
"HelpAliasesLabel": "Àlies:",
"SettingsTitle": "Configuració:",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan per investigar i presentar un pla primer",
"HomeAgentModeYoloTip": " Shift+Tab canvia el permís: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — les eines s'executen sense demanar aprovació",
"HomeYoloModeCaution": " Les operacions destructives poden executar-se a l'instant; prefereix Ask si tens dubtes",
"HomePlanModeTip": "Plan — investiga i dissenya abans d'implementar",
"HomePlanModeChecklistTip": " Presenta un pla i el progrés de tasques, després canvia a Work",
"HomeGoalModeTip": "Seguiment d'objectius - Defineix /goal <objectiu> per perseguir objectius",
"OnboardLanguageTitle": "Tria l'idioma",
"OnboardLanguageBlurb": "Tria l'idioma de la interfície. El pots canviar en qualsevol moment amb `/config locale <tag> --save`.",
"OnboardProviderTitle": "Tria el teu proveïdor de models",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "«Mantenir» deixa l'emmascarament actiu en aquest llançament; com que la configuració encara demana \"disabled\", el proper llançament tornarà a preguntar.",
"RedactionGateSaveFailed": "No s’ha pogut desar la confirmació. L’emmascarament continua activat. Torna-ho a provar o conserva’l activat.",
"RedactionGateTitle": "Emmascarament de claus a la frontera del model",
"OnboardOfflineOption": "Ctrl+O — explora sense connexió: fes una ullada ara, connecta un proveïdor més tard.",
"OnboardOfflineNotice": "Explorant sense connexió. Encara no hi ha res connectat — executa /provider quan vulguis connectar.",
"OnboardWelcomeTitle": "Codewhale treballa amb tu en aquesta carpeta.",
"OnboardWelcomeLead": "Posem-nos en marxa.",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "Explica què fa aquest projecte i llista els principals punts d'entrada.",
"OnboardSeedFolder": "Mira aquesta carpeta i suggereix una bona primera tasca.",
"SetupWizardTitle": "Setup",
"SetupWizardWhy": "Aquesta pantalla registra el progrés de Setup a setup_state.json; els canvis de configuració només s'apliquen mitjançant accions explícites de cada pas.",
"SetupWizardProgress": "Pas",
"SetupActionBack": "tornar",
"SetupActionContinue": "continuar",
"SetupActionSkip": "ometre",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "desplaçar el cos",
"SetupActionGuided": "previsualitzar/ratificar",
"SetupActionTuneGuided": "ajustar",
"SetupActionModelDraft": "esborrany del model",
"SetupActionFreeform": "paraules pròpies",
"SetupActionKeepExisting": "mantenir l'existent",
"SetupActionUseRecommended": "usar la recomanació",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "rutes de model",
"SetupActionFleet": "configuració de Fleet",
"SetupActionHotbar": "configuració de Hotbar",
"SetupActionRemote": "inici remot",
"SetupActionMode": "selector de mode",
"SetupActionConfig": "vista de config",
"SetupActionRuntimePreset": "preset",
"SetupActionApplyRuntimePreset": "previsualitzar/aplicar",
"SetupActionUseBundled": "usar l'inclòs",
"SetupActionDefer": "ajornar",
"SetupActionCancel": "cancel·lar",
"SetupStatusNotStarted": "no iniciat",
"SetupStatusRecommended": "recomanat",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "Idioma de Setup registrat.",
"SetupConstitutionChoiceLabel": "Elecció:",
"SetupConstitutionSourceLabel": "Font:",
"SetupConstitutionValidityLabel": "Validesa:",
"SetupConstitutionPreviewLabel": "Hash de previsualització:",
"SetupConstitutionExistingLabel": "Fitxer existent:",
"SetupConstitutionExpertOverrideLabel": "Override expert:",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "Plugins:",
"SetupToolsMcpReviewHint": "Enter registra aquesta instantània de configuració. Prem R per a accessos segurs (sense execució automàtica).",
"SetupToolsMcpReviewed": "Preparació d'eines/MCP registrada.",
"SetupRemoteCloudsLabel": "Destins al núvol:",
"SetupRemoteBridgesLabel": "Ponts de xat:",
"SetupRemoteProvidersLabel": "Proveïdors:",
"SetupRemoteModeLabel": "Mode remot:",
"SetupRemoteModeLocalOnly": "Només aquest ordinador:",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "Copia el missatge",
"CtxMenuCopyMessageDesc": "escriu la cel·la de transcripció clicada",
"CtxMenuOpenInEditor": "Obre a l'editor",
"CtxMenuOpenInEditorDesc": "obre fitxer:línia a $EDITOR",
"CtxMenuShowCell": "Mostra la cel·la",
"CtxMenuShowCellDesc": "desamaga aquesta cel·la de transcripció",
"CtxMenuHideCell": "Amaga la cel·la",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} fetes · {running} en curs · {failed} fallides · {pending} pendents",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (etiqueta de mode obsoleta)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Treball directe en aquesta sessió — edicions i shell demanen aprovació",
"AppModeAutoHint": "Shell activat amb revisió automàtica de risc",
"AppModePlanHint": "Recerca de només lectura primer — presenta un pla abans d'actuar",
"AppModeYoloHint": "Només compatibilitat — Work + Full Access, no és un mode visible",
"AppModeOperateHint": "Work a fons: objectiu, workers paral·lels, validat",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERIR --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Només llegeix",
"ApprovalEffectChangesFiles": "Canvia fitxers",
"ApprovalRiskDestructive": "No es pot desfer",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s permet ara i pregunta sempre abans de tornar-ho a fer",
"ApprovalOptionDeny": "No ho permetis",
"ApprovalOptionAbortTurn": "Atura aquest torn",
"ApprovalBlockTitle": "aprovació",
"ApprovalControlsHint": "Pg↑/↓ revisa · {details} més opcions · Esc atura",
"ApprovalOwnerHeader": "Agent: {agent} · {role}",
"ApprovalGoToAgent": "g ves a l'agent",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … truncat · prem {details} per a tots els detalls",
"ApprovalAsksWithoutGit": "Aquí no hi ha cap repositori Git, així que les edicions demanen permís abans.",
"ApprovalFullAccessPolicyBlocked": "{tool} blocat: Full Access no pot evitar aquesta política",
"ApprovalChooseHint": "Tria: ",
"ApprovalChooseAction": "Enter per a l'opció seleccionada, o prem y/a/d directament",
"ApprovalIntentLabel": "Intenció: ",
"ApprovalMoreLines": " … (+{count} línies)",
"ApprovalProceedQuestion": "Vols continuar?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "Compactant el context…",
"ContextCompactionQueued": "La compactació del context s'ha posat a la cua; s'executarà després del torn actiu.",
"ContextCompactionAlreadyRunning": "La compactació del context ja està en curs.",
"ContextCompactionQueueFull": "No s'ha pogut posar la compactació del context a la cua perquè el motor està ocupat; torna-ho a provar quan acabi el torn.",
"ContextCompactionQueueClosed": "La compactació del context no està disponible perquè el motor ja no s'està executant.",
"ContextCompactionRouteInvalid": "No es pot compactar perquè la ruta del proveïdor actiu no és vàlida: {error}",
"ContextCompactionStoppedOnEngineSwitch": "S'ha aturat la compactació del context; la conversa no s'ha modificat",
"ContextPurgeAbandonedOnEngineSwitch": "La neteja de la sessió s'ha abandonat amb el motor substituït; la conversa no s'ha modificat",
"CtxInspTitle": "Inspector de context",
"CtxInspSessionContext": "Context de la sessió",
"CtxInspSystemPrompt": "Estructura del prompt del sistema",
"CtxInspReferences": "Referències",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Eines, MCP, Skills i Plugins — Incorporació segura\n\n/setup només llegeix l'inventari local. Mai inicia servidors MCP, instal·la skills, executa plugins ni executa ordres no confiades.\n\nInventari actual:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Directori d'eines: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (adaptadors compartits): {hotbar_result}\n\nCamins (carpeta personal ocultada):\n- Configuració MCP: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nArrencada segura (executa-la tu mateix en un terminal normal o ordre del TUI):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install <spec>\n- Plugins: /plugin · codewhale setup --plugins\n- Directori d'eines: codewhale setup --tools\n\nLes accions amb efectes secundaris sempre requereixen confirmació explícita. Les ordres de plugins es mantenen separades de les ordres de barra; la font de plugins Hotbar queda ajornada fins que arribin les portes d'aprovació.\n\nConsulta docs/MCP.md i docs/skills/README.md per al que encara requereix configuració externa manual.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — connectat a través de Codewhale, mai un segon planificador:\n- Estat: {dsh_result}\n- Detecció només de lectura; connectar/planificar/iniciar/eliminar: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale només escriu a $CODEWHALE_HOME/integrations/dsh; mai copia claus d'API ni edita fitxers de DSH.",
"HotbarActionModeOperateName": "Mode Operate",
"HotbarActionModeOperateDescription": "Treballa una petició duradora en paral·lel fins que estigui verificada.",
"HomeOperateModeTip": "Operate — posa el teu Fleet a treballar en paral·lel",
"HomeOperateModeFleetTip": " Els rols integrats usen el model d'aquesta sessió; /fleet setup els personalitza",
"HelpSubtitle": "Comandes, habilitats i dreceres",
"CommandPaletteTitle": "Ordre",
"CommandPaletteSubtitle": "Cerca i executa una acció",
"ConfigSubtitle": "Configuració primer; claus en brut sota detall avançat",
"LaunchStartTitle": "Comença aquí",
"LaunchResumeConfirm": "Reprendre {title}? Torna a fer clic o prem Retorn per confirmar.",
"LaunchResumeConfirmTitle": "Reprendre la sessió",
"LaunchResumeConfirmBody": "Això substitueix el context actual per l'historial d'aquella sessió.",
"LaunchResumeConfirmResume": "reprèn",
"LaunchResumeConfirmCancel": "cancel·la",
"LaunchWorkDescription": "Utilitza aquesta carpeta amb eines locals; els canvis segueixen la política d’aprovació.",
"LaunchChatDescription": "Només conversa i planificació; cap canvi als fitxers.",
"LaunchWorkspaceGitReady": "Espai de treball · {name} · espai Git",
"LaunchWorkspaceFolderReady": "Espai de treball · {name} · carpeta local",
"LaunchProviderConfigured": "Proveïdor · configurat",
"LaunchProviderSetupNeeded": "Proveïdor · cal configurar-lo",
"LaunchGroupContinue": "Continua",
"LaunchGroupMore": "Més",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "carpeta",
"LaunchProviderConfiguredShort": "proveïdor configurat",
"LaunchProviderSetupShort": "configura proveïdor",
"LaunchMenuChangelog": "Registre de canvis",
"LaunchWorktreePrompt": "Anomena la branca/worktree, o prem Enter per a un nom automàtic. Esc per tornar.",
"LaunchWorktreeNeedsGit": "Un worktree nou requereix un repositori Git.",
"LaunchWorktreeNameLabel": "nom del worktree",
"LaunchHintMove": "mou",
"LaunchHintOpen": "obre",
"LaunchTipFlags": "Consell: -w <path> obre un espai de treball; -r <session-id> reprèn directament",
"LaunchSavedSessionSingular": "1 sessió desada",
"LaunchSavedSessionsPlural": "{count} sessions desades",
"LaunchCreatingWorktree": "Creant el worktree…",
"LaunchWorktreeFailed": "El worktree ha fallat: {error}",
"LaunchWorktreeCreated": "Nou worktree {path} a la branca {branch}",
"LaunchNoSavedSessions": "No hi ha sessions desades per a aquest espai de treball.",
"LaunchNoModelConnected": "cap model connectat",
"DispatchNotSentNoModel": "No hi ha cap model connectat, així que aquest missatge no s'ha enviat. Torna a ser al quadre de missatge: connecteu un model amb F3 o /provider i premeu Enter per enviar-lo.",
"DispatchNotSentSaveKey": "Deseu una clau: {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "S'està usant {model}, un model que s'executa en aquest ordinador (Ollama). Prem F3 per triar-ne un altre.",
"ProviderPickerNotReopened": "No s'ha pogut tornar a obrir la llista de proveïdors. Prem F3 per obrir-la.",
"LaunchRunCommand": "executa {command}",
"LaunchMcpConnectedOne": "1 servidor MCP connectat",
"LaunchMcpConnectedMany": "{count} servidors MCP connectats",
"LaunchMcpNeedsSignInOne": "1 necessita iniciar sessió",
"LaunchMcpNeedsSignInMany": "{count} necessiten iniciar sessió",
"PhaseIdle": "inactiu",
"PhaseDraft": "esborrany",
"PhaseWorking": "treballant",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "acabant",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "només lectura",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "mai",
"PermissionsChangedReceipt": "Permisos canviats a {label}",
"FooterHintKeys": "tecles",
"FooterHintOutput": "sortida",
"FooterHintContext": "context",
"InfoLineHelp": "ajuda",
"InfoLineContext": "context",
"InfoLineTtft": "ttft",
"InfoLinePeak": "hora punta",
"InfoLineOffPeak": "hora vall",
"InfoLineWhales": "balenes",
"InfoLineAutomation": "automatització",
"InfoLineNotConnected": "no connectat",
"InfoLineThinking": "raonament: {level}",
"EmptyStateNoGit": "sense git",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "cerca qualsevol model",
"RoutePanelHeader": "ruta",
"RouteProviderLabel": "proveïdor",
"RouteModelFirstAtomic": "ruta atòmica model-primer",
"PickerActionMove": "mou",
"PickerActionSwitch": "canvia",
"PickerActionApply": "aplica",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "esborra la cerca",
"PickerActionBrowseAll": "explora-ho tot",
"PickerActionCustom": "personalitzat",
"PickerActionJump": "salta",
"PickerActionEditKey": "edita la clau",
"PickerActionModels": "models",
"PickerActionUnavailable": "no disponible",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "deixa d'usar aquest inici de sessió",
"ProviderExternalActionChoices": "inicia sessió amb una altra app",
"ProviderExternalActionReuseGrok": "reús extern de Grok",
"ProviderExternalHintCodexReview": "Després de {login}, prem Enter per revisar les opcions d'accés desactivat/només lectura/gestionat.",
"ProviderExternalHintXaiReview": "Prem Enter per a l'inici de sessió de dispositiu gestionat per Codewhale; prem E per revisar el reús existent del Grok CLI.",
"ProviderExternalHintXaiApiKey": "O usa XAI_API_KEY i torna a obrir aquest selector.",
"XaiAuthChoiceTitle": " Autenticació d’xAI ",
"XaiAuthChoiceIntro": "Tria una font de credencials explícita. El text de la clau mai no es tracta com un testimoni OAuth.",
"XaiAuthChoiceApiKeyOption": "Clau d’API d’xAI — escriu-la o enganxa-la i desa-la a l’espai del proveïdor xAI",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " Autenticació de ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "L'inici de sessió de subscripció es factura al teu pla de ChatGPT. La ruta de clau API d'openai és un altre titular de facturació.",
"ChatgptAuthChoicePkceOption": "Inicia la sessió amb ChatGPT — PKCE al navegador, testimonis de Codewhale, facturació de la subscripció de ChatGPT",
"ChatgptAuthChoiceImportOption": "Importa credencials de la CLI de Codex — consentiment explícit de només lectura; la CLI de Codex en segueix sent la propietària",
"ProviderExternalHintChatgptReview": "Prem Enter per iniciar la sessió amb ChatGPT; prem E per revisar la reutilització existent de la CLI de Codex.",
"ProviderExternalActionReuseCodex": "reutilització externa de Codex",
"ProviderExternalDetailScope": "Extern: accés={access} | proveïdor={provider} | origen={source} | versió={version} | {state}",
"ProviderExternalDormant": "adormit",
"ProviderExternalOwnerPath": "Propietari/camí: {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "Les instantànies i /undo estan desactivats per a {workspace}: un directori d'inici o l'arrel és massa ampli per fer-ne una instantània segura. Comença en un directori de projecte per activar-los.",
"SnapshotsHistoryRepaired": "L'historial de desfer de {workspace} estava malmès (faltava el darrer punt de restauració) i s'ha reiniciat. Els punts de restauració anteriors ja no es poden restaurar; els torns nous tornen a estar protegits.",
"SnapshotsFailing": "Les instantànies fallen per a {workspace}, així que /undo no pot restaurar els torns recents: {limit}",
"SessionIdDivergedNotice": "La identitat de la sessió ha canviat sota aquesta finestra: el motor ara desa els punts de control com a {next} (abans era {previous}). Els punts anteriors queden sota l'id antic; `codewhale sessions` els llista tots dos i `codewhale resume {previous}` reobre l'anterior.",
"RuntimeStoreUnreadableNotice": "Magatzem d'execució de la sessió: no s'ha pogut llegir {record} a {path} ({reason}). Aparta aquest fitxer (o suprimeix-lo) i torna-ho a provar; la resta de registres del fil es conserven.",
"RuntimeStoreUnwritableNotice": "Magatzem d'execució de la sessió: no s'ha pogut escriure {record} a {path} ({reason}). Comprova l'espai lliure i els permisos allà i torna-ho a provar; no s'ha sobreescrit res.",
"ProviderExternalSemanticsRevoke": "{semantics} | revoca: {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "configuració",
"FleetRosterWorkers": "treballadors",
"FleetRosterMembersCount": "{count} membres",
"FleetRosterOperatorFirst": "El Coordinador lidera · el model de la sessió mou aquest Fleet",
"FleetRosterOperatorRow": "Coordinador · líder",
"FleetRosterShadowBadgeProjectOverride": "desat en aquest projecte",
"FleetRosterShadowBadgePersonalIgnored": "còpia desada ignorada",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "aquest és el teu model actual (la ruta de l'operador de l'equip); canvia de model o fes servir /fleet save per modificar-la",
"FleetModelReasonAlreadyPresent": "ja és a l'equip",
"FleetModelErrorNeedsRoute": "un model de l'equip necessita un id de provider i un id de model",
"FleetModelErrorNeedsRole": "L’agent necessita un nom de rol (per exemple, `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "no hi ha cap equip seleccionat; el teu equip és només el model de la sessió",
"FleetModelErrorOperatorRoute": "{route} és la ruta de l'operador de l'equip `{fleet}`; canvia-la amb /fleet save, no amb remove",
"FleetModelErrorNotInFleet": "{route} no és a l'equip `{fleet}`",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ adjunta · 1 coincidència",
"FilePickerMatchesPlural": "@ adjunta · {count} coincidències",
"FilePickerScanning": "Escanejant l'espai de treball…",
"BehavioralTipPlanning": "Planifiques? {key} commuta al mode Plan",
"BehavioralTipBackgroundReceipt": "Els comprovants són al panell de treball — {key} obre l'inspector",
"BehavioralTipClearedInput": "Esborrat · {chord} restaura",
"BehavioralTipMcpValidation": "{command} inicia els servidors i mostra per què",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "Model i raonament",
"SettingSubjectProvider": "Proveïdor",
"SettingSubjectPermissions": "Permisos",
"ThinkingControlledByAutoRouting": "El raonament el controla l'encaminament automàtic de models; tria primer un model fix.",
"SavedAsStartupDefault": "desat com a valor per defecte d'arrencada",
"ModeAlreadyActiveSavedAsDefault": "Ja estàs en mode {mode} — desat com a valor per defecte d'arrencada.",
"StartupDefaultNotSaved": "No s'ha desat {setting}: {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun factura el pay-as-you-go i les subscripcions Step Plan en endpoints separats. Trieu aquell al qual pertany la vostra clau.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (preu per token)",
"StepfunBillingRoutePlanOption": "Subscripció Step Plan (quota del pla)",
"StepfunPlanApiKeyHint": "Per a subscripcions StepFun Step Plan, useu la clau emesa per al vostre Step Plan, no una clau pay-as-you-go.",
"StepfunPlanRouteHint": "Aquesta ruta usa {route} i es factura contra la quota del vostre Step Plan.",
"ConfigLabelSessionsRail": "Barra de sessions",
"ConfigLabelSessionAutoResume": "Reprendre automàticament l'última sessió",
"SessionsRailTitle": "Sessions",
"SessionsRailEmpty": "Encara no hi ha sessions en aquest espai de treball",
"SessionsRailBrowseAll": "Explora totes les sessions",
"SessionsRailShowingCount": "{shown} de {total} — veure-les totes",
"SessionsRailUnavailable": "Sessions no disponibles: {error}",
"SessionsActionArchive": "arxiva",
"SessionsActionShowArchived": "arxivades",
"SessionsArchived": "Sessió {id} arxivada",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "agents",
"FooterHintToManage": "gestionar",
"AgentRailQueuedCount": "{count} a la cua",
"WorkbarSoFar": "{done}/{total} fins ara",
"WorkbarLargeWorkflow": "Flux de treball gran",
"WorkbarMoreRuns": "+{count} més",
"WorkflowLineStarted": "iniciat",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "acabat amb buits",
"WorkflowLineFailed": "ha fallat",
"WorkflowLineStopped": "aturat",
"WorkflowLineAgents": "{done}/{total} agents",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "escriu",
"AgentFocusPostureReadOnly": "només lectura",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell de només lectura",
"AgentFocusPostureShellNone": "sense shell",
"GoalReceiptSet": "Objectiu establert: \"{objective}\" · /goal mostra el progrés · /goal pause o /goal clear l'atura",
"GoalReceiptSetOperate": "◆ objectiu establert · Operate continua treballant fins que es verifica · /goal per editar-lo",
"GoalControlAccepted": "Control de l'objectiu desat; s'aplicarà al següent punt segur.",
"GoalControlRuntimeUnavailable": "El control de l'objectiu està desat, però el procés no està disponible. Es restaurarà després de reiniciar.",
"GoalStatusIdleHint": "no s'està executant — envia un missatge o /goal resume per continuar",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Objectiu actiu · torn següent d'aquí a {delay} · Esc, Ctrl+C o /goal pause atura la continuació pendent",
"GoalContinuationReady": "La continuació de l'objectiu està preparada; els controls en cua s'executen abans del torn següent.",
"GoalContinuationStopped": "S'ha aturat la continuació pendent; l'objectiu continua actiu.",
"McpCapabilitiesAdvertised": "Capacitats anunciades: {capabilities}",
"McpCapabilitiesLegacyFallback": "Capacitats anunciades: no proporcionades; s'usa el descobriment antic",
"McpCapabilitiesNotObserved": "Capacitats anunciades: no observades perquè el servidor no està connectat",
"PickerActionTestConnection": "provar la connexió",
"ProviderCustomFormBaseUrl": "URL base",
"ProviderCustomFormModel": "Model per defecte",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt temps →",
"ConfigCategoryAppearance": "Aparença",
"ConfigCategoryModelsProviders": "Models i proveïdors",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Treball",
"ConfigCategoryToolsMcp": "Eines i MCP",
"ConfigCategoryTrust": "Confiança",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "només lectura",
"ConfigRowActionNote": "acció · no és un ajust persistit",
"ConfigRowDiagnosticNote": "rebut observat · no editable aquí",
"ConfigNavHint": "←/→ o Tab categoria · ↑/↓ ajust",
"ConfigActivateAgain": "Enter o torna a fer clic:",
"ConfigSearchLabel": " Cerca: ",
"ConfigEditChooseLabel": "Tria:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Mai",
"ConfigChoiceModeAct": "Actua",
"ConfigChoiceModePlan": "Planifica (només lectura)",
"ConfigChoiceModeOperate": "Opera",
"ConfigChoicePlacementTop": "A dalt",
"ConfigChoicePlacementBottom": "Barra inferior",
"ConfigChoicePlacementLeft": "Barra lateral esquerra",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Revisa el risc de les eines automàticament i pregunta quan una decisió et necessita.",
"ConfigChoiceDetailUseTuiDefault": "Treu la sobreescriptura del config arrel i usa la tria de permís desada a la TUI.",
"ConfigChoiceDetailFullAccess": "Les eines s’executen sense preguntar, i les ordres poden accedir a tot el que hi ha en aquest ordinador.",
"ConfigChoiceDetailNever": "Bloqueja tota eina que requereixi aprovació.",
"ConfigChoiceDetailModeAgent": "Comença a punt per col·laborar i usar eines.",
"ConfigChoiceDetailModePlan": "Comença en un espai de planificació de només lectura.",
"ConfigChoiceDetailModeOperate": "Operate és Work a tota potència: cada petició substancial es converteix en un objectiu, passa per workflows i workers paral·lels, la revisa un revisor independent i continua fins que està verificada.",
"ConfigChoiceDetailPlacementTop": "Mostra Tasques, Pendents i Workers damunt de la transcripció.",
"ConfigChoiceDetailPlacementBottom": "Mostra Tasques, Pendents i Workers sota el redactor.",
"ConfigChoiceDetailPlacementLeft": "Mostra Tasques, Pendents i Workers en una barra lateral esquerra quan el terminal és prou ample.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Omple el fons del raonament del model.",
"ConfigChoiceDetailThinkingHighlightOff": "Manté la línia de raonament discontínua i el text en cursiva sense fons ple.",
"ConfigHintModel": "model de la ruta en viu d'aquesta sessió; Enter obre /model",
"ConfigHintFastModel": "l'usen l'encaminament Auto i model_strength=faster dels agents quan aquest proveïdor té un germà conegut",
"ConfigHintProvider": "credencial, model i endpoint canvien junts",
"ConfigHintApprovalMode": "només aquesta sessió: Pregunta | Revisió automàtica | Accés total",
"ConfigHintPermissionPosture": "predeterminat per a sessions noves: Pregunta | Revisió automàtica | Accés total",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "enter (0 permès) · nombre de missatges enviats que es conserven per recuperar-los i cercar a l'historial",
"ConfigHintAutoCompactThreshold": "10..=100 · llindar de compactació: percentatge de la longitud de context utilitzable en què es dispara la compactació automàtica",
"ConfigHintDefaultModel": "reserva antiga només per a DeepSeek; els altres proveïdors usen el model per proveïdor de dalt",
"ConfigHintReasoningEffort": "default restaura el predeterminat del model; els models que sempre raonen ometen off",
"ConfigHintMcpOpen": "obre el gestor MCP · Connecta / Reconnecta / Reautentica / Diagnostica",
"ConfigHintMcpReconnect": "reconnecta MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "estat de només lectura de l'indicador de funció de les eines d'edició per pedaç",
"ConfigHintFeatureMcp": "estat de només lectura de l'indicador de funció de les eines MCP",
"ConfigHintFeatureExecPolicy": "estat de només lectura de l'indicador de funció de les eines de política d'execució",
"ConfigHintFeatureVisionModel": "indicador beta per al suport d'imatges de visió/model",
"ConfigHintGoalCommand": "/goal defineix objectius, pressupostos i l'estat del context de Treball",
"ConfigHintWorkflow": "/workflow executa operacions guionades amb targetes d'execució de distribució/consolidació",
"LaunchMenuNewWorktree": "Nou worktree",
"LaunchMenuResume": "Reprendre la sessió",
"LaunchMenuQuit": "Surt",
"LaunchNoticeClaude": "Claude Code detectat. Executa /import-claude per revisar què es pot importar: servidors MCP, valors segurs i permisos. Res s'aplica sense el teu consentiment.",
"LaunchNewSession": "Nova sessió",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ per reprendre",
"LaunchHelpLine": "/help per a ordres · {dock} per a la barra de treball",
"LaunchSeeAllSessions": "Mostra totes les sessions…",
"LaunchNoRecentSessions": "Encara no hi ha sessions recents — escriu a sota per començar.",
"LaunchResumeFailed": "La represa ha fallat: {error}",
"ReceiptSessionHooks": "hooks {count}",
"AutomationEditorNew": "Automatització nova",
"AutomationEditorEdit": "Edita l’automatització",
"AutomationEditorSchedule": "Programació",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} fets",
"WorkflowPhaseCountOne": "{count} fase",
"WorkflowPhaseCountMany": "{count} fases",
"WorkflowPhaseOrdinal": "fase {n}/{total}",
"ModelPickerPinned": "S'ha fixat {route}",
"ModelPickerUnpinned": "S'ha deixat de fixar {route}",
"ModelPickerPinFailed": "No s'ha pogut actualitzar la fixació: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "S'ha substituït l'inici de sessió anterior de Codewhale a {provider} ({account}).",
"AuthReplacedPreviousSignIn": "S'ha substituït l'inici de sessió anterior de Codewhale a {provider}.",
"AuthSameAccountAsBefore": "És el mateix compte que abans; per fer servir un altre compte de {provider}, tanca'n la sessió al navegador (o fes servir una finestra privada) i torna a iniciar la sessió.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN o CODEX_ACCESS_TOKEN està definit en aquest entorn i té prioritat sobre aquest inici de sessió; les sol·licituds continuaran fent servir el compte d'aquest testimoni fins que el suprimeixis.",
"PinnedPromptJumpToMessage": "Ves a aquest missatge",
"PlanHandoffHeader": "Pla a punt",
"PlanHandoffQuestion": "Com vols continuar?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Prem Retorn per iniciar sessió al navegador o Esc per tornar. No cal cap clau API.",
"PluginOAuthReady": "{provider}: sessió iniciada. Tria un model.",
"PluginOAuthLocalLogout": "{provider}: sessió local eliminada. L’accés remot no ha canviat.",
"CmdConnectDescription": "Connecta un proveïdor de plugins amb inici de sessió al navegador",
"CmdDisconnectDescription": "Elimina l’inici de sessió local d’un proveïdor de plugins",
"ExecAutoHelp": "Activa eines amb aprovació automàtica i Full Access (sense sandbox del shell i amb el mode de confiança activat), llevat que hi hagi un sandbox més restrictiu configurat; fes servir --sandbox workspace-write per restringir les escriptures de fitxers i del shell.",
"ExecSandboxHelp": "Política de sandbox d’aquesta execució; qualsevol --sandbox diferent de danger-full-access (o un sandbox_mode equivalent a la configuració) desactiva el mode de confiança.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime hat den Ereignisstrom dieser Unterhaltung geschlossen; öffne die Unterhaltung erneut",
"MobileStreamReconnecting": "Verbindung verloren; Verbindung wird wiederhergestellt",
"MobileStreamConnected": "Verbunden",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Ein gemeinsamer Lebensraum",
"PetHabitatHints": "{back} zurück · {sound} Ton · {browser} Aussehen · {window} Fenster",
"PetHabitatQueued": "An den gemeinsamen Lebensraum gesendet. /pet on zeigt das Haustier und das Nachrichtenfeld.",
"PetWatchSoundOn": "Ton an",
"PetWatchSoundOff": "Ton aus",
"PetWatchSoundPaused": "Ton pausiert",
"PetWatchSoundUnavailable": "Die Tonausgabe wurde gestoppt. Prüfe FFmpeg (ffplay) und deinen Audioausgang und schalte den Ton erneut ein.",
"CmdPetDescription": "Nutze das animierte Haustier als Hauptansicht von Codewhale",
"ConfigLabelPetMode": "Haustiermodus",
"ConfigHintPetMode": "Beim Start von Codewhale das animierte Haustier als Hauptansicht verwenden.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "Haustiermodus aus",
"PetViewOpen": "Lebensraum offen",
"PetViewClosed": "Lebensraum geschlossen",
"PetWatchRestored": "/pet hat den Lebensraum dieser Sitzung wiederhergestellt. Warte auf neue Telemetrie.",
"PetWatchStorageUnavailable": "Watch konnte diesen Lebensraum nicht wiederherstellen oder speichern. Vorhandene Dateien wurden beibehalten. Mit {command} kannst du diesen Lauf exportieren.",
"PetWatchExported": "Watch-Aufzeichnung gespeichert: {path}",
"PetWatchExportFailed": "Die Watch-Aufzeichnung konnte nicht gespeichert werden. Sie bleibt im Arbeitsspeicher.",
"PetWatchExportQueued": "Watch-Aufzeichnung wird gespeichert…",
"PetWatchExportUnavailable": "Öffne /pet in einer gespeicherten Sitzung oder warte auf den laufenden Export.",
"PetUnobserved": "unbeobachtet",
"PetOffline": "offline — codewhale pet serve weckt ihn",
"PetDozing": "dösend",
"PetWatchUnavailable": "Die Haustier-Telemetrie pausiert. /pet on versucht es erneut.",
"ConversationChangedBeforeUndo": "Die Unterhaltung wurde geändert, bevor das Rückgängigmachen abgeschlossen war. Es wurde nichts rückgängig gemacht und kein erneuter Versuch gesendet. Prüfe die aktuelle Unterhaltung, bevor du es erneut versuchst.",
"SessionArchiveExported": "Sitzung exportiert",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Bearbeiten",
"ExtensionsHooksAddLabel": "Hook hinzufügen",
"ExtensionsHooksAddDescription": "Die Hook-Datei dieses Projekts im Editor öffnen",
"ExtensionsActionReload": "neu laden",
"ExtensionsActionConnect": "verbinden",
"ExtensionsActionReconnect": "neu verbinden",
"ExtensionsActionReauth": "neu anmelden",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "verbunden",
"ExtensionsStateEnabled": "aktiviert",
"ExtensionsStateError": "Fehler",
"ExtensionsStateInactive": "inaktiv",
"ExtensionsStateInapplicable": "nicht anwendbar",
"ExtensionsStateInvalid": "ungültig",
"ExtensionsStateNotInspected": "nicht geprüft",
"ExtensionsStateDisconnected": "getrennt",
"ExtensionsStateRejected": "abgelehnt",
"ExtensionsStateReviewedCandidate": "geprüfter Kandidat",
"ExtensionsStateUnderEvaluation": "wird geprüft",
"ExtensionsStateUnstaged": "nicht bereitgestellt",
"ExtensionsStateUnsupported": "nicht unterstützt",
"ExtensionsStateWarning": "Warnung",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ in diesen Zug senden",
"ComposerHintLongDraft": "{shortcut}: externer Editor",
"PendingSendingIntoTurnPrefix": " ↳ Wird in diesen Zug gesendet: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Konnte nicht in diesen Zug: ",
"PendingEditingFollowUpPrefix": " ↳ Folgebeitrag wird bearbeitet: ",
"PendingQueuedOnePrefix": "Warteschlange #1: ",
"PendingQueuedManyPrefix": "Warteschlange {count} · als Nächstes: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Nachgedacht",
"TranscriptThoughtFor": "{duration} nachgedacht",
"TelemetryNoticeDefaultOn": "Nutzungsstatistiken sind standardmäßig aktiviert. Aggregierte Versions-, Plattform-, Sitzungs-, Funktions- und Fehlerzahlen mit Codewhale und dem Auftragsverarbeiter PostHog teilen. Zählt außerdem Anbieter, öffentliche Katalogmodelle, Token-Summen und die Nutzung eingebauter Werkzeuge. Keine Inhalte oder IPs. docs/TELEMETRY.md Ausschalten: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale-Nutzungsstatistiken",
"TelemetryNoticeBody": "Codewhale zählt: die ausgeführte Version, Betriebssystem und Prozessorfamilie,\nSitzungsdauer und -ergebnis sowie zusammengefasste Funktions- und\nFehlerzähler.\n\nAußerdem zählt es die Anbieter und öffentlichen Katalogmodelle, die du nutzt, ihre Token-Summen und wie oft jedes eingebaute Werkzeug läuft.\n\nEs erfasst nie Unterhaltungen, Code, Prompts, Dateien, Datei-, Repository-\noder Branch-Namen, Modellinhalte oder Zugangsdaten — und sendet nie eine\nAktivitätschronik des Agenten pro Runde oder Werkzeug.\n\nZur Identifikation dient nur eine zufällige, auf diesem Gerät gespeicherte\nKennung, die alle 90 Tage ersetzt wird. Sie können Ihre Meinung jederzeit\nändern:\n codewhale config set telemetry false\n\nVollständiges Schema, Feld für Feld: docs/TELEMETRY.md\n\nNutzungsstatistiken sind standardmäßig aktiviert. Codewhale und PostHog verarbeiten diese Zahlen, wenn die Übermittlung konfiguriert ist. IPs werden nicht erfasst.",
"TelemetryNoticeCompactBody": "Zählt: Version, OS/CPU, Dauer/Ergebnis, Funktionen/Fehler.\nAußerdem: Anbieter/Modell, Token, Werkzeuge.\nLokale Zufalls-ID wechselt/90T.\nNie: Chat/Code/Prompts/Dateien/Namen; Modellinhalt/Zugangsdaten; Runden/Werkzeuge.\nSchema: docs/TELEMETRY.md\nAus: codewhale config set telemetry false\nNutzungsstatistiken sind standardmäßig aktiviert. Codewhale und PostHog verarbeiten diese Zahlen, wenn die Übermittlung konfiguriert ist. IPs werden nicht erfasst.",
"TelemetryNoticeChoiceKeep": "Ja, anonyme Zählung beibehalten",
"TelemetryNoticeChoiceDisable": "Nein, Nachverfolgung abschalten",
"TelemetryNoticeActionChoose": "wählen",
"TelemetryNoticeActionConfirm": "bestätigen",
"TelemetryNoticeActionExit": "beenden",
"TelemetryNoticeReceiptEnabled": "Anonyme Nutzungszählungen sind aktiviert. Unterhaltungen und Code werden nie erfasst. Ändern unter /settings; Schema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Die anonyme Nutzungszählung ist ausgeschaltet. Sie werden nicht erneut gefragt.",
"TelemetryNoticeReceiptEnabledUnsaved": "Anonyme Nutzungszählungen sind für diese Sitzung aktiviert. Codewhale konnte diesen Hinweis nicht speichern und zeigt ihn erneut. Ändern unter /settings; Schema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Die anonyme Nutzungszählung ist für diese Sitzung ausgeschaltet. Codewhale konnte die Auswahl nicht speichern und fragt beim nächsten Start erneut.",
"TelemetryPreferenceEnabledNextLaunch": "Anonyme Nutzungszählungen sind ab dem nächsten Start aktiviert. Unterhaltungen und Code werden nie erfasst.",
"TelemetryPreferenceDisabled": "Anonyme Nutzungszählungen sind deaktiviert. Lokale Telemetriedaten wurden gelöscht.",
"TelemetryPreferenceDisabledWithWarning": "Anonyme Nutzungszählungen sind deaktiviert, aber ein Teil der Bereinigung benötigt Aufmerksamkeit: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Keine Hotbar-Aktionen verfügbar.",
"HotbarSetupRecommended": "emp",
"HotbarSetupEmptySlot": "leer",
"HotbarSetupHelp": "Tab/Shift+Tab Quelle Up/Down Aktion 1-8 Slot Enter zuweisen Space umschalten Delete löschen s speichern Esc abbrechen",
"HotbarActionVoiceToggleName": "Spracheingabe",
"HotbarActionVoiceToggleDescription": "Sprachaufnahme über das Terminal-Mikrofon umschalten.",
"HotbarActionSessionCompactName": "Sitzung komprimieren",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Work-Modus",
"HotbarActionModeAgentDescription": "Direkt in der aktuellen Sitzung arbeiten.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Kompatibilität: Work mit Full-Access-Berechtigungen (kein eigener Modus).",
"HotbarActionReasoningCycleName": "Reasoning-Stufe wechseln",
"HotbarActionReasoningCycleDescription": "Konfigurierte Reasoning-Stufe des aktiven Providers durchwechseln.",
"HotbarActionReasoningCycleAutoDisabled": "Reasoning-Stufe wird vom automatischen Modell-Routing gesteuert.",
"HotbarActionSidebarToggleName": "Seitenleiste umschalten",
"HotbarActionSidebarToggleDescription": "Seitenleiste ein- oder ausblenden.",
"HotbarActionFileTreeToggleName": "Dateibaum umschalten",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Keine Einstellungen verfügbar.",
"ConfigNoMatchesPrefix": " Keine Einstellungen passen zu ",
"ConfigFilteredSettings": " Gefilterte Einstellungen",
"ConfigShowing": " Angezeigt",
"ConfigFooterDefault": " Tippen=Filtern, Up/Down=Auswählen, Enter=Bearbeiten, Esc=Schließen ",
"ConfigFooterScrollable": " Tippen=Filtern, Up/Down=Auswählen, Enter=Bearbeiten, PgUp/PgDn=Scrollen, Esc=Schließen ",
"ConfigFooterFiltered": " Tippen=Filtern, Backspace=Löschen, Ctrl+U/Esc=Leeren, Enter=Bearbeiten ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; Geistertext-Hinweise gelten nach folgenden Durchläufen)",
"ConfigNotificationsSetHint": "Mit /config notifications <key> <value> [--save] festlegen.",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; gilt für folgende Benachrichtigungen)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs muss eine ganze Zahl sein",
"ConfigAuditSearchProvider": "Schreibt [search] provider; folgende web_search-Aufrufe beachten weiterhin Umgebungsüberschreibungen.",
"ConfigAuditPromptSuggestion": "Schreibt prompt_suggestion auf oberster Ebene; Geistertext-Hinweise bleiben optional.",
"ConfigAuditNotifications": "Schreibt skalare [notifications]-Werte und wendet sie auf folgende Abschlussbenachrichtigungen an.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "Provider-API-URL",
"ConfigHintProviderUrl": "Aktueller Provider-Endpunkt; Xiaomi: Token-Paket | nutzungsbasierte Abrechnung | benutzerdefinierte URL",
"ConfigLabelModel": "Aktives Provider-Modell",
"ConfigLabelFastModel": "Schnelles Modell (abgeleitet)",
"ConfigLabelDefaultModel": "Legacy-Fallback-Modell (nur DeepSeek-Routen)",
"ConfigLabelReasoningEffort": "Reasoning-Stufe",
"ConfigLabelApprovalMode": "Berechtigung dieser Sitzung",
"ConfigLabelPermissionPosture": "Berechtigung neuer Sitzungen",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Aggregierte Versions-, Sitzungs-, Funktions- und Fehlerzahlen an Codewhale und PostHog; nie Inhalte oder IPs. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "An",
"ConfigValueTelemetryOff": "Aus",
"ConfigLabelStreamTimeout": "Stream-Timeout",
"ConfigLabelTheme": "Theme",
"ConfigLabelLocale": "Sprache",
"ConfigLabelBackground": "Hintergrund",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Reasoning-Hintergrund hervorheben",
"ConfigLabelShowToolDetails": "Tool-Detailgrad",
"ConfigLabelInlineDiffs": "Inline-Dateiänderungen",
"ConfigLabelStatusIndicator": "Statusanzeige",
"ConfigLabelSynchronizedOutput": "Ausgabetempo",
"ConfigLabelCostCurrency": "Kostenwährung",
"ConfigLabelTranscriptSpacing": "Transkript-Zeilenabstand",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "Composer-Dichte",
"ConfigLabelComposerBorder": "Composer-Rahmen",
"ConfigLabelComposerMultilineMode": "Composer-Mehrzeilenmodus",
"ConfigLabelComposerVimMode": "Composer-Vim-Modus",
"ConfigLabelBracketedPaste": "Bracketed Paste",
"ConfigLabelPasteBurstDetection": "Paste-Erkennung",
"ConfigLabelMentionMenuLimit": "Mention-Menü-Limit",
"ConfigLabelMentionMenuBehavior": "Mention-Menü-Verhalten",
"ConfigLabelMentionWalkDepth": "Datei-Mention-Tiefe",
"ConfigLabelWorkspaceFollowSymlinks": "Symlinks folgen",
"ConfigLabelContextPanel": "Kontext-Panel",
"ConfigLabelAutoCompact": "Auto-Komprimierung",
"ConfigLabelAutoCompactThreshold": "Komprimierungs-Schwelle",
"ConfigLabelMaxHistory": "Eingabeverlauf",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "Goal-Befehl",
"ConfigLabelWorkflow": "Workflow",
"ConfigLabelFeaturePrefix": "Feature: {name}",
"ConfigColumnSetting": "Einstellung",
"ConfigColumnValue": "Wert",
"ConfigColumnScope": "Bereich",
"ConfigActionOpenProvider": "Enter öffnet Provider-Auswahl",
"ConfigActionOpenModel": "Enter öffnet Modellauswahl",
"ConfigActionOpenMcp": "Enter öffnet den MCP-Manager",
@@ -415,6 +456,7 @@
"HelpKeybindings": "Tastenkürzel",
"HelpUserCommands": "Benutzerbefehle",
"HelpSkills": "Skills",
"HelpFooterTypeFilter": " tippen zum Filtern ",
"HelpFooterMove": " Up/Down bewegen ",
"HelpFooterJump": " PgUp/PgDn springen ",
"HelpFooterClose": " Esc schließen ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "Vorgeschlagenes Plugin: {name}",
"PluginCtaReview": "Prüfen",
"PluginCtaInstall": "Installieren",
"PluginCtaReviewTrust": "Vertrauen prüfen",
"PluginCtaEnable": "Aktivieren",
"PluginCtaDismiss": "Nicht mehr vorschlagen",
"PluginCtaDismissSaveFailed": "Für diese Sitzung ausgeblendet; die Plugin-Einstellung konnte nicht gespeichert werden.",
"PluginSuggestionReason": "Treffer für „{trigger}“",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "Plugin-Aktion fehlgeschlagen: {error}",
"CmdPluginNoneFound": "Keine ausführbaren Legacy-Plugin-Tools in {dir} gefunden",
"CmdPluginNotFound": "Plugin '{name}' nicht gefunden",
"CmdPluginListHeader": "Ausführbare Legacy-Plugin-Tools ({count}):",
"CmdPluginDetailDescription": "Beschreibung: {description}",
"CmdPluginDetailSchema": "Schema:\n{schema}",
"CmdPluginDetailApproval": "Freigabe: {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "Zwischengespeicherter Katalog; mit `codewhale models --update` die eingerichteten Anbieter aktualisieren.",
"ModelsUpdateSummary": "Modellkataloge: {updated} aktualisiert, {loaded} aus Codex geladen, {failed} fehlgeschlagen, {skipped} übersprungen.",
"ModelsUpdatePartial": "Einige Kataloge konnten nicht aktualisiert werden. Bisherige und konfigurierte Modelle bleiben verfügbar.",
"ModelsCodexHint": "ChatGPT-Modelle werden über Codex geladen. Der Abfragezeitpunkt bestätigt keine Aktualisierung des Anbieterkatalogs.",
"ModelsSourceFallback": "Mitgelieferte oder konfigurierte Modelle; Verfügbarkeit nicht geprüft.",
"CmdModelDbDescription": "Mitgelieferte Modelldatenbank durchsuchen",
"CmdNetworkDescription": "Netzwerk-Allow- und Deny-Regeln verwalten",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "Nachrichten in der Warteschlange ansehen oder bearbeiten",
"CmdQueueUsage": "Verwendung: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "{count} Nachricht(en) aus einer früheren Sitzung wiederhergestellt. Sie werden nicht automatisch gesendet: /queue send <n> sendet eine, /queue clear verwirft sie.",
"CmdQueueDraftHeader": "Nachricht aus der Warteschlange bearbeiten:",
"CmdQueueNoMessages": "Keine Nachrichten in der Warteschlange",
"CmdQueueListHeader": "Nachrichten in der Warteschlange ({count}):",
"CmdQueueTip": "Tipp: /queue send <n> sendet sofort, /queue drop <n> entfernt",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} Treffer / {miss} Miss",
"CmdTokensCacheHitOnly": "{hit} Treffer / Miss nicht gemeldet",
"CmdTokensCacheMissOnly": "Treffer nicht gemeldet / {miss} Miss",
"CmdTokensContextUnknownWindow": "~{estimated} / Fenster unbekannt",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 Agent",
"FooterAgentsPlural": "{count} Agenten",
"HeaderAgentsChip": "Agenten {count}",
"FooterPressCtrlCAgain": "Erneut Ctrl+C drücken zum Beenden",
"FooterWorking": "arbeitet",
"FooterBalancePrefix": "Guthaben",
"HelpSectionActions": "Aktionen",
"HelpSectionClipboard": "Zwischenablage",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "nicht gemeldet",
"CmdTokensReport": "Token-Verbrauch:\n ─────────────────────────────\n Aktiver Kontext: {active}\n Letzte API-Eingabe: {input} (Zug-Telemetrie; kann wiederholten Präfix über Tool-Runden zählen)\n Letzte API-Ausgabe: {output}\n Cache Treffer/Miss: {cache} (nur Telemetrie/Kosten)\n Kumulierte Tokens: {total} (Sitzungs-Nutzungstelemetrie)\n Geschätzte Kosten: {cost}\n API-Nachrichten: {api_messages}\n Chat-Nachrichten: {chat_messages}\n Modell: {model}",
"KbScrollTranscript": "Transkript scrollen, Eingabeverlauf navigieren oder Composer-Anhänge auswählen",
"KbNavigateHistory": "Eingabeverlauf navigieren",
"KbBrowseHistory": "Gesprächsverlauf durchsuchen",
"KbScrollTranscriptAlt": "Transkript scrollen",
"KbScrollPage": "Transkript seitenweise scrollen",
@@ -807,6 +858,7 @@
"KbCompactContext": "Konversationskontext komprimieren",
"KbLastMessagePager": "Pager für die letzte Nachricht öffnen (bei leerer Eingabe)",
"KbSelectedDetails": "Rohdetails zum ausgewählten Tool oder zur Nachricht anzeigen; Ctrl+Alt+O öffnet die Gesamtübersicht des Zugs",
"KbToolDetailsPager": "Rohdetails zum ausgewählten Element anzeigen (Alt+V)",
"KbExternalEditor": "Composer-Entwurf in externem Editor öffnen",
"KbLiveTranscript": "Live-Transkript-Overlay öffnen (Ctrl+Shift+T; Sticky-Tail-Auto-Scroll)",
"KbBacktrackMessage": "Zu einer früheren Benutzernachricht zurückspringen (Links/Rechts schrittweise, Enter zum Zurückspulen)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "Dieses Hilfe-Overlay öffnen (bei leerer Eingabe)",
"KbCycleWorkDock": "Durch die Arbeitsleiste blättern (Todo, Agenten, Jobs, Hintergrund), im Haustiermodus durch die Haustier-Ansichten",
"KbCycleWorkDockBack": "Rückwärts durch die Arbeitsleiste oder die Haustier-Ansichten blättern",
"KbToggleHelp": "Hilfe-Overlay umschalten",
"KbToggleHelpSlash": "Hilfe-Overlay umschalten",
"HelpUsageLabel": "Verwendung:",
"HelpAliasesLabel": "Aliase:",
"SettingsTitle": "Einstellungen:",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan, um zuerst zu recherchieren und einen Plan vorzulegen",
"HomeAgentModeYoloTip": " Shift+Tab wechselt Berechtigung: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — Tools laufen ohne Freigabeaufforderungen",
"HomeYoloModeCaution": " Destruktive Operationen können sofort laufen; im Zweifel Ask bevorzugen",
"HomePlanModeTip": "Plan — recherchieren und entwerfen vor dem Implementieren",
"HomePlanModeChecklistTip": " Plan und To-do-Fortschritt vorlegen, dann zu Work wechseln",
"HomeGoalModeTip": "Zielverfolgung – /goal <objective> setzen, um Ziele zu verfolgen",
"OnboardLanguageTitle": "Sprache wählen",
"OnboardLanguageBlurb": "Wähle die UI-Sprache. Du kannst sie jederzeit mit `/config locale <tag> --save` ändern.",
"OnboardProviderTitle": "Modellprovider wählen",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "„Beibehalten“ lässt die Schwärzung für diesen Start aktiv; da Ihre Konfiguration weiterhin \"disabled\" verlangt, fragt der nächste Start erneut.",
"RedactionGateSaveFailed": "Die Bestätigung konnte nicht gespeichert werden. Die Maskierung bleibt aktiv. Erneut versuchen oder aktiviert lassen.",
"RedactionGateTitle": "Schlüssel-Schwärzung an der Modellgrenze",
"OnboardOfflineOption": "Ctrl+O — offline erkunden: jetzt umsehen, später einen Provider verbinden.",
"OnboardOfflineNotice": "Du erkundest offline. Noch ist nichts verbunden — führe /provider aus, wenn du verbinden willst.",
"OnboardWelcomeTitle": "Codewhale arbeitet mit dir in diesem Ordner.",
"OnboardWelcomeLead": "Machen wir dich startklar.",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "Erkläre, was dieses Projekt tut, und liste die Haupteinstiegspunkte auf.",
"OnboardSeedFolder": "Sieh dir diesen Ordner an und schlage eine gute erste Aufgabe vor.",
"SetupWizardTitle": "Setup",
"SetupWizardWhy": "Diese Shell speichert den Setup-Fortschritt in setup_state.json; Konfigänderungen werden nur durch explizite Schrittaktionen angewendet.",
"SetupWizardProgress": "Schritt",
"SetupActionBack": "zurück",
"SetupActionContinue": "weiter",
"SetupActionSkip": "überspringen",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "Inhalt scrollen",
"SetupActionGuided": "Vorschau/ratifizieren",
"SetupActionTuneGuided": "anpassen",
"SetupActionModelDraft": "Modellentwurf",
"SetupActionFreeform": "eigene Worte",
"SetupActionKeepExisting": "bestehende behalten",
"SetupActionUseRecommended": "Empfehlung verwenden",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "Modellrouten",
"SetupActionFleet": "Fleet-Setup",
"SetupActionHotbar": "Hotbar-Setup",
"SetupActionRemote": "Remote-Einstieg",
"SetupActionMode": "Modusauswahl",
"SetupActionConfig": "Konfigansicht",
"SetupActionRuntimePreset": "Preset",
"SetupActionApplyRuntimePreset": "Vorschau/anwenden",
"SetupActionUseBundled": "mitgelieferte nutzen",
"SetupActionDefer": "vertagen",
"SetupActionCancel": "abbrechen",
"SetupStatusNotStarted": "nicht gestartet",
"SetupStatusRecommended": "empfohlen",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "Setup-Sprache gespeichert.",
"SetupConstitutionChoiceLabel": "Auswahl:",
"SetupConstitutionSourceLabel": "Quelle:",
"SetupConstitutionValidityLabel": "Gültigkeit:",
"SetupConstitutionPreviewLabel": "Vorschau-Hash:",
"SetupConstitutionExistingLabel": "Bestehende Datei:",
"SetupConstitutionExpertOverrideLabel": "Experten-Override:",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "Plugins:",
"SetupToolsMcpReviewHint": "Enter speichert diesen Setup-Snapshot. R für sichere Einstiege (kein Auto-Run) drücken.",
"SetupToolsMcpReviewed": "Tools-/MCP-Bereitschaft gespeichert.",
"SetupRemoteCloudsLabel": "Cloud-Ziele:",
"SetupRemoteBridgesLabel": "Chat-Bridges:",
"SetupRemoteProvidersLabel": "Provider:",
"SetupRemoteModeLabel": "Remote-Modus:",
"SetupRemoteModeLocalOnly": "Nur dieser Rechner:",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "Nachricht kopieren",
"CtxMenuCopyMessageDesc": "angeklickte Transkriptzelle kopieren",
"CtxMenuOpenInEditor": "Im Editor öffnen",
"CtxMenuOpenInEditorDesc": "Datei:Zeile in $EDITOR öffnen",
"CtxMenuShowCell": "Zelle einblenden",
"CtxMenuShowCellDesc": "diese Transkriptzelle einblenden",
"CtxMenuHideCell": "Zelle ausblenden",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} fertig · {running} läuft · {failed} fehlgeschlagen · {pending} ausstehend",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (veralteter Modusname)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Direktes Arbeiten in dieser Sitzung — Edits und Shell fragen nach Freigabe",
"AppModeAutoHint": "Shell aktiv mit automatischer Risikoprüfung",
"AppModePlanHint": "Read-only-Recherche zuerst — Plan vorlegen, bevor gehandelt wird",
"AppModeYoloHint": "Nur Kompatibilität — Work + Full Access, kein sichtbarer Modus",
"AppModeOperateHint": "Work auf Volllast: Ziel, parallele Worker, geprüft",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERT --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Nur lesen",
"ApprovalEffectChangesFiles": "Ändert Dateien",
"ApprovalRiskDestructive": "Nicht rückgängig zu machen",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s jetzt erlauben und künftig immer vorher fragen",
"ApprovalOptionDeny": "Nicht erlauben",
"ApprovalOptionAbortTurn": "Diese Runde stoppen",
"ApprovalBlockTitle": "Freigabe",
"ApprovalControlsHint": "Pg↑/↓ prüfen · {details} weitere Optionen · Esc stoppen",
"ApprovalOwnerHeader": "Agent: {agent} · {role}",
"ApprovalGoToAgent": "g zum Agenten",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … gekürzt · {details} für volle Details",
"ApprovalAsksWithoutGit": "Hier gibt es kein Git-Repository, daher wird vor Änderungen gefragt.",
"ApprovalFullAccessPolicyBlocked": "{tool} blockiert: Full Access kann diese Policy nicht umgehen",
"ApprovalChooseHint": "Wahl: ",
"ApprovalChooseAction": "Enter wählt die Option, oder direkt y/a/d drücken",
"ApprovalIntentLabel": "Absicht: ",
"ApprovalMoreLines": " … (+{count} Zeilen)",
"ApprovalProceedQuestion": "Möchten Sie fortfahren?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "Kontext wird komprimiert…",
"ContextCompactionQueued": "Die Kontextkomprimierung wurde eingereiht; sie wird nach dem aktiven Zug ausgeführt.",
"ContextCompactionAlreadyRunning": "Die Kontextkomprimierung läuft bereits.",
"ContextCompactionQueueFull": "Die Kontextkomprimierung konnte nicht eingereiht werden, weil die Engine ausgelastet ist; versuche es nach Abschluss des Zugs erneut.",
"ContextCompactionQueueClosed": "Die Kontextkomprimierung ist nicht verfügbar, weil die Engine nicht mehr läuft.",
"ContextCompactionRouteInvalid": "Die Komprimierung ist nicht möglich, weil die aktive Provider-Route ungültig ist: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Kontextkomprimierung gestoppt; die Unterhaltung wurde nicht geändert",
"ContextPurgeAbandonedOnEngineSwitch": "Die Sitzungsbereinigung wurde mit der ersetzten Engine abgebrochen; die Unterhaltung wurde nicht geändert",
"CtxInspTitle": "Kontext-Inspektor",
"CtxInspSessionContext": "Sitzungskontext",
"CtxInspSystemPrompt": "System-Prompt-Struktur",
"CtxInspReferences": "Referenzen",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — Sichere Einstiege\n\n/setup liest nur das lokale Inventar. Es startet nie MCP-Server, installiert keine Skills, führt keine Plugins aus und führt keine unvertrauenswürdigen Befehle aus.\n\nAktuelles Inventar:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools-Verzeichnis: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (geteilte Adapter): {hotbar_result}\n\nPfade (Home geschwärzt):\n- MCP-Config: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nSicherer Bootstrap (selbst in einem normalen Terminal oder TUI-Befehl ausführen):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install <spec>\n- Plugins: /plugin · codewhale setup --plugins\n- Tools-Verzeichnis: codewhale setup --tools\n\nAktionen mit Nebenwirkungen erfordern immer eine explizite Bestätigung. Plugin-Befehle bleiben von Slash-Befehlen getrennt; die Hotbar-Plugin-Quelle bleibt zurückgestellt, bis Freigabe-Gates landen.\n\nSiehe docs/MCP.md und docs/skills/README.md für alles, was weiterhin manuelle externe Einrichtung braucht.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — über Codewhale verbunden, nie ein zweiter Scheduler:\n- Zustand: {dsh_result}\n- Nur-Lese-Erkennung; verbinden/planen/starten/entfernen: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale schreibt nur nach $CODEWHALE_HOME/integrations/dsh; es kopiert nie API-Schlüssel und ändert keine DSH-Dateien.",
"HotbarActionModeOperateName": "Operate-Modus",
"HotbarActionModeOperateDescription": "Eine dauerhafte Anfrage parallel bearbeiten, bis sie verifiziert ist.",
"HomeOperateModeTip": "Operate — Ihren Fleet parallel arbeiten lassen",
"HomeOperateModeFleetTip": " Eingebaute Rollen nutzen das Modell dieser Sitzung; /fleet setup passt sie an",
"HelpSubtitle": "Befehle, Skills und Tastenkürzel",
"CommandPaletteTitle": "Befehl",
"CommandPaletteSubtitle": "Eine Aktion finden und ausführen",
"ConfigSubtitle": "Einstellungen zuerst; Rohschlüssel im erweiterten Detail",
"LaunchStartTitle": "Hier starten",
"LaunchResumeConfirm": "{title} fortsetzen? Erneut klicken oder Enter drücken zum Bestätigen.",
"LaunchResumeConfirmTitle": "Sitzung fortsetzen",
"LaunchResumeConfirmBody": "Das ersetzt den aktuellen Kontext durch den Verlauf jener Sitzung.",
"LaunchResumeConfirmResume": "fortsetzen",
"LaunchResumeConfirmCancel": "abbrechen",
"LaunchWorkDescription": "Diesen Ordner mit lokalen Werkzeugen verwenden; Änderungen folgen der Genehmigungsrichtlinie.",
"LaunchChatDescription": "Nur Unterhaltung und Planung; keine Dateiänderungen.",
"LaunchWorkspaceGitReady": "Arbeitsbereich · {name} · Git-Arbeitsbereich",
"LaunchWorkspaceFolderReady": "Arbeitsbereich · {name} · lokaler Ordner",
"LaunchProviderConfigured": "Anbieter · konfiguriert",
"LaunchProviderSetupNeeded": "Anbieter · Einrichtung erforderlich",
"LaunchGroupContinue": "Weiter",
"LaunchGroupMore": "Mehr",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "Ordner",
"LaunchProviderConfiguredShort": "Anbieter eingerichtet",
"LaunchProviderSetupShort": "Anbieter einrichten",
"LaunchMenuChangelog": "Changelog",
"LaunchWorktreePrompt": "Branch/Worktree benennen oder Enter für einen automatischen Namen. Esc zurück.",
"LaunchWorktreeNeedsGit": "Neuer Worktree erfordert ein Git-Repository.",
"LaunchWorktreeNameLabel": "Worktree-Name",
"LaunchHintMove": "bewegen",
"LaunchHintOpen": "öffnen",
"LaunchTipFlags": "Tipp: -w <path> öffnet einen Workspace; -r <session-id> setzt direkt fort",
"LaunchSavedSessionSingular": "1 gespeicherte Sitzung",
"LaunchSavedSessionsPlural": "{count} gespeicherte Sitzungen",
"LaunchCreatingWorktree": "Worktree wird erstellt…",
"LaunchWorktreeFailed": "Worktree fehlgeschlagen: {error}",
"LaunchWorktreeCreated": "Neuer Worktree {path} auf Branch {branch}",
"LaunchNoSavedSessions": "Keine gespeicherten Sitzungen für diesen Workspace.",
"LaunchNoModelConnected": "kein Modell verbunden",
"DispatchNotSentNoModel": "Es ist kein Modell verbunden, daher wurde diese Nachricht nicht gesendet. Sie steht wieder im Eingabefeld: Verbinden Sie ein Modell mit F3 oder /provider und drücken Sie dann Enter, um sie zu senden.",
"DispatchNotSentSaveKey": "Schlüssel speichern: {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "Verwendet wird {model}, ein Modell auf diesem Computer (Ollama). Mit F3 ein anderes wählen.",
"ProviderPickerNotReopened": "Die Anbieterliste konnte nicht erneut geöffnet werden. Mit F3 öffnen.",
"LaunchRunCommand": "{command} ausführen",
"LaunchMcpConnectedOne": "1 MCP-Server verbunden",
"LaunchMcpConnectedMany": "{count} MCP-Server verbunden",
"LaunchMcpNeedsSignInOne": "1 braucht Anmeldung",
"LaunchMcpNeedsSignInMany": "{count} brauchen Anmeldung",
"PhaseIdle": "ruhend",
"PhaseDraft": "entwurf",
"PhaseWorking": "arbeitet",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "schließt ab",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "nur lesen",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "nie",
"PermissionsChangedReceipt": "Berechtigungen geändert auf {label}",
"FooterHintKeys": "Tasten",
"FooterHintOutput": "Ausgabe",
"FooterHintContext": "Kontext",
"InfoLineHelp": "Hilfe",
"InfoLineContext": "Kontext",
"InfoLineTtft": "ttft",
"InfoLinePeak": "Spitzenzeit",
"InfoLineOffPeak": "Nebenzeit",
"InfoLineWhales": "Wale",
"InfoLineAutomation": "Automatisierung",
"InfoLineNotConnected": "nicht verbunden",
"InfoLineThinking": "Denken: {level}",
"EmptyStateNoGit": "kein git",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "beliebiges Modell suchen",
"RoutePanelHeader": "Route",
"RouteProviderLabel": "Provider",
"RouteModelFirstAtomic": "atomare Model-first-Route",
"PickerActionMove": "bewegen",
"PickerActionSwitch": "wechseln",
"PickerActionApply": "anwenden",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "Suche leeren",
"PickerActionBrowseAll": "alle durchsuchen",
"PickerActionCustom": "benutzerdefiniert",
"PickerActionJump": "springen",
"PickerActionEditKey": "Schlüssel bearbeiten",
"PickerActionModels": "Modelle",
"PickerActionUnavailable": "nicht verfügbar",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "diese Anmeldung nicht mehr nutzen",
"ProviderExternalActionChoices": "über andere App anmelden",
"ProviderExternalActionReuseGrok": "externe Grok-Wiederverwendung",
"ProviderExternalHintCodexReview": "Nach {login} Enter drücken, um Optionen für deaktivierten/Read-only/verwalteten Zugriff zu prüfen.",
"ProviderExternalHintXaiReview": "Enter für Codewhale-eigenes Device-Login; E drücken, um bestehende Grok-CLI-Wiederverwendung zu prüfen.",
"ProviderExternalHintXaiApiKey": "Oder XAI_API_KEY nutzen und diesen Picker erneut öffnen.",
"XaiAuthChoiceTitle": " xAI-Authentifizierung ",
"XaiAuthChoiceIntro": "Wählen Sie genau eine Anmeldedatenquelle. Schlüsseltext wird nie als OAuth-Token behandelt.",
"XaiAuthChoiceApiKeyOption": "xAI-API-Schlüssel — eingeben oder einfügen und im xAI-Anbieterplatz speichern",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT-/Codex-Authentifizierung ",
"ChatgptAuthChoiceIntro": "Die Abo-Anmeldung wird über deinen ChatGPT-Plan abgerechnet. Die openai-API-Schlüsselroute hat einen anderen Rechnungseigner.",
"ChatgptAuthChoicePkceOption": "Mit ChatGPT anmelden — Browser-PKCE, Codewhale-eigene Tokens, ChatGPT-Abo-Abrechnung",
"ChatgptAuthChoiceImportOption": "Codex-CLI-Anmeldedaten importieren — ausdrückliche Nur-Lese-Zustimmung; die Codex-CLI bleibt Eigentümerin",
"ProviderExternalHintChatgptReview": "Enter zum Anmelden mit ChatGPT; E, um die vorhandene Codex-CLI-Wiederverwendung zu prüfen.",
"ProviderExternalActionReuseCodex": "externe Codex-Wiederverwendung",
"ProviderExternalDetailScope": "Extern: Zugriff={access} | Provider={provider} | Quelle={source} | Version={version} | {state}",
"ProviderExternalDormant": "ruhend",
"ProviderExternalOwnerPath": "Eigentümer/Pfad: {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "Snapshots und /undo sind für {workspace} aus: ein Home- oder Wurzelverzeichnis ist zu weit gefasst für einen sicheren Snapshot. Starte in einem Projektverzeichnis, um sie einzuschalten.",
"SnapshotsHistoryRepaired": "Der Undo-Verlauf für {workspace} war beschädigt (der letzte Wiederherstellungspunkt fehlte) und wurde neu gestartet. Frühere Wiederherstellungspunkte lassen sich nicht mehr wiederherstellen; neue Züge sind wieder geschützt.",
"SnapshotsFailing": "Snapshots für {workspace} schlagen fehl, daher kann /undo die letzten Züge nicht wiederherstellen: {limit}",
"SessionIdDivergedNotice": "Die Sitzungsidentität unter diesem Fenster hat sich geändert: Die Engine speichert Checkpoints jetzt als {next} (vorher {previous}). Frühere Checkpoints bleiben unter der alten ID; `codewhale sessions` listet beide und `codewhale resume {previous}` öffnet die frühere wieder.",
"RuntimeStoreUnreadableNotice": "Laufzeitspeicher der Sitzung: {record} unter {path} konnte nicht gelesen werden ({reason}). Verschiebe diese Datei beiseite (oder lösche sie) und versuche es erneut; die übrigen Datensätze des Threads bleiben erhalten.",
"RuntimeStoreUnwritableNotice": "Laufzeitspeicher der Sitzung: {record} unter {path} konnte nicht geschrieben werden ({reason}). Prüfe dort freien Speicherplatz und Berechtigungen und versuche es erneut; nichts wurde überschrieben.",
"ProviderExternalSemanticsRevoke": "{semantics} | Widerruf: {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "Setup",
"FleetRosterWorkers": "Worker",
"FleetRosterMembersCount": "{count} Mitglieder",
"FleetRosterOperatorFirst": "Der Koordinator führt · das Sitzungsmodell treibt diesen Fleet an",
"FleetRosterOperatorRow": "Koordinator · Leitung",
"FleetRosterShadowBadgeProjectOverride": "in diesem Projekt gespeichert",
"FleetRosterShadowBadgePersonalIgnored": "gespeicherte Kopie ignoriert",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "das ist dein aktuelles Modell (die Operator-Route des Teams); wechsle das Modell oder ändere sie mit /fleet save",
"FleetModelReasonAlreadyPresent": "bereits im Team",
"FleetModelErrorNeedsRoute": "ein Team-Modell braucht sowohl eine Provider-ID als auch eine Modell-ID",
"FleetModelErrorNeedsRole": "Ein Agent benötigt einen Rollennamen (zum Beispiel `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "kein Team ausgewählt; dein Team ist nur das Sitzungsmodell",
"FleetModelErrorOperatorRoute": "{route} ist die Operator-Route des Teams `{fleet}`; ändere sie mit /fleet save, nicht mit remove",
"FleetModelErrorNotInFleet": "{route} ist nicht im Team `{fleet}`",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ anhängen · 1 Treffer",
"FilePickerMatchesPlural": "@ anhängen · {count} Treffer",
"FilePickerScanning": "Workspace wird gescannt…",
"BehavioralTipPlanning": "Planung? {key} wechselt in den Plan-Modus",
"BehavioralTipBackgroundReceipt": "Belege liegen im Work-Panel — {key} öffnet den Inspektor",
"BehavioralTipClearedInput": "Geleert · {chord} stellt wieder her",
"BehavioralTipMcpValidation": "{command} startet Server und zeigt warum",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "Modell und Thinking",
"SettingSubjectProvider": "Provider",
"SettingSubjectPermissions": "Berechtigungen",
"ThinkingControlledByAutoRouting": "Thinking wird durch automatisches Modell-Routing gesteuert; zuerst ein festes Modell wählen.",
"SavedAsStartupDefault": "als Start-Default gespeichert",
"ModeAlreadyActiveSavedAsDefault": "Bereits im Modus {mode} — als Start-Default gespeichert.",
"StartupDefaultNotSaved": "{setting} wurde nicht gespeichert: {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun rechnet Pay-as-you-go und Step-Plan-Abos über getrennte Endpunkte ab. Wählen Sie den, zu dem Ihr Schlüssel gehört.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (Token-Preis)",
"StepfunBillingRoutePlanOption": "Step-Plan-Abo (Plankontingent)",
"StepfunPlanApiKeyHint": "Verwenden Sie für StepFun-Step-Plan-Abos den für Ihren Step Plan ausgestellten Schlüssel, keinen Pay-as-you-go-Schlüssel.",
"StepfunPlanRouteHint": "Diese Route nutzt {route} und wird gegen Ihr Step-Plan-Kontingent abgerechnet.",
"ConfigLabelSessionsRail": "Sitzungsleiste",
"ConfigLabelSessionAutoResume": "Letzte Sitzung automatisch fortsetzen",
"SessionsRailTitle": "Sitzungen",
"SessionsRailEmpty": "Noch keine Sitzungen in diesem Arbeitsbereich",
"SessionsRailBrowseAll": "Alle Sitzungen durchsuchen",
"SessionsRailShowingCount": "{shown} von {total} — alle anzeigen",
"SessionsRailUnavailable": "Sitzungen nicht verfügbar: {error}",
"SessionsActionArchive": "archivieren",
"SessionsActionShowArchived": "archiviert",
"SessionsArchived": "Sitzung {id} archiviert",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "Agenten",
"FooterHintToManage": "verwalten",
"AgentRailQueuedCount": "{count} eingereiht",
"WorkbarSoFar": "{done}/{total} bisher",
"WorkbarLargeWorkflow": "Großer Workflow",
"WorkbarMoreRuns": "+{count} weitere",
"WorkflowLineStarted": "gestartet",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "fertig mit Lücken",
"WorkflowLineFailed": "fehlgeschlagen",
"WorkflowLineStopped": "gestoppt",
"WorkflowLineAgents": "{done}/{total} Agenten",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "schreibt",
"AgentFocusPostureReadOnly": "nur lesen",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "Nur-Lese-Shell",
"AgentFocusPostureShellNone": "keine Shell",
"GoalReceiptSet": "Ziel gesetzt: \"{objective}\" · /goal zeigt den Fortschritt · /goal pause oder /goal clear beendet es",
"GoalReceiptSetOperate": "◆ Ziel gesetzt · Operate arbeitet weiter, bis es verifiziert ist · /goal zum Bearbeiten",
"GoalControlAccepted": "Zielsteuerung gespeichert; sie wird am nächsten sicheren Übergang angewendet.",
"GoalControlRuntimeUnavailable": "Die Zielsteuerung ist gespeichert, aber die Laufzeit ist nicht verfügbar. Sie wird nach dem Neustart wiederhergestellt.",
"GoalStatusIdleHint": "läuft gerade nicht — Nachricht senden oder /goal resume zum Fortsetzen",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Ziel aktiv · nächster Durchlauf in {delay} · Esc, Ctrl+C oder /goal pause stoppt die ausstehende Fortsetzung",
"GoalContinuationReady": "Zielfortsetzung bereit; wartende Steuerbefehle laufen vor dem nächsten Durchlauf.",
"GoalContinuationStopped": "Ausstehende Zielfortsetzung gestoppt; das Ziel bleibt aktiv.",
"McpCapabilitiesAdvertised": "Angekündigte Fähigkeiten: {capabilities}",
"McpCapabilitiesLegacyFallback": "Angekündigte Fähigkeiten: nicht angegeben; ältere Erkennung wird ersatzweise verwendet",
"McpCapabilitiesNotObserved": "Angekündigte Fähigkeiten: nicht beobachtet, da der Server nicht verbunden ist",
"PickerActionTestConnection": "Verbindung testen",
"ProviderCustomFormBaseUrl": "Basis-URL",
"ProviderCustomFormModel": "Standardmodell",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "Gantt Zeit →",
"ConfigCategoryAppearance": "Darstellung",
"ConfigCategoryModelsProviders": "Modelle & Anbieter",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Arbeit",
"ConfigCategoryToolsMcp": "Werkzeuge & MCP",
"ConfigCategoryTrust": "Vertrauen",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "schreibgeschützt",
"ConfigRowActionNote": "Aktion · keine gespeicherte Einstellung",
"ConfigRowDiagnosticNote": "beobachteter Beleg · hier nicht bearbeitbar",
"ConfigNavHint": "←/→ oder Tab Kategorie · ↑/↓ Einstellung",
"ConfigActivateAgain": "Enter oder erneut klicken:",
"ConfigSearchLabel": " Suche: ",
"ConfigEditChooseLabel": "Auswahl:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Nie",
"ConfigChoiceModeAct": "Handeln",
"ConfigChoiceModePlan": "Planen (nur lesen)",
"ConfigChoiceModeOperate": "Steuern",
"ConfigChoicePlacementTop": "Oben",
"ConfigChoicePlacementBottom": "Untere Leiste",
"ConfigChoicePlacementLeft": "Linke Seitenleiste",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Prüft das Werkzeugrisiko automatisch und fragt, wenn eine Entscheidung dich braucht.",
"ConfigChoiceDetailUseTuiDefault": "Entfernt den Override der Root-Konfiguration und nutzt die gespeicherte TUI-Berechtigungswahl.",
"ConfigChoiceDetailFullAccess": "Werkzeuge laufen ohne Rückfrage, und Befehle können auf alles auf diesem Computer zugreifen.",
"ConfigChoiceDetailNever": "Blockiert jedes Werkzeug, das eine Freigabe braucht.",
"ConfigChoiceDetailModeAgent": "Startet bereit zur Zusammenarbeit und Werkzeugnutzung.",
"ConfigChoiceDetailModePlan": "Startet in einem schreibgeschützten Planungsbereich.",
"ConfigChoiceDetailModeOperate": "Operate ist Work mit voller Kraft: Jede substanzielle Anfrage wird zum Ziel, läuft über Workflows und parallele Worker, wird von einem unabhängigen Reviewer geprüft und läuft weiter, bis sie verifiziert ist.",
"ConfigChoiceDetailPlacementTop": "Zeigt Aufgaben, To-do und Worker über dem Transkript.",
"ConfigChoiceDetailPlacementBottom": "Zeigt Aufgaben, To-do und Worker unter dem Composer.",
"ConfigChoiceDetailPlacementLeft": "Zeigt Aufgaben, To-do und Worker in einer linken Seitenleiste, wenn das Terminal breit genug ist.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Füllt den Hintergrund des Modell-Reasonings.",
"ConfigChoiceDetailThinkingHighlightOff": "Behält die gestrichelte Leiste und den kursiven Text ohne gefüllten Hintergrund.",
"ConfigHintModel": "Modell der Live-Route dieser Sitzung; Enter öffnet /model",
"ConfigHintFastModel": "wird von Auto-Routing und agentischem model_strength=faster genutzt, wenn dieser Anbieter ein bekanntes Schwestermodell hat",
"ConfigHintProvider": "Zugangsdaten, Modell und Endpunkt wechseln gemeinsam",
"ConfigHintApprovalMode": "nur diese Sitzung: Nachfragen | Automatische Prüfung | Vollzugriff",
"ConfigHintPermissionPosture": "Standard für neue Sitzungen: Nachfragen | Automatische Prüfung | Vollzugriff",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "Ganzzahl (0 erlaubt) · Anzahl gesendeter Nachrichten, die zum Abrufen und für die Verlaufssuche aufbewahrt werden",
"ConfigHintAutoCompactThreshold": "10..=100 · Verdichtungsschwelle: Prozent der nutzbaren Kontextlänge, bei dem die automatische Verdichtung auslöst",
"ConfigHintDefaultModel": "Alt-Fallback nur für DeepSeek; andere Anbieter nutzen ihr anbieterspezifisches Modell oben",
"ConfigHintReasoningEffort": "default stellt den Standard des Modells wieder her; Modelle, die immer denken, lassen off weg",
"ConfigHintMcpOpen": "MCP-Manager öffnen · Verbinden / Neu verbinden / Neu anmelden / Diagnose",
"ConfigHintMcpReconnect": "MCP neu verbinden · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "schreibgeschützter Feature-Flag-Zustand für Patch-Bearbeitungswerkzeuge",
"ConfigHintFeatureMcp": "schreibgeschützter Feature-Flag-Zustand für MCP-Werkzeuge",
"ConfigHintFeatureExecPolicy": "schreibgeschützter Feature-Flag-Zustand für Ausführungsrichtlinien-Werkzeuge",
"ConfigHintFeatureVisionModel": "Beta-Feature-Flag für Bildunterstützung von Vision/Modell",
"ConfigHintGoalCommand": "/goal setzt Ziele, Budgets und den Status des Arbeitskontexts",
"ConfigHintWorkflow": "/workflow führt skriptgesteuerte Abläufe mit Verteilungs-/Sammel-Laufkarten aus",
"LaunchMenuNewWorktree": "Neuer Worktree",
"LaunchMenuResume": "Sitzung fortsetzen",
"LaunchMenuQuit": "Beenden",
"LaunchNoticeClaude": "Claude Code erkannt. Führe /import-claude aus, um zu prüfen, was übernommen werden kann: MCP-Server, sichere Einstellungen und Berechtigungen. Nichts wird ohne deine Zustimmung angewendet.",
"LaunchNewSession": "Neue Sitzung",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ zum Fortsetzen",
"LaunchHelpLine": "/help für Befehle · {dock} für die Arbeitsleiste",
"LaunchSeeAllSessions": "Alle Sitzungen anzeigen…",
"LaunchNoRecentSessions": "Noch keine aktuellen Sitzungen — unten tippen, um zu starten.",
"LaunchResumeFailed": "Fortsetzen fehlgeschlagen: {error}",
"ReceiptSessionHooks": "Hooks {count}",
"AutomationEditorNew": "Neue Automation",
"AutomationEditorEdit": "Automation bearbeiten",
"AutomationEditorSchedule": "Zeitplan",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} fertig",
"WorkflowPhaseCountOne": "{count} Phase",
"WorkflowPhaseCountMany": "{count} Phasen",
"WorkflowPhaseOrdinal": "Phase {n}/{total}",
"ModelPickerPinned": "{route} angeheftet",
"ModelPickerUnpinned": "{route} gelöst",
"ModelPickerPinFailed": "Anheften konnte nicht aktualisiert werden: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Die vorherige Codewhale-Anmeldung bei {provider} ({account}) wurde ersetzt.",
"AuthReplacedPreviousSignIn": "Die vorherige Codewhale-Anmeldung bei {provider} wurde ersetzt.",
"AuthSameAccountAsBefore": "Das ist dasselbe Konto wie zuvor. Um ein anderes {provider}-Konto zu verwenden, melde dich im Browser davon ab (oder nutze ein privates Fenster) und melde dich erneut an.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN oder CODEX_ACCESS_TOKEN ist in dieser Umgebung gesetzt und hat Vorrang vor dieser Anmeldung; Anfragen nutzen weiter das Konto dieses Tokens, bis du die Variable entfernst.",
"PinnedPromptJumpToMessage": "Zu dieser Nachricht springen",
"PlanHandoffHeader": "Plan fertig",
"PlanHandoffQuestion": "Wie möchtest du fortfahren?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Mit Eingabe im Browser anmelden, mit Esc zurück. Kein API-Schlüssel erforderlich.",
"PluginOAuthReady": "{provider}: angemeldet. Wählen Sie ein Modell.",
"PluginOAuthLocalLogout": "{provider}: lokale Anmeldung entfernt. Der Fernzugriff bleibt unverändert.",
"CmdConnectDescription": "Plugin-Anbieter per Browser-Anmeldung verbinden",
"CmdDisconnectDescription": "Lokale Anmeldung eines Plugin-Anbieters entfernen",
"ExecAutoHelp": "Aktiviert Tools mit automatischer Genehmigung und Full Access (keine Shell-Sandbox, Vertrauensmodus aktiv), sofern keine strengere Sandbox konfiguriert ist; --sandbox workspace-write beschränkt Schreibzugriffe von Datei-Tools und Shell.",
"ExecSandboxHelp": "Sandbox-Richtlinie für diesen Lauf; jedes --sandbox außer danger-full-access (oder ein entsprechender sandbox_mode in der Konfiguration) deaktiviert den Vertrauensmodus.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime closed this conversation's event stream; reopen the thread",
"MobileStreamReconnecting": "Connection lost; reconnecting",
"MobileStreamConnected": "Connected",
"PetHabitatTitle": "CODEWHALE / WHALESONG · One shared habitat",
"PetHabitatHints": "{back} back · {sound} sound · {browser} appearance · {window} window",
"PetHabitatQueued": "Sent to the shared habitat. /pet on shows the pet with your message box.",
"PetWatchSoundOn": "Sound on",
"PetWatchSoundOff": "Sound off",
"PetWatchSoundPaused": "Sound paused",
"PetWatchSoundUnavailable": "Pet sound stopped. Check FFmpeg (ffplay) and your audio output, then enable sound again.",
"CmdPetDescription": "Use the animated pet as your main Codewhale view",
"ConfigLabelPetMode": "Pet mode",
"ConfigHintPetMode": "Use the animated pet as the main view when Codewhale starts.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "pet mode off",
"PetViewOpen": "habitat open",
"PetViewClosed": "habitat closed",
"PetWatchRestored": "/pet restored this session’s habitat. Waiting for fresh telemetry.",
"PetWatchStorageUnavailable": "Watch could not restore or save this habitat. Existing files were kept. Use {command} to export this run.",
"PetWatchExported": "Watch replay saved: {path}",
"PetWatchExportFailed": "Watch replay could not be saved. The recording remains in memory.",
"PetWatchExportQueued": "Saving Watch replay…",
"PetWatchExportUnavailable": "Open /pet in a saved session, or wait for the current export.",
"PetUnobserved": "resting",
"PetOffline": "offline — codewhale pet serve wakes it",
"PetDozing": "dozing",
"PetWatchUnavailable": "Pet telemetry paused. /pet on retries.",
"ConversationChangedBeforeUndo": "The conversation changed before undo could finish. Nothing was undone and no retry was sent. Review the current conversation before trying again.",
"SessionArchiveExported": "Exported session",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Edit",
"ExtensionsHooksAddLabel": "Add a hook",
"ExtensionsHooksAddDescription": "Open this project's hooks file in your editor",
"ExtensionsActionReload": "reload",
"ExtensionsActionConnect": "connect",
"ExtensionsActionReconnect": "reconnect",
"ExtensionsActionReauth": "re-auth",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "connected",
"ExtensionsStateEnabled": "enabled",
"ExtensionsStateError": "error",
"ExtensionsStateInactive": "inactive",
"ExtensionsStateInapplicable": "not applicable",
"ExtensionsStateInvalid": "invalid",
"ExtensionsStateNotInspected": "not inspected",
"ExtensionsStateDisconnected": "disconnected",
"ExtensionsStateRejected": "rejected",
"ExtensionsStateReviewedCandidate": "reviewed candidate",
"ExtensionsStateUnderEvaluation": "under evaluation",
"ExtensionsStateUnstaged": "not staged",
"ExtensionsStateUnsupported": "unsupported",
"ExtensionsStateWarning": "warning",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ send into this turn",
"ComposerHintLongDraft": "{shortcut}: external editor",
"PendingSendingIntoTurnPrefix": " ↳ Sending into this turn: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Held for next turn: ",
"PendingEditingFollowUpPrefix": " ↳ Editing follow-up: ",
"PendingQueuedOnePrefix": "Queued #1: ",
"PendingQueuedManyPrefix": "Queued {count} · next: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Thought",
"TranscriptThoughtFor": "Thought for {duration}",
"TelemetryNoticeDefaultOn": "Usage reporting is on by default. Share aggregate version/platform, session, feature and error counts with Codewhale and PostHog (processor). Also counts providers, public catalog models, token totals and built-in tool use. No content or IP. docs/TELEMETRY.md Turn off: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale usage reporting",
"TelemetryNoticeBody": "Codewhale counts: which version you run, OS and CPU family, session\nduration and outcome, and aggregate feature and error counters.\n\nIt also counts the providers and public catalog models you use, their\ntoken totals, and how often each built-in tool runs.\n\nIt never collects your conversations, code, prompts, files, repo or\nbranch names, model content, or credentials — and it never sends a\nper-turn or per-tool timeline of agent activity.\n\nYou are identified only by a random ID stored on this machine, replaced\nevery 90 days. Change your mind any time:\n codewhale config set telemetry false\n\nFull schema, field by field: docs/TELEMETRY.md\n\nUsage reporting is on by default. Codewhale and PostHog process these counts when delivery is configured. No IP is collected.",
"TelemetryNoticeCompactBody": "Counts: version, OS/CPU, session\ntime/result, feature/error totals.\nAlso: provider/model, tokens, tools.\nRandom local ID rotates every 90d.\nNever: chat/code/prompts/files/names;\nmodel content/credentials; turn/tools.\nSchema: docs/TELEMETRY.md\nOff: codewhale config set telemetry\nfalse\nUsage reporting is on by default. Codewhale and PostHog process these counts when delivery is configured. No IP is collected.",
"TelemetryNoticeChoiceKeep": "Yes, keep anonymous counts",
"TelemetryNoticeChoiceDisable": "No, turn off tracking",
"TelemetryNoticeActionChoose": "choose",
"TelemetryNoticeActionConfirm": "confirm",
"TelemetryNoticeActionExit": "exit",
"TelemetryNoticeReceiptEnabled": "Usage reporting is on. Conversations and code are never collected. Change this in /settings; schema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Usage reporting is off. You will not be asked again.",
"TelemetryNoticeReceiptEnabledUnsaved": "Usage reporting is on for this session. Codewhale could not save this notice, so it will appear again. Change this in /settings; schema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Usage reporting is off for this session. Codewhale could not save the choice, so it will ask again next launch.",
"TelemetryPreferenceEnabledNextLaunch": "Usage reporting will be on next launch. Conversations and code are never collected.",
"TelemetryPreferenceDisabled": "Usage reporting is off. Local telemetry state was erased.",
"TelemetryPreferenceDisabledWithWarning": "Usage reporting is off, but part of the cleanup needs attention: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "No hotbar actions available.",
"HotbarSetupRecommended": "rec",
"HotbarSetupEmptySlot": "empty",
"HotbarSetupHelp": "Tab/Shift+Tab source Up/Down action 1-8 slot Enter assign Space toggle Delete clear s save Esc cancel",
"HotbarActionVoiceToggleName": "Voice input",
"HotbarActionVoiceToggleDescription": "Toggle voice capture from the terminal microphone.",
"HotbarActionSessionCompactName": "Compact session",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Work mode",
"HotbarActionModeAgentDescription": "Do direct work in the current session.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Compatibility: Work with Full Access permissions (not a separate mode).",
"HotbarActionReasoningCycleName": "Cycle reasoning",
"HotbarActionReasoningCycleDescription": "Step through reasoning levels for the active provider.",
"HotbarActionReasoningCycleAutoDisabled": "Thinking level is set by auto model routing.",
"HotbarActionSidebarToggleName": "Toggle workbar",
"HotbarActionSidebarToggleDescription": "Show or hide the workbar.",
"HotbarActionFileTreeToggleName": "Toggle file tree",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " No settings available.",
"ConfigNoMatchesPrefix": " No settings match ",
"ConfigFilteredSettings": " Filtered settings",
"ConfigShowing": " Showing",
"ConfigFooterDefault": " type=filter, Up/Down=select, Enter=edit, Esc=close ",
"ConfigFooterScrollable": " type=filter, Up/Down=select, Enter=edit, PgUp/PgDn=scroll, Esc=close ",
"ConfigFooterFiltered": " type=filter, Backspace=delete, Ctrl+U/Esc=clear, Enter=edit ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; ghost text applies from next turn)",
"ConfigNotificationsSetHint": "Set with /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; applies to later alerts)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs must be a whole number",
"ConfigAuditSearchProvider": "Writes [search] provider; subsequent web_search calls still honor environment overrides.",
"ConfigAuditPromptSuggestion": "Writes top-level prompt_suggestion; ghost-text hints stay opt-in.",
"ConfigAuditNotifications": "Writes [notifications] scalars and applies them to subsequent turn-complete alerts.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "Provider API URL",
"ConfigHintProviderUrl": "Current provider endpoint; Xiaomi: token plan | pay as you go | custom URL",
"ConfigLabelModel": "Active provider model",
"ConfigLabelFastModel": "Fast model (derived)",
"ConfigLabelDefaultModel": "Legacy fallback model (DeepSeek routes only)",
"ConfigLabelReasoningEffort": "Thinking level",
"ConfigLabelFleetSpawnDepth": "agent depth",
"ConfigLabelApprovalMode": "This session's permission",
@@ -347,6 +377,7 @@
"ConfigHintTelemetry": "Aggregate version, session, feature and error counts to Codewhale and PostHog; never content or IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "On",
"ConfigValueTelemetryOff": "Off",
"ConfigLabelStreamTimeout": "Stream timeout",
"ConfigLabelTheme": "Theme",
"ConfigLabelLocale": "Language",
"ConfigLabelBackground": "Background",
@@ -370,6 +401,7 @@
"ConfigLabelThinkingHighlight": "Thinking background highlight",
"ConfigLabelShowToolDetails": "Tool detail level",
"ConfigLabelInlineDiffs": "Inline file changes",
"ConfigLabelStatusIndicator": "Status indicator",
"ConfigLabelSynchronizedOutput": "Output pacing",
"ConfigLabelCostCurrency": "Cost currency",
"ConfigLabelTranscriptSpacing": "Transcript spacing",
@@ -377,7 +409,16 @@
"ConfigLabelComposerDensity": "Composer density",
"ConfigLabelComposerBorder": "Composer border",
"ConfigLabelComposerMultilineMode": "Composer multiline mode",
"ConfigLabelComposerVimMode": "Composer Vim mode",
"ConfigLabelBracketedPaste": "Bracketed paste",
"ConfigLabelPasteBurstDetection": "Paste detection",
"ConfigLabelMentionMenuLimit": "Mention menu limit",
"ConfigLabelMentionMenuBehavior": "Mention menu behavior",
"ConfigLabelMentionWalkDepth": "File mention depth",
"ConfigLabelWorkspaceFollowSymlinks": "Follow symlinks",
"ConfigLabelContextPanel": "Context panel",
"ConfigLabelSessionsRail": "Sessions workbar",
"ConfigLabelSessionAutoResume": "Auto-resume last session",
"ConfigLabelAutoCompact": "Auto compact",
"ConfigLabelAutoCompactThreshold": "Compact at",
"ConfigLabelMaxHistory": "Input history",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "Goal command",
"ConfigLabelWorkflow": "Workflow",
"ConfigLabelFeaturePrefix": "Feature: {name}",
"ConfigColumnSetting": "Setting",
"ConfigColumnValue": "Value",
"ConfigColumnScope": "Scope",
"ConfigActionOpenProvider": "Enter opens provider picker",
"ConfigActionOpenModel": "Enter opens model picker",
"ConfigActionOpenMcp": "Enter opens MCP manager",
@@ -416,6 +459,7 @@
"HelpKeybindings": "Keybindings",
"HelpUserCommands": "User commands",
"HelpSkills": "Skills",
"HelpFooterTypeFilter": " type to filter ",
"HelpFooterMove": " Up/Down move ",
"HelpFooterJump": " PgUp/PgDn jump ",
"HelpFooterClose": " Esc close ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "Suggested plugin: {name}",
"PluginCtaReview": "Review",
"PluginCtaInstall": "Install",
"PluginCtaReviewTrust": "Review trust",
"PluginCtaEnable": "Enable",
"PluginCtaDismiss": "Don't suggest again",
"PluginCtaDismissSaveFailed": "Hidden for this session; could not save the plugin preference.",
"PluginSuggestionReason": "Matched “{trigger}”",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "Plugin action didn't finish: {error}",
"CmdPluginNoneFound": "No legacy plugin tools in {dir}",
"CmdPluginNotFound": "No plugin named '{name}'",
"CmdPluginListHeader": "Legacy executable plugin tools ({count}):",
"CmdPluginDetailDescription": "Description: {description}",
"CmdPluginDetailSchema": "Schema:\n{schema}",
"CmdPluginDetailApproval": "Approval: {approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "Cached catalog; run `codewhale models --update` to refresh configured providers.",
"ModelsUpdateSummary": "Model catalogs: {updated} updated, {loaded} loaded from Codex, {failed} failed, {skipped} skipped.",
"ModelsUpdatePartial": "Some catalogs could not be refreshed. Previous and configured models remain available.",
"ModelsCodexHint": "ChatGPT models are loaded through Codex. The lookup time does not confirm an upstream catalog refresh.",
"ModelsSourceFallback": "Bundled or configured models; availability not verified.",
"CmdModelDbDescription": "Browse the bundled model database",
"CmdNetworkDescription": "Manage network allow/deny rules",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "See or edit queued messages",
"CmdQueueUsage": "Usage: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "Restored {count} queued message(s) from an earlier session. They are not sent automatically: /queue send <n> sends one, /queue clear discards them.",
"CmdQueueDraftHeader": "Editing queued message:",
"CmdQueueNoMessages": "No queued messages",
"CmdQueueListHeader": "Queued messages ({count}):",
"CmdQueueTip": "Tip: /queue send <n> sends now, /queue drop <n> removes",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "{hit} hit / miss not reported",
"CmdTokensCacheMissOnly": "hit not reported / {miss} miss",
"CmdTokensCacheWriteTotal": "Cache-write (cache-creation) tokens this session: {write}. Billed above the input rate where the provider publishes a write premium; see /cache for the per-turn breakdown.",
"CmdTokensContextUnknownWindow": "~{estimated} / unknown window",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 agent",
"FooterAgentsPlural": "{count} agents",
"HeaderAgentsChip": "agents {count}",
"FooterPressCtrlCAgain": "Press Ctrl+C again to quit",
"FooterWorking": "working",
"FooterBalancePrefix": "balance",
"HelpSectionActions": "Actions",
"HelpSectionClipboard": "Clipboard",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "not reported",
"CmdTokensReport": "Token Usage:\n ─────────────────────────────\n Active context: {active}\n Last API input: {input} (turn telemetry; may count repeated prefix across tool rounds)\n Last API output: {output}\n Cache hit/miss: {cache} (telemetry/cost only)\n Cumulative tokens: {total} (session usage telemetry)\n Priced amount: {cost}\n API messages: {api_messages}\n Chat messages: {chat_messages}\n Model: {model}",
"KbScrollTranscript": "Scroll, browse input history, or pick attachments",
"KbNavigateHistory": "Browse input history",
"KbBrowseHistory": "Browse conversation history",
"KbScrollTranscriptAlt": "Scroll transcript",
"KbScrollPage": "Scroll transcript by page",
@@ -822,6 +875,7 @@
"KbCompactContext": "Compact the conversation",
"KbLastMessagePager": "Page the last message (empty input)",
"KbSelectedDetails": "Show raw detail for the selection; Ctrl+Alt+O opens the turn overview",
"KbToolDetailsPager": "Show raw detail for the selected item (Alt+V)",
"KbExternalEditor": "Edit the draft externally",
"KbLiveTranscript": "Open the live transcript overlay",
"KbBacktrackMessage": "Rewind to an earlier message (Left/Right steps, Enter rewinds)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "Open help (empty input)",
"KbCycleWorkDock": "Cycle the workbar (to-do, agents, jobs, background), or the pet's views in pet mode",
"KbCycleWorkDockBack": "Cycle the workbar or the pet's views backwards",
"KbToggleHelp": "Toggle help overlay",
"KbToggleHelpSlash": "Toggle help overlay",
"HelpUsageLabel": "Usage:",
"HelpAliasesLabel": "Aliases:",
"SettingsTitle": "Settings:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " /mode plan to research and present a plan first",
"HomeAgentModeYoloTip": " Shift+Tab cycles permission: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — tools run without asking first",
"HomeYoloModeCaution": " Destructive operations can run immediately; prefer Ask when unsure",
"HomePlanModeTip": "Plan — research and design first",
"HomePlanModeChecklistTip": " Present a plan and To-do progress, then switch to Work",
"HomeGoalModeTip": "Goal tracking — /goal <objective> pursues one objective",
"OnboardLanguageTitle": "Choose your language",
"OnboardLanguageBlurb": "Pick the UI language — change it anytime with `/config locale <tag> --save`.",
"OnboardProviderTitle": "Choose your model provider",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "StepFun bills pay-as-you-go and Step Plan on separate endpoints. Pick your key's home.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (token pricing)",
"StepfunBillingRoutePlanOption": "Step Plan subscription (plan allowance)",
"StepfunPlanApiKeyHint": "Use your Step Plan key here, not a pay-as-you-go key.",
"StepfunPlanRouteHint": "This route uses {route}, billed to your Step Plan.",
"OnboardApiKeyRejectedEnv": "The {provider} API key from {env} was rejected. Paste a valid key to save it to {path}, or update the environment variable.",
"OnboardTrustTitle": "Know this workspace",
"OnboardTrustQuestion": "Should Codewhale work with the instructions and files in this workspace?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "Choosing \"keep\" leaves masking on for this launch; because your config still requests \"disabled\", the next launch will ask again.",
"RedactionGateSaveFailed": "Could not save confirmation. Masking remains on. Retry or choose keep masking on.",
"RedactionGateTitle": "Model-bound key redaction",
"OnboardOfflineOption": "Ctrl+O — look around offline; connect later.",
"OnboardOfflineNotice": "Exploring offline — run /provider whenever you're ready to connect.",
"OnboardWelcomeTitle": "Codewhale works with you in this folder.",
"OnboardWelcomeLead": "Let's get you ready.",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "Explain this project and list its main entry points.",
"OnboardSeedFolder": "Look at this folder and suggest a good first task.",
"SetupWizardTitle": "Setup",
"SetupWizardWhy": "This shell records setup progress in setup_state.json; config changes are only applied by explicit step actions.",
"SetupWizardProgress": "Step",
"SetupActionBack": "back",
"SetupActionContinue": "continue",
"SetupActionSkip": "skip",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "scroll body",
"SetupActionGuided": "preview/ratify",
"SetupActionTuneGuided": "tune",
"SetupActionModelDraft": "model draft",
"SetupActionFreeform": "own words",
"SetupActionKeepExisting": "keep existing",
"SetupActionUseRecommended": "use recommended",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "model routes",
"SetupActionFleet": "fleet setup",
"SetupActionHotbar": "hotbar setup",
"SetupActionRemote": "remote on-ramp",
"SetupActionMode": "mode picker",
"SetupActionConfig": "config view",
"SetupActionRuntimePreset": "preset",
"SetupActionApplyRuntimePreset": "preview/apply",
"SetupActionUseBundled": "use bundled",
"SetupActionDefer": "defer",
"SetupActionCancel": "cancel",
"SetupStatusNotStarted": "not started",
"SetupStatusRecommended": "recommended",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "Setup language recorded.",
"SetupConstitutionChoiceLabel": "Choice:",
"SetupConstitutionSourceLabel": "Source:",
"SetupConstitutionValidityLabel": "Validity:",
"SetupConstitutionPreviewLabel": "Preview hash:",
"SetupConstitutionExistingLabel": "Existing file:",
"SetupConstitutionExpertOverrideLabel": "Expert override:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "Plugins:",
"SetupToolsMcpReviewHint": "Enter records this setup snapshot. Press R for safe on-ramps (no auto-run).",
"SetupToolsMcpReviewed": "Tools/MCP readiness recorded.",
"SetupRemoteCloudsLabel": "Cloud targets:",
"SetupRemoteBridgesLabel": "Chat bridges:",
"SetupRemoteProvidersLabel": "Providers:",
"SetupRemoteModeLabel": "Remote mode:",
"SetupRemoteModeLocalOnly": "This machine only:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "Copy message",
"CtxMenuCopyMessageDesc": "write clicked transcript cell",
"CtxMenuOpenInEditor": "Open in editor",
"CtxMenuOpenInEditorDesc": "open file:line in $EDITOR",
"CtxMenuShowCell": "Show cell",
"CtxMenuShowCellDesc": "unhide this transcript cell",
"CtxMenuHideCell": "Hide cell",
@@ -1216,9 +1290,17 @@
"FanoutCounts": "{done} done · {running} running · {failed} failed · {pending} pending",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (deprecated mode label)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Direct work in this session — edits and shell ask for approval",
"AppModeAutoHint": "Shell enabled with automatic risk review",
"AppModePlanHint": "Read-only research first — present a plan before acting",
"AppModeYoloHint": "Compatibility only — Work + Full Access, not a visible mode",
"AppModeOperateHint": "Work at full strength: a goal, parallel agents, verified before it stops",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERT --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Reads only",
"ApprovalEffectChangesFiles": "Changes files",
"ApprovalRiskDestructive": "Can't be undone",
@@ -1246,6 +1328,7 @@
"ApprovalSaveAskRuleHint": " · s allow now, and always ask before this again",
"ApprovalOptionDeny": "Don't allow",
"ApprovalOptionAbortTurn": "Stop this turn",
"ApprovalBlockTitle": "approval",
"ApprovalControlsHint": "Pg↑/↓ review · {details} more choices · Esc stop",
"ApprovalOwnerHeader": "Agent: {agent} · {role}",
"ApprovalGoToAgent": "g go to agent",
@@ -1271,6 +1354,8 @@
"ApprovalTruncationHint": " … truncated · press {details} for full details",
"ApprovalAsksWithoutGit": "No Git repository here, so edits ask first.",
"ApprovalFullAccessPolicyBlocked": "Blocked {tool}: Full Access cannot bypass this policy",
"ApprovalChooseHint": "Choose: ",
"ApprovalChooseAction": "Enter selected option, or press y/a/d directly",
"ApprovalIntentLabel": "Intent: ",
"ApprovalMoreLines": " … (+{count} lines)",
"ApprovalProceedQuestion": "Do you want to proceed?",
@@ -1310,10 +1395,12 @@
"ContextManualCompacting": "Compacting context…",
"ContextCompactionQueued": "Making room is queued — it runs after this turn.",
"ContextCompactionAlreadyRunning": "Already making room.",
"ContextCompactionQueueFull": "Making room has to wait — the engine is busy. Try again after this turn.",
"ContextCompactionQueueClosed": "Can't make room — the engine stopped.",
"ContextCompactionRouteInvalid": "Can't compact — the active provider route is invalid: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Making room stopped; the conversation was not changed",
"ContextPurgeAbandonedOnEngineSwitch": "Session cleanup was abandoned with the replaced engine; the conversation was not changed",
"CtxInspTitle": "Context inspector",
"CtxInspSessionContext": "Session Context",
"CtxInspSystemPrompt": "System Prompt Structure",
"CtxInspReferences": "References",
@@ -1545,21 +1632,45 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — Safe On-Ramps\n\n/setup only reads local inventory. It never starts MCP servers, installs skills, runs plugins, or executes untrusted commands.\n\nCurrent inventory:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools dir: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (shared adapters): {hotbar_result}\n\nPaths (redacted home):\n- MCP config: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nSafe bootstrap (run yourself in a normal terminal or TUI command):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install <spec>\n- Plugins: /plugin · codewhale setup --plugins\n- Tools dir: codewhale setup --tools\n\nSide-effectful actions always require explicit confirmation. Plugin commands stay distinct from slash commands; the Hotbar plugin source remains deferred until approval gates land.\n\nSee docs/MCP.md and docs/skills/README.md for what still needs manual external setup.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — connected through Codewhale, never a second scheduler:\n- State: {dsh_result}\n- Read-only detection; connect/plan/launch/remove: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale writes only $CODEWHALE_HOME/integrations/dsh; it never copies API keys or edits DSH files.",
"HotbarActionModeOperateName": "Operate mode",
"HotbarActionModeOperateDescription": "Work a durable request in parallel until it is verified.",
"HomeOperateModeTip": "Operate — put your fleet to work in parallel",
"HomeOperateModeFleetTip": " Roles borrow this session's model; /fleet setup customizes them",
"HelpSubtitle": "Commands, skills, and keys",
"CommandPaletteTitle": "Command",
"CommandPaletteSubtitle": "Find and run one action",
"ConfigSubtitle": "Settings first; raw keys under advanced detail",
"LaunchStartTitle": "Start here",
"LaunchResumeConfirm": "Resume {title}? Click again or press Enter to confirm.",
"LaunchResumeConfirmTitle": "Resume session",
"LaunchResumeConfirmBody": "This replaces the current context with that session's history.",
"LaunchResumeConfirmResume": "resume",
"LaunchResumeConfirmCancel": "cancel",
"LaunchWorkDescription": "Work in this folder; changes follow your permissions.",
"LaunchChatDescription": "Just talk and plan — nothing changes on disk.",
"LaunchWorkspaceGitReady": "Workspace · {name} · Git workspace",
"LaunchWorkspaceFolderReady": "Workspace · {name} · local folder",
"LaunchProviderConfigured": "Provider · configured",
"LaunchProviderSetupNeeded": "Provider · setup needed",
"LaunchGroupContinue": "Continue",
"LaunchGroupMore": "More",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "folder",
"LaunchProviderConfiguredShort": "provider set",
"LaunchProviderSetupShort": "provider setup",
"LaunchMenuChangelog": "Changelog",
"LaunchWorktreePrompt": "Name the branch/worktree, or press Enter for an automatic name. Esc back.",
"LaunchWorktreeNeedsGit": "Worktrees need a Git repo.",
"LaunchWorktreeNameLabel": "worktree name",
"LaunchHintMove": "move",
"LaunchHintOpen": "open",
"LaunchTipFlags": "Tip: -w <path> opens a workspace; -r <session-id> resumes directly",
"LaunchSavedSessionSingular": "1 saved session",
"LaunchSavedSessionsPlural": "{count} saved sessions",
"LaunchCreatingWorktree": "Creating worktree…",
"LaunchWorktreeFailed": "Could not create the worktree: {error}",
"LaunchWorktreeCreated": "New worktree {path} on branch {branch}",
"LaunchNoSavedSessions": "No saved sessions here yet.",
"LaunchNoModelConnected": "no model connected",
"DispatchNotSentNoModel": "No model is connected, so this message was not sent. It is back in the message box: connect a model with F3 or /provider, then press Enter to send it.",
"DispatchNotSentSaveKey": "Save a key: {command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "Using {model}, a model running on this computer (Ollama). Press F3 to choose another.",
"ProviderPickerNotReopened": "The provider list could not be reopened. Press F3 to open it.",
"LaunchRunCommand": "run {command}",
"LaunchMcpConnectedOne": "1 MCP server connected",
"LaunchMcpConnectedMany": "{count} MCP servers connected",
"LaunchMcpNeedsSignInOne": "1 needs sign-in",
"LaunchMcpNeedsSignInMany": "{count} need sign-in",
"PhaseIdle": "idle",
"PhaseDraft": "draft",
"PhaseWorking": "working",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "finishing",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "read only",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "Permissions changed to {label}",
"FooterHintKeys": "keys",
"FooterHintOutput": "output",
"FooterHintContext": "context",
"InfoLineHelp": "help",
"InfoLineContext": "context",
"InfoLineTtft": "ttft",
"InfoLinePeak": "peak",
"InfoLineOffPeak": "off-peak",
"InfoLineWhales": "whales",
"InfoLineAutomation": "automation",
"InfoLineNotConnected": "not connected",
"InfoLineThinking": "thinking: {level}",
"EmptyStateNoGit": "no git",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "search any model",
"RoutePanelHeader": "route",
"RouteProviderLabel": "provider",
"RouteModelFirstAtomic": "model-first atomic route",
"PickerActionMove": "move",
"PickerActionSwitch": "switch",
"PickerActionApply": "apply",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "clear search",
"PickerActionBrowseAll": "browse all",
"PickerActionCustom": "custom",
"PickerActionJump": "jump",
"PickerActionEditKey": "edit key",
"PickerActionModels": "models",
"PickerActionUnavailable": "unavailable",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "stop using that sign-in",
"ProviderExternalActionChoices": "sign in via another app",
"ProviderExternalActionReuseGrok": "external Grok reuse",
"ProviderExternalHintCodexReview": "After {login}, press Enter to review disabled/read-only/managed access choices.",
"ProviderExternalHintXaiReview": "Press Enter for Codewhale-owned device login; press E to review existing Grok CLI reuse.",
"ProviderExternalHintXaiApiKey": "Or use XAI_API_KEY and re-open this picker.",
"XaiAuthChoiceTitle": " xAI authentication ",
"XaiAuthChoiceIntro": "Choose one explicit credential source. Key text is never an OAuth token.",
"XaiAuthChoiceApiKeyOption": "xAI API key — type or paste, then save in the xAI provider slot",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT / Codex authentication ",
"ChatgptAuthChoiceIntro": "Subscription sign-in bills your ChatGPT plan. The openai API-key route is a different billing owner.",
"ChatgptAuthChoicePkceOption": "Sign in with ChatGPT — browser PKCE, Codewhale-owned tokens, ChatGPT subscription billing",
"ChatgptAuthChoiceImportOption": "Import Codex CLI credentials — explicit read-only consent; Codex CLI remains the owner",
"ProviderExternalHintChatgptReview": "Press Enter to Sign in with ChatGPT; press E to review existing Codex CLI reuse.",
"ProviderExternalActionReuseCodex": "external Codex reuse",
"ProviderExternalDetailScope": "External: access={access} | provider={provider} | source={source} | version={version} | {state}",
"ProviderExternalDormant": "dormant",
"ProviderExternalOwnerPath": "Owner/path: {owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "Snapshots and /undo are off for {workspace}: a home or root directory is too broad to snapshot safely. Start in a project directory to turn them on.",
"SnapshotsHistoryRepaired": "Undo history for {workspace} was damaged (its latest restore point was missing) and has been restarted. Earlier restore points can no longer be restored; new turns are protected again.",
"SnapshotsFailing": "Snapshots are failing for {workspace}, so /undo cannot restore recent turns: {limit}",
"SessionIdDivergedNotice": "Session identity changed under this window: the engine now saves checkpoints as {next} (it was {previous}). Earlier checkpoints stay under the old id; `codewhale sessions` lists both and `codewhale resume {previous}` reopens the earlier one.",
"RuntimeStoreUnreadableNotice": "Session runtime store: {record} at {path} could not be read ({reason}). Move that file aside (or delete it) and retry; the thread's other records stay in place.",
"RuntimeStoreUnwritableNotice": "Session runtime store: {record} at {path} could not be written ({reason}). Check free space and permissions there, then retry; nothing was overwritten.",
"ProviderExternalSemanticsRevoke": "{semantics} | revoke: {revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "setup",
"FleetRosterWorkers": "workers",
"FleetRosterMembersCount": "{count} members",
"FleetRosterOperatorFirst": "Coordinator leads · your session model runs this fleet",
"FleetRosterOperatorRow": "Coordinator · you",
"FleetRosterShadowBadgeProjectOverride": "saved in this project",
"FleetRosterShadowBadgePersonalIgnored": "saved copy ignored",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "this is your current model (the Fleet's coordinator route); switch models or use /fleet save to change it",
"FleetModelReasonAlreadyPresent": "already on the team",
"FleetModelErrorNeedsRoute": "a team model needs both a provider id and a model id",
"FleetModelErrorNeedsRole": "An agent needs a role name (for example `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "no team is selected; your team is the session model only",
"FleetModelErrorOperatorRoute": "{route} is the coordinator route of the Fleet `{fleet}`; change it with /fleet save, not remove",
"FleetModelErrorNotInFleet": "{route} is not on the team `{fleet}`",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ attach · 1 match",
"FilePickerMatchesPlural": "@ attach · {count} matches",
"FilePickerScanning": "Scanning workspace…",
"BehavioralTipPlanning": "Planning? {key} cycles to Plan mode",
"BehavioralTipBackgroundReceipt": "Receipts live in the Work panel — {key} opens the inspector",
"BehavioralTipClearedInput": "Cleared · {chord} restores",
"BehavioralTipMcpValidation": "{command} starts servers and shows why",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "Model and thinking",
"SettingSubjectProvider": "Provider",
"SettingSubjectPermissions": "Permissions",
"ThinkingControlledByAutoRouting": "Auto routing controls thinking; pick a fixed model first.",
"SavedAsStartupDefault": "saved as startup default",
"ModeAlreadyActiveSavedAsDefault": "Already in {mode} — saved as startup default.",
"StartupDefaultNotSaved": "{setting} was not saved: {error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "thinking level",
"StartupDefaultSubjectModel": "model",
"StartupDefaultSubjectAll": "startup defaults",
"SessionsRailTitle": "Sessions",
"SessionsRailEmpty": "No sessions here yet",
"SessionsRailBrowseAll": "Browse all sessions",
"SessionsRailShowingCount": "{shown} of {total} — browse all",
"SessionsRailUnavailable": "Sessions unavailable: {error}",
"SessionsActionArchive": "archive",
"SessionsActionShowArchived": "archived",
"SessionsArchived": "Archived {id}",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "for agents",
"FooterHintToManage": "to manage",
"AgentRailQueuedCount": "{count} queued",
"WorkbarSoFar": "{done}/{total} so far",
"WorkbarLargeWorkflow": "Large workflow",
"WorkbarMoreRuns": "+{count} more",
"WorkflowLineStarted": "started",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "finished with gaps",
"WorkflowLineFailed": "failed",
"WorkflowLineStopped": "stopped",
"WorkflowLineAgents": "{done}/{total} agents",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "writes",
"AgentFocusPostureReadOnly": "read-only",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "read-only shell",
"AgentFocusPostureShellNone": "no shell",
"GoalReceiptSet": "Goal set: \"{objective}\" · /goal shows progress · /goal pause or /goal clear stops it",
"GoalReceiptSetOperate": "◆ goal set · Operate keeps working until it is verified · /goal to edit",
"GoalControlAccepted": "Goal control saved; applying at the next safe boundary.",
"GoalControlRuntimeUnavailable": "Goal control is saved, but the runtime is unavailable. It will be restored after restart.",
"GoalStatusIdleHint": "not running now — send a message or /goal resume to continue",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Goal active · next turn in {delay} · Esc, Ctrl+C, or /goal pause stops the pending continuation",
"GoalContinuationReady": "Goal continuation ready; queued controls run before the next turn.",
"GoalContinuationStopped": "Pending goal continuation stopped; the goal remains active.",
"McpCapabilitiesAdvertised": "Advertised capabilities: {capabilities}",
"McpCapabilitiesLegacyFallback": "Advertised capabilities: not provided; using legacy discovery fallback",
"McpCapabilitiesNotObserved": "Advertised capabilities: not observed because the server is not connected",
"PickerActionTestConnection": "test connection",
"ProviderCustomFormBaseUrl": "Base URL",
"ProviderCustomFormModel": "Default model",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt time →",
"ConfigCategoryAppearance": "Appearance",
"ConfigCategoryModelsProviders": "Models & providers",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Work",
"ConfigCategoryToolsMcp": "Tools & MCP",
"ConfigCategoryTrust": "Trust",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "read-only",
"ConfigRowActionNote": "action · not a persisted setting",
"ConfigRowDiagnosticNote": "observed receipt · not editable here",
"ConfigNavHint": "←/→ or Tab category · ↑/↓ setting",
"ConfigActivateAgain": "Enter or click again:",
"ConfigSearchLabel": " Search: ",
"ConfigEditChooseLabel": "Choose:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Never",
"ConfigChoiceModeAct": "Work",
"ConfigChoiceModePlan": "Plan (read only)",
"ConfigChoiceModeOperate": "Operate",
"ConfigChoicePlacementTop": "Top",
"ConfigChoicePlacementBottom": "Bottom bar",
"ConfigChoicePlacementLeft": "Left workbar",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Review tool risk automatically and ask when a decision needs you.",
"ConfigChoiceDetailUseTuiDefault": "Drop the raw config override; use the saved choice.",
"ConfigChoiceDetailFullAccess": "Tools run without asking first, and commands can reach anything on this computer.",
"ConfigChoiceDetailNever": "Block every tool that requires approval.",
"ConfigChoiceDetailModeAgent": "Start ready to work with tools.",
"ConfigChoiceDetailModePlan": "Start in a read-only planning workspace.",
"ConfigChoiceDetailModeOperate": "Operate is Work at full strength: each substantive request becomes a goal, runs through workflows and parallel agents, is checked by an independent reviewer, and keeps going until it is verified.",
"ConfigChoiceDetailPlacementTop": "Show Tasks, To-do, and Agents above the transcript.",
"ConfigChoiceDetailPlacementBottom": "Show Tasks, To-do, and Agents under the composer.",
"ConfigChoiceDetailPlacementLeft": "Show Tasks, To-do, and Agents in a left workbar when the terminal is wide enough.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Fill reasoning's background.",
"ConfigChoiceDetailThinkingHighlightOff": "Keep the dashed reasoning line and italic text without a filled background.",
"ConfigHintModel": "this session's model; Enter opens /model",
"ConfigHintFastModel": "used by Auto routing and model_strength=faster when this provider has a known sibling",
"ConfigHintProvider": "credential, model and endpoint switch together",
"ConfigHintApprovalMode": "this session only: Ask | Auto-Review | Full Access",
"ConfigHintPermissionPosture": "default for new sessions: Ask | Auto-Review | Full Access",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "integer (0 allowed) · number of sent messages kept for recall and history search",
"ConfigHintAutoCompactThreshold": "10..=100 · compaction threshold: percent of the model's context at which older turns are summarized",
"ConfigHintDefaultModel": "DeepSeek-only legacy fallback; other providers use their provider-scoped model above",
"ConfigHintReasoningEffort": "default restores the model's own default; always-thinking models skip off",
"ConfigHintMcpOpen": "open the MCP manager · Connect / Reconnect / Re-auth / Diagnose",
"ConfigHintMcpReconnect": "reconnect MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "read-only flag for patch editing tools",
"ConfigHintFeatureMcp": "read-only flag for MCP tools",
"ConfigHintFeatureExecPolicy": "read-only feature flag state for execution policy tools",
"ConfigHintFeatureVisionModel": "beta feature flag for vision/model image support",
"ConfigHintGoalCommand": "/goal tracks objectives, budgets, and status",
"ConfigHintWorkflow": "/workflow runs scripted ops with fan-out",
"LaunchMenuNewWorktree": "New worktree",
"LaunchMenuResume": "Resume session",
"LaunchMenuQuit": "Quit",
"LaunchNoticeClaude": "Claude Code found. /import-claude to review; you approve every change.",
"LaunchNewSession": "New session",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ to resume",
"LaunchHelpLine": "/help for commands · {dock} for the workbar",
"LaunchSeeAllSessions": "See all sessions…",
"LaunchNoRecentSessions": "No recent sessions yet — type below to start.",
"LaunchResumeFailed": "Resume failed: {error}",
"ReceiptSessionHooks": "hooks {count}",
"AutomationEditorNew": "New automation",
"AutomationEditorEdit": "Edit automation",
"AutomationEditorSchedule": "Schedule",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} done",
"WorkflowPhaseCountOne": "{count} phase",
"WorkflowPhaseCountMany": "{count} phases",
"WorkflowPhaseOrdinal": "phase {n}/{total}",
"ModelPickerPinned": "Pinned {route}",
"ModelPickerUnpinned": "Unpinned {route}",
"ModelPickerPinFailed": "Could not update pin: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Replaced the previous Codewhale {provider} sign-in ({account}).",
"AuthReplacedPreviousSignIn": "Replaced the previous Codewhale {provider} sign-in.",
"AuthSameAccountAsBefore": "This is the same account as before; to use another {provider} account, sign out of it in the browser (or use a private window) and sign in again.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN or CODEX_ACCESS_TOKEN is set in this environment and outranks this sign-in; requests keep using that token's account until you unset it.",
"PinnedPromptJumpToMessage": "Jump to this message",
"PlanHandoffHeader": "Plan ready",
"PlanHandoffQuestion": "How do you want to continue?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Press Enter to connect in your browser. Esc returns. No API key is needed.",
"PluginOAuthReady": "{provider}: connected. Choose a model.",
"PluginOAuthLocalLogout": "{provider}: disconnected on this device. Remote access is unchanged.",
"CmdConnectDescription": "Connect a plugin provider with browser sign-in",
"CmdDisconnectDescription": "Remove a plugin provider's local sign-in",
"ExecAutoHelp": "Enable tools with automatic approvals and Full Access (no shell sandbox, trust mode on), unless a stricter sandbox is configured; use --sandbox workspace-write to restrict file and shell writes.",
"ExecSandboxHelp": "Sandbox policy for this run; any --sandbox other than danger-full-access (or an equivalent sandbox_mode in config) disables trust mode.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "El Runtime cerró el flujo de eventos de esta conversación; vuelve a abrirla",
"MobileStreamReconnecting": "Se perdió la conexión; reconectando",
"MobileStreamConnected": "Conectado",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Un hábitat compartido",
"PetHabitatHints": "{back} volver · {sound} sonido · {browser} apariencia · {window} ventana",
"PetHabitatQueued": "Enviado al hábitat compartido. /pet on muestra la mascota y el cuadro de mensaje.",
"PetWatchSoundOn": "Sonido activado",
"PetWatchSoundOff": "Sonido desactivado",
"PetWatchSoundPaused": "Sonido en pausa",
"PetWatchSoundUnavailable": "El sonido de Codewhale se detuvo. Revisa FFmpeg (ffplay) y la salida de audio, y vuelve a activar el sonido.",
"CmdPetDescription": "Usa la mascota animada como vista principal de Codewhale",
"ConfigLabelPetMode": "Modo mascota",
"ConfigHintPetMode": "Usa la mascota animada como vista principal al iniciar Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "modo mascota desactivado",
"PetViewOpen": "hábitat abierto",
"PetViewClosed": "hábitat cerrado",
"PetWatchRestored": "/pet restauró el hábitat de esta sesión. Esperando telemetría nueva.",
"PetWatchStorageUnavailable": "Watch no pudo restaurar ni guardar este hábitat. Se conservaron los archivos existentes. Usa {command} para exportar esta ejecución.",
"PetWatchExported": "Reproducción de Watch guardada: {path}",
"PetWatchExportFailed": "No se pudo guardar la reproducción de Watch. La grabación sigue en la memoria.",
"PetWatchExportQueued": "Guardando reproducción de Watch…",
"PetWatchExportUnavailable": "Abre /pet en una sesión guardada o espera a que termine la exportación actual.",
"PetUnobserved": "sin observación",
"PetOffline": "sin conexión — codewhale pet serve lo despierta",
"PetDozing": "dormitando",
"PetWatchUnavailable": "La telemetría de la mascota está en pausa. /pet on reintenta.",
"ConversationChangedBeforeUndo": "La conversación cambió antes de completar la acción de deshacer. No se deshizo nada ni se envió un nuevo intento. Revisa la conversación actual antes de volver a intentarlo.",
"SessionArchiveExported": "Sesión exportada",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Editar",
"ExtensionsHooksAddLabel": "Agregar un hook",
"ExtensionsHooksAddDescription": "Abre el archivo de hooks de este proyecto en tu editor",
"ExtensionsActionReload": "recargar",
"ExtensionsActionConnect": "conectar",
"ExtensionsActionReconnect": "reconectar",
"ExtensionsActionReauth": "reautenticar",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "conectado",
"ExtensionsStateEnabled": "habilitado",
"ExtensionsStateError": "error",
"ExtensionsStateInactive": "inactivo",
"ExtensionsStateInapplicable": "no aplicable",
"ExtensionsStateInvalid": "inválido",
"ExtensionsStateNotInspected": "no inspeccionado",
"ExtensionsStateDisconnected": "desconectado",
"ExtensionsStateRejected": "rechazado",
"ExtensionsStateReviewedCandidate": "candidato revisado",
"ExtensionsStateUnderEvaluation": "en evaluación",
"ExtensionsStateUnstaged": "sin preparar",
"ExtensionsStateUnsupported": "no compatible",
"ExtensionsStateWarning": "advertencia",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ enviar a este turno",
"ComposerHintLongDraft": "{shortcut}: editor externo",
"PendingSendingIntoTurnPrefix": " ↳ Enviando a este turno: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ No se pudo enviar a este turno: ",
"PendingEditingFollowUpPrefix": " ↳ Editando el seguimiento: ",
"PendingQueuedOnePrefix": "En cola #1: ",
"PendingQueuedManyPrefix": "En cola {count} · siguiente: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Pensamiento terminado",
"TranscriptThoughtFor": "Pensó durante {duration}",
"TelemetryNoticeDefaultOn": "Las estadísticas de uso están activadas de forma predeterminada. Compartir totales de versión, plataforma, sesiones, funciones y errores con Codewhale y su procesador PostHog. También cuenta proveedores, modelos del catálogo público, totales de tokens y el uso de herramientas integradas. Sin contenido ni IP. docs/TELEMETRY.md Desactivar: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Estadísticas de uso de Codewhale",
"TelemetryNoticeBody": "Codewhale cuenta: la versión que ejecutas, el sistema operativo y la familia\nde CPU, la duración y el resultado de la sesión, y conteos agregados de\nfunciones y errores.\n\nTambién cuenta los proveedores y modelos del catálogo público que usas, sus totales de tokens y cuántas veces se ejecuta cada herramienta integrada.\n\nNunca recopila tus conversaciones, código, prompts, archivos, nombres de\narchivos, repositorios o ramas, contenido del modelo ni credenciales — y nunca\nenvía una cronología de la actividad del agente por turno o herramienta.\n\nSolo te identifica un ID aleatorio almacenado en esta máquina, que se\nreemplaza cada 90 días. Cambia de opinión cuando quieras:\n codewhale config set telemetry false\n\nEsquema completo, campo por campo: docs/TELEMETRY.md\n\nLas estadísticas de uso están activadas de forma predeterminada. Codewhale y PostHog procesan estos totales cuando el envío está configurado. No se recopilan IP.",
"TelemetryNoticeCompactBody": "Cuenta: versión, SO/CPU, tiempo/resultado, funciones/errores.\nTambién: proveedor/modelo, tokens, herramientas.\nID local rota/90d.\nNunca: chats/código/prompts/archivos/nombres; datos del modelo/credenciales; turnos/herramientas.\nVer: docs/TELEMETRY.md\nApag.: codewhale config set telemetry false\nLas estadísticas de uso están activadas de forma predeterminada. Codewhale y PostHog procesan estos totales cuando el envío está configurado. No se recopilan IP.",
"TelemetryNoticeChoiceKeep": "Sí, mantener el conteo anónimo",
"TelemetryNoticeChoiceDisable": "No, desactivar el seguimiento",
"TelemetryNoticeActionChoose": "elegir",
"TelemetryNoticeActionConfirm": "confirmar",
"TelemetryNoticeActionExit": "salir",
"TelemetryNoticeReceiptEnabled": "El conteo anónimo de uso está activado. Nunca se recopilan conversaciones ni código. Cámbialo en /settings; esquema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "El conteo anónimo de uso está desactivado. No volveremos a preguntarte.",
"TelemetryNoticeReceiptEnabledUnsaved": "El conteo anónimo de uso está activado en esta sesión. Codewhale no pudo guardar este aviso y volverá a mostrarlo. Cámbialo en /settings; esquema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "El conteo anónimo de uso está desactivado en esta sesión. Codewhale no pudo guardar la opción, así que volverá a preguntar en el próximo inicio.",
"TelemetryPreferenceEnabledNextLaunch": "El conteo anónimo de uso se activará en el próximo inicio. Nunca se recopilan conversaciones ni código.",
"TelemetryPreferenceDisabled": "El conteo anónimo de uso está desactivado. Se borraron los datos locales de telemetría.",
"TelemetryPreferenceDisabledWithWarning": "El conteo anónimo de uso está desactivado, pero parte de la limpieza requiere atención: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "No hay acciones de Hotbar disponibles.",
"HotbarSetupRecommended": "rec",
"HotbarSetupEmptySlot": "vacío",
"HotbarSetupHelp": "Tab/Shift+Tab origen Up/Down acción 1-8 ranura Enter asignar Space alternar Delete limpiar s guardar Esc cancelar",
"HotbarActionVoiceToggleName": "Entrada de voz",
"HotbarActionVoiceToggleDescription": "Alternar captura de voz desde el micrófono de la terminal.",
"HotbarActionSessionCompactName": "Compactar sesión",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Modo Work",
"HotbarActionModeAgentDescription": "Trabaja directo en la sesión actual.",
"HotbarActionModeYoloName": "Acceso total (Work)",
"HotbarActionModeYoloDescription": "Compatibilidad: Work con acceso total (no es un modo aparte).",
"HotbarActionReasoningCycleName": "Alternar razonamiento",
"HotbarActionReasoningCycleDescription": "Alternar el esfuerzo de razonamiento configurado para el proveedor activo.",
"HotbarActionReasoningCycleAutoDisabled": "El esfuerzo de razonamiento lo controla el enrutamiento automático de modelo.",
"HotbarActionSidebarToggleName": "Alternar barra lateral",
"HotbarActionSidebarToggleDescription": "Mostrar u ocultar la barra lateral.",
"HotbarActionFileTreeToggleName": "Alternar árbol de archivos",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " No hay configuraciones disponibles.",
"ConfigNoMatchesPrefix": " Ninguna configuración coincide con ",
"ConfigFilteredSettings": " Configuraciones filtradas",
"ConfigShowing": " Mostrando",
"ConfigFooterDefault": " escribir=filtrar, Arriba/Abajo=seleccionar, Enter=editar, Esc=cerrar ",
"ConfigFooterScrollable": " escribir=filtrar, Arriba/Abajo=seleccionar, Enter=editar, PgUp/PgDn=desplazar, Esc=cerrar ",
"ConfigFooterFiltered": " escribir=filtrar, Backspace=borrar, Ctrl+U/Esc=limpiar, Enter=editar ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; las sugerencias de texto fantasma se aplican después de los próximos turnos)",
"ConfigNotificationsSetHint": "Configura con /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; se aplica a las próximas alertas)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs debe ser un número entero",
"ConfigAuditSearchProvider": "Escribe [search] provider; las próximas llamadas a web_search siguen respetando las variables de entorno.",
"ConfigAuditPromptSuggestion": "Escribe prompt_suggestion en el nivel superior; las sugerencias de texto fantasma siguen siendo opcionales.",
"ConfigAuditNotifications": "Escribe valores escalares de [notifications] y los aplica a las próximas alertas al terminar un turno.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL de API del proveedor",
"ConfigHintProviderUrl": "Endpoint actual del proveedor; Xiaomi: plan de tokens | pago por uso | URL personalizada",
"ConfigLabelModel": "Modelo activo del proveedor",
"ConfigLabelFastModel": "Modelo rápido (derivado)",
"ConfigLabelDefaultModel": "Modelo alternativo heredado (solo rutas DeepSeek)",
"ConfigLabelReasoningEffort": "Nivel de razonamiento",
"ConfigLabelApprovalMode": "Permiso de esta sesión",
"ConfigLabelPermissionPosture": "Permiso de sesiones nuevas",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Totales de versión, sesiones, funciones y errores a Codewhale y PostHog; nunca contenido ni IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Activado",
"ConfigValueTelemetryOff": "Desactivado",
"ConfigLabelStreamTimeout": "Tiempo límite del flujo",
"ConfigLabelTheme": "Tema",
"ConfigLabelLocale": "Idioma",
"ConfigLabelBackground": "Fondo",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Resaltado de fondo del razonamiento",
"ConfigLabelShowToolDetails": "Nivel de detalle de herramientas",
"ConfigLabelInlineDiffs": "Cambios de archivo en línea",
"ConfigLabelStatusIndicator": "Indicador de estado",
"ConfigLabelSynchronizedOutput": "Ritmo de salida",
"ConfigLabelCostCurrency": "Moneda de costos",
"ConfigLabelTranscriptSpacing": "Espaciado de conversación",
@@ -376,7 +408,16 @@
"ConfigLabelComposerDensity": "Densidad del editor",
"ConfigLabelComposerBorder": "Borde del editor",
"ConfigLabelComposerMultilineMode": "Modo multilínea del editor",
"ConfigLabelComposerVimMode": "Modo Vim del editor",
"ConfigLabelBracketedPaste": "Pegado entre corchetes",
"ConfigLabelPasteBurstDetection": "Detección de pegado",
"ConfigLabelMentionMenuLimit": "Límite del menú de menciones",
"ConfigLabelMentionMenuBehavior": "Comportamiento del menú de menciones",
"ConfigLabelMentionWalkDepth": "Profundidad de menciones de archivos",
"ConfigLabelWorkspaceFollowSymlinks": "Seguir enlaces simbólicos",
"ConfigLabelContextPanel": "Panel de contexto",
"ConfigLabelSessionsRail": "Barra de sesiones",
"ConfigLabelSessionAutoResume": "Reanudar automáticamente la última sesión",
"ConfigLabelAutoCompact": "Compactación automática",
"ConfigLabelAutoCompactThreshold": "Umbral de compactación",
"ConfigLabelMaxHistory": "Historial de entrada",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "Comando de objetivo",
"ConfigLabelWorkflow": "Flujo de trabajo",
"ConfigLabelFeaturePrefix": "Función: {name}",
"ConfigColumnSetting": "Ajuste",
"ConfigColumnValue": "Valor",
"ConfigColumnScope": "Alcance",
"ConfigActionOpenProvider": "Enter abre el selector de proveedor",
"ConfigActionOpenModel": "Enter abre el selector de modelo",
"ConfigActionOpenMcp": "Enter abre el administrador MCP",
@@ -416,6 +459,7 @@
"HelpKeybindings": "Atajos de teclado",
"HelpUserCommands": "Comandos de usuario",
"HelpSkills": "Habilidades",
"HelpFooterTypeFilter": " escribir para filtrar ",
"HelpFooterMove": " Arriba/Abajo mover ",
"HelpFooterJump": " PgUp/PgDn saltar ",
"HelpFooterClose": " Esc cerrar ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "Plugin sugerido: {name}",
"PluginCtaReview": "Revisar",
"PluginCtaInstall": "Instalar",
"PluginCtaReviewTrust": "Revisar confianza",
"PluginCtaEnable": "Habilitar",
"PluginCtaDismiss": "No volver a sugerir",
"PluginCtaDismissSaveFailed": "Oculto durante esta sesión; no se pudo guardar la preferencia del complemento.",
"PluginSuggestionReason": "Coincide con «{trigger}»",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "Falló la acción del plugin: {error}",
"CmdPluginNoneFound": "No se encontraron herramientas ejecutables heredadas de plugins en {dir}",
"CmdPluginNotFound": "No se encontró el plugin '{name}'",
"CmdPluginListHeader": "Herramientas ejecutables heredadas de plugins ({count}):",
"CmdPluginDetailDescription": "Descripción: {description}",
"CmdPluginDetailSchema": "Esquema:\n{schema}",
"CmdPluginDetailApproval": "Aprobación: {approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "Catálogo en caché; ejecuta `codewhale models --update` para actualizar los proveedores configurados.",
"ModelsUpdateSummary": "Catálogos de modelos: {updated} actualizados, {loaded} cargados desde Codex, {failed} fallidos, {skipped} omitidos.",
"ModelsUpdatePartial": "No se pudieron actualizar algunos catálogos. Los modelos anteriores y configurados siguen disponibles.",
"ModelsCodexHint": "Los modelos de ChatGPT se cargan mediante Codex. La hora de consulta no confirma una actualización del catálogo del proveedor.",
"ModelsSourceFallback": "Modelos incluidos o configurados; disponibilidad sin verificar.",
"CmdModelDbDescription": "Explorar la base de datos de modelos integrada",
"CmdNetworkDescription": "Gestionar reglas de red permitidas y bloqueadas",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "Ver o editar mensajes en cola",
"CmdQueueUsage": "Uso: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "Se restauraron {count} mensajes en cola de una sesión anterior. No se envían automáticamente: /queue send <n> envía uno, /queue clear los descarta.",
"CmdQueueDraftHeader": "Editando mensaje en cola:",
"CmdQueueNoMessages": "No hay mensajes en cola",
"CmdQueueListHeader": "Mensajes en cola ({count}):",
"CmdQueueTip": "Consejo: /queue send <n> para enviar ahora, /queue drop <n> para eliminar",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "{hit} hit / miss no reportado",
"CmdTokensCacheMissOnly": "hit no reportado / {miss} miss",
"CmdTokensCacheWriteTotal": "Tokens de escritura de caché (creación) en esta sesión: {write}. Se facturan por encima de la tarifa de entrada cuando el proveedor publica un recargo de escritura; consulta /cache para el detalle por turno.",
"CmdTokensContextUnknownWindow": "~{estimated} / ventana desconocida",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 sub-agente",
"FooterAgentsPlural": "{count} sub-agentes",
"HeaderAgentsChip": "sub-agentes {count}",
"FooterPressCtrlCAgain": "Presiona Ctrl+C de nuevo para salir",
"FooterWorking": "trabajando",
"FooterBalancePrefix": "saldo",
"HelpSectionActions": "Acciones",
"HelpSectionClipboard": "Portapapeles",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "no reportado",
"CmdTokensReport": "Uso de tokens:\n─────────────────────────────\nContexto activo: {active}\nÚltima entrada de API: {input} (telemetría por turno; puede contar el mismo prefijo varias veces en rondas con herramientas)\nÚltima salida de API: {output}\nHit/miss del caché: {cache} (solo para telemetría/costo)\nTokens acumulados: {total} (telemetría de uso de la sesión)\nImporte con precio: {cost}\nMensajes de API: {api_messages}\nMensajes del chat: {chat_messages}\nModelo: {model}",
"KbScrollTranscript": "Desplazar transcripción, navegar historial de entrada o seleccionar adjuntos del compositor",
"KbNavigateHistory": "Navegar historial de entrada",
"KbBrowseHistory": "Explorar historial de conversación",
"KbScrollTranscriptAlt": "Desplazar transcripción",
"KbScrollPage": "Desplazar transcripción por página",
@@ -822,6 +875,7 @@
"KbCompactContext": "Compactar el contexto de la conversación",
"KbLastMessagePager": "Abrir paginador para el último mensaje (cuando la entrada está vacía)",
"KbSelectedDetails": "Mostrar el detalle sin procesar de la herramienta o mensaje seleccionado; Ctrl+Alt+O abre la vista general de todo el turno",
"KbToolDetailsPager": "Mostrar el detalle sin procesar del elemento seleccionado (Alt+V)",
"KbExternalEditor": "Abrir borrador en el editor externo",
"KbLiveTranscript": "Abrir superposición de transcripción en vivo (auto-scroll)",
"KbBacktrackMessage": "Retroceder al mensaje anterior del usuario (izquierda/derecha, Enter para rebobinar)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "Abrir esta superposición de ayuda (cuando la entrada está vacía)",
"KbCycleWorkDock": "Recorrer la barra de trabajo (tareas, agentes, trabajos, segundo plano) o, en modo mascota, las vistas de la mascota",
"KbCycleWorkDockBack": "Recorrer la barra de trabajo o las vistas de la mascota hacia atrás",
"KbToggleHelp": "Alternar superposición de ayuda",
"KbToggleHelpSlash": "Alternar superposición de ayuda",
"HelpUsageLabel": "Uso:",
"HelpAliasesLabel": "Alias:",
"SettingsTitle": "Configuraciones:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " /mode plan para investigar y presentar un plan primero",
"HomeAgentModeYoloTip": " Shift+Tab cicla permiso: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + acceso total — herramientas sin pedir aprobación",
"HomeYoloModeCaution": " Las operaciones destructivas pueden correr al instante; usa Ask si dudas",
"HomePlanModeTip": "Plan — investiga y diseña antes de implementar",
"HomePlanModeChecklistTip": " Presenta el plan y luego cambia a Work",
"HomeGoalModeTip": "Seguimiento de Goal - Usa /goal <objetivo> para seguir un objetivo persistente",
"OnboardLanguageTitle": "Elige el idioma",
"OnboardLanguageBlurb": "Elige el idioma de la interfaz. Puedes cambiarlo en cualquier momento con `/config locale <etiqueta> --save`.",
"OnboardProviderTitle": "Elige tu proveedor de modelos",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "StepFun cobra el pago por uso y las suscripciones Step Plan en endpoints distintos. Elige el que corresponde a tu clave.",
"StepfunBillingRoutePaygOption": "Pago por uso (precio por tokens)",
"StepfunBillingRoutePlanOption": "Suscripción Step Plan (cupo del plan)",
"StepfunPlanApiKeyHint": "Para las suscripciones Step Plan de StepFun, usa la clave emitida para tu Step Plan, no una clave de pago por uso.",
"StepfunPlanRouteHint": "Esta ruta usa {route} y se cobra contra el cupo de tu Step Plan.",
"OnboardApiKeyRejectedEnv": "Se rechazó la clave de API de {provider} obtenida de {env}. Pega una clave válida para guardarla en {path} o actualiza la variable de entorno.",
"OnboardTrustTitle": "Conoce este workspace",
"OnboardTrustQuestion": "¿Codewhale puede trabajar con las instrucciones y los archivos de este workspace?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "“Mantener” deja el enmascaramiento activo en este lanzamiento; como tu configuración aún pide \"disabled\", el próximo lanzamiento volverá a preguntar.",
"RedactionGateSaveFailed": "No se pudo guardar la confirmación. El enmascaramiento sigue activo. Reintenta o mantenlo activado.",
"RedactionGateTitle": "Enmascaramiento de claves en el límite del modelo",
"OnboardOfflineOption": "Ctrl+O — explorar sin conexión: mira ahora, conecta un proveedor después.",
"OnboardOfflineNotice": "Explorando sin conexión. Nada conectado todavía: usa /provider cuando quieras conectar.",
"OnboardWelcomeTitle": "Codewhale trabaja contigo en esta carpeta.",
"OnboardWelcomeLead": "Preparémoslo todo.",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "Explica qué hace este proyecto y lista sus principales puntos de entrada.",
"OnboardSeedFolder": "Mira esta carpeta y sugiere una buena primera tarea.",
"SetupWizardTitle": "Setup",
"SetupWizardWhy": "Esta pantalla registra el progreso del setup en setup_state.json; los cambios de configuración solo se aplican mediante acciones explícitas de cada paso.",
"SetupWizardProgress": "Paso",
"SetupActionBack": "volver",
"SetupActionContinue": "continuar",
"SetupActionSkip": "saltar",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "desplazar cuerpo",
"SetupActionGuided": "previsualizar/ratificar",
"SetupActionTuneGuided": "ajustar",
"SetupActionModelDraft": "borrador del modelo",
"SetupActionFreeform": "tus palabras",
"SetupActionKeepExisting": "mantener existente",
"SetupActionUseRecommended": "usar recomendado",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "rutas de modelo",
"SetupActionFleet": "configuración de Fleet",
"SetupActionHotbar": "configuración de Hotbar",
"SetupActionRemote": "inicio remoto",
"SetupActionMode": "selector de modo",
"SetupActionConfig": "vista de config",
"SetupActionRuntimePreset": "preset",
"SetupActionApplyRuntimePreset": "previsualizar/aplicar",
"SetupActionUseBundled": "usar incluido",
"SetupActionDefer": "posponer",
"SetupActionCancel": "cancelar",
"SetupStatusNotStarted": "sin iniciar",
"SetupStatusRecommended": "recomendado",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "Idioma del setup registrado.",
"SetupConstitutionChoiceLabel": "Elección:",
"SetupConstitutionSourceLabel": "Fuente:",
"SetupConstitutionValidityLabel": "Validez:",
"SetupConstitutionPreviewLabel": "Hash de previsualización:",
"SetupConstitutionExistingLabel": "Archivo existente:",
"SetupConstitutionExpertOverrideLabel": "Override experto:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "Plugins:",
"SetupToolsMcpReviewHint": "Enter registra los datos actuales de Tools/MCP. R muestra on-ramps seguros (sin autoejecución).",
"SetupToolsMcpReviewed": "Preparación de Tools/MCP registrada.",
"SetupRemoteCloudsLabel": "Destinos cloud:",
"SetupRemoteBridgesLabel": "Puentes de chat:",
"SetupRemoteProvidersLabel": "Proveedores:",
"SetupRemoteModeLabel": "Modo remoto:",
"SetupRemoteModeLocalOnly": "Solo esta computadora:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "Copiar mensaje",
"CtxMenuCopyMessageDesc": "copiar celda de transcripción seleccionada",
"CtxMenuOpenInEditor": "Abrir en editor",
"CtxMenuOpenInEditorDesc": "abrir file:line en $EDITOR",
"CtxMenuShowCell": "Mostrar celda",
"CtxMenuShowCellDesc": "volver a mostrar esta celda de transcripción",
"CtxMenuHideCell": "Ocultar celda",
@@ -1216,9 +1290,15 @@
"FanoutCounts": "{done} completado · {running} ejecutando · {failed} falló · {pending} pendiente",
"AppModeAgent": "Work",
"AppModeAuto": "Automático",
"AppModeYolo": "Acceso total (etiqueta obsoleta)",
"AppModePlan": "Plan",
"AppModeAgentHint": "Trabajo directo en esta sesión — ediciones y shell piden aprobación",
"AppModeAutoHint": "Shell habilitado con revisión automática de riesgo",
"AppModePlanHint": "Investigación de solo lectura primero — presenta un plan antes de actuar",
"AppModeYoloHint": "Solo compatibilidad — Work + acceso total, no un modo visible",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERTAR --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Solo lee",
"ApprovalEffectChangesFiles": "Cambia archivos",
"ApprovalRiskDestructive": "No se puede deshacer",
@@ -1246,6 +1326,7 @@
"ApprovalSaveAskRuleHint": " · s permitir ahora y preguntar siempre antes de repetirlo",
"ApprovalOptionDeny": "No permitir",
"ApprovalOptionAbortTurn": "Detener este turno",
"ApprovalBlockTitle": "aprobación",
"ApprovalControlsHint": "Pg↑/↓ revisar · {details} más opciones · Esc detener",
"ApprovalOwnerHeader": "Agente: {agent} · {role}",
"ApprovalGoToAgent": "g ir al agente",
@@ -1271,6 +1352,8 @@
"ApprovalTruncationHint": " … truncado · presiona {details} para ver todos los detalles",
"ApprovalAsksWithoutGit": "Aquí no hay un repositorio Git, así que las ediciones piden permiso antes.",
"ApprovalFullAccessPolicyBlocked": "Bloqueado {tool}: Full Access no puede omitir esta política",
"ApprovalChooseHint": "Elegir: ",
"ApprovalChooseAction": "Enter para seleccionar, o presione y/a/d directamente",
"ApprovalIntentLabel": "Intención: ",
"ApprovalMoreLines": " … (+{count} líneas)",
"ApprovalProceedQuestion": "¿Quieres continuar?",
@@ -1310,10 +1393,12 @@
"ContextManualCompacting": "Compactando el contexto…",
"ContextCompactionQueued": "La compactación del contexto quedó en cola; se ejecutará después del turno activo.",
"ContextCompactionAlreadyRunning": "La compactación del contexto ya está en curso.",
"ContextCompactionQueueFull": "No se pudo poner en cola la compactación del contexto porque el motor está ocupado; inténtalo de nuevo cuando termine el turno.",
"ContextCompactionQueueClosed": "La compactación del contexto no está disponible porque el motor ya no está en ejecución.",
"ContextCompactionRouteInvalid": "No se puede compactar porque la ruta del proveedor activo no es válida: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Se detuvo la compactación del contexto; la conversación no cambió",
"ContextPurgeAbandonedOnEngineSwitch": "La limpieza de la sesión se abandonó con el motor reemplazado; la conversación no cambió",
"CtxInspTitle": "Inspector de contexto",
"CtxInspSessionContext": "Contexto de la sesión",
"CtxInspSystemPrompt": "Estructura del prompt del sistema",
"CtxInspReferences": "Referencias",
@@ -1545,21 +1630,47 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills y Plugins — On-ramps seguros\n\n/setup solo lee el inventario local. No inicia servidores MCP, no instala skills, no ejecuta plugins ni comandos no confiables.\n\nInventario actual:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (adaptadores compartidos): {hotbar_result}\n\nRutas:\n- MCP: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nBootstrap seguro (ejecútalo tú):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills\n- Plugins: /plugin · codewhale setup --plugins\n- Tools: codewhale setup --tools\n\nLas acciones con efectos secundarios siempre requieren confirmación explícita. Ver docs/MCP.md.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — conectado a través de Codewhale, nunca un segundo planificador:\n- Estado: {dsh_result}\n- Detección de solo lectura; conectar/planear/iniciar/quitar: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale solo escribe en $CODEWHALE_HOME/integrations/dsh; nunca copia claves de API ni edita archivos de DSH.",
"HotbarActionModeOperateName": "Modo Operate",
"HotbarActionModeOperateDescription": "Trabaja una solicitud duradera en paralelo hasta que esté verificada.",
"HomeOperateModeTip": "Operate — pon tu Fleet a trabajar en paralelo",
"HomeOperateModeFleetTip": " Los roles integrados usan el modelo de esta sesión; /fleet setup los personaliza",
"AppModeOperate": "Operate",
"AppModeOperateHint": "Work a fondo: meta, workers paralelos, verificado",
"HelpSubtitle": "Comandos, habilidades y atajos",
"CommandPaletteTitle": "Comando",
"CommandPaletteSubtitle": "Encuentra y ejecuta una acción",
"ConfigSubtitle": "Ajustes primero; claves crudas en detalle avanzado",
"LaunchStartTitle": "Empieza aquí",
"LaunchResumeConfirm": "¿Reanudar {title}? Haz clic otra vez o pulsa Enter para confirmar.",
"LaunchResumeConfirmTitle": "Reanudar sesión",
"LaunchResumeConfirmBody": "Esto reemplaza el contexto actual con el historial de esa sesión.",
"LaunchResumeConfirmResume": "reanudar",
"LaunchResumeConfirmCancel": "cancelar",
"LaunchWorkDescription": "Usa esta carpeta con herramientas locales; los cambios siguen tu política de aprobación.",
"LaunchChatDescription": "Solo conversación y planificación; no se modifican archivos.",
"LaunchWorkspaceGitReady": "Espacio de trabajo · {name} · espacio Git",
"LaunchWorkspaceFolderReady": "Espacio de trabajo · {name} · carpeta local",
"LaunchProviderConfigured": "Proveedor · configurado",
"LaunchProviderSetupNeeded": "Proveedor · requiere configuración",
"LaunchGroupContinue": "Continuar",
"LaunchGroupMore": "Más",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "carpeta",
"LaunchProviderConfiguredShort": "proveedor configurado",
"LaunchProviderSetupShort": "configurar proveedor",
"LaunchMenuChangelog": "Changelog",
"LaunchWorktreePrompt": "Nombra la rama/worktree, o presiona Enter para un nombre automático. Esc para volver.",
"LaunchWorktreeNeedsGit": "Un worktree nuevo requiere un repositorio Git.",
"LaunchWorktreeNameLabel": "nombre del worktree",
"LaunchHintMove": "mover",
"LaunchHintOpen": "abrir",
"LaunchTipFlags": "Tip: -w <ruta> abre un workspace; -r <id-de-sesión> reanuda directamente",
"LaunchSavedSessionSingular": "1 sesión guardada",
"LaunchSavedSessionsPlural": "{count} sesiones guardadas",
"LaunchCreatingWorktree": "Creando worktree…",
"LaunchWorktreeFailed": "El worktree falló: {error}",
"LaunchWorktreeCreated": "Nuevo worktree {path} en la rama {branch}",
"LaunchNoSavedSessions": "No hay sesiones guardadas para este workspace.",
"LaunchNoModelConnected": "ningún modelo conectado",
"DispatchNotSentNoModel": "No hay ningún modelo conectado, así que este mensaje no se envió. Volvió al cuadro de mensaje: conecta un modelo con F3 o /provider y presiona Enter para enviarlo.",
"DispatchNotSentSaveKey": "Guarda una clave: {command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "Usando {model}, un modelo que se ejecuta en esta computadora (Ollama). Presiona F3 para elegir otro.",
"ProviderPickerNotReopened": "No se pudo volver a abrir la lista de proveedores. Presiona F3 para abrirla.",
"LaunchRunCommand": "ejecuta {command}",
"LaunchMcpConnectedOne": "1 servidor MCP conectado",
"LaunchMcpConnectedMany": "{count} servidores MCP conectados",
"LaunchMcpNeedsSignInOne": "1 necesita iniciar sesión",
"LaunchMcpNeedsSignInMany": "{count} necesitan iniciar sesión",
"PhaseIdle": "inactivo",
"PhaseDraft": "borrador",
"PhaseWorking": "trabajando",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "finalizando",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "solo lectura",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "Permisos cambiados a {label}",
"FooterHintKeys": "teclas",
"FooterHintOutput": "salida",
"FooterHintContext": "contexto",
"InfoLineHelp": "ayuda",
"InfoLineContext": "contexto",
"InfoLineTtft": "ttft",
"InfoLinePeak": "hora pico",
"InfoLineOffPeak": "fuera de pico",
"InfoLineWhales": "ballenas",
"InfoLineAutomation": "automatización",
"InfoLineNotConnected": "no conectado",
"InfoLineThinking": "razonamiento: {level}",
"EmptyStateNoGit": "sin git",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "buscar cualquier modelo",
"RoutePanelHeader": "ruta",
"RouteProviderLabel": "proveedor",
"RouteModelFirstAtomic": "ruta atómica modelo-primero",
"PickerActionMove": "mover",
"PickerActionSwitch": "cambiar",
"PickerActionApply": "aplicar",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "borrar búsqueda",
"PickerActionBrowseAll": "ver todos",
"PickerActionCustom": "personalizado",
"PickerActionJump": "saltar",
"PickerActionEditKey": "editar clave",
"PickerActionModels": "modelos",
"PickerActionUnavailable": "no disponible",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "dejar de usar ese inicio de sesión",
"ProviderExternalActionChoices": "iniciar sesión con otra app",
"ProviderExternalActionReuseGrok": "reutilizar credencial externa de Grok",
"ProviderExternalHintCodexReview": "Después de {login}, presiona Enter para revisar las opciones desactivada, solo lectura y administrada.",
"ProviderExternalHintXaiReview": "Presiona Enter para el acceso de dispositivo propio de Codewhale; presiona E para revisar la reutilización de Grok CLI.",
"ProviderExternalHintXaiApiKey": "O usa XAI_API_KEY y vuelve a abrir este selector.",
"XaiAuthChoiceTitle": " Autenticación de xAI ",
"XaiAuthChoiceIntro": "Elige una fuente de credenciales explícita. El texto de la clave nunca se trata como un token OAuth.",
"XaiAuthChoiceApiKeyOption": "Clave de API de xAI — escríbela o pégala y guárdala en la ranura del proveedor xAI",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " Autenticación de ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "El inicio de sesión de suscripción se factura a tu plan de ChatGPT. La ruta de clave API de openai es otro titular de facturación.",
"ChatgptAuthChoicePkceOption": "Iniciar sesión con ChatGPT — PKCE en el navegador, tokens de Codewhale, facturación de la suscripción de ChatGPT",
"ChatgptAuthChoiceImportOption": "Importar credenciales de la CLI de Codex — consentimiento explícito de solo lectura; la CLI de Codex sigue siendo la dueña",
"ProviderExternalHintChatgptReview": "Pulsa Enter para iniciar sesión con ChatGPT; pulsa E para revisar el reúso existente de la CLI de Codex.",
"ProviderExternalActionReuseCodex": "reúso externo de Codex",
"ProviderExternalDetailScope": "Externa: acceso={access} | proveedor={provider} | origen={source} | versión={version} | {state}",
"ProviderExternalDormant": "inactivo",
"ProviderExternalOwnerPath": "Propietario/ruta: {owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "Las instantáneas y /undo están desactivados para {workspace}: un directorio raíz o personal es demasiado amplio para una instantánea segura. Empieza en un directorio de proyecto para activarlos.",
"SnapshotsHistoryRepaired": "El historial de deshacer de {workspace} estaba dañado (faltaba su último punto de restauración) y se reinició. Los puntos de restauración anteriores ya no se pueden restaurar; los turnos nuevos vuelven a estar protegidos.",
"SnapshotsFailing": "Las instantáneas están fallando para {workspace}, así que /undo no puede restaurar los turnos recientes: {limit}",
"SessionIdDivergedNotice": "La identidad de la sesión cambió bajo esta ventana: el motor ahora guarda checkpoints como {next} (antes era {previous}). Los checkpoints anteriores quedan bajo el id anterior; `codewhale sessions` lista ambos y `codewhale resume {previous}` reabre el anterior.",
"RuntimeStoreUnreadableNotice": "Almacén de ejecución de la sesión: no se pudo leer {record} en {path} ({reason}). Aparta ese archivo (o elimínalo) y vuelve a intentar; los demás registros del hilo se conservan.",
"RuntimeStoreUnwritableNotice": "Almacén de ejecución de la sesión: no se pudo escribir {record} en {path} ({reason}). Revisa el espacio libre y los permisos allí y vuelve a intentar; no se sobrescribió nada.",
"ProviderExternalSemanticsRevoke": "{semantics} | revocar: {revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "setup",
"FleetRosterWorkers": "workers",
"FleetRosterMembersCount": "{count} miembros",
"FleetRosterOperatorFirst": "El Coordinador lidera · el modelo de la sesión dirige este Fleet",
"FleetRosterOperatorRow": "Coordinador · líder",
"FleetRosterShadowBadgeProjectOverride": "guardado en este proyecto",
"FleetRosterShadowBadgePersonalIgnored": "copia guardada ignorada",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "este es tu modelo actual (la ruta del operador del equipo); cambia de modelo o usa /fleet save para modificarla",
"FleetModelReasonAlreadyPresent": "ya está en el equipo",
"FleetModelErrorNeedsRoute": "un modelo del equipo necesita un id de provider y un id de modelo",
"FleetModelErrorNeedsRole": "El agente necesita un nombre de rol (por ejemplo, `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "no hay ningún equipo seleccionado; tu equipo es solo el modelo de la sesión",
"FleetModelErrorOperatorRoute": "{route} es la ruta del operador del equipo `{fleet}`; cámbiala con /fleet save, no con remove",
"FleetModelErrorNotInFleet": "{route} no está en el equipo `{fleet}`",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ adjuntar · 1 coincidencia",
"FilePickerMatchesPlural": "@ adjuntar · {count} coincidencias",
"FilePickerScanning": "Escaneando el espacio de trabajo…",
"BehavioralTipPlanning": "¿Planificando? {key} cambia al modo Plan",
"BehavioralTipBackgroundReceipt": "Los recibos están en el panel Work — {key} abre el inspector",
"BehavioralTipClearedInput": "Borrado · {chord} restaura",
"BehavioralTipMcpValidation": "{command} inicia los servidores y muestra el motivo",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "El modelo y el razonamiento",
"SettingSubjectProvider": "El proveedor",
"SettingSubjectPermissions": "Los permisos",
"ThinkingControlledByAutoRouting": "El razonamiento lo controla el enrutamiento automático de modelos; elige primero un modelo fijo.",
"SavedAsStartupDefault": "guardado como valor predeterminado de inicio",
"ModeAlreadyActiveSavedAsDefault": "Ya estás en modo {mode}: guardado como valor predeterminado de inicio.",
"StartupDefaultNotSaved": "No se pudo guardar {setting}: {error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "el nivel de razonamiento",
"StartupDefaultSubjectModel": "el modelo",
"StartupDefaultSubjectAll": "los valores predeterminados de inicio",
"SessionsRailTitle": "Sesiones",
"SessionsRailEmpty": "Aún no hay sesiones en este espacio de trabajo",
"SessionsRailBrowseAll": "Ver todas las sesiones",
"SessionsRailShowingCount": "{shown} de {total} — ver todas",
"SessionsRailUnavailable": "Sesiones no disponibles: {error}",
"SessionsActionArchive": "archivar",
"SessionsActionShowArchived": "archivadas",
"SessionsArchived": "Sesión {id} archivada",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "agentes",
"FooterHintToManage": "gestionar",
"AgentRailQueuedCount": "{count} en cola",
"WorkbarSoFar": "{done}/{total} hasta ahora",
"WorkbarLargeWorkflow": "Flujo de trabajo grande",
"WorkbarMoreRuns": "+{count} más",
"WorkflowLineStarted": "iniciado",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "terminado con huecos",
"WorkflowLineFailed": "falló",
"WorkflowLineStopped": "detenido",
"WorkflowLineAgents": "{done}/{total} agentes",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "escribe",
"AgentFocusPostureReadOnly": "solo lectura",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell de solo lectura",
"AgentFocusPostureShellNone": "sin shell",
"GoalReceiptSet": "Meta definida: \"{objective}\" · /goal muestra el progreso · /goal pause o /goal clear la detiene",
"GoalReceiptSetOperate": "◆ meta definida · Operate sigue trabajando hasta verificarla · /goal para editarla",
"GoalControlAccepted": "Control de meta guardado; se aplicará en el siguiente límite seguro.",
"GoalControlRuntimeUnavailable": "El control de meta está guardado, pero el proceso no está disponible. Se restaurará después de reiniciar.",
"GoalStatusIdleHint": "no está en ejecución — envía un mensaje o /goal resume para continuar",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Objetivo activo · siguiente turno en {delay} · Esc, Ctrl+C o /goal pause detiene la continuación pendiente",
"GoalContinuationReady": "La continuación del objetivo está lista; los controles en cola se ejecutan antes del siguiente turno.",
"GoalContinuationStopped": "Se detuvo la continuación pendiente; el objetivo sigue activo.",
"McpCapabilitiesAdvertised": "Capacidades anunciadas: {capabilities}",
"McpCapabilitiesLegacyFallback": "Capacidades anunciadas: no proporcionadas; se usa el descubrimiento heredado",
"McpCapabilitiesNotObserved": "Capacidades anunciadas: no observadas porque el servidor no está conectado",
"PickerActionTestConnection": "probar conexión",
"ProviderCustomFormBaseUrl": "URL base",
"ProviderCustomFormModel": "Modelo predeterminado",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt tiempo →",
"ConfigCategoryAppearance": "Apariencia",
"ConfigCategoryModelsProviders": "Modelos y proveedores",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Trabajo",
"ConfigCategoryToolsMcp": "Herramientas y MCP",
"ConfigCategoryTrust": "Confianza",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "solo lectura",
"ConfigRowActionNote": "acción · no es un ajuste persistido",
"ConfigRowDiagnosticNote": "recibo observado · no editable aquí",
"ConfigNavHint": "←/→ o Tab categoría · ↑/↓ ajuste",
"ConfigActivateAgain": "Enter o vuelve a hacer clic:",
"ConfigSearchLabel": " Buscar: ",
"ConfigEditChooseLabel": "Elige:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Nunca",
"ConfigChoiceModeAct": "Actuar",
"ConfigChoiceModePlan": "Planificar (solo lectura)",
"ConfigChoiceModeOperate": "Operar",
"ConfigChoicePlacementTop": "Arriba",
"ConfigChoicePlacementBottom": "Barra inferior",
"ConfigChoicePlacementLeft": "Barra lateral izquierda",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Revisa el riesgo de las herramientas automáticamente y pregunta cuando una decisión te necesita.",
"ConfigChoiceDetailUseTuiDefault": "Quita la anulación del config raíz y usa la elección de permiso guardada en la TUI.",
"ConfigChoiceDetailFullAccess": "Las herramientas se ejecutan sin preguntar y los comandos pueden acceder a todo lo que hay en esta computadora.",
"ConfigChoiceDetailNever": "Bloquea toda herramienta que requiera aprobación.",
"ConfigChoiceDetailModeAgent": "Empieza listo para colaborar y usar herramientas.",
"ConfigChoiceDetailModePlan": "Empieza en un espacio de planificación de solo lectura.",
"ConfigChoiceDetailModeOperate": "Operate es Work a toda potencia: cada solicitud sustancial se vuelve una meta, pasa por workflows y workers paralelos, la revisa un revisor independiente y sigue hasta que está verificada.",
"ConfigChoiceDetailPlacementTop": "Muestra Tareas, Pendientes y Workers encima de la transcripción.",
"ConfigChoiceDetailPlacementBottom": "Muestra Tareas, Pendientes y Workers debajo del editor.",
"ConfigChoiceDetailPlacementLeft": "Muestra Tareas, Pendientes y Workers en una barra lateral izquierda cuando la terminal es lo bastante ancha.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Rellena el fondo del razonamiento del modelo.",
"ConfigChoiceDetailThinkingHighlightOff": "Mantiene la línea de razonamiento punteada y el texto en cursiva sin fondo relleno.",
"ConfigHintModel": "modelo de la ruta en vivo de esta sesión; Enter abre /model",
"ConfigHintFastModel": "lo usan el enrutamiento Auto y model_strength=faster de los agentes cuando este proveedor tiene un hermano conocido",
"ConfigHintProvider": "credencial, modelo y endpoint cambian juntos",
"ConfigHintApprovalMode": "solo esta sesión: Preguntar | Revisión automática | Acceso total",
"ConfigHintPermissionPosture": "predeterminado para sesiones nuevas: Preguntar | Revisión automática | Acceso total",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "entero (0 permitido) · cantidad de mensajes enviados que se conservan para recuperarlos y buscar en el historial",
"ConfigHintAutoCompactThreshold": "10..=100 · umbral de compactación: porcentaje de la longitud de contexto utilizable en que se dispara la compactación automática",
"ConfigHintDefaultModel": "respaldo heredado solo para DeepSeek; otros proveedores usan el modelo por proveedor de arriba",
"ConfigHintReasoningEffort": "default restaura el predeterminado del modelo; los modelos que siempre razonan omiten off",
"ConfigHintMcpOpen": "abre el administrador MCP · Conectar / Reconectar / Reautenticar / Diagnosticar",
"ConfigHintMcpReconnect": "reconecta MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "estado de solo lectura del flag de función de las herramientas de edición por parche",
"ConfigHintFeatureMcp": "estado de solo lectura del flag de función de las herramientas MCP",
"ConfigHintFeatureExecPolicy": "estado de solo lectura del flag de función de las herramientas de política de ejecución",
"ConfigHintFeatureVisionModel": "flag beta para soporte de imágenes de visión/modelo",
"ConfigHintGoalCommand": "/goal define objetivos, presupuestos y el estado del contexto de Trabajo",
"ConfigHintWorkflow": "/workflow ejecuta operaciones guionadas con tarjetas de ejecución de distribución/consolidación",
"LaunchMenuNewWorktree": "Nuevo worktree",
"LaunchMenuResume": "Reanudar sesión",
"LaunchMenuQuit": "Salir",
"LaunchNoticeClaude": "Claude Code detectado. Ejecuta /import-claude para revisar qué puede importarse: servidores MCP, ajustes seguros y permisos. Nada se aplica sin tu aprobación.",
"LaunchNewSession": "Nueva sesión",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ para reanudar",
"LaunchHelpLine": "/help para comandos · {dock} para la barra de trabajo",
"LaunchSeeAllSessions": "Ver todas las sesiones…",
"LaunchNoRecentSessions": "Aún no hay sesiones recientes — escribe abajo para empezar.",
"LaunchResumeFailed": "No se pudo reanudar: {error}",
"ReceiptSessionHooks": "hooks {count}",
"AutomationEditorNew": "Nueva automatización",
"AutomationEditorEdit": "Editar automatización",
"AutomationEditorSchedule": "Programación",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} listos",
"WorkflowPhaseCountOne": "{count} fase",
"WorkflowPhaseCountMany": "{count} fases",
"WorkflowPhaseOrdinal": "fase {n}/{total}",
"ModelPickerPinned": "Se fijó {route}",
"ModelPickerUnpinned": "Se dejó de fijar {route}",
"ModelPickerPinFailed": "No se pudo actualizar la fijación: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Se reemplazó el inicio de sesión anterior de Codewhale en {provider} ({account}).",
"AuthReplacedPreviousSignIn": "Se reemplazó el inicio de sesión anterior de Codewhale en {provider}.",
"AuthSameAccountAsBefore": "Es la misma cuenta que antes; para usar otra cuenta de {provider}, cierra sesión en el navegador (o usa una ventana privada) y vuelve a iniciar sesión.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN o CODEX_ACCESS_TOKEN está definido en este entorno y tiene prioridad sobre este inicio de sesión; las solicitudes seguirán usando la cuenta de ese token hasta que lo quites.",
"PinnedPromptJumpToMessage": "Ir a este mensaje",
"PlanHandoffHeader": "Plan listo",
"PlanHandoffQuestion": "¿Cómo quieres continuar?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Presiona Intro para iniciar sesión en el navegador o Esc para volver. No se necesita una clave API.",
"PluginOAuthReady": "{provider}: sesión iniciada. Elige un modelo.",
"PluginOAuthLocalLogout": "{provider}: se eliminó la sesión local. El acceso remoto no cambió.",
"CmdConnectDescription": "Conecta un proveedor de plugins con inicio de sesión en el navegador",
"CmdDisconnectDescription": "Elimina el inicio de sesión local de un proveedor de plugins",
"ExecAutoHelp": "Activa herramientas con aprobación automática y Full Access (sin sandbox del shell, modo de confianza activado), salvo que haya un sandbox más restrictivo configurado; usa --sandbox workspace-write para restringir escrituras de archivos y del shell.",
"ExecSandboxHelp": "Política de sandbox para esta ejecución; cualquier --sandbox distinto de danger-full-access (o un sandbox_mode equivalente en la configuración) desactiva el modo de confianza.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Le Runtime a fermé le flux d’événements de cette conversation ; rouvrez-la",
"MobileStreamReconnecting": "Connexion perdue ; reconnexion",
"MobileStreamConnected": "Connecté",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Un habitat partagé",
"PetHabitatHints": "{back} retour · {sound} son · {browser} apparence · {window} fenêtre",
"PetHabitatQueued": "Envoyé à l’habitat partagé. /pet on affiche l’animal et le champ de message.",
"PetWatchSoundOn": "Son activé",
"PetWatchSoundOff": "Son désactivé",
"PetWatchSoundPaused": "Son en pause",
"PetWatchSoundUnavailable": "Le son de Codewhale s’est arrêté. Vérifiez FFmpeg (ffplay) et la sortie audio, puis réactivez le son.",
"CmdPetDescription": "Utiliser l’animal animé comme vue principale de Codewhale",
"ConfigLabelPetMode": "Mode compagnon",
"ConfigHintPetMode": "Utiliser le compagnon animé comme vue principale au démarrage de Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "mode mascotte désactivé",
"PetViewOpen": "habitat ouvert",
"PetViewClosed": "habitat fermé",
"PetWatchRestored": "/pet a restauré l’habitat de cette session. En attente de nouvelles données de télémétrie.",
"PetWatchStorageUnavailable": "Watch n’a pas pu restaurer ou enregistrer cet habitat. Les fichiers existants ont été conservés. Utilisez {command} pour exporter cette exécution.",
"PetWatchExported": "Enregistrement Watch sauvegardé : {path}",
"PetWatchExportFailed": "Impossible de sauvegarder l’enregistrement Watch. Il reste en mémoire.",
"PetWatchExportQueued": "Sauvegarde de l’enregistrement Watch…",
"PetWatchExportUnavailable": "Ouvrez /pet dans une session enregistrée ou attendez la fin de l’exportation en cours.",
"PetUnobserved": "non observé",
"PetOffline": "hors ligne — codewhale pet serve le réveille",
"PetDozing": "assoupi",
"PetWatchUnavailable": "La télémétrie de la mascotte est en pause. /pet on réessaie.",
"ConversationChangedBeforeUndo": "La conversation a changé avant la fin de l’annulation. Rien n’a été annulé et aucune nouvelle tentative n’a été envoyée. Vérifiez la conversation actuelle avant de réessayer.",
"SessionArchiveExported": "Session exportée",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Modifier",
"ExtensionsHooksAddLabel": "Ajouter un hook",
"ExtensionsHooksAddDescription": "Ouvre le fichier de hooks de ce projet dans votre éditeur",
"ExtensionsActionReload": "recharger",
"ExtensionsActionConnect": "connecter",
"ExtensionsActionReconnect": "reconnecter",
"ExtensionsActionReauth": "réauthentifier",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "connecté",
"ExtensionsStateEnabled": "activé",
"ExtensionsStateError": "erreur",
"ExtensionsStateInactive": "inactif",
"ExtensionsStateInapplicable": "non applicable",
"ExtensionsStateInvalid": "invalide",
"ExtensionsStateNotInspected": "non inspecté",
"ExtensionsStateDisconnected": "déconnecté",
"ExtensionsStateRejected": "rejeté",
"ExtensionsStateReviewedCandidate": "candidat examiné",
"ExtensionsStateUnderEvaluation": "en cours d'évaluation",
"ExtensionsStateUnstaged": "non préparé",
"ExtensionsStateUnsupported": "non pris en charge",
"ExtensionsStateWarning": "avertissement",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ envoyer dans ce tour",
"ComposerHintLongDraft": "{shortcut} : éditeur externe",
"PendingSendingIntoTurnPrefix": " ↳ Envoi dans ce tour : ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Impossible d'envoyer dans ce tour : ",
"PendingEditingFollowUpPrefix": " ↳ Modification du suivi : ",
"PendingQueuedOnePrefix": "En file #1 : ",
"PendingQueuedManyPrefix": "En file {count} · suivant : ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Réflexion terminée",
"TranscriptThoughtFor": "Réflexion pendant {duration}",
"TelemetryNoticeDefaultOn": "Les statistiques d’utilisation sont activées par défaut. Partager les totaux de versions, plateformes, sessions, fonctions et erreurs avec Codewhale et son sous-traitant PostHog. Compte aussi les fournisseurs, les modèles du catalogue public, les totaux de jetons et l’usage des outils intégrés. Aucun contenu ni IP. docs/TELEMETRY.md Désactiver : codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Statistiques d’utilisation de Codewhale",
"TelemetryNoticeBody": "Codewhale compte : la version exécutée, le système d'exploitation et la\nfamille du processeur, la durée et le résultat de la session, ainsi que les\ntotaux de fonctions et d'erreurs.\n\nIl compte aussi les fournisseurs et modèles du catalogue public que vous utilisez, leurs totaux de jetons et la fréquence d’exécution de chaque outil intégré.\n\nIl ne collecte jamais vos conversations, votre code, vos prompts, fichiers,\nnoms de fichiers, de dépôts ou de branches, contenus du modèle ou identifiants\n— et n'envoie jamais de chronologie de l'activité par tour ou par outil.\n\nVous êtes identifié uniquement par un identifiant aléatoire stocké sur cette\nmachine, remplacé tous les 90 jours. Changez d'avis à tout moment :\n codewhale config set telemetry false\n\nSchéma complet, champ par champ : docs/TELEMETRY.md\n\nLes statistiques d’utilisation sont activées par défaut. Codewhale et PostHog traitent ces statistiques lorsque l’envoi est configuré. Aucune IP n’est collectée.",
"TelemetryNoticeCompactBody": "Compte: version, OS/CPU, durée/résultat, fonctions/erreurs.\nAussi : fournisseur/modèle, jetons, outils.\nID local aléatoire change/90j.\nJamais: chats/code/prompts/fichiers/noms; contenu modèle/identifiants; tours/outils.\nVoir: docs/TELEMETRY.md\nArrêt: codewhale config set telemetry false\nLes statistiques d’utilisation sont activées par défaut. Codewhale et PostHog traitent ces statistiques lorsque l’envoi est configuré. Aucune IP n’est collectée.",
"TelemetryNoticeChoiceKeep": "Oui, conserver le comptage anonyme",
"TelemetryNoticeChoiceDisable": "Non, désactiver le suivi",
"TelemetryNoticeActionChoose": "choisir",
"TelemetryNoticeActionConfirm": "confirmer",
"TelemetryNoticeActionExit": "quitter",
"TelemetryNoticeReceiptEnabled": "Le comptage anonyme est activé. Les conversations et le code ne sont jamais collectés. Modifiez-le dans /settings ; schéma : docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Le comptage anonyme de l'utilisation est désactivé. La question ne sera plus posée.",
"TelemetryNoticeReceiptEnabledUnsaved": "Le comptage anonyme est activé pour cette session. Codewhale n'a pas pu enregistrer cet avis et le montrera de nouveau. Modifiez-le dans /settings ; schéma : docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Le comptage anonyme est désactivé pour cette session. Codewhale n'a pas pu enregistrer le choix et reposera la question au prochain lancement.",
"TelemetryPreferenceEnabledNextLaunch": "Le comptage anonyme sera activé au prochain lancement. Les conversations et le code ne sont jamais collectés.",
"TelemetryPreferenceDisabled": "Le comptage anonyme est désactivé. Les données locales de télémétrie ont été effacées.",
"TelemetryPreferenceDisabledWithWarning": "Le comptage anonyme est désactivé, mais une partie du nettoyage demande votre attention : {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Aucune action de Hotbar disponible.",
"HotbarSetupRecommended": "rec",
"HotbarSetupEmptySlot": "vide",
"HotbarSetupHelp": "Tab/Shift+Tab source Up/Down action 1-8 slot Enter assigner Space basculer Delete effacer s enregistrer Esc annuler",
"HotbarActionVoiceToggleName": "Saisie vocale",
"HotbarActionVoiceToggleDescription": "Activer ou couper la capture vocale du micro du terminal.",
"HotbarActionSessionCompactName": "Compacter la session",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Mode Work",
"HotbarActionModeAgentDescription": "Travailler directement dans la session en cours.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Compatibilité : Work avec les permissions Full Access (pas un mode à part).",
"HotbarActionReasoningCycleName": "Cycler le raisonnement",
"HotbarActionReasoningCycleDescription": "Cycler l'effort de raisonnement configuré pour le fournisseur actif.",
"HotbarActionReasoningCycleAutoDisabled": "L'effort de raisonnement est contrôlé par le routage automatique du modèle.",
"HotbarActionSidebarToggleName": "Basculer la barre latérale",
"HotbarActionSidebarToggleDescription": "Afficher ou masquer la barre latérale.",
"HotbarActionFileTreeToggleName": "Basculer l'arborescence",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Aucun paramètre disponible.",
"ConfigNoMatchesPrefix": " Aucun paramètre ne correspond à ",
"ConfigFilteredSettings": " Paramètres filtrés",
"ConfigShowing": " Affichage",
"ConfigFooterDefault": " taper=filtrer, Up/Down=sélection, Enter=éditer, Esc=fermer ",
"ConfigFooterScrollable": " taper=filtrer, Up/Down=sélection, Enter=éditer, PgUp/PgDn=défiler, Esc=fermer ",
"ConfigFooterFiltered": " taper=filtrer, Backspace=effacer, Ctrl+U/Esc=vider, Enter=éditer ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope} ; les suggestions fantômes s’appliquent après les prochains tours)",
"ConfigNotificationsSetHint": "Définissez avec /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope} ; s’applique aux prochaines alertes)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs doit être un nombre entier",
"ConfigAuditSearchProvider": "Écrit [search] provider ; les prochains appels web_search respectent toujours les remplacements d’environnement.",
"ConfigAuditPromptSuggestion": "Écrit prompt_suggestion au niveau racine ; les suggestions fantômes restent optionnelles.",
"ConfigAuditNotifications": "Écrit les valeurs scalaires de [notifications] et les applique aux prochaines alertes de fin de tour.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL de l'API du fournisseur",
"ConfigHintProviderUrl": "Endpoint actuel du fournisseur ; Xiaomi : forfait de jetons | paiement à l’usage | URL personnalisée",
"ConfigLabelModel": "Modèle actif du fournisseur",
"ConfigLabelFastModel": "Modèle rapide (dérivé)",
"ConfigLabelDefaultModel": "Modèle de secours hérité (routes DeepSeek uniquement)",
"ConfigLabelReasoningEffort": "Niveau de raisonnement",
"ConfigLabelApprovalMode": "Permission de cette session",
"ConfigLabelPermissionPosture": "Permission des nouvelles sessions",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Totaux de versions, sessions, fonctions et erreurs vers Codewhale et PostHog ; jamais de contenu ni d'IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Activé",
"ConfigValueTelemetryOff": "Désactivé",
"ConfigLabelStreamTimeout": "Délai du flux",
"ConfigLabelTheme": "Thème",
"ConfigLabelLocale": "Langue",
"ConfigLabelBackground": "Arrière-plan",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Surlignage du fond du raisonnement",
"ConfigLabelShowToolDetails": "Niveau de détail des outils",
"ConfigLabelInlineDiffs": "Modifications de fichiers en ligne",
"ConfigLabelStatusIndicator": "Indicateur d'état",
"ConfigLabelSynchronizedOutput": "Cadence de sortie",
"ConfigLabelCostCurrency": "Devise des coûts",
"ConfigLabelTranscriptSpacing": "Espacement de la transcription",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "Densité du composer",
"ConfigLabelComposerBorder": "Bordure du composer",
"ConfigLabelComposerMultilineMode": "Mode multiligne du composer",
"ConfigLabelComposerVimMode": "Mode Vim du composer",
"ConfigLabelBracketedPaste": "Collage encadré",
"ConfigLabelPasteBurstDetection": "Détection de collage",
"ConfigLabelMentionMenuLimit": "Limite du menu de mentions",
"ConfigLabelMentionMenuBehavior": "Comportement du menu de mentions",
"ConfigLabelMentionWalkDepth": "Profondeur des mentions de fichiers",
"ConfigLabelWorkspaceFollowSymlinks": "Suivre les liens symboliques",
"ConfigLabelContextPanel": "Panneau de contexte",
"ConfigLabelAutoCompact": "Compaction automatique",
"ConfigLabelAutoCompactThreshold": "Seuil de compaction",
"ConfigLabelMaxHistory": "Historique de saisie",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "Commande d'objectif",
"ConfigLabelWorkflow": "Workflow",
"ConfigLabelFeaturePrefix": "Fonctionnalité : {name}",
"ConfigColumnSetting": "Paramètre",
"ConfigColumnValue": "Valeur",
"ConfigColumnScope": "Portée",
"ConfigActionOpenProvider": "Enter ouvre le sélecteur de fournisseur",
"ConfigActionOpenModel": "Enter ouvre le sélecteur de modèle",
"ConfigActionOpenMcp": "Entrée ouvre le gestionnaire MCP",
@@ -415,6 +456,7 @@
"HelpKeybindings": "Raccourcis clavier",
"HelpUserCommands": "Commandes utilisateur",
"HelpSkills": "Skills",
"HelpFooterTypeFilter": " taper pour filtrer ",
"HelpFooterMove": " Up/Down déplacer ",
"HelpFooterJump": " PgUp/PgDn sauter ",
"HelpFooterClose": " Esc fermer ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "Plugin suggéré : {name}",
"PluginCtaReview": "Examiner",
"PluginCtaInstall": "Installer",
"PluginCtaReviewTrust": "Examiner la confiance",
"PluginCtaEnable": "Activer",
"PluginCtaDismiss": "Ne plus suggérer",
"PluginCtaDismissSaveFailed": "Masqué pour cette session ; impossible d’enregistrer la préférence du plugin.",
"PluginSuggestionReason": "Correspond à « {trigger} »",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "Échec de l'action du plugin : {error}",
"CmdPluginNoneFound": "Aucun outil de plugin exécutable hérité trouvé dans {dir}",
"CmdPluginNotFound": "Plugin '{name}' introuvable",
"CmdPluginListHeader": "Outils de plugins exécutables hérités ({count}) :",
"CmdPluginDetailDescription": "Description : {description}",
"CmdPluginDetailSchema": "Schéma :\n{schema}",
"CmdPluginDetailApproval": "Approbation : {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "Catalogue en cache ; lancez `codewhale models --update` pour actualiser les fournisseurs configurés.",
"ModelsUpdateSummary": "Catalogues de modèles : {updated} actualisés, {loaded} chargés depuis Codex, {failed} en échec, {skipped} ignorés.",
"ModelsUpdatePartial": "Certains catalogues n’ont pas pu être actualisés. Les modèles précédents et configurés restent disponibles.",
"ModelsCodexHint": "Les modèles ChatGPT sont chargés via Codex. L’heure de consultation ne confirme pas une actualisation du catalogue du fournisseur.",
"ModelsSourceFallback": "Modèles fournis ou configurés ; disponibilité non vérifiée.",
"CmdModelDbDescription": "Parcourir la base de modèles intégrée",
"CmdNetworkDescription": "Gérer les règles réseau d'autorisation et de refus",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "Voir ou modifier les messages en file",
"CmdQueueUsage": "Usage : /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "{count} message(s) en file restauré(s) d'une session précédente. Ils ne partent pas automatiquement : /queue send <n> en envoie un, /queue clear les supprime.",
"CmdQueueDraftHeader": "Modification du message en file :",
"CmdQueueNoMessages": "Aucun message en file",
"CmdQueueListHeader": "Messages en file ({count}) :",
"CmdQueueTip": "Astuce : /queue send <n> pour envoyer maintenant, /queue drop <n> pour retirer",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} hit / {miss} miss",
"CmdTokensCacheHitOnly": "{hit} hit / miss non rapporté",
"CmdTokensCacheMissOnly": "hit non rapporté / {miss} miss",
"CmdTokensContextUnknownWindow": "~{estimated} / fenêtre inconnue",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 agent",
"FooterAgentsPlural": "{count} agents",
"HeaderAgentsChip": "agents {count}",
"FooterPressCtrlCAgain": "Appuyez à nouveau sur Ctrl+C pour quitter",
"FooterWorking": "en cours",
"FooterBalancePrefix": "solde",
"HelpSectionActions": "Actions",
"HelpSectionClipboard": "Presse-papiers",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "non rapporté",
"CmdTokensReport": "Usage de tokens :\n ─────────────────────────────\n Contexte actif : {active}\n Dernière entrée API : {input} (télémétrie du tour ; peut compter le préfixe répété entre les rounds d'outils)\n Dernière sortie API : {output}\n Hit/miss du cache : {cache} (télémétrie/coût uniquement)\n Tokens cumulés : {total} (télémétrie d'usage de la session)\n Coût approx. session : {cost}\n Messages API : {api_messages}\n Messages du chat : {chat_messages}\n Modèle : {model}",
"KbScrollTranscript": "Faire défiler la transcription, naviguer dans l'historique de saisie ou sélectionner des pièces jointes du composer",
"KbNavigateHistory": "Naviguer dans l'historique de saisie",
"KbBrowseHistory": "Parcourir l'historique de la conversation",
"KbScrollTranscriptAlt": "Faire défiler la transcription",
"KbScrollPage": "Faire défiler la transcription page par page",
@@ -807,6 +858,7 @@
"KbCompactContext": "Compacter le contexte de la conversation",
"KbLastMessagePager": "Ouvrir le pager du dernier message (quand la saisie est vide)",
"KbSelectedDetails": "Afficher le détail brut de l'outil ou du message sélectionné ; Ctrl+Alt+O ouvre la vue d'ensemble du tour",
"KbToolDetailsPager": "Afficher le détail brut de l'élément sélectionné (Alt+V)",
"KbExternalEditor": "Ouvrir le brouillon du composer dans un éditeur externe",
"KbLiveTranscript": "Ouvrir la transcription en direct (Ctrl+Shift+T ; défilement automatique)",
"KbBacktrackMessage": "Revenir à un message utilisateur précédent (Gauche/Droite pour naviguer, Enter pour rembobiner)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "Ouvrir cette aide (quand la saisie est vide)",
"KbCycleWorkDock": "Parcourir la barre de travail (tâches, agents, jobs, arrière-plan) ou, en mode compagnon, les vues de la mascotte",
"KbCycleWorkDockBack": "Parcourir la barre de travail ou les vues de la mascotte en arrière",
"KbToggleHelp": "Basculer l'aide",
"KbToggleHelpSlash": "Basculer l'aide",
"HelpUsageLabel": "Usage :",
"HelpAliasesLabel": "Alias :",
"SettingsTitle": "Paramètres :",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan pour d'abord rechercher et présenter un plan",
"HomeAgentModeYoloTip": " Shift+Tab cycle la permission : Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — les outils s'exécutent sans demande d'approbation",
"HomeYoloModeCaution": " Les opérations destructives peuvent s'exécuter immédiatement ; préférez Ask en cas de doute",
"HomePlanModeTip": "Plan — recherche et conception avant l'implémentation",
"HomePlanModeChecklistTip": " Présentez un plan et l'avancement des tâches, puis passez à Work",
"HomeGoalModeTip": "Suivi d'objectif — définissez /goal <objectif> pour poursuivre des objectifs",
"OnboardLanguageTitle": "Choisissez votre langue",
"OnboardLanguageBlurb": "Choisissez la langue de l'interface. Vous pouvez la changer à tout moment avec `/config locale <tag> --save`.",
"OnboardProviderTitle": "Choisissez votre fournisseur de modèles",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "« Garder » laisse le masquage actif pour ce lancement ; comme la configuration demande toujours \"disabled\", le prochain lancement redemandera.",
"RedactionGateSaveFailed": "Impossible d’enregistrer la confirmation. Le masquage reste actif. Réessayez ou conservez-le activé.",
"RedactionGateTitle": "Masquage des clés à la frontière du modèle",
"OnboardOfflineOption": "Ctrl+O — explorer hors ligne : regardez maintenant, connectez un fournisseur plus tard.",
"OnboardOfflineNotice": "Exploration hors ligne. Rien n'est encore connecté — lancez /provider quand vous voulez vous connecter.",
"OnboardWelcomeTitle": "Codewhale travaille avec vous dans ce dossier.",
"OnboardWelcomeLead": "Préparons tout.",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "Expliquez ce que fait ce projet et listez ses principaux points d'entrée.",
"OnboardSeedFolder": "Regardez ce dossier et proposez une bonne première tâche.",
"SetupWizardTitle": "Setup",
"SetupWizardWhy": "Cet écran enregistre la progression du setup dans setup_state.json ; les changements de config ne sont appliqués que par des actions d'étape explicites.",
"SetupWizardProgress": "Étape",
"SetupActionBack": "retour",
"SetupActionContinue": "continuer",
"SetupActionSkip": "ignorer",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "défiler le corps",
"SetupActionGuided": "aperçu/ratifier",
"SetupActionTuneGuided": "ajuster",
"SetupActionModelDraft": "brouillon du modèle",
"SetupActionFreeform": "vos mots",
"SetupActionKeepExisting": "garder l'existant",
"SetupActionUseRecommended": "utiliser la recommandation",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "routes de modèle",
"SetupActionFleet": "setup Fleet",
"SetupActionHotbar": "setup Hotbar",
"SetupActionRemote": "accès distant",
"SetupActionMode": "sélecteur de mode",
"SetupActionConfig": "vue config",
"SetupActionRuntimePreset": "préréglage",
"SetupActionApplyRuntimePreset": "aperçu/appliquer",
"SetupActionUseBundled": "utiliser l'intégré",
"SetupActionDefer": "reporter",
"SetupActionCancel": "annuler",
"SetupStatusNotStarted": "pas commencé",
"SetupStatusRecommended": "recommandé",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "Langue du setup enregistrée.",
"SetupConstitutionChoiceLabel": "Choix :",
"SetupConstitutionSourceLabel": "Source :",
"SetupConstitutionValidityLabel": "Validité :",
"SetupConstitutionPreviewLabel": "Hash de l'aperçu :",
"SetupConstitutionExistingLabel": "Fichier existant :",
"SetupConstitutionExpertOverrideLabel": "Dérogation experte :",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "Plugins :",
"SetupToolsMcpReviewHint": "Enter enregistre ce snapshot du setup. Appuyez sur R pour des accès sûrs (sans exécution automatique).",
"SetupToolsMcpReviewed": "Disponibilité Outils/MCP enregistrée.",
"SetupRemoteCloudsLabel": "Cibles cloud :",
"SetupRemoteBridgesLabel": "Bridges de chat :",
"SetupRemoteProvidersLabel": "Fournisseurs :",
"SetupRemoteModeLabel": "Mode distant :",
"SetupRemoteModeLocalOnly": "Cet ordinateur uniquement :",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "Copier le message",
"CtxMenuCopyMessageDesc": "copier la cellule de transcription cliquée",
"CtxMenuOpenInEditor": "Ouvrir dans l'éditeur",
"CtxMenuOpenInEditorDesc": "ouvrir file:line dans $EDITOR",
"CtxMenuShowCell": "Afficher la cellule",
"CtxMenuShowCellDesc": "réafficher cette cellule de transcription",
"CtxMenuHideCell": "Masquer la cellule",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} terminé · {running} en cours · {failed} échoué · {pending} en attente",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (étiquette de mode obsolète)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Travail direct dans cette session — les éditions et le shell demandent une approbation",
"AppModeAutoHint": "Shell activé avec revue automatique des risques",
"AppModePlanHint": "Recherche en lecture seule d'abord — présentez un plan avant d'agir",
"AppModeYoloHint": "Compatibilité uniquement — Work + Full Access, pas un mode visible",
"AppModeOperateHint": "Work à fond : objectif, workers parallèles, vérifié",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERTION --",
"VimModeVisual": "-- VISUEL --",
"ApprovalEffectReadsOnly": "Lecture seule",
"ApprovalEffectChangesFiles": "Modifie des fichiers",
"ApprovalRiskDestructive": "Irréversible",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s autoriser maintenant et toujours demander avant de recommencer",
"ApprovalOptionDeny": "Ne pas autoriser",
"ApprovalOptionAbortTurn": "Arrêter ce tour",
"ApprovalBlockTitle": "approbation",
"ApprovalControlsHint": "Pg↑/↓ réviser · {details} plus d'options · Esc arrêter",
"ApprovalOwnerHeader": "Agent : {agent} · {role}",
"ApprovalGoToAgent": "g aller à l'agent",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … tronqué · appuyez sur {details} pour tous les détails",
"ApprovalAsksWithoutGit": "Pas de dépôt Git ici : les modifications demandent d'abord votre accord.",
"ApprovalFullAccessPolicyBlocked": "{tool} bloqué : Full Access ne peut pas contourner cette politique",
"ApprovalChooseHint": "Choix : ",
"ApprovalChooseAction": "Enter pour l'option sélectionnée, ou appuyez directement sur y/a/d",
"ApprovalIntentLabel": "Intention : ",
"ApprovalMoreLines": " … (+{count} lignes)",
"ApprovalProceedQuestion": "Voulez-vous continuer ?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "Compression du contexte en cours…",
"ContextCompactionQueued": "La compression du contexte a été mise en file d’attente ; elle s’exécutera après le tour actif.",
"ContextCompactionAlreadyRunning": "La compression du contexte est déjà en cours.",
"ContextCompactionQueueFull": "La compression du contexte n’a pas pu être mise en file d’attente car le moteur est occupé ; réessayez une fois le tour terminé.",
"ContextCompactionQueueClosed": "La compression du contexte est indisponible car le moteur ne fonctionne plus.",
"ContextCompactionRouteInvalid": "Impossible de compacter, car la route du fournisseur actif n’est pas valide : {error}",
"ContextCompactionStoppedOnEngineSwitch": "Compression du contexte arrêtée ; la conversation n’a pas été modifiée",
"ContextPurgeAbandonedOnEngineSwitch": "Nettoyage de la session abandonné avec le moteur remplacé ; la conversation n’a pas été modifiée",
"CtxInspTitle": "Inspecteur de contexte",
"CtxInspSessionContext": "Contexte de la session",
"CtxInspSystemPrompt": "Structure du prompt système",
"CtxInspReferences": "Références",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — Amorçages sûrs\n\n/setup ne fait que lire l'inventaire local. Il ne démarre jamais de serveurs MCP, n'installe pas de skills, n'exécute pas de plugins ni de commandes non fiables.\n\nInventaire actuel :\n- MCP : {mcp_result}\n- Skills : {skills_result}\n- Répertoire tools : {tools_result}\n- Plugins : {plugins_result}\n- Hotbar (adaptateurs partagés) : {hotbar_result}\n\nChemins (home masqué) :\n- Config MCP : {mcp_path}\n- Skills : {skills_path}\n- Plugins : {plugins_path}\n\nAmorçage sûr (à exécuter vous-même dans un terminal normal ou une commande TUI) :\n- MCP : /mcp · codewhale mcp init · codewhale doctor\n- Skills : /skills · codewhale setup --skills · /skills install <spec>\n- Plugins : /plugin · codewhale setup --plugins\n- Répertoire tools : codewhale setup --tools\n\nLes actions à effets de bord exigent toujours une confirmation explicite. Les commandes de plugins restent distinctes des commandes slash ; la source de plugins du Hotbar reste différée jusqu'à l'arrivée des gates d'approbation.\n\nVoir docs/MCP.md et docs/skills/README.md pour ce qui nécessite encore une configuration externe manuelle.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh) :",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — connecté via Codewhale, jamais un second ordonnanceur :\n- État : {dsh_result}\n- Détection en lecture seule ; connecter/planifier/lancer/retirer : codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale n'écrit que dans $CODEWHALE_HOME/integrations/dsh ; il ne copie jamais de clés d'API et ne modifie aucun fichier DSH.",
"HotbarActionModeOperateName": "Mode Operate",
"HotbarActionModeOperateDescription": "Traite une demande durable en parallèle jusqu'à ce qu'elle soit vérifiée.",
"HomeOperateModeTip": "Operate — faites travailler votre Fleet en parallèle",
"HomeOperateModeFleetTip": " Les rôles intégrés utilisent le modèle de cette session ; /fleet setup les personnalise",
"HelpSubtitle": "Commandes, compétences et raccourcis",
"CommandPaletteTitle": "Commande",
"CommandPaletteSubtitle": "Trouvez et exécutez une action",
"ConfigSubtitle": "Réglages d'abord ; clés brutes dans le détail avancé",
"LaunchStartTitle": "Commencer ici",
"LaunchResumeConfirm": "Reprendre {title} ? Cliquez à nouveau ou appuyez sur Entrée pour confirmer.",
"LaunchResumeConfirmTitle": "Reprendre la session",
"LaunchResumeConfirmBody": "Cela remplace le contexte actuel par l'historique de cette session.",
"LaunchResumeConfirmResume": "reprendre",
"LaunchResumeConfirmCancel": "annuler",
"LaunchWorkDescription": "Utilisez ce dossier avec les outils locaux ; les modifications suivent votre politique d’approbation.",
"LaunchChatDescription": "Discussion et planification uniquement ; aucun fichier n’est modifié.",
"LaunchWorkspaceGitReady": "Espace de travail · {name} · espace Git",
"LaunchWorkspaceFolderReady": "Espace de travail · {name} · dossier local",
"LaunchProviderConfigured": "Fournisseur · configuré",
"LaunchProviderSetupNeeded": "Fournisseur · configuration requise",
"LaunchGroupContinue": "Continuer",
"LaunchGroupMore": "Plus",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "dossier",
"LaunchProviderConfiguredShort": "fournisseur configuré",
"LaunchProviderSetupShort": "configurer fournisseur",
"LaunchMenuChangelog": "Changelog",
"LaunchWorktreePrompt": "Nommez la branche/worktree, ou appuyez sur Enter pour un nom automatique. Esc pour revenir.",
"LaunchWorktreeNeedsGit": "Un nouveau worktree nécessite un dépôt Git.",
"LaunchWorktreeNameLabel": "nom du worktree",
"LaunchHintMove": "déplacer",
"LaunchHintOpen": "ouvrir",
"LaunchTipFlags": "Astuce : -w <path> ouvre un workspace ; -r <session-id> reprend directement",
"LaunchSavedSessionSingular": "1 session enregistrée",
"LaunchSavedSessionsPlural": "{count} sessions enregistrées",
"LaunchCreatingWorktree": "Création du worktree…",
"LaunchWorktreeFailed": "Échec du worktree : {error}",
"LaunchWorktreeCreated": "Nouveau worktree {path} sur la branche {branch}",
"LaunchNoSavedSessions": "Aucune session enregistrée pour ce workspace.",
"LaunchNoModelConnected": "aucun modèle connecté",
"DispatchNotSentNoModel": "Aucun modèle n'est connecté, ce message n'a donc pas été envoyé. Il est de retour dans la zone de saisie : connectez un modèle avec F3 ou /provider, puis appuyez sur Enter pour l'envoyer.",
"DispatchNotSentSaveKey": "Enregistrer une clé : {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "Utilisation de {model}, un modèle qui tourne sur cet ordinateur (Ollama). Appuyez sur F3 pour en choisir un autre.",
"ProviderPickerNotReopened": "Impossible de rouvrir la liste des fournisseurs. Appuyez sur F3 pour l'ouvrir.",
"LaunchRunCommand": "lancez {command}",
"LaunchMcpConnectedOne": "1 serveur MCP connecté",
"LaunchMcpConnectedMany": "{count} serveurs MCP connectés",
"LaunchMcpNeedsSignInOne": "1 nécessite une connexion",
"LaunchMcpNeedsSignInMany": "{count} nécessitent une connexion",
"PhaseIdle": "inactif",
"PhaseDraft": "brouillon",
"PhaseWorking": "travail en cours",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "finalisation",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "lecture seule",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "jamais",
"PermissionsChangedReceipt": "Permissions changées en {label}",
"FooterHintKeys": "touches",
"FooterHintOutput": "sortie",
"FooterHintContext": "contexte",
"InfoLineHelp": "aide",
"InfoLineContext": "contexte",
"InfoLineTtft": "ttft",
"InfoLinePeak": "heures pleines",
"InfoLineOffPeak": "heures creuses",
"InfoLineWhales": "baleines",
"InfoLineAutomation": "automatisation",
"InfoLineNotConnected": "non connecté",
"InfoLineThinking": "réflexion : {level}",
"EmptyStateNoGit": "pas de git",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "chercher un modèle",
"RoutePanelHeader": "route",
"RouteProviderLabel": "fournisseur",
"RouteModelFirstAtomic": "route atomique modèle-d'abord",
"PickerActionMove": "déplacer",
"PickerActionSwitch": "changer",
"PickerActionApply": "appliquer",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "effacer la recherche",
"PickerActionBrowseAll": "tout parcourir",
"PickerActionCustom": "personnalisé",
"PickerActionJump": "aller à",
"PickerActionEditKey": "modifier la clé",
"PickerActionModels": "modèles",
"PickerActionUnavailable": "indisponible",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "ne plus utiliser cette connexion",
"ProviderExternalActionChoices": "se connecter via une autre app",
"ProviderExternalActionReuseGrok": "réutilisation externe de Grok",
"ProviderExternalHintCodexReview": "Après {login}, appuyez sur Enter pour revoir les choix d'accès désactivé/lecture seule/géré.",
"ProviderExternalHintXaiReview": "Appuyez sur Enter pour la connexion appareil gérée par Codewhale ; appuyez sur E pour revoir la réutilisation existante du Grok CLI.",
"ProviderExternalHintXaiApiKey": "Ou utilisez XAI_API_KEY et rouvrez ce sélecteur.",
"XaiAuthChoiceTitle": " Authentification xAI ",
"XaiAuthChoiceIntro": "Choisissez une source d’identifiants explicite. Le texte de la clé n’est jamais traité comme un jeton OAuth.",
"XaiAuthChoiceApiKeyOption": "Clé API xAI — saisissez-la ou collez-la, puis enregistrez-la dans l’emplacement du fournisseur xAI",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " Authentification ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "La connexion d'abonnement est facturée sur votre forfait ChatGPT. La route de clé API openai a un autre titulaire de facturation.",
"ChatgptAuthChoicePkceOption": "Se connecter avec ChatGPT — PKCE dans le navigateur, jetons détenus par Codewhale, facturation de l'abonnement ChatGPT",
"ChatgptAuthChoiceImportOption": "Importer les identifiants de la CLI Codex — consentement explicite en lecture seule ; la CLI Codex reste propriétaire",
"ProviderExternalHintChatgptReview": "Appuyez sur Entrée pour vous connecter avec ChatGPT ; appuyez sur E pour examiner la réutilisation existante de la CLI Codex.",
"ProviderExternalActionReuseCodex": "réutilisation Codex externe",
"ProviderExternalDetailScope": "Externe : accès={access} | fournisseur={provider} | source={source} | version={version} | {state}",
"ProviderExternalDormant": "dormant",
"ProviderExternalOwnerPath": "Propriétaire/chemin : {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "Les instantanés et /undo sont désactivés pour {workspace} : un répertoire personnel ou racine est trop vaste pour un instantané sûr. Démarrez dans un répertoire de projet pour les activer.",
"SnapshotsHistoryRepaired": "L'historique d'annulation de {workspace} était endommagé (son dernier point de restauration manquait) et a été redémarré. Les points de restauration antérieurs ne peuvent plus être restaurés ; les nouveaux tours sont de nouveau protégés.",
"SnapshotsFailing": "Les instantanés échouent pour {workspace}, donc /undo ne peut pas restaurer les tours récents : {limit}",
"SessionIdDivergedNotice": "L'identité de session a changé sous cette fenêtre : le moteur enregistre désormais les points de reprise sous {next} (c'était {previous}). Les points antérieurs restent sous l'ancien identifiant ; `codewhale sessions` liste les deux et `codewhale resume {previous}` rouvre l'ancien.",
"RuntimeStoreUnreadableNotice": "Magasin d'exécution de la session : impossible de lire {record} dans {path} ({reason}). Mettez ce fichier de côté (ou supprimez-le) et réessayez ; les autres enregistrements du fil restent en place.",
"RuntimeStoreUnwritableNotice": "Magasin d'exécution de la session : impossible d'écrire {record} dans {path} ({reason}). Vérifiez l'espace libre et les permissions à cet endroit, puis réessayez ; rien n'a été écrasé.",
"ProviderExternalSemanticsRevoke": "{semantics} | révocation : {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "setup",
"FleetRosterWorkers": "workers",
"FleetRosterMembersCount": "{count} membres",
"FleetRosterOperatorFirst": "Le Coordinateur mène · le modèle de session pilote ce Fleet",
"FleetRosterOperatorRow": "Coordinateur · leader",
"FleetRosterShadowBadgeProjectOverride": "enregistré dans ce projet",
"FleetRosterShadowBadgePersonalIgnored": "copie enregistrée ignorée",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "c'est votre modèle actuel (la route opérateur de l'équipe) ; changez de modèle ou utilisez /fleet save pour la modifier",
"FleetModelReasonAlreadyPresent": "déjà dans l'équipe",
"FleetModelErrorNeedsRoute": "un modèle de l'équipe a besoin d'un id de provider et d'un id de modèle",
"FleetModelErrorNeedsRole": "Un agent a besoin d’un nom de rôle (par exemple `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "aucune équipe n'est sélectionnée ; votre équipe se limite au modèle de la session",
"FleetModelErrorOperatorRoute": "{route} est la route opérateur de l'équipe `{fleet}` ; modifiez-la avec /fleet save, pas avec remove",
"FleetModelErrorNotInFleet": "{route} n'est pas dans l'équipe `{fleet}`",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ joindre · 1 correspondance",
"FilePickerMatchesPlural": "@ joindre · {count} correspondances",
"FilePickerScanning": "Analyse du workspace…",
"BehavioralTipPlanning": "Planification ? {key} bascule vers le mode Plan",
"BehavioralTipBackgroundReceipt": "Les reçus vivent dans le panneau Work — {key} ouvre l'inspecteur",
"BehavioralTipClearedInput": "Effacé · {chord} restaure",
"BehavioralTipMcpValidation": "{command} démarre les serveurs et montre pourquoi",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "Le modèle et le raisonnement",
"SettingSubjectProvider": "Le fournisseur",
"SettingSubjectPermissions": "Les permissions",
"ThinkingControlledByAutoRouting": "Le raisonnement est contrôlé par le routage automatique de modèles ; choisissez d'abord un modèle fixe.",
"SavedAsStartupDefault": "enregistré comme défaut de démarrage",
"ModeAlreadyActiveSavedAsDefault": "Déjà en mode {mode} — enregistré comme défaut de démarrage.",
"StartupDefaultNotSaved": "{setting} n'a pas été enregistré : {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun facture le pay-as-you-go et les abonnements Step Plan sur des endpoints distincts. Choisissez celui auquel appartient votre clé.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (tarif au token)",
"StepfunBillingRoutePlanOption": "Abonnement Step Plan (quota du plan)",
"StepfunPlanApiKeyHint": "Pour les abonnements StepFun Step Plan, utilisez la clé émise pour votre Step Plan, pas une clé pay-as-you-go.",
"StepfunPlanRouteHint": "Cette route utilise {route} et est facturée sur le quota de votre Step Plan.",
"ConfigLabelSessionsRail": "Volet des sessions",
"ConfigLabelSessionAutoResume": "Reprendre automatiquement la dernière session",
"SessionsRailTitle": "Sessions",
"SessionsRailEmpty": "Aucune session dans cet espace de travail pour l'instant",
"SessionsRailBrowseAll": "Parcourir toutes les sessions",
"SessionsRailShowingCount": "{shown} sur {total} — tout parcourir",
"SessionsRailUnavailable": "Sessions indisponibles : {error}",
"SessionsActionArchive": "archiver",
"SessionsActionShowArchived": "archivées",
"SessionsArchived": "Session {id} archivée",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "agents",
"FooterHintToManage": "gérer",
"AgentRailQueuedCount": "{count} en file",
"WorkbarSoFar": "{done}/{total} pour l’instant",
"WorkbarLargeWorkflow": "Workflow volumineux",
"WorkbarMoreRuns": "+{count} de plus",
"WorkflowLineStarted": "lancé",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "terminé avec des lacunes",
"WorkflowLineFailed": "échec",
"WorkflowLineStopped": "arrêté",
"WorkflowLineAgents": "{done}/{total} agents",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "écrit",
"AgentFocusPostureReadOnly": "lecture seule",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell en lecture seule",
"AgentFocusPostureShellNone": "sans shell",
"GoalReceiptSet": "Objectif défini : « {objective} » · /goal affiche la progression · /goal pause ou /goal clear l'arrête",
"GoalReceiptSetOperate": "◆ objectif défini · Operate continue jusqu'à vérification · /goal pour le modifier",
"GoalControlAccepted": "Commande d'objectif enregistrée ; elle sera appliquée au prochain point sûr.",
"GoalControlRuntimeUnavailable": "La commande d'objectif est enregistrée, mais le moteur est indisponible. Elle sera restaurée après le redémarrage.",
"GoalStatusIdleHint": "à l'arrêt pour l'instant — envoyez un message ou /goal resume pour continuer",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Objectif actif · prochain tour dans {delay} · Échap, Ctrl+C ou /goal pause arrête la continuation en attente",
"GoalContinuationReady": "La continuation de l'objectif est prête ; les contrôles en attente passent avant le prochain tour.",
"GoalContinuationStopped": "Continuation en attente arrêtée ; l'objectif reste actif.",
"McpCapabilitiesAdvertised": "Capacités annoncées : {capabilities}",
"McpCapabilitiesLegacyFallback": "Capacités annoncées : non fournies ; utilisation de la détection héritée",
"McpCapabilitiesNotObserved": "Capacités annoncées : non observées car le serveur n'est pas connecté",
"PickerActionTestConnection": "tester la connexion",
"ProviderCustomFormBaseUrl": "URL de base",
"ProviderCustomFormModel": "Modèle par défaut",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt temps →",
"ConfigCategoryAppearance": "Apparence",
"ConfigCategoryModelsProviders": "Modèles et fournisseurs",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Travail",
"ConfigCategoryToolsMcp": "Outils et MCP",
"ConfigCategoryTrust": "Confiance",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "lecture seule",
"ConfigRowActionNote": "action · pas un réglage persistant",
"ConfigRowDiagnosticNote": "reçu observé · non modifiable ici",
"ConfigNavHint": "←/→ ou Tab catégorie · ↑/↓ réglage",
"ConfigActivateAgain": "Entrée ou cliquez à nouveau :",
"ConfigSearchLabel": " Recherche : ",
"ConfigEditChooseLabel": "Choisir :",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Jamais",
"ConfigChoiceModeAct": "Agir",
"ConfigChoiceModePlan": "Planifier (lecture seule)",
"ConfigChoiceModeOperate": "Piloter",
"ConfigChoicePlacementTop": "En haut",
"ConfigChoicePlacementBottom": "Barre inférieure",
"ConfigChoicePlacementLeft": "Barre latérale gauche",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Évalue automatiquement le risque des outils et demande quand une décision vous revient.",
"ConfigChoiceDetailUseTuiDefault": "Retire la surcharge de la config racine et utilise le choix de permission enregistré dans la TUI.",
"ConfigChoiceDetailFullAccess": "Les outils s’exécutent sans demander, et les commandes peuvent accéder à tout ce qui se trouve sur cet ordinateur.",
"ConfigChoiceDetailNever": "Bloque tout outil qui requiert une approbation.",
"ConfigChoiceDetailModeAgent": "Démarre prêt à collaborer et à utiliser des outils.",
"ConfigChoiceDetailModePlan": "Démarre dans un espace de planification en lecture seule.",
"ConfigChoiceDetailModeOperate": "Operate, c'est Work à pleine puissance : chaque demande substantielle devient un objectif, passe par des workflows et des workers parallèles, est contrôlée par un relecteur indépendant et continue jusqu'à être vérifiée.",
"ConfigChoiceDetailPlacementTop": "Affiche Tâches, À faire et Workers au-dessus de la transcription.",
"ConfigChoiceDetailPlacementBottom": "Affiche Tâches, À faire et Workers sous le composer.",
"ConfigChoiceDetailPlacementLeft": "Affiche Tâches, À faire et Workers dans une barre latérale gauche quand le terminal est assez large.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Remplit l'arrière-plan du raisonnement du modèle.",
"ConfigChoiceDetailThinkingHighlightOff": "Garde la ligne de raisonnement en pointillés et le texte en italique sans arrière-plan rempli.",
"ConfigHintModel": "modèle de la route en direct de cette session ; Entrée ouvre /model",
"ConfigHintFastModel": "utilisé par le routage Auto et par model_strength=faster des agents quand ce fournisseur a un modèle frère connu",
"ConfigHintProvider": "identifiants, modèle et point de terminaison changent ensemble",
"ConfigHintApprovalMode": "cette session seulement : Demander | Revue automatique | Accès complet",
"ConfigHintPermissionPosture": "défaut pour les nouvelles sessions : Demander | Revue automatique | Accès complet",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "entier (0 autorisé) · nombre de messages envoyés conservés pour les rappeler et chercher dans l'historique",
"ConfigHintAutoCompactThreshold": "10..=100 · seuil de compaction : pourcentage de la longueur de contexte utilisable auquel la compaction automatique se déclenche",
"ConfigHintDefaultModel": "repli hérité réservé à DeepSeek ; les autres fournisseurs utilisent leur modèle par fournisseur ci-dessus",
"ConfigHintReasoningEffort": "default rétablit le défaut du modèle ; les modèles qui raisonnent toujours omettent off",
"ConfigHintMcpOpen": "ouvre le gestionnaire MCP · Connecter / Reconnecter / Ré-authentifier / Diagnostiquer",
"ConfigHintMcpReconnect": "reconnecte MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "état en lecture seule du drapeau de fonctionnalité des outils d'édition par patch",
"ConfigHintFeatureMcp": "état en lecture seule du drapeau de fonctionnalité des outils MCP",
"ConfigHintFeatureExecPolicy": "état en lecture seule du drapeau de fonctionnalité des outils de politique d'exécution",
"ConfigHintFeatureVisionModel": "drapeau bêta pour la prise en charge des images vision/modèle",
"ConfigHintGoalCommand": "/goal définit les objectifs, les budgets et l'état du contexte de Travail",
"ConfigHintWorkflow": "/workflow exécute des opérations scriptées avec des cartes d'exécution de distribution/regroupement",
"LaunchMenuNewWorktree": "Nouveau worktree",
"LaunchMenuResume": "Reprendre la session",
"LaunchMenuQuit": "Quitter",
"LaunchNoticeClaude": "Claude Code détecté. Lancez /import-claude pour examiner ce qui peut être repris : serveurs MCP, réglages sûrs et permissions. Rien n'est appliqué sans votre accord.",
"LaunchNewSession": "Nouvelle session",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ pour reprendre",
"LaunchHelpLine": "/help pour les commandes · {dock} pour la barre de travail",
"LaunchSeeAllSessions": "Voir toutes les sessions…",
"LaunchNoRecentSessions": "Aucune session récente — écrivez ci-dessous pour commencer.",
"LaunchResumeFailed": "Échec de la reprise : {error}",
"ReceiptSessionHooks": "hooks {count}",
"AutomationEditorNew": "Nouvelle automatisation",
"AutomationEditorEdit": "Modifier l’automatisation",
"AutomationEditorSchedule": "Planification",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} terminés",
"WorkflowPhaseCountOne": "{count} phase",
"WorkflowPhaseCountMany": "{count} phases",
"WorkflowPhaseOrdinal": "phase {n}/{total}",
"ModelPickerPinned": "{route} épinglé",
"ModelPickerUnpinned": "{route} désépinglé",
"ModelPickerPinFailed": "Impossible de mettre à jour l’épingle : {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "La connexion Codewhale précédente à {provider} ({account}) a été remplacée.",
"AuthReplacedPreviousSignIn": "La connexion Codewhale précédente à {provider} a été remplacée.",
"AuthSameAccountAsBefore": "C'est le même compte qu'avant ; pour utiliser un autre compte {provider}, déconnectez-vous-en dans le navigateur (ou utilisez une fenêtre privée), puis reconnectez-vous.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN ou CODEX_ACCESS_TOKEN est défini dans cet environnement et prime sur cette connexion ; les requêtes continuent d'utiliser le compte de ce jeton tant que vous ne l'avez pas supprimé.",
"PinnedPromptJumpToMessage": "Aller à ce message",
"PlanHandoffHeader": "Plan prêt",
"PlanHandoffQuestion": "Comment voulez-vous continuer ?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Appuyez sur Entrée pour vous connecter dans le navigateur, ou Échap pour revenir. Aucune clé API nécessaire.",
"PluginOAuthReady": "{provider} : connexion établie. Choisissez un modèle.",
"PluginOAuthLocalLogout": "{provider} : connexion locale supprimée. L’accès distant reste inchangé.",
"CmdConnectDescription": "Connecter un fournisseur de plugin par connexion dans le navigateur",
"CmdDisconnectDescription": "Supprimer la connexion locale d’un fournisseur de plugin",
"ExecAutoHelp": "Active les outils avec approbation automatique et Full Access (sans bac à sable du shell, mode de confiance activé), sauf si un bac à sable plus strict est configuré ; utilisez --sandbox workspace-write pour limiter les écritures des outils de fichiers et du shell.",
"ExecSandboxHelp": "Politique de sandbox pour cette exécution ; tout --sandbox autre que danger-full-access (ou un sandbox_mode équivalent dans la configuration) désactive le mode de confiance.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime ने इस बातचीत की इवेंट स्ट्रीम बंद कर दी; बातचीत फिर से खोलें",
"MobileStreamReconnecting": "कनेक्शन टूट गया; फिर से कनेक्ट हो रहा है",
"MobileStreamConnected": "कनेक्ट हो गया",
"PetHabitatTitle": "CODEWHALE / WHALESONG · एक साझा आवास",
"PetHabitatHints": "{back} वापस · {sound} ध्वनि · {browser} रूप · {window} विंडो",
"PetHabitatQueued": "साझा आवास में भेज दिया गया। /pet on से पेट और संदेश बॉक्स दिखते हैं।",
"PetWatchSoundOn": "ध्वनि चालू",
"PetWatchSoundOff": "ध्वनि बंद",
"PetWatchSoundPaused": "ध्वनि रुकी हुई",
"PetWatchSoundUnavailable": "Codewhale की ध्वनि रुक गई। FFmpeg (ffplay) और ऑडियो आउटपुट की जाँच करें, फिर ध्वनि फिर से चालू करें।",
"CmdPetDescription": "Codewhale के मुख्य दृश्य में एनिमेटेड पेट इस्तेमाल करें",
"ConfigLabelPetMode": "पेट मोड",
"ConfigHintPetMode": "Codewhale शुरू होने पर एनिमेटेड पेट को मुख्य दृश्य के रूप में दिखाएँ।",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "पालतू मोड बंद",
"PetViewOpen": "आवास खुला",
"PetViewClosed": "आवास बंद",
"PetWatchRestored": "/pet ने इस सत्र का आवास बहाल कर दिया है। नई टेलीमेट्री की प्रतीक्षा है।",
"PetWatchStorageUnavailable": "Watch इस आवास को बहाल या सहेज नहीं सका। मौजूदा फ़ाइलें सुरक्षित हैं। इस रन को निर्यात करने के लिए {command} इस्तेमाल करें।",
"PetWatchExported": "Watch रिकॉर्डिंग सहेजी गई: {path}",
"PetWatchExportFailed": "Watch रिकॉर्डिंग सहेजी नहीं जा सकी। रिकॉर्डिंग अभी मेमोरी में है।",
"PetWatchExportQueued": "Watch रिकॉर्डिंग सहेजी जा रही है…",
"PetWatchExportUnavailable": "सहेजे गए सत्र में /pet खोलें या मौजूदा निर्यात पूरा होने की प्रतीक्षा करें।",
"PetUnobserved": "अवलोकन नहीं हुआ",
"PetOffline": "ऑफ़लाइन — codewhale pet serve इसे जगाता है",
"PetDozing": "ऊँघ रहा है",
"PetWatchUnavailable": "पालतू की टेलीमेट्री रुकी हुई है। /pet on से फिर कोशिश करें।",
"ConversationChangedBeforeUndo": "पूर्ववत करने की प्रक्रिया पूरी होने से पहले बातचीत बदल गई। कुछ भी पूर्ववत नहीं किया गया और दोबारा अनुरोध नहीं भेजा गया। फिर से कोशिश करने से पहले मौजूदा बातचीत की समीक्षा करें।",
"SessionArchiveExported": "सत्र निर्यात किया गया",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "संपादित करें",
"ExtensionsHooksAddLabel": "हुक जोड़ें",
"ExtensionsHooksAddDescription": "इस प्रोजेक्ट की हुक फ़ाइल अपने एडिटर में खोलें",
"ExtensionsActionReload": "पुनः लोड करें",
"ExtensionsActionConnect": "कनेक्ट करें",
"ExtensionsActionReconnect": "फिर कनेक्ट करें",
"ExtensionsActionReauth": "फिर प्रमाणित करें",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "कनेक्टेड",
"ExtensionsStateEnabled": "सक्षम",
"ExtensionsStateError": "त्रुटि",
"ExtensionsStateInactive": "निष्क्रिय",
"ExtensionsStateInapplicable": "लागू नहीं",
"ExtensionsStateInvalid": "अमान्य",
"ExtensionsStateNotInspected": "जाँच नहीं हुई",
"ExtensionsStateDisconnected": "डिस्कनेक्ट",
"ExtensionsStateRejected": "अस्वीकृत",
"ExtensionsStateReviewedCandidate": "समीक्षित उम्मीदवार",
"ExtensionsStateUnderEvaluation": "मूल्यांकन जारी",
"ExtensionsStateUnstaged": "स्टेज नहीं किया गया",
"ExtensionsStateUnsupported": "असमर्थित",
"ExtensionsStateWarning": "चेतावनी",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ इस टर्न में भेजें",
"ComposerHintLongDraft": "{shortcut}: बाहरी संपादक",
"PendingSendingIntoTurnPrefix": " ↳ इस टर्न में भेजा जा रहा है: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ इस टर्न में नहीं भेजा जा सका: ",
"PendingEditingFollowUpPrefix": " ↳ फॉलो-अप संपादित हो रहा है: ",
"PendingQueuedOnePrefix": "कतार #1: ",
"PendingQueuedManyPrefix": "कतार {count} · अगला: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "सोच पूरी हुई",
"TranscriptThoughtFor": "{duration} तक सोचा",
"TelemetryNoticeDefaultOn": "उपयोग आँकड़ों की रिपोर्टिंग डिफ़ॉल्ट रूप से चालू है। संस्करण, प्लेटफ़ॉर्म, सत्र, सुविधा और त्रुटि के कुल आँकड़े Codewhale और प्रोसेसर PostHog से साझा करें। यह प्रदाता, सार्वजनिक कैटलॉग मॉडल, टोकन योग और अंतर्निहित औज़ारों का उपयोग भी गिनता है। सामग्री या IP नहीं। docs/TELEMETRY.md बंद करें: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale उपयोग आँकड़े",
"TelemetryNoticeBody": "Codewhale गणना करता है: चल रहा संस्करण, ऑपरेटिंग सिस्टम व प्रोसेसर परिवार,\nसत्र की अवधि व परिणाम, और सुविधाओं व त्रुटियों की कुल गणना।\n\nयह आपके इस्तेमाल किए गए प्रदाताओं और सार्वजनिक कैटलॉग मॉडलों, उनके टोकन योग, और हर अंतर्निहित औज़ार कितनी बार चलता है, यह भी गिनता है।\n\nयह आपकी बातचीत, कोड, प्रॉम्प्ट, फ़ाइलें, फ़ाइल, भंडार या शाखा के नाम,\nमॉडल की सामग्री या परिचय प्रमाण कभी एकत्र नहीं करता, और प्रत्येक चरण या\nऔज़ार की एजेंट गतिविधि का क्रम भी कभी नहीं भेजता।\n\nपहचान के लिए केवल इस मशीन पर रखी एक आकस्मिक पहचान संख्या उपयोग होती है,\nजो हर 90 दिन में बदल दी जाती है। कभी भी अपना निर्णय बदलें:\n codewhale config set telemetry false\n\nहर क्षेत्र सहित पूरा प्रारूप: docs/TELEMETRY.md\n\nउपयोग आँकड़ों की रिपोर्टिंग डिफ़ॉल्ट रूप से चालू है। भेजने की व्यवस्था कॉन्फ़िगर होने पर Codewhale और PostHog इन आँकड़ों को संसाधित करते हैं। IP एकत्र नहीं किया जाता।",
"TelemetryNoticeCompactBody": "गणना: संस्करण, सिस्टम/प्रोसेसर, सत्र अवधि/परिणाम और सुविधा/त्रुटि योग।\nसाथ ही: प्रदाता/मॉडल, टोकन, औज़ार उपयोग।\nआकस्मिक स्थानीय पहचान हर 90 दिन में बदलती है।\nकभी नहीं: बातचीत/कोड/प्रॉम्प्ट/फ़ाइल/नाम, मॉडल सामग्री/परिचय प्रमाण, चरण/औज़ार।\nप्रारूप: docs/TELEMETRY.md\nबंद: codewhale config set telemetry false\nउपयोग आँकड़ों की रिपोर्टिंग डिफ़ॉल्ट रूप से चालू है। भेजने की व्यवस्था कॉन्फ़िगर होने पर Codewhale और PostHog इन आँकड़ों को संसाधित करते हैं। IP एकत्र नहीं किया जाता।",
"TelemetryNoticeChoiceKeep": "हाँ, अनाम गणना जारी रखें",
"TelemetryNoticeChoiceDisable": "नहीं, ट्रैकिंग बंद करें",
"TelemetryNoticeActionChoose": "चुनें",
"TelemetryNoticeActionConfirm": "पुष्टि",
"TelemetryNoticeActionExit": "बाहर",
"TelemetryNoticeReceiptEnabled": "अनाम उपयोग गणना चालू है। बातचीत और कोड कभी एकत्र नहीं किए जाते। इसे /settings में बदलें; स्कीमा: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "अनाम उपयोग गणना बंद है। दोबारा नहीं पूछा जाएगा।",
"TelemetryNoticeReceiptEnabledUnsaved": "इस सत्र में अनाम उपयोग गणना चालू है। Codewhale इस सूचना को सहेज नहीं सका, इसलिए यह फिर दिखाई देगी। इसे /settings में बदलें; स्कीमा: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "इस सत्र में अनाम उपयोग गणना बंद है। Codewhale चयन सहेज नहीं सका, इसलिए अगली बार शुरू होने पर फिर पूछेगा।",
"TelemetryPreferenceEnabledNextLaunch": "अगली बार शुरू होने पर अनाम उपयोग गणना चालू होगी। बातचीत और कोड कभी एकत्र नहीं किए जाते।",
"TelemetryPreferenceDisabled": "अनाम उपयोग गणना बंद है। स्थानीय टेलीमेट्री डेटा मिटा दिया गया है।",
"TelemetryPreferenceDisabledWithWarning": "अनाम उपयोग गणना बंद है, लेकिन सफ़ाई के एक हिस्से पर ध्यान देना होगा: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "कोई Hotbar क्रिया उपलब्ध नहीं है।",
"HotbarSetupRecommended": "सुझाव",
"HotbarSetupEmptySlot": "खाली",
"HotbarSetupHelp": "Tab/Shift+Tab स्रोत Up/Down क्रिया 1-8 स्लॉट Enter असाइन Space टॉगल Delete साफ़ s सहेजें Esc रद्द",
"HotbarActionVoiceToggleName": "वॉइस इनपुट",
"HotbarActionVoiceToggleDescription": "टर्मिनल माइक्रोफ़ोन से वॉइस कैप्चर चालू/बंद करें।",
"HotbarActionSessionCompactName": "सत्र कॉम्पैक्ट करें",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Work मोड",
"HotbarActionModeAgentDescription": "वर्तमान सत्र में सीधे काम करें।",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "संगतता: Full Access अनुमतियों के साथ Work (अलग मोड नहीं)।",
"HotbarActionReasoningCycleName": "रीज़निंग बदलें",
"HotbarActionReasoningCycleDescription": "सक्रिय प्रोवाइडर के लिए कॉन्फ़िगर किया गया रीज़निंग स्तर बदलें।",
"HotbarActionReasoningCycleAutoDisabled": "रीज़निंग स्तर ऑटो मॉडल रूटिंग द्वारा नियंत्रित है।",
"HotbarActionSidebarToggleName": "साइडबार टॉगल करें",
"HotbarActionSidebarToggleDescription": "साइडबार दिखाएँ या छिपाएँ।",
"HotbarActionFileTreeToggleName": "फ़ाइल ट्री टॉगल करें",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " कोई सेटिंग उपलब्ध नहीं।",
"ConfigNoMatchesPrefix": " कोई सेटिंग मेल नहीं खाती ",
"ConfigFilteredSettings": " फ़िल्टर की गई सेटिंग्स",
"ConfigShowing": " दिखा रहे हैं",
"ConfigFooterDefault": " type=फ़िल्टर, Up/Down=चुनें, Enter=संपादन, Esc=बंद ",
"ConfigFooterScrollable": " type=फ़िल्टर, Up/Down=चुनें, Enter=संपादन, PgUp/PgDn=स्क्रॉल, Esc=बंद ",
"ConfigFooterFiltered": " type=फ़िल्टर, Backspace=हटाएँ, Ctrl+U/Esc=साफ़, Enter=संपादन ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; घोस्ट-टेक्स्ट सुझाव आगे के टर्न के बाद लागू होंगे)",
"ConfigNotificationsSetHint": "/config notifications <key> <value> [--save] से सेट करें।",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; आगे की सूचनाओं पर लागू)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs एक पूर्णांक होना चाहिए",
"ConfigAuditSearchProvider": "[search] provider लिखता है; आगे की web_search कॉल पर्यावरण ओवरराइड का सम्मान करती रहेंगी।",
"ConfigAuditPromptSuggestion": "शीर्ष-स्तरीय prompt_suggestion लिखता है; घोस्ट-टेक्स्ट सुझाव वैकल्पिक रहते हैं।",
"ConfigAuditNotifications": "[notifications] के स्केलर मान लिखता है और उन्हें आगे की टर्न-पूर्णता सूचनाओं पर लागू करता है।",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "प्रोवाइडर API URL",
"ConfigHintProviderUrl": "मौजूदा प्रोवाइडर एंडपॉइंट; Xiaomi: टोकन प्लान | उपयोग के अनुसार भुगतान | कस्टम URL",
"ConfigLabelModel": "सक्रिय प्रोवाइडर मॉडल",
"ConfigLabelFastModel": "तेज़ मॉडल (व्युत्पन्न)",
"ConfigLabelDefaultModel": "लीगेसी फ़ॉलबैक मॉडल (केवल DeepSeek रूट)",
"ConfigLabelReasoningEffort": "रीज़निंग स्तर",
"ConfigLabelApprovalMode": "इस सत्र की अनुमति",
"ConfigLabelPermissionPosture": "नए सत्रों की अनुमति",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "संस्करण, सत्र, सुविधा और त्रुटि के कुल आँकड़े Codewhale और PostHog को; सामग्री या IP कभी नहीं। docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "चालू",
"ConfigValueTelemetryOff": "बंद",
"ConfigLabelStreamTimeout": "स्ट्रीम टाइमआउट",
"ConfigLabelTheme": "थीम",
"ConfigLabelLocale": "भाषा",
"ConfigLabelBackground": "पृष्ठभूमि",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "रीज़निंग पृष्ठभूमि हाइलाइट",
"ConfigLabelShowToolDetails": "टूल विवरण स्तर",
"ConfigLabelInlineDiffs": "इनलाइन फ़ाइल बदलाव",
"ConfigLabelStatusIndicator": "स्थिति सूचक",
"ConfigLabelSynchronizedOutput": "आउटपुट पेसिंग",
"ConfigLabelCostCurrency": "लागत मुद्रा",
"ConfigLabelTranscriptSpacing": "ट्रांसक्रिप्ट रिक्ति",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "कम्पोज़र घनत्व",
"ConfigLabelComposerBorder": "कम्पोज़र बॉर्डर",
"ConfigLabelComposerMultilineMode": "कम्पोज़र बहुपंक्ति मोड",
"ConfigLabelComposerVimMode": "कम्पोज़र Vim मोड",
"ConfigLabelBracketedPaste": "ब्रैकेटेड पेस्ट",
"ConfigLabelPasteBurstDetection": "पेस्ट पहचान",
"ConfigLabelMentionMenuLimit": "मेंशन मेनू सीमा",
"ConfigLabelMentionMenuBehavior": "मेंशन मेनू व्यवहार",
"ConfigLabelMentionWalkDepth": "फ़ाइल मेंशन गहराई",
"ConfigLabelWorkspaceFollowSymlinks": "सिमलिंक फ़ॉलो करें",
"ConfigLabelContextPanel": "संदर्भ पैनल",
"ConfigLabelAutoCompact": "ऑटो कॉम्पैक्ट",
"ConfigLabelAutoCompactThreshold": "कॉम्पैक्ट सीमा",
"ConfigLabelMaxHistory": "इनपुट इतिहास",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "गोल कमांड",
"ConfigLabelWorkflow": "वर्कफ़्लो",
"ConfigLabelFeaturePrefix": "फ़ीचर: {name}",
"ConfigColumnSetting": "सेटिंग",
"ConfigColumnValue": "मान",
"ConfigColumnScope": "दायरा",
"ConfigActionOpenProvider": "Enter प्रोवाइडर चयनकर्ता खोलता है",
"ConfigActionOpenModel": "Enter मॉडल चयनकर्ता खोलता है",
"ConfigActionOpenMcp": "Enter MCP प्रबंधक खोलता है",
@@ -415,6 +456,7 @@
"HelpKeybindings": "कीबाइंडिंग",
"HelpUserCommands": "उपयोगकर्ता कमांड",
"HelpSkills": "स्किल",
"HelpFooterTypeFilter": " फ़िल्टर करने के लिए टाइप करें ",
"HelpFooterMove": " Up/Down घुमाएँ ",
"HelpFooterJump": " PgUp/PgDn जंप ",
"HelpFooterClose": " Esc बंद ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "सुझाया गया प्लगइन: {name}",
"PluginCtaReview": "समीक्षा",
"PluginCtaInstall": "इंस्टॉल करें",
"PluginCtaReviewTrust": "भरोसे की समीक्षा करें",
"PluginCtaEnable": "सक्षम करें",
"PluginCtaDismiss": "फिर से सुझाव न दें",
"PluginCtaDismissSaveFailed": "इस सत्र के लिए छिपाया गया; प्लगइन की प्राथमिकता सहेजी नहीं जा सकी।",
"PluginSuggestionReason": "“{trigger}” से मेल खाता है",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "प्लगिन क्रिया विफल: {error}",
"CmdPluginNoneFound": "{dir} में कोई लीगेसी एक्ज़िक्यूटेबल प्लगिन टूल नहीं मिला",
"CmdPluginNotFound": "प्लगिन '{name}' नहीं मिला",
"CmdPluginListHeader": "लीगेसी एक्ज़िक्यूटेबल प्लगिन टूल ({count}):",
"CmdPluginDetailDescription": "विवरण: {description}",
"CmdPluginDetailSchema": "स्कीमा:\n{schema}",
"CmdPluginDetailApproval": "अनुमति: {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "कैश में सहेजी सूची; कॉन्फ़िगर किए प्रदाताओं को अपडेट करने के लिए `codewhale models --update` चलाएँ।",
"ModelsUpdateSummary": "मॉडल कैटलॉग: {updated} अपडेट हुए, {loaded} Codex से लोड हुए, {failed} विफल हुए, {skipped} छोड़े गए।",
"ModelsUpdatePartial": "कुछ सूचियाँ अपडेट नहीं हो सकीं। पिछले और कॉन्फ़िगर किए मॉडल उपलब्ध हैं।",
"ModelsCodexHint": "ChatGPT मॉडल Codex के ज़रिए लोड होते हैं। खोज का समय प्रदाता के कैटलॉग के अपडेट होने की पुष्टि नहीं करता।",
"ModelsSourceFallback": "शामिल या कॉन्फ़िगर किए मॉडल; उपलब्धता सत्यापित नहीं है।",
"CmdModelDbDescription": "बंडल किया मॉडल डेटाबेस ब्राउज़ करें",
"CmdNetworkDescription": "नेटवर्क अनुमति और निषेध नियम प्रबंधित करें",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "कतारबद्ध संदेश देखें या संपादित करें",
"CmdQueueUsage": "उपयोग: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "पिछले सत्र के कतार के {count} संदेश बहाल किए गए। ये अपने आप नहीं भेजे जाते: /queue send <n> एक भेजता है, /queue clear इन्हें हटाता है।",
"CmdQueueDraftHeader": "कतारबद्ध संदेश संपादित हो रहा है:",
"CmdQueueNoMessages": "कोई कतारबद्ध संदेश नहीं",
"CmdQueueListHeader": "कतारबद्ध संदेश ({count}):",
"CmdQueueTip": "सुझाव: अभी भेजने के लिए /queue send <n>, हटाने के लिए /queue drop <n>",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} हिट / {miss} मिस",
"CmdTokensCacheHitOnly": "{hit} हिट / मिस रिपोर्ट नहीं",
"CmdTokensCacheMissOnly": "हिट रिपोर्ट नहीं / {miss} मिस",
"CmdTokensContextUnknownWindow": "~{estimated} / अज्ञात विंडो",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 एजेंट",
"FooterAgentsPlural": "{count} एजेंट",
"HeaderAgentsChip": "एजेंट {count}",
"FooterPressCtrlCAgain": "बाहर निकलने के लिए Ctrl+C फिर दबाएँ",
"FooterWorking": "काम जारी",
"FooterBalancePrefix": "शेष",
"HelpSectionActions": "क्रियाएँ",
"HelpSectionClipboard": "क्लिपबोर्ड",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "रिपोर्ट नहीं",
"CmdTokensReport": "टोकन उपयोग:\n ─────────────────────────────\n सक्रिय संदर्भ: {active}\n अंतिम API इनपुट: {input} (टर्न टेलीमेट्री; टूल राउंड में दोहराया प्रीफ़िक्स गिना जा सकता है)\n अंतिम API आउटपुट: {output}\n कैश हिट/मिस: {cache} (केवल टेलीमेट्री/लागत)\n संचयी टोकन: {total} (सत्र उपयोग टेलीमेट्री)\n अनुमानित सत्र लागत: {cost}\n API संदेश: {api_messages}\n चैट संदेश: {chat_messages}\n मॉडल: {model}",
"KbScrollTranscript": "ट्रांसक्रिप्ट स्क्रॉल करें, इनपुट इतिहास नेविगेट करें, या कम्पोज़र अटैचमेंट चुनें",
"KbNavigateHistory": "इनपुट इतिहास नेविगेट करें",
"KbBrowseHistory": "वार्तालाप इतिहास ब्राउज़ करें",
"KbScrollTranscriptAlt": "ट्रांसक्रिप्ट स्क्रॉल करें",
"KbScrollPage": "ट्रांसक्रिप्ट पृष्ठ-दर-पृष्ठ स्क्रॉल करें",
@@ -807,6 +858,7 @@
"KbCompactContext": "वार्तालाप संदर्भ संपीड़ित करें",
"KbLastMessagePager": "अंतिम संदेश के लिए पेजर खोलें (जब इनपुट खाली हो)",
"KbSelectedDetails": "चुने टूल या संदेश का कच्चा विवरण दिखाएँ; Ctrl+Alt+O पूरे टर्न का अवलोकन खोलता है",
"KbToolDetailsPager": "चुने आइटम का कच्चा विवरण दिखाएँ (Alt+V)",
"KbExternalEditor": "कम्पोज़र मसौदा बाहरी संपादक में खोलें",
"KbLiveTranscript": "लाइव ट्रांसक्रिप्ट ओवरले खोलें (Ctrl+Shift+T; स्टिकी-टेल ऑटो-स्क्रॉल)",
"KbBacktrackMessage": "पिछले उपयोगकर्ता संदेश पर वापस जाएँ (Left/Right कदम, रिवाइंड के लिए Enter)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "यह मदद ओवरले खोलें (जब इनपुट खाली हो)",
"KbCycleWorkDock": "वर्क डॉक बदलें (टूडू, एजेंट, जॉब, बैकग्राउंड), या पेट मोड में पालतू के दृश्य बदलें",
"KbCycleWorkDockBack": "वर्क डॉक या पालतू के दृश्य पीछे की ओर बदलें",
"KbToggleHelp": "मदद ओवरले टॉगल करें",
"KbToggleHelpSlash": "मदद ओवरले टॉगल करें",
"HelpUsageLabel": "उपयोग:",
"HelpAliasesLabel": "उपनाम:",
"SettingsTitle": "सेटिंग्स:",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan से पहले शोध कर योजना प्रस्तुत करें",
"HomeAgentModeYoloTip": " Shift+Tab अनुमति बदलता है: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — टूल बिना अनुमति प्रॉम्प्ट के चलते हैं",
"HomeYoloModeCaution": " विनाशकारी कार्रवाइयाँ तुरंत चल सकती हैं; संदेह हो तो Ask चुनें",
"HomePlanModeTip": "Plan — कार्यान्वयन से पहले शोध और डिज़ाइन",
"HomePlanModeChecklistTip": " योजना और To-do प्रगति प्रस्तुत करें, फिर Work पर जाएँ",
"HomeGoalModeTip": "गोल ट्रैकिंग - लक्ष्य के लिए /goal <objective> सेट करें",
"OnboardLanguageTitle": "अपनी भाषा चुनें",
"OnboardLanguageBlurb": "UI भाषा चुनें। इसे कभी भी `/config locale <tag> --save` से बदल सकते हैं।",
"OnboardProviderTitle": "अपना मॉडल प्रोवाइडर चुनें",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "“बनाए रखें” चुनने पर इस लॉन्च में मास्किंग चालू रहती है; चूँकि कॉन्फ़िग अभी भी \"disabled\" माँगता है, अगला लॉन्च फिर पूछेगा।",
"RedactionGateSaveFailed": "पुष्टि सहेजी नहीं जा सकी। मास्किंग चालू है। फिर कोशिश करें या मास्किंग चालू रखें।",
"RedactionGateTitle": "मॉडल सीमा पर कुंजी मास्किंग",
"OnboardOfflineOption": "Ctrl+O — ऑफ़लाइन देखें: अभी घूमकर देखिए, प्रोवाइडर बाद में जोड़िए।",
"OnboardOfflineNotice": "ऑफ़लाइन देख रहे हैं। अभी कुछ भी जुड़ा नहीं है — जोड़ना हो तो /provider चलाइए।",
"OnboardWelcomeTitle": "Codewhale इस फ़ोल्डर में आपके साथ काम करता है।",
"OnboardWelcomeLead": "चलिए तैयारी करें।",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "बताइए यह प्रोजेक्ट क्या करता है और इसके मुख्य एंट्री पॉइंट लिखिए।",
"OnboardSeedFolder": "इस फ़ोल्डर को देखिए और एक अच्छा पहला काम सुझाइए।",
"SetupWizardTitle": "सेटअप",
"SetupWizardWhy": "यह शेल setup_state.json में सेटअप प्रगति दर्ज करता है; कॉन्फ़िग बदलाव केवल स्पष्ट चरण क्रियाओं से लागू होते हैं।",
"SetupWizardProgress": "चरण",
"SetupActionBack": "वापस",
"SetupActionContinue": "जारी रखें",
"SetupActionSkip": "छोड़ें",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "बॉडी स्क्रॉल करें",
"SetupActionGuided": "पूर्वावलोकन/अंगीकार",
"SetupActionTuneGuided": "समायोजित करें",
"SetupActionModelDraft": "मॉडल मसौदा",
"SetupActionFreeform": "अपने शब्द",
"SetupActionKeepExisting": "मौजूदा रखें",
"SetupActionUseRecommended": "सुझाया विकल्प अपनाएँ",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "मॉडल रूट",
"SetupActionFleet": "Fleet सेटअप",
"SetupActionHotbar": "Hotbar सेटअप",
"SetupActionRemote": "रिमोट ऑन-रैम्प",
"SetupActionMode": "मोड चयनकर्ता",
"SetupActionConfig": "कॉन्फ़िग व्यू",
"SetupActionRuntimePreset": "प्रीसेट",
"SetupActionApplyRuntimePreset": "पूर्वावलोकन/लागू करें",
"SetupActionUseBundled": "bundled उपयोग करें",
"SetupActionDefer": "टालें",
"SetupActionCancel": "रद्द करें",
"SetupStatusNotStarted": "शुरू नहीं हुआ",
"SetupStatusRecommended": "अनुशंसित",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "सेटअप भाषा दर्ज हुई।",
"SetupConstitutionChoiceLabel": "पसंद:",
"SetupConstitutionSourceLabel": "स्रोत:",
"SetupConstitutionValidityLabel": "वैधता:",
"SetupConstitutionPreviewLabel": "पूर्वावलोकन हैश:",
"SetupConstitutionExistingLabel": "मौजूदा फ़ाइल:",
"SetupConstitutionExpertOverrideLabel": "विशेषज्ञ ओवरराइड:",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "प्लगिन:",
"SetupToolsMcpReviewHint": "Enter इस सेटअप स्नैपशॉट को दर्ज करता है। सुरक्षित ऑन-रैम्प के लिए R दबाएँ (कोई ऑटो-रन नहीं)।",
"SetupToolsMcpReviewed": "टूल/MCP तैयारी दर्ज हुई।",
"SetupRemoteCloudsLabel": "क्लाउड लक्ष्य:",
"SetupRemoteBridgesLabel": "चैट ब्रिज:",
"SetupRemoteProvidersLabel": "प्रोवाइडर:",
"SetupRemoteModeLabel": "रिमोट मोड:",
"SetupRemoteModeLocalOnly": "सिर्फ़ यह मशीन:",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "संदेश कॉपी करें",
"CtxMenuCopyMessageDesc": "क्लिक किया ट्रांसक्रिप्ट सेल लिखें",
"CtxMenuOpenInEditor": "एडिटर में खोलें",
"CtxMenuOpenInEditorDesc": "$EDITOR में file:line खोलें",
"CtxMenuShowCell": "सेल दिखाएँ",
"CtxMenuShowCellDesc": "यह ट्रांसक्रिप्ट सेल दिखाएँ",
"CtxMenuHideCell": "सेल छिपाएँ",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} पूर्ण · {running} चल रहे · {failed} विफल · {pending} लंबित",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (अप्रचलित मोड लेबल)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "इस सत्र में सीधा काम — संपादन और शेल अनुमति माँगते हैं",
"AppModeAutoHint": "स्वचालित जोखिम समीक्षा के साथ शेल सक्षम",
"AppModePlanHint": "पहले रीड-ओनली शोध — कार्रवाई से पहले योजना प्रस्तुत करें",
"AppModeYoloHint": "केवल संगतता — Work + Full Access, दृश्य मोड नहीं",
"AppModeOperateHint": "पूरी ताक़त से Work: लक्ष्य, समानांतर वर्कर, सत्यापन",
"VimModeNormal": "-- सामान्य --",
"VimModeInsert": "-- डालना --",
"VimModeVisual": "-- विज़ुअल --",
"ApprovalEffectReadsOnly": "केवल पढ़ता है",
"ApprovalEffectChangesFiles": "फ़ाइलें बदलता है",
"ApprovalRiskDestructive": "पूर्ववत नहीं हो सकता",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s अभी अनुमति दें, और अगली बार हमेशा पहले पूछें",
"ApprovalOptionDeny": "अनुमति न दें",
"ApprovalOptionAbortTurn": "यह टर्न रोकें",
"ApprovalBlockTitle": "अनुमति",
"ApprovalControlsHint": "Pg↑/↓ समीक्षा · {details} और विकल्प · Esc रोकें",
"ApprovalOwnerHeader": "एजेंट: {agent} · {role}",
"ApprovalGoToAgent": "g एजेंट पर जाएँ",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … छाँटा गया · पूरा विवरण के लिए {details} दबाएँ",
"ApprovalAsksWithoutGit": "यहाँ कोई Git रिपॉज़िटरी नहीं है, इसलिए बदलाव से पहले पूछा जाता है।",
"ApprovalFullAccessPolicyBlocked": "{tool} अवरुद्ध: Full Access इस नीति को दरकिनार नहीं कर सकता",
"ApprovalChooseHint": "चुनें: ",
"ApprovalChooseAction": "चुना विकल्प भेजें, या सीधे y/a/d दबाएँ",
"ApprovalIntentLabel": "इरादा: ",
"ApprovalMoreLines": " … (+{count} पंक्तियाँ)",
"ApprovalProceedQuestion": "क्या आप आगे बढ़ना चाहते हैं?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "संदर्भ संपीड़ित किया जा रहा है…",
"ContextCompactionQueued": "संदर्भ संपीड़न कतार में लगा दिया गया है; यह सक्रिय टर्न के बाद चलेगा।",
"ContextCompactionAlreadyRunning": "संदर्भ संपीड़न पहले से जारी है।",
"ContextCompactionQueueFull": "इंजन व्यस्त होने के कारण संदर्भ संपीड़न को कतार में नहीं लगाया जा सका; टर्न पूरा होने के बाद फिर कोशिश करें।",
"ContextCompactionQueueClosed": "संदर्भ संपीड़न उपलब्ध नहीं है क्योंकि इंजन अब नहीं चल रहा है।",
"ContextCompactionRouteInvalid": "संपीड़ित नहीं किया जा सकता क्योंकि सक्रिय प्रोवाइडर रूट अमान्य है: {error}",
"ContextCompactionStoppedOnEngineSwitch": "संदर्भ संपीड़न रोक दिया गया; बातचीत में कोई बदलाव नहीं हुआ",
"ContextPurgeAbandonedOnEngineSwitch": "बदले गए इंजन के साथ सत्र की सफ़ाई छोड़ दी गई; बातचीत में कोई बदलाव नहीं हुआ",
"CtxInspTitle": "कॉन्टेक्स्ट इंस्पेक्टर",
"CtxInspSessionContext": "सत्र कॉन्टेक्स्ट",
"CtxInspSystemPrompt": "सिस्टम प्रॉम्प्ट संरचना",
"CtxInspReferences": "संदर्भ",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills और Plugins — सुरक्षित ऑन-रैंप\n\n/setup केवल लोकल इन्वेंटरी पढ़ता है। यह कभी MCP सर्वर शुरू नहीं करता, स्किल इंस्टॉल नहीं करता, प्लगइन नहीं चलाता, या अविश्वसनीय कमांड निष्पादित नहीं करता।\n\nवर्तमान इन्वेंटरी:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools डायरेक्टरी: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (साझा एडॉप्टर): {hotbar_result}\n\nपथ (होम छिपा):\n- MCP कॉन्फ़िग: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nसुरक्षित बूटस्ट्रैप (सामान्य टर्मिनल या TUI कमांड में खुद चलाएँ):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install <spec>\n- Plugins: /plugin · codewhale setup --plugins\n- Tools डायरेक्टरी: codewhale setup --tools\n\nदुष्प्रभावी कार्रवाइयों के लिए हमेशा स्पष्ट पुष्टि आवश्यक है। प्लगइन कमांड स्लैश कमांड से अलग रहते हैं; Hotbar प्लगइन स्रोत अनुमति गेट आने तक स्थगित रहता है।\n\nजो अभी मैन्युअल बाहरी सेटअप माँगता है, उसके लिए docs/MCP.md और docs/skills/README.md देखें।",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — Codewhale के माध्यम से जुड़ा, कभी दूसरा शेड्यूलर नहीं:\n- स्थिति: {dsh_result}\n- केवल-पढ़ने वाली पहचान; जोड़ें/योजना/चलाएँ/हटाएँ: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale केवल $CODEWHALE_HOME/integrations/dsh में लिखता है; API कुंजियाँ कभी कॉपी नहीं करता और DSH फ़ाइलें नहीं बदलता।",
"HotbarActionModeOperateName": "Operate मोड",
"HotbarActionModeOperateDescription": "किसी स्थायी अनुरोध पर तब तक समानांतर काम करें जब तक वह सत्यापित न हो जाए।",
"HomeOperateModeTip": "Operate — अपने Fleet को समानांतर काम पर लगाएँ",
"HomeOperateModeFleetTip": " बिल्ट-इन भूमिकाएँ इस सत्र का मॉडल इस्तेमाल करती हैं; /fleet setup उन्हें अनुकूलित करता है",
"HelpSubtitle": "कमांड, स्किल और कीबाइंडिंग",
"CommandPaletteTitle": "कमांड",
"CommandPaletteSubtitle": "एक कार्रवाई खोजें और चलाएँ",
"ConfigSubtitle": "पहले सेटिंग्स; रॉ कुंजियाँ उन्नत विवरण में",
"LaunchStartTitle": "यहाँ से शुरू करें",
"LaunchResumeConfirm": "{title} फिर से शुरू करें? पुष्टि के लिए दोबारा क्लिक करें या Enter दबाएँ।",
"LaunchResumeConfirmTitle": "सत्र फिर से शुरू करें",
"LaunchResumeConfirmBody": "इससे मौजूदा संदर्भ उस सत्र के इतिहास से बदल जाएगा।",
"LaunchResumeConfirmResume": "जारी रखें",
"LaunchResumeConfirmCancel": "रद्द करें",
"LaunchWorkDescription": "इस फ़ोल्डर में स्थानीय टूल इस्तेमाल करें; बदलाव आपकी स्वीकृति नीति के अनुसार होंगे।",
"LaunchChatDescription": "सिर्फ़ बातचीत और योजना; फ़ाइलों में कोई बदलाव नहीं।",
"LaunchWorkspaceGitReady": "वर्कस्पेस · {name} · Git वर्कस्पेस",
"LaunchWorkspaceFolderReady": "वर्कस्पेस · {name} · स्थानीय फ़ोल्डर",
"LaunchProviderConfigured": "प्रोवाइडर · कॉन्फ़िगर किया गया",
"LaunchProviderSetupNeeded": "प्रोवाइडर · सेटअप आवश्यक",
"LaunchGroupContinue": "जारी रखें",
"LaunchGroupMore": "और",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "फ़ोल्डर",
"LaunchProviderConfiguredShort": "प्रोवाइडर सेट",
"LaunchProviderSetupShort": "प्रोवाइडर सेटअप",
"LaunchMenuChangelog": "चेंजलॉग",
"LaunchWorktreePrompt": "ब्रांच/worktree का नाम दें, या स्वचालित नाम के लिए Enter दबाएँ। Esc से वापस।",
"LaunchWorktreeNeedsGit": "नए worktree के लिए Git रिपॉज़िटरी आवश्यक।",
"LaunchWorktreeNameLabel": "worktree नाम",
"LaunchHintMove": "घुमाएँ",
"LaunchHintOpen": "खोलें",
"LaunchTipFlags": "सुझाव: -w <path> वर्कस्पेस खोलता है; -r <session-id> सीधे फिर शुरू करता है",
"LaunchSavedSessionSingular": "1 सहेजा सत्र",
"LaunchSavedSessionsPlural": "{count} सहेजे सत्र",
"LaunchCreatingWorktree": "worktree बन रहा है…",
"LaunchWorktreeFailed": "worktree विफल: {error}",
"LaunchWorktreeCreated": "नया worktree {path}, ब्रांच {branch} पर",
"LaunchNoSavedSessions": "इस वर्कस्पेस के लिए कोई सहेजा सत्र नहीं।",
"LaunchNoModelConnected": "कोई मॉडल कनेक्ट नहीं",
"DispatchNotSentNoModel": "कोई मॉडल जुड़ा नहीं है, इसलिए यह संदेश नहीं भेजा गया। यह संदेश बॉक्स में वापस है: F3 या /provider से मॉडल जोड़ें, फिर भेजने के लिए Enter दबाएँ।",
"DispatchNotSentSaveKey": "कुंजी सहेजें: {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "{model} इस्तेमाल हो रहा है, जो इसी कंप्यूटर पर चलने वाला मॉडल है (Ollama)। दूसरा चुनने के लिए F3 दबाएँ।",
"ProviderPickerNotReopened": "प्रदाता सूची दोबारा नहीं खुल सकी। इसे खोलने के लिए F3 दबाएँ।",
"LaunchRunCommand": "{command} चलाएँ",
"LaunchMcpConnectedOne": "1 MCP सर्वर कनेक्टेड",
"LaunchMcpConnectedMany": "{count} MCP सर्वर कनेक्टेड",
"LaunchMcpNeedsSignInOne": "1 को साइन-इन चाहिए",
"LaunchMcpNeedsSignInMany": "{count} को साइन-इन चाहिए",
"PhaseIdle": "निष्क्रिय",
"PhaseDraft": "मसौदा",
"PhaseWorking": "काम चल रहा",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "समापन हो रहा",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "केवल पठन",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "कभी नहीं",
"PermissionsChangedReceipt": "अनुमतियाँ बदलकर {label} हुईं",
"FooterHintKeys": "कुंजियाँ",
"FooterHintOutput": "आउटपुट",
"FooterHintContext": "कॉन्टेक्स्ट",
"InfoLineHelp": "मदद",
"InfoLineContext": "संदर्भ",
"InfoLineTtft": "ttft",
"InfoLinePeak": "पीक",
"InfoLineOffPeak": "ऑफ-पीक",
"InfoLineWhales": "व्हेल",
"InfoLineAutomation": "स्वचालन",
"InfoLineNotConnected": "कनेक्ट नहीं है",
"InfoLineThinking": "सोच: {level}",
"EmptyStateNoGit": "git नहीं",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "कोई भी मॉडल खोजें",
"RoutePanelHeader": "रूट",
"RouteProviderLabel": "प्रोवाइडर",
"RouteModelFirstAtomic": "मॉडल-प्रथम एटॉमिक रूट",
"PickerActionMove": "घुमाएँ",
"PickerActionSwitch": "बदलें",
"PickerActionApply": "लागू करें",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "खोज साफ़ करें",
"PickerActionBrowseAll": "सब ब्राउज़ करें",
"PickerActionCustom": "कस्टम",
"PickerActionJump": "जंप",
"PickerActionEditKey": "कुंजी संपादित करें",
"PickerActionModels": "मॉडल",
"PickerActionUnavailable": "अनुपलब्ध",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "वह साइन-इन इस्तेमाल करना बंद करें",
"ProviderExternalActionChoices": "किसी दूसरे ऐप से साइन इन करें",
"ProviderExternalActionReuseGrok": "बाहरी Grok पुनःउपयोग",
"ProviderExternalHintCodexReview": "{login} के बाद, अक्षम/रीड-ओनली/मैनेज्ड एक्सेस विकल्पों की समीक्षा के लिए Enter दबाएँ।",
"ProviderExternalHintXaiReview": "Codewhale-स्वामित्व डिवाइस लॉगिन के लिए Enter दबाएँ; मौजूदा Grok CLI पुनःउपयोग की समीक्षा के लिए E दबाएँ।",
"ProviderExternalHintXaiApiKey": "या XAI_API_KEY इस्तेमाल करें और यह पिकर फिर खोलें।",
"XaiAuthChoiceTitle": " xAI प्रमाणीकरण ",
"XaiAuthChoiceIntro": "एक स्पष्ट क्रेडेंशल स्रोत चुनें। कुंजी के पाठ को कभी OAuth टोकन नहीं माना जाता।",
"XaiAuthChoiceApiKeyOption": "xAI API कुंजी — लिखें या चिपकाएँ, फिर xAI प्रदाता स्लॉट में सहेजें",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT / Codex प्रमाणीकरण ",
"ChatgptAuthChoiceIntro": "सदस्यता साइन-इन आपके ChatGPT प्लान पर बिल होता है। openai API-कुंजी मार्ग का बिलिंग स्वामी अलग है।",
"ChatgptAuthChoicePkceOption": "ChatGPT से साइन इन करें — ब्राउज़र PKCE, Codewhale के स्वामित्व वाले टोकन, ChatGPT सदस्यता बिलिंग",
"ChatgptAuthChoiceImportOption": "Codex CLI क्रेडेंशियल आयात करें — स्पष्ट केवल-पढ़ने की सहमति; स्वामी Codex CLI ही रहता है",
"ProviderExternalHintChatgptReview": "ChatGPT से साइन इन करने के लिए Enter दबाएँ; मौजूदा Codex CLI पुनः उपयोग देखने के लिए E दबाएँ।",
"ProviderExternalActionReuseCodex": "बाह्य Codex पुनः उपयोग",
"ProviderExternalDetailScope": "बाहरी: एक्सेस={access} | प्रोवाइडर={provider} | स्रोत={source} | संस्करण={version} | {state}",
"ProviderExternalDormant": "निष्क्रिय",
"ProviderExternalOwnerPath": "स्वामी/पथ: {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "{workspace} के लिए स्नैपशॉट और /undo बंद हैं: होम या रूट निर्देशिका सुरक्षित स्नैपशॉट के लिए बहुत बड़ी है। इन्हें चालू करने के लिए किसी प्रोजेक्ट निर्देशिका में शुरू करें।",
"SnapshotsHistoryRepaired": "{workspace} का undo इतिहास क्षतिग्रस्त था (उसका नवीनतम पुनर्स्थापना बिंदु गायब था) और इसे फिर से शुरू किया गया है। पहले के पुनर्स्थापना बिंदु अब पुनर्स्थापित नहीं किए जा सकते; नए टर्न फिर से सुरक्षित हैं।",
"SnapshotsFailing": "{workspace} के लिए स्नैपशॉट विफल हो रहे हैं, इसलिए /undo हाल के टर्न पुनर्स्थापित नहीं कर सकता: {limit}",
"SessionIdDivergedNotice": "इस विंडो की सत्र पहचान बदल गई है: इंजन अब चेकपॉइंट {next} के रूप में सहेजता है (पहले {previous} था)। पुराने चेकपॉइंट पुराने id के तहत ही रहेंगे; `codewhale sessions` दोनों दिखाता है और `codewhale resume {previous}` पुराना सत्र फिर खोलता है।",
"RuntimeStoreUnreadableNotice": "सत्र रनटाइम स्टोर: {path} पर {record} पढ़ा नहीं जा सका ({reason})। उस फ़ाइल को अलग रख दें (या हटा दें) और फिर से कोशिश करें; थ्रेड के बाकी रिकॉर्ड यथावत रहते हैं।",
"RuntimeStoreUnwritableNotice": "सत्र रनटाइम स्टोर: {path} पर {record} लिखा नहीं जा सका ({reason})। वहाँ खाली जगह और अनुमतियाँ जाँचें, फिर दोबारा कोशिश करें; कुछ भी अधिलेखित नहीं हुआ।",
"ProviderExternalSemanticsRevoke": "{semantics} | रद्द: {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "सेटअप",
"FleetRosterWorkers": "वर्कर",
"FleetRosterMembersCount": "{count} सदस्य",
"FleetRosterOperatorFirst": "समन्वयक का नेतृत्व · सत्र मॉडल इस Fleet को चलाता है",
"FleetRosterOperatorRow": "समन्वयक · नेता",
"FleetRosterShadowBadgeProjectOverride": "इस प्रोजेक्ट में सहेजा गया",
"FleetRosterShadowBadgePersonalIgnored": "सहेजी गई प्रतिलिपि अनदेखी",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "यह आपका वर्तमान मॉडल है (टीम का operator रूट); मॉडल बदलें या इसे बदलने के लिए /fleet save का उपयोग करें",
"FleetModelReasonAlreadyPresent": "पहले से टीम में है",
"FleetModelErrorNeedsRoute": "टीम मॉडल के लिए provider id और model id दोनों ज़रूरी हैं",
"FleetModelErrorNeedsRole": "एजेंट के लिए भूमिका का नाम ज़रूरी है (जैसे `/fleet add {route} scout`)।",
"FleetModelErrorNoSelection": "कोई टीम चयनित नहीं है; आपकी टीम केवल सत्र मॉडल है",
"FleetModelErrorOperatorRoute": "{route} टीम `{fleet}` का operator रूट है; इसे remove से नहीं, /fleet save से बदलें",
"FleetModelErrorNotInFleet": "{route} टीम `{fleet}` में नहीं है",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ जोड़ें · 1 मिलान",
"FilePickerMatchesPlural": "@ जोड़ें · {count} मिलान",
"FilePickerScanning": "वर्कस्पेस स्कैन हो रहा…",
"BehavioralTipPlanning": "योजना बना रहे? {key} से Plan मोड में जाएँ",
"BehavioralTipBackgroundReceipt": "रसीदें Work पैनल में रहती हैं — {key} इंस्पेक्टर खोलता है",
"BehavioralTipClearedInput": "साफ़ हुआ · {chord} से पुनर्स्थापित",
"BehavioralTipMcpValidation": "{command} सर्वर शुरू करता है और कारण दिखाता है",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "मॉडल और थिंकिंग",
"SettingSubjectProvider": "प्रोवाइडर",
"SettingSubjectPermissions": "अनुमतियाँ",
"ThinkingControlledByAutoRouting": "थिंकिंग स्वचालित मॉडल रूटिंग से नियंत्रित है; पहले कोई निश्चित मॉडल चुनें।",
"SavedAsStartupDefault": "स्टार्टअप डिफ़ॉल्ट के रूप में सहेजा",
"ModeAlreadyActiveSavedAsDefault": "पहले से {mode} मोड में — स्टार्टअप डिफ़ॉल्ट के रूप में सहेजा।",
"StartupDefaultNotSaved": "{setting} सहेजा नहीं गया: {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun pay-as-you-go और Step Plan सदस्यताओं का बिल अलग-अलग endpoints पर बनाता है। वही चुनें जिससे आपकी कुंजी संबंधित है।",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (टोकन मूल्य)",
"StepfunBillingRoutePlanOption": "Step Plan सदस्यता (प्लान भत्ता)",
"StepfunPlanApiKeyHint": "StepFun Step Plan सदस्यताओं के लिए अपने Step Plan के लिए जारी कुंजी उपयोग करें, pay-as-you-go कुंजी नहीं।",
"StepfunPlanRouteHint": "यह मार्ग {route} उपयोग करता है और आपके Step Plan भत्ते से बिल होता है।",
"ConfigLabelSessionsRail": "सत्र पट्टी",
"ConfigLabelSessionAutoResume": "अंतिम सत्र स्वतः फिर शुरू करें",
"SessionsRailTitle": "सत्र",
"SessionsRailEmpty": "इस कार्यक्षेत्र में अभी कोई सत्र नहीं",
"SessionsRailBrowseAll": "सभी सत्र देखें",
"SessionsRailShowingCount": "{total} में से {shown} — सभी देखें",
"SessionsRailUnavailable": "सत्र अनुपलब्ध: {error}",
"SessionsActionArchive": "संग्रहित करें",
"SessionsActionShowArchived": "संग्रहित",
"SessionsArchived": "सत्र {id} संग्रहित हुआ",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "एजेंट",
"FooterHintToManage": "प्रबंधन",
"AgentRailQueuedCount": "{count} कतार में",
"WorkbarSoFar": "अब तक {done}/{total}",
"WorkbarLargeWorkflow": "बड़ा वर्कफ़्लो",
"WorkbarMoreRuns": "+{count} और",
"WorkflowLineStarted": "शुरू हुआ",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "कमियों के साथ पूरा हुआ",
"WorkflowLineFailed": "विफल",
"WorkflowLineStopped": "रोका गया",
"WorkflowLineAgents": "{done}/{total} एजेंट",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "लिख सकता है",
"AgentFocusPostureReadOnly": "केवल-पढ़ने",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "केवल-पढ़ने शेल",
"AgentFocusPostureShellNone": "शेल नहीं",
"GoalReceiptSet": "लक्ष्य सेट: \"{objective}\" · /goal प्रगति दिखाता है · /goal pause या /goal clear इसे रोकता है",
"GoalReceiptSetOperate": "◆ लक्ष्य सेट · Operate सत्यापित होने तक काम करता रहेगा · संपादित करने के लिए /goal",
"GoalControlAccepted": "लक्ष्य नियंत्रण सहेजा गया; इसे अगले सुरक्षित विराम पर लागू किया जाएगा।",
"GoalControlRuntimeUnavailable": "लक्ष्य नियंत्रण सहेजा गया है, लेकिन रनटाइम उपलब्ध नहीं है। पुनः आरंभ के बाद इसे बहाल किया जाएगा।",
"GoalStatusIdleHint": "अभी नहीं चल रहा — जारी रखने के लिए संदेश भेजें या /goal resume",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "लक्ष्य सक्रिय · अगला टर्न {delay} में · Esc, Ctrl+C या /goal pause लंबित जारीकरण रोकता है",
"GoalContinuationReady": "लक्ष्य जारीकरण तैयार है; अगली टर्न से पहले कतारबद्ध नियंत्रण चलेंगे।",
"GoalContinuationStopped": "लंबित लक्ष्य जारीकरण रोक दिया गया; लक्ष्य सक्रिय है।",
"McpCapabilitiesAdvertised": "घोषित क्षमताएँ: {capabilities}",
"McpCapabilitiesLegacyFallback": "घोषित क्षमताएँ: उपलब्ध नहीं; पुराने खोज फ़ॉलबैक का उपयोग",
"McpCapabilitiesNotObserved": "घोषित क्षमताएँ: सर्वर कनेक्ट न होने के कारण अभी नहीं देखी गईं",
"PickerActionTestConnection": "कनेक्शन जाँचें",
"ProviderCustomFormBaseUrl": "बेस URL",
"ProviderCustomFormModel": "डिफ़ॉल्ट मॉडल",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "गैंट समय →",
"ConfigCategoryAppearance": "रूप",
"ConfigCategoryModelsProviders": "मॉडल और प्रदाता",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "कार्य",
"ConfigCategoryToolsMcp": "टूल और MCP",
"ConfigCategoryTrust": "भरोसा",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "केवल पढ़ने योग्य",
"ConfigRowActionNote": "क्रिया · सहेजी गई सेटिंग नहीं",
"ConfigRowDiagnosticNote": "देखी गई रसीद · यहाँ संपादन योग्य नहीं",
"ConfigNavHint": "←/→ या Tab श्रेणी · ↑/↓ सेटिंग",
"ConfigActivateAgain": "Enter दबाएँ या फिर क्लिक करें:",
"ConfigSearchLabel": " खोज: ",
"ConfigEditChooseLabel": "चुनें:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "कभी नहीं",
"ConfigChoiceModeAct": "कार्य",
"ConfigChoiceModePlan": "योजना (केवल पढ़ने योग्य)",
"ConfigChoiceModeOperate": "संचालन",
"ConfigChoicePlacementTop": "ऊपर",
"ConfigChoicePlacementBottom": "निचली पट्टी",
"ConfigChoicePlacementLeft": "बायाँ साइडबार",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "टूल के जोखिम की स्वतः समीक्षा करता है और निर्णय आपकी ज़रूरत होने पर पूछता है।",
"ConfigChoiceDetailUseTuiDefault": "रूट config का अधिभाव हटाकर TUI में सहेजी गई अनुमति का विकल्प उपयोग करता है।",
"ConfigChoiceDetailFullAccess": "टूल बिना पूछे चलेंगे, और कमांड इस कंप्यूटर पर किसी भी चीज़ तक पहुँच सकती हैं।",
"ConfigChoiceDetailNever": "अनुमोदन चाहने वाले हर टूल को रोकता है।",
"ConfigChoiceDetailModeAgent": "सहयोग और टूल उपयोग के लिए तैयार अवस्था में शुरू होता है।",
"ConfigChoiceDetailModePlan": "केवल पढ़ने योग्य योजना क्षेत्र में शुरू होता है।",
"ConfigChoiceDetailModeOperate": "Operate पूरी ताक़त वाला Work है: हर ठोस अनुरोध एक लक्ष्य बनता है, वर्कफ़्लो और समानांतर वर्करों से गुज़रता है, एक स्वतंत्र समीक्षक उसकी जाँच करता है, और सत्यापित होने तक काम चलता रहता है।",
"ConfigChoiceDetailPlacementTop": "कार्य, करने योग्य और Worker को ट्रांसक्रिप्ट के ऊपर दिखाता है।",
"ConfigChoiceDetailPlacementBottom": "कार्य, करने योग्य और Worker को कम्पोज़र के नीचे दिखाता है।",
"ConfigChoiceDetailPlacementLeft": "टर्मिनल पर्याप्त चौड़ा होने पर कार्य, करने योग्य और Worker को बाएँ साइडबार में दिखाता है।",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "मॉडल तर्क की पृष्ठभूमि भरता है।",
"ConfigChoiceDetailThinkingHighlightOff": "बिना भरी पृष्ठभूमि के बिंदीदार तर्क रेखा और तिरछा पाठ रखता है।",
"ConfigHintModel": "इस सत्र के लाइव रूट का मॉडल; Enter से /model खुलता है",
"ConfigHintFastModel": "जब इस प्रदाता का कोई ज्ञात सहोदर मॉडल हो तो Auto रूटिंग और एजेंट का model_strength=faster इसे उपयोग करता है",
"ConfigHintProvider": "क्रेडेंशियल, मॉडल और endpoint एक साथ बदलते हैं",
"ConfigHintApprovalMode": "केवल इस सत्र में: पूछें | स्वचालित समीक्षा | पूर्ण पहुँच",
"ConfigHintPermissionPosture": "नए सत्रों का डिफ़ॉल्ट: पूछें | स्वचालित समीक्षा | पूर्ण पहुँच",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "पूर्णांक (0 मान्य) · दोबारा लाने और इतिहास खोज के लिए रखे जाने वाले भेजे गए संदेशों की संख्या",
"ConfigHintAutoCompactThreshold": "10..=100 · संपीड़न सीमा: उपयोग योग्य संदर्भ लंबाई का वह प्रतिशत जिस पर स्वतः संपीड़न चलता है",
"ConfigHintDefaultModel": "केवल DeepSeek के लिए पुराना फ़ॉलबैक; अन्य प्रदाता ऊपर अपने प्रदाता-विशिष्ट मॉडल का उपयोग करते हैं",
"ConfigHintReasoningEffort": "default मॉडल का अपना डिफ़ॉल्ट लौटाता है; हमेशा सोचने वाले मॉडल में off नहीं होता",
"ConfigHintMcpOpen": "MCP प्रबंधक खोलें · कनेक्ट / पुनः कनेक्ट / पुनः प्रमाणीकरण / निदान",
"ConfigHintMcpReconnect": "MCP पुनः कनेक्ट · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "पैच संपादन टूल की केवल पढ़ने योग्य फ़ीचर फ़्लैग स्थिति",
"ConfigHintFeatureMcp": "MCP टूल की केवल पढ़ने योग्य फ़ीचर फ़्लैग स्थिति",
"ConfigHintFeatureExecPolicy": "निष्पादन नीति टूल की केवल पढ़ने योग्य फ़ीचर फ़्लैग स्थिति",
"ConfigHintFeatureVisionModel": "दृष्टि/मॉडल छवि समर्थन के लिए बीटा फ़ीचर फ़्लैग",
"ConfigHintGoalCommand": "/goal लक्ष्य, बजट और कार्य-संदर्भ स्थिति सेट करता है",
"ConfigHintWorkflow": "/workflow वितरण/समेकन रन कार्ड के साथ स्क्रिप्टेड संचालन चलाता है",
"LaunchMenuNewWorktree": "नया वर्कट्री",
"LaunchMenuResume": "सेशन फिर से शुरू करें",
"LaunchMenuQuit": "बंद करें",
"LaunchNoticeClaude": "Claude Code मिला। क्या लाया जा सकता है यह देखने के लिए /import-claude चलाएँ: MCP सर्वर, सुरक्षित सेटिंग्स और अनुमतियाँ। आपकी स्वीकृति के बिना कुछ लागू नहीं होता।",
"LaunchNewSession": "नया सत्र",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "फिर से शुरू करने के लिए ↑",
"LaunchHelpLine": "कमांड के लिए /help · वर्क बार के लिए {dock}",
"LaunchSeeAllSessions": "सभी सत्र देखें…",
"LaunchNoRecentSessions": "अभी कोई हालिया सत्र नहीं — शुरू करने के लिए नीचे लिखें।",
"LaunchResumeFailed": "फिर से शुरू विफल: {error}",
"ReceiptSessionHooks": "हुक {count}",
"AutomationEditorNew": "नया स्वचालन",
"AutomationEditorEdit": "स्वचालन संपादित करें",
"AutomationEditorSchedule": "समय-सारणी",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} पूरे",
"WorkflowPhaseCountOne": "{count} चरण",
"WorkflowPhaseCountMany": "{count} चरण",
"WorkflowPhaseOrdinal": "चरण {n}/{total}",
"ModelPickerPinned": "{route} पिन किया गया",
"ModelPickerUnpinned": "{route} का पिन हटाया गया",
"ModelPickerPinFailed": "पिन अपडेट नहीं हो सका: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "पिछला Codewhale {provider} साइन-इन ({account}) बदल दिया गया।",
"AuthReplacedPreviousSignIn": "पिछला Codewhale {provider} साइन-इन बदल दिया गया।",
"AuthSameAccountAsBefore": "यह पहले वाला ही खाता है; किसी दूसरे {provider} खाते का उपयोग करने के लिए ब्राउज़र में इससे साइन आउट करें (या निजी विंडो खोलें) और फिर से साइन इन करें।",
"AuthEnvTokenOutranksSignIn": "इस परिवेश में OPENAI_CODEX_ACCESS_TOKEN या CODEX_ACCESS_TOKEN सेट है और यह इस साइन-इन पर प्राथमिकता रखता है; जब तक आप इसे हटा नहीं देते, अनुरोध उसी टोकन के खाते का उपयोग करते रहेंगे।",
"PinnedPromptJumpToMessage": "इस संदेश पर जाएँ",
"PlanHandoffHeader": "योजना तैयार",
"PlanHandoffQuestion": "आप आगे कैसे बढ़ना चाहते हैं?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "ब्राउज़र से साइन इन करने के लिए Enter दबाएँ। वापस जाने के लिए Esc दबाएँ। API कुंजी की ज़रूरत नहीं है।",
"PluginOAuthReady": "{provider}: साइन इन हो गया। मॉडल चुनें।",
"PluginOAuthLocalLogout": "{provider}: स्थानीय साइन इन हटाया गया। दूरस्थ पहुँच नहीं बदली है।",
"CmdConnectDescription": "ब्राउज़र साइन-इन से किसी प्लगइन प्रदाता को जोड़ें",
"CmdDisconnectDescription": "किसी प्लगइन प्रदाता का स्थानीय साइन-इन हटाएँ",
"ExecAutoHelp": "अपने-आप मंज़ूरी और Full Access (शेल सैंडबॉक्स नहीं, भरोसा मोड चालू) के साथ टूल चालू करें, जब तक कोई अधिक सख्त सैंडबॉक्स कॉन्फ़िगर न हो; फ़ाइल और शेल से लिखने को सीमित करने के लिए --sandbox workspace-write इस्तेमाल करें।",
"ExecSandboxHelp": "इस रन की sandbox नीति; danger-full-access के अलावा कोई भी --sandbox (या कॉन्फ़िगरेशन में समान sandbox_mode) ट्रस्ट मोड बंद करता है।",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime menutup aliran peristiwa percakapan ini; buka kembali percakapan",
"MobileStreamReconnecting": "Koneksi terputus; menghubungkan kembali",
"MobileStreamConnected": "Terhubung",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Satu habitat bersama",
"PetHabitatHints": "{back} kembali · {sound} suara · {browser} tampilan · {window} jendela",
"PetHabitatQueued": "Dikirim ke habitat bersama. /pet on menampilkan peliharaan dan kotak pesan.",
"PetWatchSoundOn": "Suara aktif",
"PetWatchSoundOff": "Suara nonaktif",
"PetWatchSoundPaused": "Suara dijeda",
"PetWatchSoundUnavailable": "Suara Codewhale berhenti. Periksa FFmpeg (ffplay) dan keluaran audio, lalu aktifkan suara kembali.",
"CmdPetDescription": "Gunakan peliharaan animasi sebagai tampilan utama Codewhale",
"ConfigLabelPetMode": "Mode peliharaan",
"ConfigHintPetMode": "Gunakan peliharaan animasi sebagai tampilan utama saat Codewhale dimulai.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "mode hewan peliharaan nonaktif",
"PetViewOpen": "habitat terbuka",
"PetViewClosed": "habitat tertutup",
"PetWatchRestored": "/pet memulihkan habitat sesi ini. Menunggu telemetri baru.",
"PetWatchStorageUnavailable": "Watch tidak dapat memulihkan atau menyimpan habitat ini. Berkas yang ada tetap disimpan. Gunakan {command} untuk mengekspor proses ini.",
"PetWatchExported": "Rekaman Watch disimpan: {path}",
"PetWatchExportFailed": "Rekaman Watch tidak dapat disimpan. Rekaman tetap ada di memori.",
"PetWatchExportQueued": "Menyimpan rekaman Watch…",
"PetWatchExportUnavailable": "Buka /pet dalam sesi tersimpan atau tunggu ekspor saat ini selesai.",
"PetUnobserved": "belum teramati",
"PetOffline": "luring — codewhale pet serve membangunkannya",
"PetDozing": "terlelap",
"PetWatchUnavailable": "Telemetri hewan peliharaan dijeda. /pet on mencoba lagi.",
"ConversationChangedBeforeUndo": "Percakapan berubah sebelum pembatalan selesai. Tidak ada yang dibatalkan dan tidak ada permintaan coba lagi yang dikirim. Periksa percakapan saat ini sebelum mencoba lagi.",
"SessionArchiveExported": "Sesi diekspor",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Ubah",
"ExtensionsHooksAddLabel": "Tambah hook",
"ExtensionsHooksAddDescription": "Buka berkas hook proyek ini di editor Anda",
"ExtensionsActionReload": "muat ulang",
"ExtensionsActionConnect": "hubungkan",
"ExtensionsActionReconnect": "hubungkan ulang",
"ExtensionsActionReauth": "otentikasi ulang",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "terhubung",
"ExtensionsStateEnabled": "diaktifkan",
"ExtensionsStateError": "galat",
"ExtensionsStateInactive": "tidak aktif",
"ExtensionsStateInapplicable": "tidak berlaku",
"ExtensionsStateInvalid": "tidak valid",
"ExtensionsStateNotInspected": "belum diperiksa",
"ExtensionsStateDisconnected": "terputus",
"ExtensionsStateRejected": "ditolak",
"ExtensionsStateReviewedCandidate": "kandidat tertinjau",
"ExtensionsStateUnderEvaluation": "sedang dievaluasi",
"ExtensionsStateUnstaged": "belum disiapkan",
"ExtensionsStateUnsupported": "tidak didukung",
"ExtensionsStateWarning": "peringatan",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ kirim ke giliran ini",
"ComposerHintLongDraft": "{shortcut}: editor eksternal",
"PendingSendingIntoTurnPrefix": " ↳ Mengirim ke giliran ini: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Tidak bisa mengirim ke giliran ini: ",
"PendingEditingFollowUpPrefix": " ↳ Menyunting tindak lanjut: ",
"PendingQueuedOnePrefix": "Antrean #1: ",
"PendingQueuedManyPrefix": "Antrean {count} · berikutnya: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Selesai berpikir",
"TranscriptThoughtFor": "Berpikir selama {duration}",
"TelemetryNoticeDefaultOn": "Pelaporan penggunaan aktif secara bawaan. Bagikan total versi, platform, sesi, fitur, dan galat dengan Codewhale dan pemroses PostHog. Juga menghitung penyedia, model katalog publik, total token, dan penggunaan alat bawaan. Tanpa konten atau IP. docs/TELEMETRY.md Nonaktifkan: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Pelaporan penggunaan Codewhale",
"TelemetryNoticeBody": "Codewhale menghitung: versi yang dijalankan, sistem operasi dan keluarga CPU,\ndurasi dan hasil sesi, serta hitungan agregat fitur dan galat.\n\nJuga menghitung penyedia dan model katalog publik yang Anda gunakan, total tokennya, dan seberapa sering setiap alat bawaan dijalankan.\n\nIa tidak pernah mengumpulkan percakapan, kode, prompt, berkas, nama berkas,\nrepositori atau cabang, konten model, maupun kredensial Anda — dan tidak pernah\nmengirim linimasa aktivitas agen per giliran atau per alat.\n\nAnda hanya dikenali melalui ID acak yang disimpan di mesin ini, diganti setiap\n90 hari. Ubah keputusan kapan saja:\n codewhale config set telemetry false\n\nSkema lengkap, per bidang: docs/TELEMETRY.md\n\nPelaporan penggunaan aktif secara bawaan. Codewhale dan PostHog memproses hitungan ini jika pengiriman dikonfigurasi. IP tidak dikumpulkan.",
"TelemetryNoticeCompactBody": "Hitungan: versi, sistem/CPU, durasi/hasil, serta total fitur/galat.\nJuga: penyedia/model, token, alat.\nID lokal acak diganti setiap 90 hari.\nTidak pernah: percakapan/kode/prompt/berkas/nama, konten model/kredensial, giliran/alat.\nSkema: docs/TELEMETRY.md\nNonaktifkan: codewhale config set telemetry false\nPelaporan penggunaan aktif secara bawaan. Codewhale dan PostHog memproses hitungan ini jika pengiriman dikonfigurasi. IP tidak dikumpulkan.",
"TelemetryNoticeChoiceKeep": "Ya, pertahankan penghitungan anonim",
"TelemetryNoticeChoiceDisable": "Tidak, matikan pelacakan",
"TelemetryNoticeActionChoose": "pilih",
"TelemetryNoticeActionConfirm": "konfirmasi",
"TelemetryNoticeActionExit": "keluar",
"TelemetryNoticeReceiptEnabled": "Penghitungan penggunaan anonim aktif. Percakapan dan kode tidak pernah dikumpulkan. Ubah di /settings; skema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Penghitungan penggunaan anonim dinonaktifkan. Anda tidak akan ditanya lagi.",
"TelemetryNoticeReceiptEnabledUnsaved": "Penghitungan penggunaan anonim aktif untuk sesi ini. Codewhale tidak dapat menyimpan pemberitahuan ini, sehingga akan muncul lagi. Ubah di /settings; skema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Penghitungan penggunaan anonim dinonaktifkan untuk sesi ini. Codewhale tidak dapat menyimpan pilihan, sehingga akan bertanya lagi saat peluncuran berikutnya.",
"TelemetryPreferenceEnabledNextLaunch": "Penghitungan penggunaan anonim akan aktif pada peluncuran berikutnya. Percakapan dan kode tidak pernah dikumpulkan.",
"TelemetryPreferenceDisabled": "Penghitungan penggunaan anonim dinonaktifkan. Data telemetri lokal telah dihapus.",
"TelemetryPreferenceDisabledWithWarning": "Penghitungan penggunaan anonim dinonaktifkan, tetapi sebagian pembersihan perlu diperhatikan: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Tidak ada aksi hotbar yang tersedia.",
"HotbarSetupRecommended": "saran",
"HotbarSetupEmptySlot": "kosong",
"HotbarSetupHelp": "Tab/Shift+Tab sumber Up/Down aksi 1-8 slot Enter tetapkan Space alihkan Delete hapus s simpan Esc batal",
"HotbarActionVoiceToggleName": "Input suara",
"HotbarActionVoiceToggleDescription": "Alihkan perekaman suara dari mikrofon terminal.",
"HotbarActionSessionCompactName": "Padatkan sesi",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Mode Work",
"HotbarActionModeAgentDescription": "Bekerja langsung di sesi saat ini.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Kompatibilitas: Work dengan izin Full Access (bukan mode terpisah).",
"HotbarActionReasoningCycleName": "Ganti penalaran",
"HotbarActionReasoningCycleDescription": "Ganti upaya penalaran terkonfigurasi untuk penyedia aktif.",
"HotbarActionReasoningCycleAutoDisabled": "Upaya penalaran dikendalikan oleh perutean model otomatis.",
"HotbarActionSidebarToggleName": "Alihkan bilah sisi",
"HotbarActionSidebarToggleDescription": "Tampilkan atau sembunyikan bilah sisi.",
"HotbarActionFileTreeToggleName": "Alihkan pohon file",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Tidak ada pengaturan tersedia.",
"ConfigNoMatchesPrefix": " Tidak ada pengaturan yang cocok dengan ",
"ConfigFilteredSettings": " Pengaturan tersaring",
"ConfigShowing": " Menampilkan",
"ConfigFooterDefault": " ketik=saring, Up/Down=pilih, Enter=edit, Esc=tutup ",
"ConfigFooterScrollable": " ketik=saring, Up/Down=pilih, Enter=edit, PgUp/PgDn=gulir, Esc=tutup ",
"ConfigFooterFiltered": " ketik=saring, Backspace=hapus, Ctrl+U/Esc=bersihkan, Enter=edit ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; saran teks bayangan berlaku setelah giliran berikutnya)",
"ConfigNotificationsSetHint": "Atur dengan /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; berlaku untuk peringatan berikutnya)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs harus berupa bilangan bulat",
"ConfigAuditSearchProvider": "Menulis [search] provider; pemanggilan web_search berikutnya tetap menghormati penggantian lingkungan.",
"ConfigAuditPromptSuggestion": "Menulis prompt_suggestion tingkat atas; saran teks bayangan tetap opsional.",
"ConfigAuditNotifications": "Menulis nilai skalar [notifications] dan menerapkannya pada peringatan penyelesaian giliran berikutnya.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL API penyedia",
"ConfigHintProviderUrl": "Endpoint penyedia saat ini; Xiaomi: paket token | bayar sesuai pemakaian | URL kustom",
"ConfigLabelModel": "Model penyedia aktif",
"ConfigLabelFastModel": "Model cepat (turunan)",
"ConfigLabelDefaultModel": "Model cadangan lama (khusus rute DeepSeek)",
"ConfigLabelReasoningEffort": "Tingkat penalaran",
"ConfigLabelApprovalMode": "Izin sesi ini",
"ConfigLabelPermissionPosture": "Izin sesi baru",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Total versi, sesi, fitur, dan galat ke Codewhale dan PostHog; tidak pernah konten atau IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Aktif",
"ConfigValueTelemetryOff": "Nonaktif",
"ConfigLabelStreamTimeout": "Batas waktu stream",
"ConfigLabelTheme": "Tema",
"ConfigLabelLocale": "Bahasa",
"ConfigLabelBackground": "Latar belakang",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Sorotan latar penalaran",
"ConfigLabelShowToolDetails": "Tingkat detail alat",
"ConfigLabelInlineDiffs": "Perubahan file inline",
"ConfigLabelStatusIndicator": "Indikator status",
"ConfigLabelSynchronizedOutput": "Laju output",
"ConfigLabelCostCurrency": "Mata uang biaya",
"ConfigLabelTranscriptSpacing": "Jarak transkrip",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "Kepadatan komposer",
"ConfigLabelComposerBorder": "Bingkai komposer",
"ConfigLabelComposerMultilineMode": "Mode multibaris komposer",
"ConfigLabelComposerVimMode": "Mode Vim komposer",
"ConfigLabelBracketedPaste": "Bracketed paste",
"ConfigLabelPasteBurstDetection": "Deteksi tempel",
"ConfigLabelMentionMenuLimit": "Batas menu mention",
"ConfigLabelMentionMenuBehavior": "Perilaku menu mention",
"ConfigLabelMentionWalkDepth": "Kedalaman mention file",
"ConfigLabelWorkspaceFollowSymlinks": "Ikuti symlink",
"ConfigLabelContextPanel": "Panel konteks",
"ConfigLabelAutoCompact": "Padatkan otomatis",
"ConfigLabelAutoCompactThreshold": "Ambang pemadatan",
"ConfigLabelMaxHistory": "Riwayat input",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "Perintah tujuan",
"ConfigLabelWorkflow": "Alur kerja",
"ConfigLabelFeaturePrefix": "Fitur: {name}",
"ConfigColumnSetting": "Pengaturan",
"ConfigColumnValue": "Nilai",
"ConfigColumnScope": "Cakupan",
"ConfigActionOpenProvider": "Enter membuka pemilih penyedia",
"ConfigActionOpenModel": "Enter membuka pemilih model",
"ConfigActionOpenMcp": "Enter membuka pengelola MCP",
@@ -415,6 +456,7 @@
"HelpKeybindings": "Pintasan keyboard",
"HelpUserCommands": "Perintah pengguna",
"HelpSkills": "Keterampilan",
"HelpFooterTypeFilter": " ketik untuk menyaring ",
"HelpFooterMove": " Up/Down pindah ",
"HelpFooterJump": " PgUp/PgDn lompat ",
"HelpFooterClose": " Esc tutup ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "Plugin yang disarankan: {name}",
"PluginCtaReview": "Tinjau",
"PluginCtaInstall": "Pasang",
"PluginCtaReviewTrust": "Tinjau kepercayaan",
"PluginCtaEnable": "Aktifkan",
"PluginCtaDismiss": "Jangan sarankan lagi",
"PluginCtaDismissSaveFailed": "Disembunyikan untuk sesi ini; preferensi plugin tidak dapat disimpan.",
"PluginSuggestionReason": "Cocok dengan “{trigger}”",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "Aksi plugin gagal: {error}",
"CmdPluginNoneFound": "Tidak ada alat plugin eksekusi lama yang ditemukan di {dir}",
"CmdPluginNotFound": "Plugin '{name}' tidak ditemukan",
"CmdPluginListHeader": "Alat plugin eksekusi lama ({count}):",
"CmdPluginDetailDescription": "Deskripsi: {description}",
"CmdPluginDetailSchema": "Skema:\n{schema}",
"CmdPluginDetailApproval": "Persetujuan: {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "Katalog tersimpan; jalankan `codewhale models --update` untuk memperbarui penyedia yang dikonfigurasi.",
"ModelsUpdateSummary": "Katalog model: {updated} diperbarui, {loaded} dimuat dari Codex, {failed} gagal, {skipped} dilewati.",
"ModelsUpdatePartial": "Beberapa katalog tidak dapat diperbarui. Model sebelumnya dan yang dikonfigurasi tetap tersedia.",
"ModelsCodexHint": "Model ChatGPT dimuat melalui Codex. Waktu pencarian tidak memastikan katalog penyedia telah diperbarui.",
"ModelsSourceFallback": "Model bawaan atau yang dikonfigurasi; ketersediaan belum diverifikasi.",
"CmdModelDbDescription": "Telusuri database model bawaan",
"CmdNetworkDescription": "Kelola aturan izinkan dan tolak jaringan",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "Lihat atau edit pesan dalam antrean",
"CmdQueueUsage": "Penggunaan: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "{count} pesan dalam antrean dari sesi sebelumnya dipulihkan. Pesan tidak dikirim otomatis: /queue send <n> mengirim satu, /queue clear membuangnya.",
"CmdQueueDraftHeader": "Mengedit pesan dalam antrean:",
"CmdQueueNoMessages": "Tidak ada pesan dalam antrean",
"CmdQueueListHeader": "Pesan dalam antrean ({count}):",
"CmdQueueTip": "Kiat: /queue send <n> untuk mengirim sekarang, /queue drop <n> untuk menghapus",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} hit / {miss} miss",
"CmdTokensCacheHitOnly": "{hit} hit / miss tidak dilaporkan",
"CmdTokensCacheMissOnly": "hit tidak dilaporkan / {miss} miss",
"CmdTokensContextUnknownWindow": "~{estimated} / jendela tidak diketahui",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 agen",
"FooterAgentsPlural": "{count} agen",
"HeaderAgentsChip": "agen {count}",
"FooterPressCtrlCAgain": "Tekan Ctrl+C lagi untuk keluar",
"FooterWorking": "bekerja",
"FooterBalancePrefix": "saldo",
"HelpSectionActions": "Aksi",
"HelpSectionClipboard": "Papan klip",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "tidak dilaporkan",
"CmdTokensReport": "Penggunaan Token:\n─────────────────────────────\nKonteks aktif: {active}\nInput API terakhir: {input} (telemetri per giliran; prefiks berulang dapat terhitung lintas putaran alat)\nOutput API terakhir: {output}\nHit/miss cache: {cache} (khusus telemetri/biaya)\nToken kumulatif: {total} (telemetri penggunaan sesi)\nPerkiraan biaya sesi: {cost}\nPesan API: {api_messages}\nPesan chat: {chat_messages}\nModel: {model}",
"KbScrollTranscript": "Gulir transkrip, navigasi riwayat input, atau pilih lampiran komposer",
"KbNavigateHistory": "Navigasi riwayat input",
"KbBrowseHistory": "Telusuri riwayat percakapan",
"KbScrollTranscriptAlt": "Gulir transkrip",
"KbScrollPage": "Gulir transkrip per halaman",
@@ -807,6 +858,7 @@
"KbCompactContext": "Ringkas konteks percakapan",
"KbLastMessagePager": "Buka pager untuk pesan terakhir (saat input kosong)",
"KbSelectedDetails": "Tampilkan detail mentah alat atau pesan terpilih; Ctrl+Alt+O membuka ikhtisar seluruh giliran",
"KbToolDetailsPager": "Tampilkan detail mentah item terpilih (Alt+V)",
"KbExternalEditor": "Buka draf komposer di editor eksternal",
"KbLiveTranscript": "Buka overlay transkrip langsung (Ctrl+Shift+T; auto-scroll mengikuti ekor)",
"KbBacktrackMessage": "Mundur ke pesan pengguna sebelumnya (Left/Right berpindah, Enter untuk memutar balik)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "Buka overlay bantuan ini (saat input kosong)",
"KbCycleWorkDock": "Putar bilah kerja (todo, agen, pekerjaan, latar belakang), atau tampilan peliharaan di mode peliharaan",
"KbCycleWorkDockBack": "Putar bilah kerja atau tampilan peliharaan mundur",
"KbToggleHelp": "Alihkan overlay bantuan",
"KbToggleHelpSlash": "Alihkan overlay bantuan",
"HelpUsageLabel": "Penggunaan:",
"HelpAliasesLabel": "Alias:",
"SettingsTitle": "Pengaturan:",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan untuk meneliti dan menyajikan rencana dulu",
"HomeAgentModeYoloTip": " Shift+Tab mengganti izin: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — alat berjalan tanpa prompt persetujuan",
"HomeYoloModeCaution": " Operasi destruktif dapat langsung berjalan; pilih Ask bila ragu",
"HomePlanModeTip": "Plan — teliti dan rancang sebelum mengimplementasikan",
"HomePlanModeChecklistTip": " Sajikan rencana dan progres To-do, lalu beralih ke Work",
"HomeGoalModeTip": "Pelacakan tujuan - Atur /goal <objective> untuk mengejar sasaran",
"OnboardLanguageTitle": "Pilih bahasa Anda",
"OnboardLanguageBlurb": "Pilih bahasa UI. Anda dapat mengubahnya kapan saja dengan `/config locale <tag> --save`.",
"OnboardProviderTitle": "Pilih penyedia model Anda",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "Memilih “pertahankan” membuat penyembunyian tetap aktif untuk peluncuran ini; karena konfigurasi masih meminta \"disabled\", peluncuran berikutnya akan bertanya lagi.",
"RedactionGateSaveFailed": "Konfirmasi tidak dapat disimpan. Penyamaran tetap aktif. Coba lagi atau biarkan penyamaran aktif.",
"RedactionGateTitle": "Penyembunyian kunci di batas model",
"OnboardOfflineOption": "Ctrl+O — jelajahi offline: lihat-lihat dulu, hubungkan penyedia nanti.",
"OnboardOfflineNotice": "Menjelajah offline. Belum ada yang terhubung — jalankan /provider saat Anda ingin terhubung.",
"OnboardWelcomeTitle": "Codewhale bekerja bersama Anda di folder ini.",
"OnboardWelcomeLead": "Mari bersiap.",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "Jelaskan apa yang dilakukan proyek ini dan sebutkan titik masuk utamanya.",
"OnboardSeedFolder": "Lihat folder ini dan sarankan tugas pertama yang baik.",
"SetupWizardTitle": "Penyiapan",
"SetupWizardWhy": "Shell ini mencatat progres penyiapan di setup_state.json; perubahan konfig hanya diterapkan lewat aksi langkah eksplisit.",
"SetupWizardProgress": "Langkah",
"SetupActionBack": "kembali",
"SetupActionContinue": "lanjut",
"SetupActionSkip": "lewati",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "gulir isi",
"SetupActionGuided": "pratinjau/ratifikasi",
"SetupActionTuneGuided": "sesuaikan",
"SetupActionModelDraft": "draf model",
"SetupActionFreeform": "kata sendiri",
"SetupActionKeepExisting": "pertahankan yang ada",
"SetupActionUseRecommended": "gunakan rekomendasi",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "rute model",
"SetupActionFleet": "penyiapan Fleet",
"SetupActionHotbar": "penyiapan Hotbar",
"SetupActionRemote": "jalur masuk remote",
"SetupActionMode": "pemilih mode",
"SetupActionConfig": "tampilan konfig",
"SetupActionRuntimePreset": "preset",
"SetupActionApplyRuntimePreset": "pratinjau/terapkan",
"SetupActionUseBundled": "pakai bawaan",
"SetupActionDefer": "tunda",
"SetupActionCancel": "batal",
"SetupStatusNotStarted": "belum dimulai",
"SetupStatusRecommended": "direkomendasikan",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "Bahasa penyiapan dicatat.",
"SetupConstitutionChoiceLabel": "Pilihan:",
"SetupConstitutionSourceLabel": "Sumber:",
"SetupConstitutionValidityLabel": "Validitas:",
"SetupConstitutionPreviewLabel": "Hash pratinjau:",
"SetupConstitutionExistingLabel": "File yang ada:",
"SetupConstitutionExpertOverrideLabel": "Override ahli:",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "Plugin:",
"SetupToolsMcpReviewHint": "Enter mencatat snapshot penyiapan ini. Tekan R untuk jalur masuk aman (tanpa auto-run).",
"SetupToolsMcpReviewed": "Kesiapan Tools/MCP dicatat.",
"SetupRemoteCloudsLabel": "Target cloud:",
"SetupRemoteBridgesLabel": "Jembatan chat:",
"SetupRemoteProvidersLabel": "Penyedia:",
"SetupRemoteModeLabel": "Mode remote:",
"SetupRemoteModeLocalOnly": "Hanya komputer ini:",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "Salin pesan",
"CtxMenuCopyMessageDesc": "tulis sel transkrip yang diklik",
"CtxMenuOpenInEditor": "Buka di editor",
"CtxMenuOpenInEditorDesc": "buka file:baris di $EDITOR",
"CtxMenuShowCell": "Tampilkan sel",
"CtxMenuShowCellDesc": "tampilkan lagi sel transkrip ini",
"CtxMenuHideCell": "Sembunyikan sel",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} selesai · {running} berjalan · {failed} gagal · {pending} menunggu",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Akses penuh (label mode usang)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Kerja langsung di sesi ini — edit dan shell meminta persetujuan",
"AppModeAutoHint": "Shell aktif dengan tinjauan risiko otomatis",
"AppModePlanHint": "Riset baca-saja dulu — ajukan rencana sebelum bertindak",
"AppModeYoloHint": "Hanya kompatibilitas — Work + akses penuh, bukan mode yang terlihat",
"AppModeOperateHint": "Work penuh: tujuan, worker paralel, terverifikasi",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- SISIP --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Hanya membaca",
"ApprovalEffectChangesFiles": "Mengubah file",
"ApprovalRiskDestructive": "Tidak dapat dibatalkan",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s izinkan sekarang, dan selalu tanya dulu lain kali",
"ApprovalOptionDeny": "Jangan izinkan",
"ApprovalOptionAbortTurn": "Hentikan giliran ini",
"ApprovalBlockTitle": "persetujuan",
"ApprovalControlsHint": "Pg↑/↓ tinjau · {details} opsi lain · Esc hentikan",
"ApprovalOwnerHeader": "Agen: {agent} · {role}",
"ApprovalGoToAgent": "g buka agen",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … terpotong · tekan {details} untuk detail lengkap",
"ApprovalAsksWithoutGit": "Tidak ada repositori Git di sini, jadi perubahan meminta izin dulu.",
"ApprovalFullAccessPolicyBlocked": "Diblokir {tool}: Full Access tidak dapat melewati kebijakan ini",
"ApprovalChooseHint": "Pilih: ",
"ApprovalChooseAction": "Enter untuk opsi terpilih, atau tekan y/a/d langsung",
"ApprovalIntentLabel": "Maksud: ",
"ApprovalMoreLines": " … (+{count} baris)",
"ApprovalProceedQuestion": "Apakah Anda ingin melanjutkan?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "Sedang memadatkan konteks…",
"ContextCompactionQueued": "Pemadatan konteks telah masuk antrean; proses akan berjalan setelah giliran aktif selesai.",
"ContextCompactionAlreadyRunning": "Pemadatan konteks sedang berlangsung.",
"ContextCompactionQueueFull": "Pemadatan konteks tidak dapat dimasukkan ke antrean karena mesin sedang sibuk; coba lagi setelah giliran selesai.",
"ContextCompactionQueueClosed": "Pemadatan konteks tidak tersedia karena mesin tidak lagi berjalan.",
"ContextCompactionRouteInvalid": "Tidak dapat memadatkan karena rute penyedia aktif tidak valid: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Pemadatan konteks dihentikan; percakapan tidak diubah",
"ContextPurgeAbandonedOnEngineSwitch": "Pembersihan sesi dibatalkan bersama mesin yang diganti; percakapan tidak diubah",
"CtxInspTitle": "Inspektor konteks",
"CtxInspSessionContext": "Konteks Sesi",
"CtxInspSystemPrompt": "Struktur System Prompt",
"CtxInspReferences": "Referensi",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — Jalur Awal Aman\n\n/setup hanya membaca inventaris lokal. Tidak pernah memulai server MCP, menginstal skill, menjalankan plugin, atau mengeksekusi perintah tak tepercaya.\n\nInventaris saat ini:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Direktori tools: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (adapter bersama): {hotbar_result}\n\nPath (home disamarkan):\n- Konfigurasi MCP: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nBootstrap aman (jalankan sendiri di terminal normal atau perintah TUI):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install <spec>\n- Plugins: /plugin · codewhale setup --plugins\n- Direktori tools: codewhale setup --tools\n\nAksi berefek samping selalu memerlukan konfirmasi eksplisit. Perintah plugin tetap berbeda dari perintah slash; sumber plugin Hotbar tetap ditunda sampai gate persetujuan hadir.\n\nLihat docs/MCP.md dan docs/skills/README.md untuk yang masih perlu setup eksternal manual.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — terhubung melalui Codewhale, bukan penjadwal kedua:\n- Status: {dsh_result}\n- Deteksi hanya-baca; hubungkan/rencanakan/jalankan/hapus: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale hanya menulis ke $CODEWHALE_HOME/integrations/dsh; tidak pernah menyalin kunci API atau mengubah berkas DSH.",
"HotbarActionModeOperateName": "Mode Operate",
"HotbarActionModeOperateDescription": "Kerjakan permintaan jangka panjang secara paralel sampai terverifikasi.",
"HomeOperateModeTip": "Operate — kerahkan Fleet Anda untuk bekerja paralel",
"HomeOperateModeFleetTip": " Peran bawaan memakai model sesi ini; /fleet setup menyesuaikannya",
"HelpSubtitle": "Perintah, keahlian, dan pintasan",
"CommandPaletteTitle": "Perintah",
"CommandPaletteSubtitle": "Temukan dan jalankan satu aksi",
"ConfigSubtitle": "Pengaturan dulu; kunci mentah di detail lanjutan",
"LaunchStartTitle": "Mulai di sini",
"LaunchResumeConfirm": "Lanjutkan {title}? Klik lagi atau tekan Enter untuk mengonfirmasi.",
"LaunchResumeConfirmTitle": "Lanjutkan sesi",
"LaunchResumeConfirmBody": "Ini mengganti konteks saat ini dengan riwayat sesi tersebut.",
"LaunchResumeConfirmResume": "lanjutkan",
"LaunchResumeConfirmCancel": "batal",
"LaunchWorkDescription": "Gunakan folder ini dengan alat lokal; perubahan mengikuti kebijakan persetujuan Anda.",
"LaunchChatDescription": "Hanya percakapan dan perencanaan; tidak ada perubahan file.",
"LaunchWorkspaceGitReady": "Ruang kerja · {name} · ruang kerja Git",
"LaunchWorkspaceFolderReady": "Ruang kerja · {name} · folder lokal",
"LaunchProviderConfigured": "Penyedia · dikonfigurasi",
"LaunchProviderSetupNeeded": "Penyedia · perlu disiapkan",
"LaunchGroupContinue": "Lanjutkan",
"LaunchGroupMore": "Lainnya",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "folder",
"LaunchProviderConfiguredShort": "penyedia dikonfigurasi",
"LaunchProviderSetupShort": "siapkan penyedia",
"LaunchMenuChangelog": "Changelog",
"LaunchWorktreePrompt": "Beri nama branch/worktree, atau tekan Enter untuk nama otomatis. Esc untuk kembali.",
"LaunchWorktreeNeedsGit": "Worktree baru memerlukan repositori Git.",
"LaunchWorktreeNameLabel": "nama worktree",
"LaunchHintMove": "pindah",
"LaunchHintOpen": "buka",
"LaunchTipFlags": "Tip: -w <path> membuka workspace; -r <session-id> melanjutkan langsung",
"LaunchSavedSessionSingular": "1 sesi tersimpan",
"LaunchSavedSessionsPlural": "{count} sesi tersimpan",
"LaunchCreatingWorktree": "Membuat worktree…",
"LaunchWorktreeFailed": "Worktree gagal: {error}",
"LaunchWorktreeCreated": "Worktree baru {path} di branch {branch}",
"LaunchNoSavedSessions": "Tidak ada sesi tersimpan untuk workspace ini.",
"LaunchNoModelConnected": "tidak ada model terhubung",
"DispatchNotSentNoModel": "Belum ada model yang terhubung, jadi pesan ini tidak terkirim. Pesan sudah kembali di kotak pesan: hubungkan model dengan F3 atau /provider, lalu tekan Enter untuk mengirimnya.",
"DispatchNotSentSaveKey": "Simpan kunci: {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "Memakai {model}, model yang berjalan di komputer ini (Ollama). Tekan F3 untuk memilih yang lain.",
"ProviderPickerNotReopened": "Daftar penyedia tidak dapat dibuka lagi. Tekan F3 untuk membukanya.",
"LaunchRunCommand": "jalankan {command}",
"LaunchMcpConnectedOne": "1 server MCP terhubung",
"LaunchMcpConnectedMany": "{count} server MCP terhubung",
"LaunchMcpNeedsSignInOne": "1 perlu masuk",
"LaunchMcpNeedsSignInMany": "{count} perlu masuk",
"PhaseIdle": "diam",
"PhaseDraft": "draf",
"PhaseWorking": "bekerja",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "menyelesaikan",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "baca saja",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "Izin diubah ke {label}",
"FooterHintKeys": "tombol",
"FooterHintOutput": "output",
"FooterHintContext": "konteks",
"InfoLineHelp": "bantuan",
"InfoLineContext": "konteks",
"InfoLineTtft": "ttft",
"InfoLinePeak": "jam puncak",
"InfoLineOffPeak": "non-puncak",
"InfoLineWhales": "paus",
"InfoLineAutomation": "otomatisasi",
"InfoLineNotConnected": "tidak terhubung",
"InfoLineThinking": "berpikir: {level}",
"EmptyStateNoGit": "tanpa git",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "cari model apa pun",
"RoutePanelHeader": "rute",
"RouteProviderLabel": "provider",
"RouteModelFirstAtomic": "rute atomik model-first",
"PickerActionMove": "pindah",
"PickerActionSwitch": "alih",
"PickerActionApply": "terapkan",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "hapus pencarian",
"PickerActionBrowseAll": "telusuri semua",
"PickerActionCustom": "kustom",
"PickerActionJump": "lompat",
"PickerActionEditKey": "edit kunci",
"PickerActionModels": "model",
"PickerActionUnavailable": "tidak tersedia",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "berhenti memakai login itu",
"ProviderExternalActionChoices": "masuk lewat aplikasi lain",
"ProviderExternalActionReuseGrok": "penggunaan ulang Grok eksternal",
"ProviderExternalHintCodexReview": "Setelah {login}, tekan Enter untuk meninjau pilihan akses nonaktif/baca-saja/terkelola.",
"ProviderExternalHintXaiReview": "Tekan Enter untuk login perangkat milik Codewhale; tekan E untuk meninjau penggunaan ulang Grok CLI yang ada.",
"ProviderExternalHintXaiApiKey": "Atau gunakan XAI_API_KEY dan buka ulang picker ini.",
"XaiAuthChoiceTitle": " Autentikasi xAI ",
"XaiAuthChoiceIntro": "Pilih satu sumber kredensial yang eksplisit. Teks kunci tidak pernah diperlakukan sebagai token OAuth.",
"XaiAuthChoiceApiKeyOption": "Kunci API xAI — ketik atau tempel, lalu simpan di slot penyedia xAI",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " Autentikasi ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "Masuk langganan ditagihkan ke paket ChatGPT Anda. Rute kunci API openai memiliki pemilik penagihan yang berbeda.",
"ChatgptAuthChoicePkceOption": "Masuk dengan ChatGPT — PKCE browser, token milik Codewhale, penagihan langganan ChatGPT",
"ChatgptAuthChoiceImportOption": "Impor kredensial CLI Codex — persetujuan eksplisit hanya-baca; CLI Codex tetap pemiliknya",
"ProviderExternalHintChatgptReview": "Tekan Enter untuk masuk dengan ChatGPT; tekan E untuk meninjau penggunaan ulang CLI Codex yang ada.",
"ProviderExternalActionReuseCodex": "penggunaan ulang Codex eksternal",
"ProviderExternalDetailScope": "Eksternal: access={access} | provider={provider} | source={source} | version={version} | {state}",
"ProviderExternalDormant": "dorman",
"ProviderExternalOwnerPath": "Pemilik/path: {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "Snapshot dan /undo nonaktif untuk {workspace}: direktori home atau root terlalu luas untuk di-snapshot dengan aman. Mulailah di direktori proyek untuk mengaktifkannya.",
"SnapshotsHistoryRepaired": "Riwayat undo untuk {workspace} rusak (titik pemulihan terakhirnya hilang) dan telah dimulai ulang. Titik pemulihan sebelumnya tidak dapat dipulihkan lagi; giliran baru kembali terlindungi.",
"SnapshotsFailing": "Snapshot gagal untuk {workspace}, jadi /undo tidak dapat memulihkan giliran terbaru: {limit}",
"SessionIdDivergedNotice": "Identitas sesi di jendela ini berubah: engine kini menyimpan checkpoint sebagai {next} (sebelumnya {previous}). Checkpoint lama tetap di id lama; `codewhale sessions` menampilkan keduanya dan `codewhale resume {previous}` membuka kembali yang lama.",
"RuntimeStoreUnreadableNotice": "Penyimpanan runtime sesi: {record} di {path} tidak dapat dibaca ({reason}). Pindahkan berkas itu (atau hapus) lalu coba lagi; rekaman lain di thread ini tetap utuh.",
"RuntimeStoreUnwritableNotice": "Penyimpanan runtime sesi: {record} di {path} tidak dapat ditulis ({reason}). Periksa ruang kosong dan izin di sana, lalu coba lagi; tidak ada yang ditimpa.",
"ProviderExternalSemanticsRevoke": "{semantics} | cabut: {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "setup",
"FleetRosterWorkers": "worker",
"FleetRosterMembersCount": "{count} anggota",
"FleetRosterOperatorFirst": "Koordinator memimpin · model sesi menjalankan Fleet ini",
"FleetRosterOperatorRow": "Koordinator · pemimpin",
"FleetRosterShadowBadgeProjectOverride": "disimpan untuk proyek ini",
"FleetRosterShadowBadgePersonalIgnored": "salinan tersimpan diabaikan",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "ini model Anda saat ini (rute operator tim); ganti model atau gunakan /fleet save untuk mengubahnya",
"FleetModelReasonAlreadyPresent": "sudah ada di tim",
"FleetModelErrorNeedsRoute": "model tim memerlukan id provider dan id model",
"FleetModelErrorNeedsRole": "Agen memerlukan nama peran (misalnya `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "tidak ada tim yang dipilih; tim Anda hanya model sesi",
"FleetModelErrorOperatorRoute": "{route} adalah rute operator tim `{fleet}`; ubah dengan /fleet save, bukan remove",
"FleetModelErrorNotInFleet": "{route} tidak ada di tim `{fleet}`",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ lampirkan · 1 cocok",
"FilePickerMatchesPlural": "@ lampirkan · {count} cocok",
"FilePickerScanning": "Memindai workspace…",
"BehavioralTipPlanning": "Merencanakan? {key} beralih ke mode Plan",
"BehavioralTipBackgroundReceipt": "Bukti ada di panel Work — {key} membuka inspektor",
"BehavioralTipClearedInput": "Terhapus · {chord} memulihkan",
"BehavioralTipMcpValidation": "{command} memulai server dan menunjukkan alasannya",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "Model dan thinking",
"SettingSubjectProvider": "Provider",
"SettingSubjectPermissions": "Izin",
"ThinkingControlledByAutoRouting": "Thinking dikendalikan oleh routing model otomatis; pilih model tetap dulu.",
"SavedAsStartupDefault": "disimpan sebagai default startup",
"ModeAlreadyActiveSavedAsDefault": "Sudah dalam mode {mode} — disimpan sebagai default startup.",
"StartupDefaultNotSaved": "{setting} tidak tersimpan: {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun menagih pay-as-you-go dan langganan Step Plan pada endpoint terpisah. Pilih yang sesuai dengan kunci Anda.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (harga per token)",
"StepfunBillingRoutePlanOption": "Langganan Step Plan (jatah paket)",
"StepfunPlanApiKeyHint": "Untuk langganan StepFun Step Plan, gunakan kunci yang diterbitkan untuk Step Plan Anda, bukan kunci pay-as-you-go.",
"StepfunPlanRouteHint": "Rute ini memakai {route} dan ditagih dari jatah Step Plan Anda.",
"ConfigLabelSessionsRail": "Panel sesi",
"ConfigLabelSessionAutoResume": "Lanjutkan otomatis sesi terakhir",
"SessionsRailTitle": "Sesi",
"SessionsRailEmpty": "Belum ada sesi di ruang kerja ini",
"SessionsRailBrowseAll": "Jelajahi semua sesi",
"SessionsRailShowingCount": "{shown} dari {total} — lihat semua",
"SessionsRailUnavailable": "Sesi tidak tersedia: {error}",
"SessionsActionArchive": "arsipkan",
"SessionsActionShowArchived": "diarsipkan",
"SessionsArchived": "Sesi {id} diarsipkan",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "agen",
"FooterHintToManage": "kelola",
"AgentRailQueuedCount": "{count} antre",
"WorkbarSoFar": "{done}/{total} sejauh ini",
"WorkbarLargeWorkflow": "Alur kerja besar",
"WorkbarMoreRuns": "+{count} lagi",
"WorkflowLineStarted": "dimulai",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "selesai dengan celah",
"WorkflowLineFailed": "gagal",
"WorkflowLineStopped": "dihentikan",
"WorkflowLineAgents": "{done}/{total} agen",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "menulis",
"AgentFocusPostureReadOnly": "hanya-baca",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell hanya-baca",
"AgentFocusPostureShellNone": "tanpa shell",
"GoalReceiptSet": "Tujuan ditetapkan: \"{objective}\" · /goal menampilkan progres · /goal pause atau /goal clear menghentikannya",
"GoalReceiptSetOperate": "◆ tujuan ditetapkan · Operate terus bekerja sampai terverifikasi · /goal untuk mengubah",
"GoalControlAccepted": "Kontrol tujuan disimpan; akan diterapkan pada batas aman berikutnya.",
"GoalControlRuntimeUnavailable": "Kontrol tujuan tersimpan, tetapi runtime tidak tersedia. Kontrol akan dipulihkan setelah dimulai ulang.",
"GoalStatusIdleHint": "tidak sedang berjalan — kirim pesan atau /goal resume untuk melanjutkan",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Sasaran aktif · giliran berikutnya dalam {delay} · Esc, Ctrl+C, atau /goal pause menghentikan kelanjutan tertunda",
"GoalContinuationReady": "Kelanjutan sasaran siap; kontrol dalam antrean dijalankan sebelum giliran berikutnya.",
"GoalContinuationStopped": "Kelanjutan sasaran tertunda dihentikan; sasaran tetap aktif.",
"McpCapabilitiesAdvertised": "Kemampuan yang diumumkan: {capabilities}",
"McpCapabilitiesLegacyFallback": "Kemampuan yang diumumkan: tidak disediakan; memakai penemuan lama sebagai cadangan",
"McpCapabilitiesNotObserved": "Kemampuan yang diumumkan: belum diamati karena server belum terhubung",
"PickerActionTestConnection": "uji koneksi",
"ProviderCustomFormBaseUrl": "URL dasar",
"ProviderCustomFormModel": "Model bawaan",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt waktu →",
"ConfigCategoryAppearance": "Tampilan",
"ConfigCategoryModelsProviders": "Model & penyedia",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Kerja",
"ConfigCategoryToolsMcp": "Alat & MCP",
"ConfigCategoryTrust": "Kepercayaan",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "hanya-baca",
"ConfigRowActionNote": "tindakan · bukan pengaturan tersimpan",
"ConfigRowDiagnosticNote": "tanda terima teramati · tidak dapat diedit di sini",
"ConfigNavHint": "←/→ atau Tab kategori · ↑/↓ pengaturan",
"ConfigActivateAgain": "Enter atau klik lagi:",
"ConfigSearchLabel": " Cari: ",
"ConfigEditChooseLabel": "Pilih:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Tidak pernah",
"ConfigChoiceModeAct": "Bertindak",
"ConfigChoiceModePlan": "Rencana (hanya-baca)",
"ConfigChoiceModeOperate": "Operasikan",
"ConfigChoicePlacementTop": "Atas",
"ConfigChoicePlacementBottom": "Bilah bawah",
"ConfigChoicePlacementLeft": "Bilah samping kiri",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Meninjau risiko alat secara otomatis dan bertanya saat keputusan membutuhkan Anda.",
"ConfigChoiceDetailUseTuiDefault": "Menghapus penimpaan config akar dan memakai pilihan izin TUI yang tersimpan.",
"ConfigChoiceDetailFullAccess": "Alat berjalan tanpa bertanya dulu, dan perintah bisa menjangkau apa pun di komputer ini.",
"ConfigChoiceDetailNever": "Memblokir setiap alat yang memerlukan persetujuan.",
"ConfigChoiceDetailModeAgent": "Mulai dalam keadaan siap berkolaborasi dan memakai alat.",
"ConfigChoiceDetailModePlan": "Mulai di ruang perencanaan hanya-baca.",
"ConfigChoiceDetailModeOperate": "Operate adalah Work dengan kekuatan penuh: setiap permintaan substansial menjadi tujuan, berjalan lewat workflow dan worker paralel, diperiksa peninjau independen, dan terus berjalan sampai terverifikasi.",
"ConfigChoiceDetailPlacementTop": "Menampilkan Tugas, Daftar tugas, dan Worker di atas transkrip.",
"ConfigChoiceDetailPlacementBottom": "Menampilkan Tugas, Daftar tugas, dan Worker di bawah komposer.",
"ConfigChoiceDetailPlacementLeft": "Menampilkan Tugas, Daftar tugas, dan Worker di bilah samping kiri saat terminal cukup lebar.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Mengisi latar penalaran model.",
"ConfigChoiceDetailThinkingHighlightOff": "Mempertahankan garis penalaran putus-putus dan teks miring tanpa latar terisi.",
"ConfigHintModel": "model rute langsung untuk sesi ini; Enter membuka /model",
"ConfigHintFastModel": "dipakai oleh perutean Auto dan model_strength=faster agen saat penyedia ini punya model saudara yang dikenal",
"ConfigHintProvider": "kredensial, model, dan endpoint berganti bersama",
"ConfigHintApprovalMode": "hanya sesi ini: Tanya | Tinjauan otomatis | Akses penuh",
"ConfigHintPermissionPosture": "bawaan untuk sesi baru: Tanya | Tinjauan otomatis | Akses penuh",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "bilangan bulat (0 diperbolehkan) · jumlah pesan terkirim yang disimpan untuk dipanggil kembali dan pencarian riwayat",
"ConfigHintAutoCompactThreshold": "10..=100 · ambang pemadatan: persentase panjang konteks yang dapat dipakai saat pemadatan otomatis dipicu",
"ConfigHintDefaultModel": "cadangan lama khusus DeepSeek; penyedia lain memakai model per penyedia di atas",
"ConfigHintReasoningEffort": "default mengembalikan bawaan model; model yang selalu berpikir tidak punya off",
"ConfigHintMcpOpen": "membuka pengelola MCP · Hubungkan / Hubungkan ulang / Autentikasi ulang / Diagnosis",
"ConfigHintMcpReconnect": "menghubungkan ulang MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "status bendera fitur hanya-baca untuk alat penyuntingan patch",
"ConfigHintFeatureMcp": "status bendera fitur hanya-baca untuk alat MCP",
"ConfigHintFeatureExecPolicy": "status bendera fitur hanya-baca untuk alat kebijakan eksekusi",
"ConfigHintFeatureVisionModel": "bendera fitur beta untuk dukungan gambar visi/model",
"ConfigHintGoalCommand": "/goal mengatur tujuan, anggaran, dan status konteks Kerja",
"ConfigHintWorkflow": "/workflow menjalankan operasi terskrip dengan kartu jalan penyebaran/penggabungan",
"LaunchMenuNewWorktree": "Worktree baru",
"LaunchMenuResume": "Lanjutkan sesi",
"LaunchMenuQuit": "Keluar",
"LaunchNoticeClaude": "Claude Code terdeteksi. Jalankan /import-claude untuk meninjau apa yang bisa dibawa: server MCP, pengaturan aman, dan izin. Tidak ada yang diterapkan tanpa persetujuan Anda.",
"LaunchNewSession": "Sesi baru",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ untuk melanjutkan",
"LaunchHelpLine": "/help untuk perintah · {dock} untuk bilah kerja",
"LaunchSeeAllSessions": "Lihat semua sesi…",
"LaunchNoRecentSessions": "Belum ada sesi terkini — ketik di bawah untuk memulai.",
"LaunchResumeFailed": "Melanjutkan gagal: {error}",
"ReceiptSessionHooks": "hook {count}",
"AutomationEditorNew": "Otomasi baru",
"AutomationEditorEdit": "Edit otomasi",
"AutomationEditorSchedule": "Jadwal",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} selesai",
"WorkflowPhaseCountOne": "{count} fase",
"WorkflowPhaseCountMany": "{count} fase",
"WorkflowPhaseOrdinal": "fase {n}/{total}",
"ModelPickerPinned": "{route} disematkan",
"ModelPickerUnpinned": "Sematan {route} dilepas",
"ModelPickerPinFailed": "Tidak dapat memperbarui sematan: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Menggantikan login Codewhale {provider} sebelumnya ({account}).",
"AuthReplacedPreviousSignIn": "Menggantikan login Codewhale {provider} sebelumnya.",
"AuthSameAccountAsBefore": "Ini akun yang sama seperti sebelumnya; untuk memakai akun {provider} lain, keluar dari akun ini di browser (atau gunakan jendela pribadi) lalu masuk lagi.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN atau CODEX_ACCESS_TOKEN diatur di lingkungan ini dan lebih diutamakan daripada login ini; permintaan tetap memakai akun token tersebut sampai Anda menghapusnya.",
"PinnedPromptJumpToMessage": "Lompat ke pesan ini",
"PlanHandoffHeader": "Rencana siap",
"PlanHandoffQuestion": "Bagaimana Anda ingin melanjutkan?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Tekan Enter untuk masuk melalui peramban atau Esc untuk kembali. Kunci API tidak diperlukan.",
"PluginOAuthReady": "{provider}: berhasil masuk. Pilih model.",
"PluginOAuthLocalLogout": "{provider}: data masuk lokal dihapus. Akses jarak jauh tidak berubah.",
"CmdConnectDescription": "Hubungkan penyedia plugin dengan masuk lewat peramban",
"CmdDisconnectDescription": "Hapus data masuk lokal penyedia plugin",
"ExecAutoHelp": "Aktifkan alat dengan persetujuan otomatis dan Full Access (tanpa sandbox shell, mode kepercayaan aktif), kecuali sandbox yang lebih ketat telah dikonfigurasi; gunakan --sandbox workspace-write untuk membatasi penulisan oleh alat berkas dan shell.",
"ExecSandboxHelp": "Kebijakan sandbox untuk proses ini; setiap --sandbox selain danger-full-access (atau sandbox_mode yang setara dalam konfigurasi) menonaktifkan mode kepercayaan.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime がこの会話のイベントストリームを閉じました。スレッドを開き直してください",
"MobileStreamReconnecting": "接続が切れました。再接続中",
"MobileStreamConnected": "接続済み",
"PetHabitatTitle": "CODEWHALE / WHALESONG · 共有ハビタット",
"PetHabitatHints": "{back} 戻る · {sound} 音 · {browser} 外観 · {window} ウィンドウ",
"PetHabitatQueued": "共有の生息地に送りました。/pet on でペットと入力欄を表示します。",
"PetWatchSoundOn": "サウンド有効",
"PetWatchSoundOff": "サウンド無効",
"PetWatchSoundPaused": "サウンド一時停止",
"PetWatchSoundUnavailable": "Codewhaleのサウンドが停止しました。FFmpeg (ffplay) とオーディオ出力を確認し、サウンドを再度有効にしてください。",
"CmdPetDescription": "動くペットをCodewhaleのメイン画面にする",
"ConfigLabelPetMode": "ペットモード",
"ConfigHintPetMode": "Codewhale の起動時にアニメーションするペットをメイン画面に表示します。",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "ペットモード オフ",
"PetViewOpen": "ハビタット表示中",
"PetViewClosed": "ハビタット非表示",
"PetWatchRestored": "/pet がこのセッションの生息環境を復元しました。新しいテレメトリを待っています。",
"PetWatchStorageUnavailable": "Watch はこの生息環境を復元または保存できませんでした。既存のファイルは保持されています。{command} で今回の記録をエクスポートできます。",
"PetWatchExported": "Watch の記録を保存しました: {path}",
"PetWatchExportFailed": "Watch の記録を保存できませんでした。記録はメモリ内に残っています。",
"PetWatchExportQueued": "Watch の記録を保存中…",
"PetWatchExportUnavailable": "保存済みのセッションで /pet を開くか、現在のエクスポートが完了するまでお待ちください。",
"PetUnobserved": "未観測",
"PetOffline": "オフライン — codewhale pet serve で起こせます",
"PetDozing": "うたた寝",
"PetWatchUnavailable": "ペットの計測が一時停止しました。/pet on で再試行します。",
"ConversationChangedBeforeUndo": "取り消しが完了する前に会話が変更されました。取り消しも再試行の送信も行っていません。現在の会話を確認してから、もう一度お試しください。",
"SessionArchiveExported": "セッションをエクスポートしました",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "編集",
"ExtensionsHooksAddLabel": "フックを追加",
"ExtensionsHooksAddDescription": "このプロジェクトのフックファイルをエディタで開く",
"ExtensionsActionReload": "再読み込み",
"ExtensionsActionConnect": "接続",
"ExtensionsActionReconnect": "再接続",
"ExtensionsActionReauth": "再認証",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "接続済み",
"ExtensionsStateEnabled": "有効",
"ExtensionsStateError": "エラー",
"ExtensionsStateInactive": "非アクティブ",
"ExtensionsStateInapplicable": "適用不可",
"ExtensionsStateInvalid": "無効",
"ExtensionsStateNotInspected": "未確認",
"ExtensionsStateDisconnected": "切断",
"ExtensionsStateRejected": "拒否済み",
"ExtensionsStateReviewedCandidate": "レビュー済み候補",
"ExtensionsStateUnderEvaluation": "評価中",
"ExtensionsStateUnstaged": "未ステージ",
"ExtensionsStateUnsupported": "未対応",
"ExtensionsStateWarning": "警告",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ このターンに送る",
"ComposerHintLongDraft": "{shortcut}: 外部エディター",
"PendingSendingIntoTurnPrefix": " ↳ このターンに送信中: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ このターンに送れませんでした: ",
"PendingEditingFollowUpPrefix": " ↳ フォローアップを編集中: ",
"PendingQueuedOnePrefix": "待機 #1: ",
"PendingQueuedManyPrefix": "待機 {count} · 次: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "思考しました",
"TranscriptThoughtFor": "{duration}思考しました",
"TelemetryNoticeDefaultOn": "使用統計の送信は既定でオンです。 バージョン・環境・セッション・機能・エラーの集計値を Codewhale と処理委託先 PostHog に共有。プロバイダー、公開カタログのモデル、トークン合計、組み込みツールの使用回数も集計します。内容や IP は収集しません。docs/TELEMETRY.md 無効にする: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale の使用統計",
"TelemetryNoticeBody": "Codewhale が集計するのは次の情報です。実行中のバージョン、OS と CPU の種類、\nセッション時間と結果、機能およびエラーの集計カウンター。\n\n使用するプロバイダーと公開カタログのモデル、そのトークン合計、各組み込みツールの実行回数も集計します。\n\n会話、コード、プロンプト、ファイル、リポジトリ名やブランチ名、モデルの内容、\n認証情報は収集しません。また、ターンごと、ツールごとのエージェント活動の\n履歴も送信しません。\n\n識別には、このマシンに保存されたランダム ID のみを使用します。この ID は\n90 日ごとに置き換えられます。あとからいつでも変更できます:\n codewhale config set telemetry false\n\n全フィールドのスキーマ: docs/TELEMETRY.md\n\n使用統計の送信は既定でオンです。 送信先が設定されている場合、Codewhale と PostHog が集計値を処理します。IP は収集しません。",
"TelemetryNoticeCompactBody": "集計: 版、OS/CPU、時間/結果、機能/エラー。\n他: プロバイダー/モデル、トークン、ツール。\nローカルのランダムIDは90日ごとに更新。\n収集なし: 会話/コード/プロンプト/ファイル/名前、モデル内容/認証情報、ターン/ツール。\nスキーマ: docs/TELEMETRY.md\n無効: codewhale config set telemetry false\n使用統計の送信は既定でオンです。 送信先が設定されている場合、Codewhale と PostHog が集計値を処理します。IP は収集しません。",
"TelemetryNoticeChoiceKeep": "はい、匿名の利用状況集計を続けます",
"TelemetryNoticeChoiceDisable": "いいえ、利用状況集計をオフにします",
"TelemetryNoticeActionChoose": "選択",
"TelemetryNoticeActionConfirm": "確定",
"TelemetryNoticeActionExit": "終了",
"TelemetryNoticeReceiptEnabled": "匿名の利用状況集計はオンです。会話やコードは一切収集しません。/settings で変更できます。スキーマ: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "匿名の利用状況集計はオフです。今後は確認しません。",
"TelemetryNoticeReceiptEnabledUnsaved": "このセッションでは匿名の利用状況集計がオンです。Codewhale はこの通知を保存できなかったため、再度表示します。/settings で変更できます。スキーマ: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "このセッションでは匿名の利用状況集計がオフです。Codewhale は選択を保存できなかったため、次回の起動時に再度確認します。",
"TelemetryPreferenceEnabledNextLaunch": "匿名の利用状況集計は次回の起動時からオンになります。会話やコードは一切収集しません。",
"TelemetryPreferenceDisabled": "匿名の利用状況集計はオフです。ローカルのテレメトリーデータを消去しました。",
"TelemetryPreferenceDisabledWithWarning": "匿名の利用状況集計はオフですが、クリーンアップの一部に対応が必要です: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "利用可能なHotbarアクションがありません。",
"HotbarSetupRecommended": "推奨",
"HotbarSetupEmptySlot": "空",
"HotbarSetupHelp": "Tab/Shift+Tab ソース Up/Down アクション 1-8 スロット Enter 割り当て Space 切替 Delete クリア s 保存 Esc キャンセル",
"HotbarActionVoiceToggleName": "音声入力",
"HotbarActionVoiceToggleDescription": "端末マイクからの音声キャプチャを切り替えます。",
"HotbarActionSessionCompactName": "セッション圧縮",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Work モード",
"HotbarActionModeAgentDescription": "現在のセッションで直接作業します。",
"HotbarActionModeYoloName": "フルアクセス (Work)",
"HotbarActionModeYoloDescription": "互換: Work + フルアクセス権限(独立モードではありません)。",
"HotbarActionReasoningCycleName": "推論強度を切替",
"HotbarActionReasoningCycleDescription": "現在のプロバイダーで設定された推論強度を順に切り替えます。",
"HotbarActionReasoningCycleAutoDisabled": "推論強度は自動モデルルーティングで制御されています。",
"HotbarActionSidebarToggleName": "サイドバー切替",
"HotbarActionSidebarToggleDescription": "サイドバーを表示または非表示にします。",
"HotbarActionFileTreeToggleName": "ファイルツリー切替",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " 設定がありません。",
"ConfigNoMatchesPrefix": " 一致する設定なし: ",
"ConfigFilteredSettings": " 絞り込み後の設定",
"ConfigShowing": " 表示",
"ConfigFooterDefault": " 入力=絞り込み, Up/Down=選択, Enter=編集, Esc=閉じる ",
"ConfigFooterScrollable": " 入力=絞り込み, Up/Down=選択, Enter=編集, PgUp/PgDn=スクロール, Esc=閉じる ",
"ConfigFooterFiltered": " 入力=絞り込み, Backspace=削除, Ctrl+U/Esc=クリア, Enter=編集 ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value}({scope}。ゴーストテキストのヒントは以降のターン後に適用されます)",
"ConfigNotificationsSetHint": "/config notifications <key> <value> [--save] で設定します。",
"ConfigNotificationUpdated": "notifications.{key} = {value}({scope}。以降の通知に適用されます)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs は整数で指定してください",
"ConfigAuditSearchProvider": "[search] provider を書き込みます。以降の web_search は引き続き環境変数の上書きを優先します。",
"ConfigAuditPromptSuggestion": "トップレベルの prompt_suggestion を書き込みます。ゴーストテキストのヒントはオプトインのままです。",
"ConfigAuditNotifications": "[notifications] のスカラー値を書き込み、以降のターン完了通知に適用します。",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "プロバイダ API URL",
"ConfigHintProviderUrl": "現在のプロバイダーエンドポイント。Xiaomi: トークンプラン | 従量課金 | カスタム URL",
"ConfigLabelModel": "現在のプロバイダモデル",
"ConfigLabelFastModel": "高速モデル(派生)",
"ConfigLabelDefaultModel": "旧互換モデル(DeepSeek ルートのみ)",
"ConfigLabelReasoningEffort": "推論レベル",
"ConfigLabelApprovalMode": "このセッションの権限",
"ConfigLabelPermissionPosture": "新規セッションの権限",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "バージョン・セッション・機能・エラーの集計値を Codewhale と PostHog に送信。内容や IP は送りません。docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "オン",
"ConfigValueTelemetryOff": "オフ",
"ConfigLabelStreamTimeout": "ストリームタイムアウト",
"ConfigLabelTheme": "テーマ",
"ConfigLabelLocale": "言語",
"ConfigLabelBackground": "背景",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "推論の背景ハイライト",
"ConfigLabelShowToolDetails": "ツール詳細レベル",
"ConfigLabelInlineDiffs": "インライン変更",
"ConfigLabelStatusIndicator": "状態インジケータ",
"ConfigLabelSynchronizedOutput": "出力ペース",
"ConfigLabelCostCurrency": "コスト通貨",
"ConfigLabelTranscriptSpacing": "会話間隔",
@@ -376,7 +408,16 @@
"ConfigLabelComposerDensity": "入力欄の密度",
"ConfigLabelComposerBorder": "入力欄の枠線",
"ConfigLabelComposerMultilineMode": "入力欄の複数行モード",
"ConfigLabelComposerVimMode": "入力欄の Vim モード",
"ConfigLabelBracketedPaste": "ブラケットペースト",
"ConfigLabelPasteBurstDetection": "ペースト検出",
"ConfigLabelMentionMenuLimit": "メンション候補上限",
"ConfigLabelMentionMenuBehavior": "メンションメニュー動作",
"ConfigLabelMentionWalkDepth": "ファイル探索深度",
"ConfigLabelWorkspaceFollowSymlinks": "シンボリックリンクを追跡",
"ConfigLabelContextPanel": "コンテキストパネル",
"ConfigLabelSessionsRail": "セッションワークバー",
"ConfigLabelSessionAutoResume": "前回のセッションを自動再開",
"ConfigLabelAutoCompact": "自動コンパクト",
"ConfigLabelAutoCompactThreshold": "コンパクトしきい値",
"ConfigLabelMaxHistory": "入力履歴",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "目標コマンド",
"ConfigLabelWorkflow": "ワークフロー",
"ConfigLabelFeaturePrefix": "機能: {name}",
"ConfigColumnSetting": "設定",
"ConfigColumnValue": "値",
"ConfigColumnScope": "範囲",
"ConfigActionOpenProvider": "Enter でプロバイダ選択を開く",
"ConfigActionOpenModel": "Enter でモデル選択を開く",
"ConfigActionOpenMcp": "Enter で MCP マネージャを開く",
@@ -416,6 +459,7 @@
"HelpKeybindings": "キー操作",
"HelpUserCommands": "ユーザーコマンド",
"HelpSkills": "スキル",
"HelpFooterTypeFilter": " 入力して絞り込み ",
"HelpFooterMove": " Up/Down 移動 ",
"HelpFooterJump": " PgUp/PgDn ジャンプ ",
"HelpFooterClose": " Esc 閉じる ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "おすすめのプラグイン: {name}",
"PluginCtaReview": "確認",
"PluginCtaInstall": "インストール",
"PluginCtaReviewTrust": "信頼を確認",
"PluginCtaEnable": "有効化",
"PluginCtaDismiss": "今後提案しない",
"PluginCtaDismissSaveFailed": "このセッションでは非表示にしました。プラグインの設定を保存できませんでした。",
"PluginSuggestionReason": "「{trigger}」に一致",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "プラグイン操作に失敗しました: {error}",
"CmdPluginNoneFound": "{dir} で従来の実行可能プラグインツールは見つかりませんでした",
"CmdPluginNotFound": "プラグイン '{name}' が見つかりません",
"CmdPluginListHeader": "従来の実行可能プラグインツール ({count}):",
"CmdPluginDetailDescription": "説明: {description}",
"CmdPluginDetailSchema": "スキーマ:\n{schema}",
"CmdPluginDetailApproval": "承認: {approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "キャッシュ済みカタログ。設定済みプロバイダーを更新するには `codewhale models --update` を実行してください。",
"ModelsUpdateSummary": "モデルカタログ: {updated} 件更新、{loaded} 件を Codex から読み込み、{failed} 件失敗、{skipped} 件スキップ。",
"ModelsUpdatePartial": "一部のカタログを更新できませんでした。以前のモデルと設定済みモデルは引き続き利用できます。",
"ModelsCodexHint": "ChatGPT モデルは Codex 経由で読み込みます。照会時刻はプロバイダーのカタログ更新を保証するものではありません。",
"ModelsSourceFallback": "同梱または設定済みのモデル。利用可能かどうかは未確認です。",
"CmdModelDbDescription": "内蔵のモデルデータベースを閲覧する",
"CmdNetworkDescription": "ネットワーク許可・拒否ルールを管理",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "キューされたメッセージを確認・編集",
"CmdQueueUsage": "使用方法: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "前のセッションのキューのメッセージ {count} 件を復元しました。自動では送信されません。/queue send <n> で 1 件送信、/queue clear で破棄します。",
"CmdQueueDraftHeader": "キューされたメッセージを編集中:",
"CmdQueueNoMessages": "キューされたメッセージはありません",
"CmdQueueListHeader": "キューされたメッセージ ({count}):",
"CmdQueueTip": "ヒント: /queue send <n> で今すぐ送信、/queue drop <n> で削除",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "ヒット {hit} / ミスは未報告",
"CmdTokensCacheMissOnly": "ヒットは未報告 / ミス {miss}",
"CmdTokensCacheWriteTotal": "このセッションのキャッシュ書き込み(作成)トークン: {write}。書き込み割増を公開しているプロバイダーでは入力レートより高く課金されます。ターン別内訳は /cache を参照。",
"CmdTokensContextUnknownWindow": "~{estimated} / コンテキスト窓不明",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 エージェント",
"FooterAgentsPlural": "{count} エージェント",
"HeaderAgentsChip": "エージェント {count}",
"FooterPressCtrlCAgain": "もう一度 Ctrl+C で終了",
"FooterWorking": "処理中",
"FooterBalancePrefix": "残高",
"HelpSectionActions": "操作",
"HelpSectionClipboard": "クリップボード",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "未報告",
"CmdTokensReport": "トークン使用量:\n─── ──────────────────────────\nアクティブコンテキスト: {active}\n直近の API 入力: {input}(ターン単位のテレメトリ。複数回のツール往復で同じプレフィックスが重複してカウントされる場合あり)\n直近の API 出力: {output}\nキャッシュヒット/ミス: {cache}(テレメトリ/コスト用のみ)\n累計トークン: {total}(セッション使用量テレメトリ)\n算定済み金額: {cost}\nAPI メッセージ: {api_messages}\nチャットメッセージ: {chat_messages}\nモデル: {model}",
"KbScrollTranscript": "会話履歴をスクロール、入力履歴を移動、または添付ファイルを選択",
"KbNavigateHistory": "入力履歴を移動",
"KbBrowseHistory": "会話履歴を閲覧",
"KbScrollTranscriptAlt": "会話履歴をスクロール",
"KbScrollPage": "ページ単位で会話履歴をスクロール",
@@ -822,6 +875,7 @@
"KbCompactContext": "会話コンテキストを圧縮",
"KbLastMessagePager": "最後のメッセージのページャーを開く(入力が空の時)",
"KbSelectedDetails": "選択したツールまたはメッセージの生の詳細を表示(Ctrl+Alt+O でターン全体の概要)",
"KbToolDetailsPager": "選択した項目の生の詳細を表示(Alt+V)",
"KbExternalEditor": "作成中の下書きを外部エディターで開く",
"KbLiveTranscript": "ライブ会話履歴オーバーレイを開く(自動追尾スクロール)",
"KbBacktrackMessage": "前のユーザーメッセージに戻る(左右でステップ、Enter で巻き戻し)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "このヘルプオーバーレイを開く(入力が空の時)",
"KbCycleWorkDock": "ワークバーを切り替え(TODO・エージェント・ジョブ・バックグラウンド)、ペットモードではペットの表示を切り替え",
"KbCycleWorkDockBack": "ワークバーまたはペットの表示を逆順に切り替え",
"KbToggleHelp": "ヘルプオーバーレイを切り替え",
"KbToggleHelpSlash": "ヘルプオーバーレイを切り替え",
"HelpUsageLabel": "使い方:",
"HelpAliasesLabel": "エイリアス:",
"SettingsTitle": "設定:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " 先に計画するなら /mode plan",
"HomeAgentModeYoloTip": " Shift+Tab で権限: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + フルアクセス — 承認なしでツール実行",
"HomeYoloModeCaution": " 破壊的操作が即実行されることがあります。迷ったら Ask を",
"HomePlanModeTip": "Plan — 実装前に調査と設計",
"HomePlanModeChecklistTip": " 計画を提示してから Work へ",
"HomeGoalModeTip": "Goal 追跡 - /goal <目標> で持続的な目標を追跡",
"OnboardLanguageTitle": "言語を選択",
"OnboardLanguageBlurb": "UI 言語を選んでください。`/config locale <tag> --save` でいつでも変更できます。",
"OnboardProviderTitle": "モデルプロバイダーを選択",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "StepFun は従量課金と Step Plan サブスクリプションを別々のエンドポイントで課金します。お使いのキーに合うものを選んでください。",
"StepfunBillingRoutePaygOption": "従量課金(トークン単価)",
"StepfunBillingRoutePlanOption": "Step Plan サブスクリプション(プラン枠)",
"StepfunPlanApiKeyHint": "StepFun の Step Plan では、従量課金用ではなく Step Plan 用に発行されたキーを使用してください。",
"StepfunPlanRouteHint": "このルートは {route} を使用し、Step Plan の利用枠から課金されます。",
"OnboardApiKeyRejectedEnv": "{env} から読み込んだ {provider} API キーが拒否されました。有効なキーを貼り付けて {path} に保存するか、環境変数を更新してください。",
"OnboardTrustTitle": "このワークスペースを知る",
"OnboardTrustQuestion": "Codewhale がこのワークスペースの指示とファイルを使って作業してもよいですか?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "「保持」を選ぶと今回の起動は秘匿化を維持します。設定が \"disabled\" のままなので、次回起動時に再確認されます。",
"RedactionGateSaveFailed": "確認を保存できませんでした。マスキングは有効のままです。再試行するか、有効のまま続行してください。",
"RedactionGateTitle": "モデル境界のキー秘匿化",
"OnboardOfflineOption": "Ctrl+O — オフラインで見る: 今は見るだけ、プロバイダーは後で接続。",
"OnboardOfflineNotice": "オフラインで見ています。まだ接続していません — 接続したくなったら /provider を実行してください。",
"OnboardWelcomeTitle": "Codewhale はこのフォルダーで一緒に作業します。",
"OnboardWelcomeLead": "準備を始めましょう。",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "このプロジェクトが何をするのか説明し、主なエントリーポイントを列挙して。",
"OnboardSeedFolder": "このフォルダーを見て、最初のタスクを提案して。",
"SetupWizardTitle": "セットアップ",
"SetupWizardWhy": "この画面は setup_state.json にセットアップ進捗を記録します。設定変更は明示的なステップ操作でのみ適用されます。",
"SetupWizardProgress": "ステップ",
"SetupActionBack": "戻る",
"SetupActionContinue": "続行",
"SetupActionSkip": "スキップ",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "本文をスクロール",
"SetupActionGuided": "プレビュー/承認",
"SetupActionTuneGuided": "調整",
"SetupActionModelDraft": "モデル草案",
"SetupActionFreeform": "自分の言葉",
"SetupActionKeepExisting": "既存を維持",
"SetupActionUseRecommended": "推奨を使用",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "モデルルート",
"SetupActionFleet": "Fleet 設定",
"SetupActionHotbar": "Hotbar 設定",
"SetupActionRemote": "リモート導入",
"SetupActionMode": "モード選択",
"SetupActionConfig": "設定ビュー",
"SetupActionRuntimePreset": "プリセット",
"SetupActionApplyRuntimePreset": "プレビュー/適用",
"SetupActionUseBundled": "同梱版を使用",
"SetupActionDefer": "後で行う",
"SetupActionCancel": "キャンセル",
"SetupStatusNotStarted": "未開始",
"SetupStatusRecommended": "推奨",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "セットアップ言語を記録しました。",
"SetupConstitutionChoiceLabel": "選択:",
"SetupConstitutionSourceLabel": "ソース:",
"SetupConstitutionValidityLabel": "妥当性:",
"SetupConstitutionPreviewLabel": "プレビューハッシュ:",
"SetupConstitutionExistingLabel": "既存ファイル:",
"SetupConstitutionExpertOverrideLabel": "上級者オーバーライド:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "プラグイン:",
"SetupToolsMcpReviewHint": "Enter で現在の Tools/MCP の事実を記録します。R で安全なオンランプ(自動実行なし)。",
"SetupToolsMcpReviewed": "Tools/MCP の準備状態を記録しました。",
"SetupRemoteCloudsLabel": "クラウドターゲット:",
"SetupRemoteBridgesLabel": "チャットブリッジ:",
"SetupRemoteProvidersLabel": "プロバイダー:",
"SetupRemoteModeLabel": "リモートモード:",
"SetupRemoteModeLocalOnly": "このマシンのみ:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "メッセージをコピー",
"CtxMenuCopyMessageDesc": "クリックしたトランスクリプトセルを書き込む",
"CtxMenuOpenInEditor": "エディタで開く",
"CtxMenuOpenInEditorDesc": "$EDITOR で file:line を開く",
"CtxMenuShowCell": "セルを表示",
"CtxMenuShowCellDesc": "このトランスクリプトセルを再表示",
"CtxMenuHideCell": "セルを隠す",
@@ -1216,9 +1290,15 @@
"FanoutCounts": "{done} 完了 · {running} 実行中 · {failed} 失敗 · {pending} 保留",
"AppModeAgent": "Work",
"AppModeAuto": "自動",
"AppModeYolo": "フルアクセス(非推奨ラベル)",
"AppModePlan": "Plan",
"AppModeAgentHint": "このセッションで直接作業 — 編集と shell は承認あり",
"AppModeAutoHint": "シェルを有効にし、リスクを自動確認します",
"AppModePlanHint": "先に調査し、実行前に計画を提示",
"AppModeYoloHint": "互換のみ — Work + フルアクセス(表示モードではない)",
"VimModeNormal": "-- ノーマル --",
"VimModeInsert": "-- 挿入 --",
"VimModeVisual": "-- ビジュアル --",
"ApprovalEffectReadsOnly": "読み取りのみ",
"ApprovalEffectChangesFiles": "ファイルを変更",
"ApprovalRiskDestructive": "元に戻せません",
@@ -1246,6 +1326,7 @@
"ApprovalSaveAskRuleHint": " · s 今回は許可し、次回からは毎回確認",
"ApprovalOptionDeny": "許可しない",
"ApprovalOptionAbortTurn": "このターンを停止",
"ApprovalBlockTitle": "承認",
"ApprovalControlsHint": "Pg↑/↓ 履歴 · {details} その他の選択肢 · Esc 停止",
"ApprovalOwnerHeader": "エージェント: {agent} · {role}",
"ApprovalGoToAgent": "g エージェントへ移動",
@@ -1271,6 +1352,8 @@
"ApprovalTruncationHint": " … 省略 · {details} で詳細を表示",
"ApprovalAsksWithoutGit": "ここには Git リポジトリがないため、編集の前に確認します。",
"ApprovalFullAccessPolicyBlocked": "{tool} をブロック: Full Access ではこのポリシーを回避できません",
"ApprovalChooseHint": "選択:",
"ApprovalChooseAction": "Enterで選択、または y/a/d を直接入力",
"ApprovalIntentLabel": "意図:",
"ApprovalMoreLines": " … (+{count} 行)",
"ApprovalProceedQuestion": "続行しますか?",
@@ -1310,10 +1393,12 @@
"ContextManualCompacting": "コンテキストを圧縮しています…",
"ContextCompactionQueued": "コンテキスト圧縮をキューに追加しました。アクティブなターンの完了後に実行されます。",
"ContextCompactionAlreadyRunning": "コンテキスト圧縮はすでに進行中です。",
"ContextCompactionQueueFull": "エンジンがビジーなため、コンテキスト圧縮をキューに追加できませんでした。ターンの完了後にもう一度お試しください。",
"ContextCompactionQueueClosed": "エンジンがすでに停止しているため、コンテキスト圧縮を利用できません。",
"ContextCompactionRouteInvalid": "アクティブなプロバイダールートが無効なため圧縮できません: {error}",
"ContextCompactionStoppedOnEngineSwitch": "コンテキスト圧縮を停止しました。会話は変更されていません",
"ContextPurgeAbandonedOnEngineSwitch": "セッションのクリーンアップは置き換えられたエンジンとともに中止されました。会話は変更されていません",
"CtxInspTitle": "コンテキストインスペクタ",
"CtxInspSessionContext": "セッションコンテキスト",
"CtxInspSystemPrompt": "システムプロンプト構造",
"CtxInspReferences": "参照",
@@ -1545,21 +1630,47 @@
"SetupToolsMcpOnRampText": "Tools / MCP / スキル / プラグイン — 安全なオンランプ\n\n/setup はローカル在庫を読むだけです。MCP サーバー起動・スキルインストール・プラグイン実行・未信頼コマンドの自動実行は行いません。\n\n現状:\n- MCP: {mcp_result}\n- スキル: {skills_result}\n- ツール: {tools_result}\n- プラグイン: {plugins_result}\n- ホットバー(共有アダプタ): {hotbar_result}\n\nパス:\n- MCP: {mcp_path}\n- スキル: {skills_path}\n- プラグイン: {plugins_path}\n\n安全なブートストラップ(明示実行):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- スキル: /skills · codewhale setup --skills\n- プラグイン: /plugin · codewhale setup --plugins\n- ツール: codewhale setup --tools\n\n副作用のある操作は常に確認が必要です。詳細は docs/MCP.md を参照してください。",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — Codewhale 経由で接続。第二のスケジューラではありません:\n- 状態: {dsh_result}\n- 読み取り専用で検出。接続/計画/起動/削除: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale が書き込むのは $CODEWHALE_HOME/integrations/dsh のみ。API キーのコピーや DSH ファイルの編集は行いません。",
"HotbarActionModeOperateName": "Operate モード",
"HotbarActionModeOperateDescription": "長く続く依頼を、検証が済むまで並列で進めます。",
"HomeOperateModeTip": "Operate — Fleet を並列で動かす",
"HomeOperateModeFleetTip": " 組み込みロールはこのセッションのモデルを使用。/fleet setup でカスタマイズ",
"AppModeOperate": "Operate",
"AppModeOperateHint": "全力の Work:ゴール、並列ワーカー、停止前に検証",
"HelpSubtitle": "コマンド・スキル・キー操作",
"CommandPaletteTitle": "コマンド",
"CommandPaletteSubtitle": "操作を見つけて実行",
"ConfigSubtitle": "設定を先に。生キーは高度な詳細へ",
"LaunchStartTitle": "ここから始める",
"LaunchResumeConfirm": "{title} を再開しますか?もう一度クリックするか Enter で確定します。",
"LaunchResumeConfirmTitle": "セッションを再開",
"LaunchResumeConfirmBody": "現在のコンテキストがそのセッションの履歴に置き換わります。",
"LaunchResumeConfirmResume": "再開",
"LaunchResumeConfirmCancel": "キャンセル",
"LaunchWorkDescription": "このフォルダーでローカルツールを使います。変更は承認ポリシーに従います。",
"LaunchChatDescription": "会話と計画のみ。ファイルは変更しません。",
"LaunchWorkspaceGitReady": "ワークスペース · {name} · Git ワークスペース",
"LaunchWorkspaceFolderReady": "ワークスペース · {name} · ローカルフォルダー",
"LaunchProviderConfigured": "プロバイダー · 設定済み",
"LaunchProviderSetupNeeded": "プロバイダー · 設定が必要",
"LaunchGroupContinue": "続ける",
"LaunchGroupMore": "その他",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "フォルダー",
"LaunchProviderConfiguredShort": "プロバイダー設定済み",
"LaunchProviderSetupShort": "プロバイダー設定",
"LaunchMenuChangelog": "更新履歴",
"LaunchWorktreePrompt": "ブランチ/ワークツリーに名前を付けるか、Enter を押して自動命名にします。 Esc で戻ります。",
"LaunchWorktreeNeedsGit": "新規ワークツリーには Git リポジトリが必要です。",
"LaunchWorktreeNameLabel": "ワークツリー名",
"LaunchHintMove": "移動",
"LaunchHintOpen": "開く",
"LaunchTipFlags": "ヒント: -w <path> でワークスペースを開き、-r <session-id> で直接再開します",
"LaunchSavedSessionSingular": "保存済みセッション 1 件",
"LaunchSavedSessionsPlural": "保存済みセッション {count} 件",
"LaunchCreatingWorktree": "ワークツリーを作成中…",
"LaunchWorktreeFailed": "ワークツリーの作成に失敗: {error}",
"LaunchWorktreeCreated": "新しいワークツリー {path}(ブランチ {branch})",
"LaunchNoSavedSessions": "このワークスペースには保存済みセッションがありません。",
"LaunchNoModelConnected": "モデル未接続",
"DispatchNotSentNoModel": "モデルが接続されていないため、このメッセージは送信されませんでした。メッセージは入力欄に戻っています。F3 または /provider でモデルを接続してから Enter で送信してください。",
"DispatchNotSentSaveKey": "キーを保存: {command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "このコンピューターで動くモデル {model}(Ollama)を使用しています。別のモデルを選ぶには F3 を押してください。",
"ProviderPickerNotReopened": "プロバイダー一覧を再度開けませんでした。F3 を押して開いてください。",
"LaunchRunCommand": "{command} を実行",
"LaunchMcpConnectedOne": "MCP サーバー 1 台接続済み",
"LaunchMcpConnectedMany": "MCP サーバー {count} 台接続済み",
"LaunchMcpNeedsSignInOne": "1 台はサインインが必要",
"LaunchMcpNeedsSignInMany": "{count} 台はサインインが必要",
"PhaseIdle": "待機",
"PhaseDraft": "下書き",
"PhaseWorking": "処理中",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "仕上げ中",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "読み取り専用",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "権限を {label} に変更しました",
"FooterHintKeys": "キー",
"FooterHintOutput": "出力",
"FooterHintContext": "コンテキスト",
"InfoLineHelp": "ヘルプ",
"InfoLineContext": "コンテキスト",
"InfoLineTtft": "ttft",
"InfoLinePeak": "ピーク",
"InfoLineOffPeak": "オフピーク",
"InfoLineWhales": "クジラ",
"InfoLineAutomation": "自動化",
"InfoLineNotConnected": "未接続",
"InfoLineThinking": "思考: {level}",
"EmptyStateNoGit": "git なし",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "任意のモデルを検索",
"RoutePanelHeader": "ルート",
"RouteProviderLabel": "プロバイダー",
"RouteModelFirstAtomic": "モデル優先のアトミックルート",
"PickerActionMove": "移動",
"PickerActionSwitch": "切替",
"PickerActionApply": "適用",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "検索をクリア",
"PickerActionBrowseAll": "すべて表示",
"PickerActionCustom": "カスタム",
"PickerActionJump": "ジャンプ",
"PickerActionEditKey": "キー編集",
"PickerActionModels": "モデル",
"PickerActionUnavailable": "利用不可",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "そのサインインの使用をやめる",
"ProviderExternalActionChoices": "別のアプリでサインイン",
"ProviderExternalActionReuseGrok": "外部のGrok認証を再利用",
"ProviderExternalHintCodexReview": "{login} の後、Enterを押して無効・読み取り専用・管理アクセスを確認します。",
"ProviderExternalHintXaiReview": "EnterでCodewhale所有のデバイスログイン、Eで既存のGrok CLI認証の再利用を確認します。",
"ProviderExternalHintXaiApiKey": "またはXAI_API_KEYを使用して、このピッカーを再度開きます。",
"XaiAuthChoiceTitle": " xAI 認証 ",
"XaiAuthChoiceIntro": "明示的な認証情報ソースを1つ選択してください。キーの文字列がOAuthトークンとして扱われることはありません。",
"XaiAuthChoiceApiKeyOption": "xAI APIキー — 入力または貼り付けて、xAIプロバイダースロットに保存",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT / Codex 認証 ",
"ChatgptAuthChoiceIntro": "サブスクリプションのサインインは ChatGPT プランに請求されます。openai の API キー経路は別の課金主体です。",
"ChatgptAuthChoicePkceOption": "ChatGPT でサインイン — ブラウザ PKCE、Codewhale 所有トークン、ChatGPT サブスクリプション課金",
"ChatgptAuthChoiceImportOption": "Codex CLI 資格情報をインポート — 明示的な読み取り専用同意。所有者は Codex CLI のまま",
"ProviderExternalHintChatgptReview": "Enter で ChatGPT にサインイン。E で既存の Codex CLI 再利用を確認。",
"ProviderExternalActionReuseCodex": "外部 Codex 再利用",
"ProviderExternalDetailScope": "外部: アクセス={access} | プロバイダー={provider} | ソース={source} | バージョン={version} | {state}",
"ProviderExternalDormant": "休止中",
"ProviderExternalOwnerPath": "所有者/パス: {owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "{workspace} ではスナップショットと /undo が無効です: ホームディレクトリやルートディレクトリは範囲が広すぎて安全にスナップショットできません。プロジェクトのディレクトリで開始すると有効になります。",
"SnapshotsHistoryRepaired": "{workspace} の undo 履歴が破損していたため(最新の復元ポイントが見つかりませんでした)、履歴を新しく開始しました。以前の復元ポイントは復元できなくなりましたが、新しいターンは再び保護されます。",
"SnapshotsFailing": "{workspace} のスナップショットが失敗しているため、/undo で最近のターンを復元できません: {limit}",
"SessionIdDivergedNotice": "このウィンドウのセッション ID が変わりました。エンジンは今後 {next} としてチェックポイントを保存します(以前は {previous})。以前のチェックポイントは旧 ID のまま残ります。`codewhale sessions` で両方を確認でき、`codewhale resume {previous}` で以前のセッションを再開できます。",
"RuntimeStoreUnreadableNotice": "セッションのランタイムストア: {path} の {record} を読み取れませんでした({reason})。そのファイルを退避(または削除)して再試行してください。スレッドの他のレコードはそのまま残ります。",
"RuntimeStoreUnwritableNotice": "セッションのランタイムストア: {path} の {record} を書き込めませんでした({reason})。その場所の空き容量と権限を確認して再試行してください。何も上書きされていません。",
"ProviderExternalSemanticsRevoke": "{semantics} | 取消: {revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "セットアップ",
"FleetRosterWorkers": "ワーカー",
"FleetRosterMembersCount": "{count} メンバー",
"FleetRosterOperatorFirst": "コーディネーターが統率 · セッションモデルがこの Fleet を動かす",
"FleetRosterOperatorRow": "コーディネーター · リーダー",
"FleetRosterShadowBadgeProjectOverride": "このプロジェクトに保存",
"FleetRosterShadowBadgePersonalIgnored": "保存コピーは無視",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "これは現在のモデル(チーム のオペレーター経路)です。モデルを切り替えるか /fleet save で変更してください",
"FleetModelReasonAlreadyPresent": "すでに チーム に含まれています",
"FleetModelErrorNeedsRoute": "チーム のモデルにはプロバイダー ID とモデル ID の両方が必要です",
"FleetModelErrorNeedsRole": "エージェントには役割名が必要です(例:`/fleet add {route} scout`)。",
"FleetModelErrorNoSelection": "チーム が選択されていません。あなたの チーム はセッションのモデルのみです",
"FleetModelErrorOperatorRoute": "{route} は チーム `{fleet}` のオペレーター経路です。削除ではなく /fleet save で変更してください",
"FleetModelErrorNotInFleet": "{route} は チーム `{fleet}` に含まれていません",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ 添付 · 1 件一致",
"FilePickerMatchesPlural": "@ 添付 · {count} 件一致",
"FilePickerScanning": "ワークスペースをスキャン中…",
"BehavioralTipPlanning": "計画中ですか? {key} で Plan モードへ切り替えられます",
"BehavioralTipBackgroundReceipt": "レシートは Work パネルにあります — {key} でインスペクターを開く",
"BehavioralTipClearedInput": "クリアしました · {chord} で復元",
"BehavioralTipMcpValidation": "{command} はサーバーを起動し、原因を表示します",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "モデルと思考",
"SettingSubjectProvider": "プロバイダー",
"SettingSubjectPermissions": "権限",
"ThinkingControlledByAutoRouting": "思考は自動モデルルーティングが制御しています。先に固定モデルを選んでください。",
"SavedAsStartupDefault": "起動時の既定として保存しました",
"ModeAlreadyActiveSavedAsDefault": "すでに {mode} モードです — 起動時の既定として保存しました。",
"StartupDefaultNotSaved": "{setting}を保存できませんでした: {error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "思考レベル",
"StartupDefaultSubjectModel": "モデル",
"StartupDefaultSubjectAll": "起動時の既定値",
"SessionsRailTitle": "セッション",
"SessionsRailEmpty": "このワークスペースにはまだセッションがありません",
"SessionsRailBrowseAll": "すべてのセッションを表示",
"SessionsRailShowingCount": "{total} 件中 {shown} 件 — すべて表示",
"SessionsRailUnavailable": "セッションを読み込めません: {error}",
"SessionsActionArchive": "アーカイブ",
"SessionsActionShowArchived": "アーカイブ済み",
"SessionsArchived": "セッション {id} をアーカイブしました",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "エージェント",
"FooterHintToManage": "管理",
"AgentRailQueuedCount": "{count} 件キュー",
"WorkbarSoFar": "現在 {done}/{total}",
"WorkbarLargeWorkflow": "大規模なワークフロー",
"WorkbarMoreRuns": "ほか {count} 件",
"WorkflowLineStarted": "開始",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "一部欠けて完了",
"WorkflowLineFailed": "失敗",
"WorkflowLineStopped": "停止",
"WorkflowLineAgents": "{done}/{total} エージェント",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "書き込み可",
"AgentFocusPostureReadOnly": "読み取り専用",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "読み取り専用シェル",
"AgentFocusPostureShellNone": "シェル不可",
"GoalReceiptSet": "目標を設定: 「{objective}」 · /goal で進捗表示 · /goal pause または /goal clear で停止",
"GoalReceiptSetOperate": "◆ 目標を設定 · Operate は検証されるまで作業を続けます · 編集は /goal",
"GoalControlAccepted": "目標操作を保存しました。次の安全な区切りで適用します。",
"GoalControlRuntimeUnavailable": "目標操作は保存されていますが、ランタイムを利用できません。再起動後に復元します。",
"GoalStatusIdleHint": "現在は実行中ではありません — メッセージを送るか /goal resume で続行",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "目標は実行中 · 次のターンまで {delay} · Esc、Ctrl+C、または /goal pause で保留中の続行を停止",
"GoalContinuationReady": "目標の続行準備ができました。キュー内の操作を次のターンより先に実行します。",
"GoalContinuationStopped": "保留中の目標続行を停止しました。目標はアクティブなままです。",
"McpCapabilitiesAdvertised": "公開された機能: {capabilities}",
"McpCapabilitiesLegacyFallback": "公開された機能: 未提供(従来の検出フォールバックを使用)",
"McpCapabilitiesNotObserved": "公開された機能: サーバーが未接続のため未確認",
"PickerActionTestConnection": "接続テスト",
"ProviderCustomFormBaseUrl": "ベースURL",
"ProviderCustomFormModel": "既定モデル",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "ガント 時間 →",
"ConfigCategoryAppearance": "外観",
"ConfigCategoryModelsProviders": "モデルとプロバイダー",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "作業",
"ConfigCategoryToolsMcp": "ツールと MCP",
"ConfigCategoryTrust": "信頼",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "読み取り専用",
"ConfigRowActionNote": "アクション · 永続設定ではありません",
"ConfigRowDiagnosticNote": "観測レシート · ここでは編集不可",
"ConfigNavHint": "←/→ または Tab でカテゴリ · ↑/↓ で設定",
"ConfigActivateAgain": "Enter またはもう一度クリック:",
"ConfigSearchLabel": " 検索: ",
"ConfigEditChooseLabel": "選択:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "許可しない",
"ConfigChoiceModeAct": "実行",
"ConfigChoiceModePlan": "計画 (読み取り専用)",
"ConfigChoiceModeOperate": "オペレート",
"ConfigChoicePlacementTop": "上部",
"ConfigChoicePlacementBottom": "下部バー",
"ConfigChoicePlacementLeft": "左サイドバー",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "ツールのリスクを自動で確認し、判断が必要なときだけ尋ねます。",
"ConfigChoiceDetailUseTuiDefault": "ルート設定の上書きを外し、保存済みの TUI 権限設定を使います。",
"ConfigChoiceDetailFullAccess": "ツールは確認なしで実行され、コマンドはこのコンピューター上のあらゆるものにアクセスできます。",
"ConfigChoiceDetailNever": "承認が必要なツールをすべてブロックします。",
"ConfigChoiceDetailModeAgent": "ツールを使って協働できる状態で開始します。",
"ConfigChoiceDetailModePlan": "読み取り専用の計画ワークスペースで開始します。",
"ConfigChoiceDetailModeOperate": "Operate は全力の Work です。実質的な依頼はそれぞれゴールになり、ワークフローと並列ワーカーで進め、独立したレビュアーが確認し、検証が済むまで続けます。",
"ConfigChoiceDetailPlacementTop": "タスク・To-do・ワーカーをトランスクリプトの上に表示します。",
"ConfigChoiceDetailPlacementBottom": "タスク・To-do・ワーカーを入力欄の下に表示します。",
"ConfigChoiceDetailPlacementLeft": "端末が十分に広いとき、タスク・To-do・ワーカーを左サイドバーに表示します。",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "モデル推論の背景を塗りつぶします。",
"ConfigChoiceDetailThinkingHighlightOff": "背景を塗らず、破線の推論線と斜体テキストを保ちます。",
"ConfigHintModel": "このセッションのライブルートのモデル。Enter で /model を開きます",
"ConfigHintFastModel": "このプロバイダーに既知の兄弟モデルがあるとき、Auto ルーティングとエージェントの model_strength=faster が使います",
"ConfigHintProvider": "資格情報・モデル・エンドポイントを一緒に切り替えます",
"ConfigHintApprovalMode": "このセッションのみ: 確認する | 自動レビュー | フルアクセス",
"ConfigHintPermissionPosture": "新しいセッションの既定: 確認する | 自動レビュー | フルアクセス",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "整数 (0 も可) · 呼び出しと履歴検索のために保持する送信済みメッセージの数",
"ConfigHintAutoCompactThreshold": "10..=100 · 圧縮しきい値: 自動圧縮が発火する、使用可能なコンテキスト長に対する割合",
"ConfigHintDefaultModel": "DeepSeek 専用のレガシーフォールバック。他のプロバイダーは上のプロバイダー別モデルを使います",
"ConfigHintReasoningEffort": "default はモデル自身の既定に戻します。常時思考モデルには off がありません",
"ConfigHintMcpOpen": "MCP マネージャーを開く · 接続 / 再接続 / 再認証 / 診断",
"ConfigHintMcpReconnect": "MCP を再接続 · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "パッチ編集ツールの読み取り専用の機能フラグ状態",
"ConfigHintFeatureMcp": "MCP ツールの読み取り専用の機能フラグ状態",
"ConfigHintFeatureExecPolicy": "実行ポリシーツールの読み取り専用の機能フラグ状態",
"ConfigHintFeatureVisionModel": "ビジョン/モデル画像サポートのベータ機能フラグ",
"ConfigHintGoalCommand": "/goal は目標・予算・作業コンテキストの状態を設定します",
"ConfigHintWorkflow": "/workflow はファンアウト/ファンインの実行カード付きでスクリプト化した操作を実行します",
"LaunchMenuNewWorktree": "新しいワークツリー",
"LaunchMenuResume": "セッションを再開",
"LaunchMenuQuit": "終了",
"LaunchNoticeClaude": "Claude Code を検出しました。/import-claude を実行すると、MCP サーバー・安全な設定・権限のうち引き継げるものを確認できます。承認なしには何も適用されません。",
"LaunchNewSession": "新しいセッション",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ で再開",
"LaunchHelpLine": "コマンドは /help · ワークバーは {dock}",
"LaunchSeeAllSessions": "すべてのセッションを表示…",
"LaunchNoRecentSessions": "最近のセッションはまだありません — 下に入力して開始します。",
"LaunchResumeFailed": "再開に失敗しました:{error}",
"ReceiptSessionHooks": "フック {count}",
"AutomationEditorNew": "自動化を作成",
"AutomationEditorEdit": "自動化を編集",
"AutomationEditorSchedule": "スケジュール",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} 完了",
"WorkflowPhaseCountOne": "{count} フェーズ",
"WorkflowPhaseCountMany": "{count} フェーズ",
"WorkflowPhaseOrdinal": "フェーズ {n}/{total}",
"ModelPickerPinned": "{route} をピン留めしました",
"ModelPickerUnpinned": "{route} のピン留めを外しました",
"ModelPickerPinFailed": "ピン留めを更新できませんでした: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "以前の Codewhale の {provider} サインイン({account})を置き換えました。",
"AuthReplacedPreviousSignIn": "以前の Codewhale の {provider} サインインを置き換えました。",
"AuthSameAccountAsBefore": "以前と同じアカウントです。別の {provider} アカウントを使うには、ブラウザーでこのアカウントからサインアウトして(またはプライベートウィンドウを使って)、もう一度サインインしてください。",
"AuthEnvTokenOutranksSignIn": "この環境には OPENAI_CODEX_ACCESS_TOKEN または CODEX_ACCESS_TOKEN が設定されており、このサインインより優先されます。設定を解除するまで、リクエストはそのトークンのアカウントを使い続けます。",
"PinnedPromptJumpToMessage": "このメッセージへジャンプ",
"PlanHandoffHeader": "計画ができました",
"PlanHandoffQuestion": "どのように進めますか?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Enter でブラウザーからログインします。Esc で戻ります。API キーは不要です。",
"PluginOAuthReady": "{provider}:ログインしました。モデルを選択してください。",
"PluginOAuthLocalLogout": "{provider}:この端末の認証情報を削除しました。サーバーの認可は解除されていません。",
"CmdConnectDescription": "ブラウザーのログインでプラグインプロバイダーに接続します",
"CmdDisconnectDescription": "プラグインプロバイダーのこの端末のログイン情報を削除します",
"ExecAutoHelp": "ツールを自動承認と Full Access(シェルのサンドボックスなし、信頼モード有効)で有効にします。より厳しいサンドボックス設定がある場合はそれに従います。ファイルとシェルの書き込みを制限するには --sandbox workspace-write を指定してください。",
"ExecSandboxHelp": "この実行のサンドボックスポリシー。danger-full-access 以外の --sandbox(または設定内の同等の sandbox_mode)は信頼モードを無効にします。",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime이 이 대화의 이벤트 스트림을 닫았습니다. 스레드를 다시 여세요",
"MobileStreamReconnecting": "연결이 끊어졌습니다. 다시 연결 중",
"MobileStreamConnected": "연결됨",
"PetHabitatTitle": "CODEWHALE / WHALESONG · 하나의 공유 서식지",
"PetHabitatHints": "{back} 뒤로 · {sound} 소리 · {browser} 외관 · {window} 창",
"PetHabitatQueued": "공유 서식지로 보냈습니다. /pet on으로 펫과 메시지 입력란을 표시합니다.",
"PetWatchSoundOn": "소리 켜짐",
"PetWatchSoundOff": "소리 꺼짐",
"PetWatchSoundPaused": "소리 일시 중지",
"PetWatchSoundUnavailable": "Codewhale 소리가 멈췄습니다. FFmpeg (ffplay)와 오디오 출력을 확인한 후 소리를 다시 켜세요.",
"CmdPetDescription": "움직이는 펫을 Codewhale의 기본 화면으로 사용",
"ConfigLabelPetMode": "펫 모드",
"ConfigHintPetMode": "Codewhale를 시작할 때 애니메이션 펫을 기본 화면으로 표시합니다.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "펫 모드 꺼짐",
"PetViewOpen": "서식지 열림",
"PetViewClosed": "서식지 닫힘",
"PetWatchRestored": "/pet가 이 세션의 서식지를 복원했습니다. 새 원격 측정 데이터를 기다립니다.",
"PetWatchStorageUnavailable": "Watch가 이 서식지를 복원하거나 저장하지 못했습니다. 기존 파일은 유지되었습니다. {command}로 이번 실행을 내보내세요.",
"PetWatchExported": "Watch 기록 저장됨: {path}",
"PetWatchExportFailed": "Watch 기록을 저장하지 못했습니다. 기록은 메모리에 남아 있습니다.",
"PetWatchExportQueued": "Watch 기록 저장 중…",
"PetWatchExportUnavailable": "저장된 세션에서 /pet를 열거나 현재 내보내기가 끝날 때까지 기다리세요.",
"PetUnobserved": "미관측",
"PetOffline": "오프라인 — codewhale pet serve로 깨울 수 있어요",
"PetDozing": "졸고 있음",
"PetWatchUnavailable": "펫 원격 측정이 일시 중지되었습니다. /pet on 으로 재시도합니다.",
"ConversationChangedBeforeUndo": "실행 취소가 완료되기 전에 대화가 변경되었습니다. 취소된 내용이 없으며 재시도 요청도 보내지 않았습니다. 현재 대화를 확인한 후 다시 시도하세요.",
"SessionArchiveExported": "세션을 내보냈습니다",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "편집",
"ExtensionsHooksAddLabel": "훅 추가",
"ExtensionsHooksAddDescription": "이 프로젝트의 훅 파일을 편집기에서 엽니다",
"ExtensionsActionReload": "다시 로드",
"ExtensionsActionConnect": "연결",
"ExtensionsActionReconnect": "다시 연결",
"ExtensionsActionReauth": "재인증",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "연결됨",
"ExtensionsStateEnabled": "활성화됨",
"ExtensionsStateError": "오류",
"ExtensionsStateInactive": "비활성",
"ExtensionsStateInapplicable": "해당 없음",
"ExtensionsStateInvalid": "잘못됨",
"ExtensionsStateNotInspected": "검사하지 않음",
"ExtensionsStateDisconnected": "연결 끊김",
"ExtensionsStateRejected": "거부됨",
"ExtensionsStateReviewedCandidate": "검토된 후보",
"ExtensionsStateUnderEvaluation": "평가 중",
"ExtensionsStateUnstaged": "스테이징되지 않음",
"ExtensionsStateUnsupported": "지원되지 않음",
"ExtensionsStateWarning": "경고",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ 이 턴으로 보내기",
"ComposerHintLongDraft": "{shortcut}: 외부 편집기",
"PendingSendingIntoTurnPrefix": " ↳ 이 턴으로 보내는 중: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ 이 턴으로 보내지 못함: ",
"PendingEditingFollowUpPrefix": " ↳ 후속 메시지 편집 중: ",
"PendingQueuedOnePrefix": "대기 #1: ",
"PendingQueuedManyPrefix": "대기 {count} · 다음: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "생각 완료",
"TranscriptThoughtFor": "{duration} 동안 생각함",
"TelemetryNoticeDefaultOn": "사용 통계 보고는 기본적으로 켜져 있습니다. 버전·플랫폼·세션·기능·오류의 집계 수치를 Codewhale 및 처리업체 PostHog와 공유합니다. 제공업체, 공개 카탈로그 모델, 토큰 합계, 기본 제공 도구 사용 횟수도 집계합니다. 콘텐츠나 IP는 수집하지 않습니다. docs/TELEMETRY.md 끄기: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale 사용 통계",
"TelemetryNoticeBody": "Codewhale이 집계하는 항목: 실행 중인 버전, 운영 체제와 CPU 계열, 세션\n시간과 결과, 기능 및 오류의 집계 수치입니다.\n\n사용하는 제공업체와 공개 카탈로그 모델, 토큰 합계, 각 기본 제공 도구의 실행 횟수도 집계합니다.\n\n대화, 코드, 프롬프트, 파일, 파일 이름, 저장소 또는 브랜치 이름, 모델\n내용이나 자격 증명은 절대 수집하지 않으며, 턴별 또는 도구별 에이전트 활동\n기록도 전송하지 않습니다.\n\n이 컴퓨터에 저장된 임의의 ID로만 식별되며, 90일마다 새 ID로 교체됩니다.\n언제든지 변경할 수 있습니다:\n codewhale config set telemetry false\n\n필드별 전체 스키마: docs/TELEMETRY.md\n\n사용 통계 보고는 기본적으로 켜져 있습니다. 전송이 설정된 경우 Codewhale과 PostHog가 이 수치를 처리합니다. IP는 수집하지 않습니다.",
"TelemetryNoticeCompactBody": "집계: 버전, 시스템/CPU, 세션 시간/결과, 기능/오류 합계.\n추가: 제공업체/모델, 토큰, 도구 사용.\n임의의 로컬 식별자는 90일마다 교체.\n수집 안 함: 대화/코드/프롬프트/파일/이름, 모델 내용/자격 증명, 턴/도구 활동.\n스키마: docs/TELEMETRY.md\n끄기: codewhale config set telemetry false\n사용 통계 보고는 기본적으로 켜져 있습니다. 전송이 설정된 경우 Codewhale과 PostHog가 이 수치를 처리합니다. IP는 수집하지 않습니다.",
"TelemetryNoticeChoiceKeep": "네, 익명 집계를 유지합니다",
"TelemetryNoticeChoiceDisable": "아니요, 추적을 끄습니다",
"TelemetryNoticeActionChoose": "선택",
"TelemetryNoticeActionConfirm": "확인",
"TelemetryNoticeActionExit": "종료",
"TelemetryNoticeReceiptEnabled": "익명 사용량 집계가 켜져 있습니다. 대화와 코드는 수집하지 않습니다. /settings에서 변경하세요. 스키마: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "익명 사용량 집계가 꺼져 있습니다. 다시 묻지 않습니다.",
"TelemetryNoticeReceiptEnabledUnsaved": "이 세션에서는 익명 사용량 집계가 켜져 있습니다. Codewhale이 이 알림을 저장하지 못했으므로 다시 표시됩니다. /settings에서 변경하세요. 스키마: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "이 세션에서는 익명 사용량 집계가 꺼져 있습니다. Codewhale이 선택을 저장하지 못했으므로 다음 실행 때 다시 묻습니다.",
"TelemetryPreferenceEnabledNextLaunch": "익명 사용량 집계는 다음 실행부터 켜집니다. 대화와 코드는 수집하지 않습니다.",
"TelemetryPreferenceDisabled": "익명 사용량 집계가 꺼졌습니다. 로컬 텔레메트리 데이터를 지웠습니다.",
"TelemetryPreferenceDisabledWithWarning": "익명 사용량 집계가 꺼졌지만 일부 정리에 주의가 필요합니다: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "사용 가능한 핫바 동작이 없습니다.",
"HotbarSetupRecommended": "추천",
"HotbarSetupEmptySlot": "비어 있음",
"HotbarSetupHelp": "Tab/Shift+Tab 원본 Up/Down 동작 1-8 슬롯 Enter 할당 Space 전환 Delete 지우기 s 저장 Esc 취소",
"HotbarActionVoiceToggleName": "음성 입력",
"HotbarActionVoiceToggleDescription": "터미널 마이크로 음성 캡처를 켜거나 끕니다.",
"HotbarActionSessionCompactName": "세션 압축",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "실행 모드",
"HotbarActionModeAgentDescription": "현재 세션에서 바로 작업을 수행합니다.",
"HotbarActionModeYoloName": "전체 권한 (실행)",
"HotbarActionModeYoloDescription": "호환성 유지용: 전체 권한으로 실행 모드를 사용합니다 (별도 모드 아님).",
"HotbarActionReasoningCycleName": "추론 강도 전환",
"HotbarActionReasoningCycleDescription": "현재 프로바이더에 설정된 추론 강도를 순환 전환합니다.",
"HotbarActionReasoningCycleAutoDisabled": "추론 강도는 자동 모델 라우팅으로 제어됩니다.",
"HotbarActionSidebarToggleName": "사이드바 전환",
"HotbarActionSidebarToggleDescription": "사이드바를 표시하거나 숨깁니다.",
"HotbarActionFileTreeToggleName": "파일 트리 전환",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " 사용 가능한 설정이 없습니다.",
"ConfigNoMatchesPrefix": " 일치하는 설정 없음: ",
"ConfigFilteredSettings": " 필터링된 설정",
"ConfigShowing": " 표시 중",
"ConfigFooterDefault": " 입력=필터, Up/Down=선택, Enter=편집, Esc=닫기 ",
"ConfigFooterScrollable": " 입력=필터, Up/Down=선택, Enter=편집, PgUp/PgDn=스크롤, Esc=닫기 ",
"ConfigFooterFiltered": " 입력=필터, Backspace=삭제, Ctrl+U/Esc=지우기, Enter=편집 ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; 고스트 텍스트 힌트는 이후 턴이 끝난 뒤 적용됩니다)",
"ConfigNotificationsSetHint": "/config notifications <key> <value> [--save]로 설정하세요.",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; 이후 알림에 적용됩니다)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs는 정수여야 합니다",
"ConfigAuditSearchProvider": "[search] provider를 기록합니다. 이후 web_search 호출은 계속 환경 변수 재정의를 따릅니다.",
"ConfigAuditPromptSuggestion": "최상위 prompt_suggestion을 기록합니다. 고스트 텍스트 힌트는 계속 선택 사항입니다.",
"ConfigAuditNotifications": "[notifications] 스칼라 값을 기록하고 이후 턴 완료 알림에 적용합니다.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "프로바이더 API URL",
"ConfigHintProviderUrl": "현재 제공자 엔드포인트; Xiaomi: 토큰 요금제 | 사용량 기반 결제 | 사용자 지정 URL",
"ConfigLabelModel": "현재 프로바이더 모델",
"ConfigLabelFastModel": "빠른 모델 (파생됨)",
"ConfigLabelDefaultModel": "레거시 대체 모델 (DeepSeek 경로만)",
"ConfigLabelReasoningEffort": "추론 수준",
"ConfigLabelApprovalMode": "현재 세션 권한",
"ConfigLabelPermissionPosture": "새 세션 권한",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "버전·세션·기능·오류의 집계 수치만 Codewhale과 PostHog에 전송. 콘텐츠나 IP는 전송하지 않음. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "켬",
"ConfigValueTelemetryOff": "끔",
"ConfigLabelStreamTimeout": "스트림 시간 제한",
"ConfigLabelTheme": "테마",
"ConfigLabelLocale": "언어",
"ConfigLabelBackground": "배경",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "추론 배경 강조",
"ConfigLabelShowToolDetails": "도구 세부 수준",
"ConfigLabelInlineDiffs": "인라인 파일 변경",
"ConfigLabelStatusIndicator": "상태 표시기",
"ConfigLabelSynchronizedOutput": "출력 속도",
"ConfigLabelCostCurrency": "비용 통화",
"ConfigLabelTranscriptSpacing": "대화 기록 간격",
@@ -376,7 +408,16 @@
"ConfigLabelComposerDensity": "작성기 밀도",
"ConfigLabelComposerBorder": "작성기 테두리",
"ConfigLabelComposerMultilineMode": "작성기 여러 줄 모드",
"ConfigLabelComposerVimMode": "작성기 Vim 모드",
"ConfigLabelBracketedPaste": "괄호 붙여넣기",
"ConfigLabelPasteBurstDetection": "붙여넣기 감지",
"ConfigLabelMentionMenuLimit": "멘션 메뉴 제한",
"ConfigLabelMentionMenuBehavior": "멘션 메뉴 동작",
"ConfigLabelMentionWalkDepth": "파일 멘션 깊이",
"ConfigLabelWorkspaceFollowSymlinks": "심볼릭 링크 따라가기",
"ConfigLabelContextPanel": "컨텍스트 패널",
"ConfigLabelSessionsRail": "세션 작업 바",
"ConfigLabelSessionAutoResume": "마지막 세션 자동 재개",
"ConfigLabelAutoCompact": "자동 압축",
"ConfigLabelAutoCompactThreshold": "압축 임계값",
"ConfigLabelMaxHistory": "입력 기록",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "목표 명령",
"ConfigLabelWorkflow": "워크플로",
"ConfigLabelFeaturePrefix": "기능: {name}",
"ConfigColumnSetting": "설정",
"ConfigColumnValue": "값",
"ConfigColumnScope": "범위",
"ConfigActionOpenProvider": "Enter로 프로바이더 선택기 열기",
"ConfigActionOpenModel": "Enter로 모델 선택기 열기",
"ConfigActionOpenMcp": "Enter로 MCP 관리자 열기",
@@ -416,6 +459,7 @@
"HelpKeybindings": "단축키",
"HelpUserCommands": "사용자 명령",
"HelpSkills": "스킬",
"HelpFooterTypeFilter": " 입력하여 필터링 ",
"HelpFooterMove": " Up/Down 이동 ",
"HelpFooterJump": " PgUp/PgDn 이동 ",
"HelpFooterClose": " Esc 닫기 ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "추천 플러그인: {name}",
"PluginCtaReview": "검토",
"PluginCtaInstall": "설치",
"PluginCtaReviewTrust": "신뢰 검토",
"PluginCtaEnable": "활성화",
"PluginCtaDismiss": "다시 제안하지 않기",
"PluginCtaDismissSaveFailed": "이 세션에서는 숨겼습니다. 플러그인 설정을 저장하지 못했습니다.",
"PluginSuggestionReason": "“{trigger}”와 일치",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "플러그인 작업 실패: {error}",
"CmdPluginNoneFound": "{dir}에서 기존 실행형 플러그인 도구를 찾지 못했습니다",
"CmdPluginNotFound": "플러그인 '{name}'을(를) 찾을 수 없습니다",
"CmdPluginListHeader": "기존 실행형 플러그인 도구 ({count}개):",
"CmdPluginDetailDescription": "설명: {description}",
"CmdPluginDetailSchema": "스키마:\n{schema}",
"CmdPluginDetailApproval": "승인: {approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "캐시된 카탈로그입니다. 설정된 제공업체를 갱신하려면 `codewhale models --update`를 실행하세요.",
"ModelsUpdateSummary": "모델 카탈로그: {updated}개 업데이트, {loaded}개 Codex에서 불러옴, {failed}개 실패, {skipped}개 건너뜀.",
"ModelsUpdatePartial": "일부 카탈로그를 갱신하지 못했습니다. 이전 모델과 설정된 모델은 계속 사용할 수 있습니다.",
"ModelsCodexHint": "ChatGPT 모델은 Codex를 통해 불러옵니다. 조회 시각이 공급자 카탈로그의 갱신을 보장하지는 않습니다.",
"ModelsSourceFallback": "기본 제공 또는 설정된 모델입니다. 사용 가능 여부는 확인되지 않았습니다.",
"CmdModelDbDescription": "내장 모델 데이터베이스를 조회합니다",
"CmdNetworkDescription": "네트워크 허용/차단 규칙을 관리합니다",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "대기 중인 메시지를 확인하거나 편집합니다",
"CmdQueueUsage": "사용법: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "이전 세션의 대기 중인 메시지 {count}개를 복원했습니다. 자동으로 전송되지 않습니다. /queue send <n>으로 하나를 보내고 /queue clear로 삭제합니다.",
"CmdQueueDraftHeader": "대기 중인 메시지 편집 중:",
"CmdQueueNoMessages": "대기 중인 메시지가 없습니다",
"CmdQueueListHeader": "대기 중인 메시지 ({count}개):",
"CmdQueueTip": "팁: /queue send <n>으로 바로 보내거나, /queue drop <n>으로 삭제하세요",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "{hit} 적중 / 실패 미보고",
"CmdTokensCacheMissOnly": "적중 미보고 / {miss} 실패",
"CmdTokensCacheWriteTotal": "이번 세션의 캐시 쓰기(생성) 토큰: {write}. 쓰기 프리미엄을 공개한 공급자에서는 입력 요율보다 높게 과금됩니다. 턴별 내역은 /cache를 참고하세요.",
"CmdTokensContextUnknownWindow": "~{estimated} / 창 크기 알 수 없음",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "에이전트 1개",
"FooterAgentsPlural": "에이전트 {count}개",
"HeaderAgentsChip": "에이전트 {count}",
"FooterPressCtrlCAgain": "종료하려면 Ctrl+C를 다시 누르세요",
"FooterWorking": "작업 중",
"FooterBalancePrefix": "잔액",
"HelpSectionActions": "동작",
"HelpSectionClipboard": "클립보드",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "보고되지 않음",
"CmdTokensReport": "토큰 사용량:\n ─────────────────────────────\n 활성 컨텍스트: {active}\n 마지막 API 입력: {input} (턴 텔레메트리; 도구 라운드 간 반복 프리픽스가 포함될 수 있음)\n 마지막 API 출력: {output}\n 캐시 적중/실패: {cache} (텔레메트리/비용 전용)\n 누적 토큰: {total} (세션 사용량 텔레메트리)\n 가격 확인 금액: {cost}\n API 메시지: {api_messages}\n 채팅 메시지: {chat_messages}\n 모델: {model}",
"KbScrollTranscript": "대화 기록 스크롤, 입력 기록 탐색, 또는 입력창 첨부 파일 선택",
"KbNavigateHistory": "입력 기록 탐색",
"KbBrowseHistory": "대화 기록 찾아보기",
"KbScrollTranscriptAlt": "대화 기록 스크롤",
"KbScrollPage": "페이지 단위로 대화 기록 스크롤",
@@ -822,6 +875,7 @@
"KbCompactContext": "대화 컨텍스트 압축",
"KbLastMessagePager": "마지막 메시지의 페이저 열기 (입력창이 비어 있을 때)",
"KbSelectedDetails": "선택한 도구나 메시지의 원본 세부 정보 표시; Ctrl+Alt+O로 전체 턴 개요 열기",
"KbToolDetailsPager": "선택한 항목의 원본 세부 정보 표시 (Alt+V)",
"KbExternalEditor": "작성 중인 초안을 외부 편집기에서 열기",
"KbLiveTranscript": "실시간 대화 기록 오버레이 열기 (Ctrl+Shift+T; 하단 고정 자동 스크롤)",
"KbBacktrackMessage": "이전 사용자 메시지로 되돌아가기 (Left/Right로 이동, Enter로 되감기)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "이 도움말 오버레이 열기 (입력창이 비어 있을 때)",
"KbCycleWorkDock": "작업 바 순환 (할 일, 에이전트, 작업, 백그라운드), 펫 모드에서는 펫 보기 순환",
"KbCycleWorkDockBack": "작업 바 또는 펫 보기 역순 순환",
"KbToggleHelp": "도움말 오버레이 전환",
"KbToggleHelpSlash": "도움말 오버레이 전환",
"HelpUsageLabel": "사용법:",
"HelpAliasesLabel": "별칭:",
"SettingsTitle": "설정:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " /mode plan으로 먼저 조사하고 계획을 제시",
"HomeAgentModeYoloTip": " Shift+Tab으로 권한 순환: 확인 → 편집 수락 → 계획 → 자동 검토 → 전체 권한",
"HomeYoloModeTip": "실행 + 전체 권한 — 승인 없이 도구 실행",
"HomeYoloModeCaution": " 파괴적인 작업이 즉시 실행될 수 있습니다. 확실하지 않으면 확인 모드를 사용하세요",
"HomePlanModeTip": "계획 — 구현 전에 조사하고 설계",
"HomePlanModeChecklistTip": " 계획과 할 일 진행 상황을 제시한 후 실행 모드로 전환",
"HomeGoalModeTip": "목표 추적 - /goal <목표>로 목표를 설정하고 추진",
"OnboardLanguageTitle": "언어를 선택하세요",
"OnboardLanguageBlurb": "UI 언어를 선택하세요. 언제든지 `/config locale <태그> --save`로 변경할 수 있습니다.",
"OnboardProviderTitle": "모델 프로바이더를 선택하세요",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "StepFun은 종량제와 Step Plan 구독을 서로 다른 엔드포인트에서 과금합니다. 보유한 키에 맞는 항목을 선택하세요.",
"StepfunBillingRoutePaygOption": "종량제(토큰 단가)",
"StepfunBillingRoutePlanOption": "Step Plan 구독(플랜 할당량)",
"StepfunPlanApiKeyHint": "StepFun Step Plan 구독에서는 종량제 키가 아니라 Step Plan용으로 발급된 키를 사용하세요.",
"StepfunPlanRouteHint": "이 경로는 {route}를 사용하며 Step Plan 할당량에서 차감됩니다.",
"OnboardApiKeyRejectedEnv": "{env}에서 가져온 {provider} API 키가 거부되었습니다. 유효한 키를 붙여 넣어 {path}에 저장하거나 환경 변수를 업데이트하세요.",
"OnboardTrustTitle": "이 작업 공간 이해하기",
"OnboardTrustQuestion": "Codewhale이 이 작업 공간의 지침과 파일로 작업해도 될까요?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "“유지”를 고르면 이번 실행은 마스킹을 켠 채 진행됩니다. 설정이 여전히 \"disabled\"이므로 다음 실행 때 다시 묻습니다.",
"RedactionGateSaveFailed": "확인을 저장하지 못했습니다. 마스킹은 켜져 있습니다. 다시 시도하거나 마스킹을 유지하세요.",
"RedactionGateTitle": "모델 경계 키 마스킹",
"OnboardOfflineOption": "Ctrl+O — 오프라인으로 둘러보기: 지금은 구경만 하고 프로바이더는 나중에 연결합니다.",
"OnboardOfflineNotice": "오프라인으로 둘러보는 중입니다. 아직 연결되지 않았어요 — 연결하려면 /provider를 실행하세요.",
"OnboardWelcomeTitle": "Codewhale은 이 폴더에서 함께 작업합니다.",
"OnboardWelcomeLead": "준비를 시작하죠.",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "이 프로젝트가 무엇을 하는지 설명하고 주요 진입점을 나열해 줘.",
"OnboardSeedFolder": "이 폴더를 살펴보고 첫 작업을 제안해 줘.",
"SetupWizardTitle": "설정",
"SetupWizardWhy": "이 셸은 setup_state.json에 설정 진행 상황을 기록합니다. 설정 변경은 명시적인 단계별 작업으로만 적용됩니다.",
"SetupWizardProgress": "단계",
"SetupActionBack": "뒤로",
"SetupActionContinue": "계속",
"SetupActionSkip": "건너뛰기",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "본문 스크롤",
"SetupActionGuided": "미리보기/승인",
"SetupActionTuneGuided": "조정",
"SetupActionModelDraft": "모델 초안",
"SetupActionFreeform": "직접 작성",
"SetupActionKeepExisting": "기존 유지",
"SetupActionUseRecommended": "권장 설정 사용",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "모델 라우트",
"SetupActionFleet": "Fleet 설정",
"SetupActionHotbar": "핫바 설정",
"SetupActionRemote": "원격 온램프",
"SetupActionMode": "모드 선택",
"SetupActionConfig": "설정 보기",
"SetupActionRuntimePreset": "프리셋",
"SetupActionApplyRuntimePreset": "미리보기/적용",
"SetupActionUseBundled": "내장 값 사용",
"SetupActionDefer": "나중에",
"SetupActionCancel": "취소",
"SetupStatusNotStarted": "시작 안 함",
"SetupStatusRecommended": "권장",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "설정 언어를 기록했습니다.",
"SetupConstitutionChoiceLabel": "선택:",
"SetupConstitutionSourceLabel": "출처:",
"SetupConstitutionValidityLabel": "유효성:",
"SetupConstitutionPreviewLabel": "미리보기 해시:",
"SetupConstitutionExistingLabel": "기존 파일:",
"SetupConstitutionExpertOverrideLabel": "전문가 재정의:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "플러그인:",
"SetupToolsMcpReviewHint": "Enter를 누르면 이 설정 스냅샷을 기록합니다. R을 누르면 안전한 온램프를 볼 수 있습니다 (자동 실행 없음).",
"SetupToolsMcpReviewed": "도구/MCP 준비 상태를 기록했습니다.",
"SetupRemoteCloudsLabel": "클라우드 대상:",
"SetupRemoteBridgesLabel": "채팅 브리지:",
"SetupRemoteProvidersLabel": "프로바이더:",
"SetupRemoteModeLabel": "원격 모드:",
"SetupRemoteModeLocalOnly": "이 컴퓨터에서만:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "메시지 복사",
"CtxMenuCopyMessageDesc": "클릭한 대화 기록 셀 쓰기",
"CtxMenuOpenInEditor": "편집기에서 열기",
"CtxMenuOpenInEditorDesc": "$EDITOR에서 파일:줄 열기",
"CtxMenuShowCell": "셀 표시",
"CtxMenuShowCellDesc": "이 대화 기록 셀 숨김 해제",
"CtxMenuHideCell": "셀 숨기기",
@@ -1216,9 +1290,17 @@
"FanoutCounts": "완료 {done} · 실행 중 {running} · 실패 {failed} · 대기 {pending}",
"AppModeAgent": "실행",
"AppModeAuto": "자동",
"AppModeYolo": "전체 권한 (더 이상 사용되지 않는 모드 이름)",
"AppModePlan": "계획",
"AppModeOperate": "운영",
"AppModeAgentHint": "이 세션에서 바로 작업 — 편집과 셸 실행은 승인을 요청합니다",
"AppModeAutoHint": "셸 사용 가능, 자동 위험도 검토 적용",
"AppModePlanHint": "먼저 읽기 전용으로 조사 — 실행 전에 계획을 제시합니다",
"AppModeYoloHint": "호환성 유지용 — 실행 + 전체 권한이며 실제로 표시되는 모드는 아닙니다",
"AppModeOperateHint": "최대 역량의 실행: 목표, 병렬 워커, 멈추기 전에 검증",
"VimModeNormal": "-- 일반 --",
"VimModeInsert": "-- 입력 --",
"VimModeVisual": "-- 비주얼 --",
"ApprovalEffectReadsOnly": "읽기만",
"ApprovalEffectChangesFiles": "파일 변경",
"ApprovalRiskDestructive": "되돌릴 수 없음",
@@ -1246,6 +1328,7 @@
"ApprovalSaveAskRuleHint": " · s 지금 허용하고 다음부터는 항상 먼저 묻기",
"ApprovalOptionDeny": "허용 안 함",
"ApprovalOptionAbortTurn": "이번 턴 중지",
"ApprovalBlockTitle": "승인",
"ApprovalControlsHint": "Pg↑/↓ 기록 · {details} 추가 선택 · Esc 중지",
"ApprovalOwnerHeader": "에이전트: {agent} · {role}",
"ApprovalGoToAgent": "g 에이전트로 이동",
@@ -1271,6 +1354,8 @@
"ApprovalTruncationHint": " … 잘림 · 전체 상세는 {details}",
"ApprovalAsksWithoutGit": "여기에는 Git 저장소가 없어 편집 전에 먼저 묻습니다.",
"ApprovalFullAccessPolicyBlocked": "{tool} 차단됨: Full Access는 이 정책을 우회할 수 없습니다",
"ApprovalChooseHint": "선택: ",
"ApprovalChooseAction": "Enter로 선택 항목 적용, 또는 y/a/d를 바로 누르세요",
"ApprovalIntentLabel": "의도: ",
"ApprovalMoreLines": " … (+{count}줄)",
"ApprovalProceedQuestion": "계속하시겠습니까?",
@@ -1310,10 +1395,12 @@
"ContextManualCompacting": "컨텍스트 압축 중…",
"ContextCompactionQueued": "컨텍스트 압축이 대기열에 추가되었습니다. 현재 턴이 끝난 후 실행됩니다.",
"ContextCompactionAlreadyRunning": "컨텍스트 압축이 이미 진행 중입니다.",
"ContextCompactionQueueFull": "엔진이 사용 중이어서 컨텍스트 압축을 대기열에 추가할 수 없습니다. 턴이 끝난 후 다시 시도하세요.",
"ContextCompactionQueueClosed": "엔진이 더 이상 실행 중이 아니므로 컨텍스트 압축을 사용할 수 없습니다.",
"ContextCompactionRouteInvalid": "현재 프로바이더 경로가 올바르지 않아 압축할 수 없습니다: {error}",
"ContextCompactionStoppedOnEngineSwitch": "컨텍스트 압축을 중지했습니다. 대화는 변경되지 않았습니다",
"ContextPurgeAbandonedOnEngineSwitch": "교체된 엔진과 함께 세션 정리가 중단되었습니다. 대화는 변경되지 않았습니다",
"CtxInspTitle": "컨텍스트 인스펙터",
"CtxInspSessionContext": "세션 컨텍스트",
"CtxInspSystemPrompt": "시스템 프롬프트 구조",
"CtxInspReferences": "참조",
@@ -1545,21 +1632,45 @@
"SetupToolsMcpOnRampText": "도구, MCP, 스킬 및 플러그인 — 안전한 온램프\n\n/setup은 로컬 인벤토리만 읽습니다. MCP 서버를 시작하거나, 스킬을 설치하거나, 플러그인을 실행하거나, 신뢰할 수 없는 명령을 실행하는 일은 절대 없습니다.\n\n현재 인벤토리:\n- MCP: {mcp_result}\n- 스킬: {skills_result}\n- 도구 디렉터리: {tools_result}\n- 플러그인: {plugins_result}\n- 핫바 (공유 어댑터): {hotbar_result}\n\n경로 (홈 디렉터리 가림):\n- MCP 설정: {mcp_path}\n- 스킬: {skills_path}\n- 플러그인: {plugins_path}\n\n안전한 부트스트랩 (일반 터미널이나 TUI 명령에서 직접 실행하세요):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- 스킬: /skills · codewhale setup --skills · /skills install <spec>\n- 플러그인: /plugin · codewhale setup --plugins\n- 도구 디렉터리: codewhale setup --tools\n\n부작용이 있는 동작은 항상 명시적 확인이 필요합니다. 플러그인 명령어는 슬래시 명령어와는 별개이며, 핫바 플러그인 소스는 승인 게이트가 도입될 때까지 보류됩니다.\n\n아직 수동으로 외부 설정이 필요한 항목은 docs/MCP.md와 docs/skills/README.md를 참고하세요.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — Codewhale를 통해 연결되며 두 번째 스케줄러가 아닙니다:\n- 상태: {dsh_result}\n- 읽기 전용 감지; 연결/계획/실행/제거: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale는 $CODEWHALE_HOME/integrations/dsh 에만 기록하며 API 키를 복사하거나 DSH 파일을 수정하지 않습니다.",
"HotbarActionModeOperateName": "운영 모드",
"HotbarActionModeOperateDescription": "오래 걸리는 요청을 검증될 때까지 병렬로 진행합니다.",
"HomeOperateModeTip": "Operate — Fleet를 병렬로 작업에 투입",
"HomeOperateModeFleetTip": " 내장 역할은 이 세션의 모델을 사용합니다. /fleet setup에서 커스터마이징",
"HelpSubtitle": "명령어, 스킬, 단축키",
"CommandPaletteTitle": "명령",
"CommandPaletteSubtitle": "동작을 찾아 실행하세요",
"ConfigSubtitle": "설정을 우선 표시하고, 원시 키는 고급 정보에서 확인",
"LaunchStartTitle": "여기서 시작",
"LaunchResumeConfirm": "{title}을(를) 이어서 진행할까요? 다시 클릭하거나 Enter를 눌러 확인하세요.",
"LaunchResumeConfirmTitle": "세션 이어하기",
"LaunchResumeConfirmBody": "현재 컨텍스트가 해당 세션의 기록으로 대체됩니다.",
"LaunchResumeConfirmResume": "이어하기",
"LaunchResumeConfirmCancel": "취소",
"LaunchWorkDescription": "이 폴더에서 로컬 도구를 사용합니다. 변경은 승인 정책을 따릅니다.",
"LaunchChatDescription": "대화와 계획만 수행하며 파일은 변경하지 않습니다.",
"LaunchWorkspaceGitReady": "작업 공간 · {name} · Git 작업 공간",
"LaunchWorkspaceFolderReady": "작업 공간 · {name} · 로컬 폴더",
"LaunchProviderConfigured": "공급자 · 설정됨",
"LaunchProviderSetupNeeded": "공급자 · 설정 필요",
"LaunchGroupContinue": "계속",
"LaunchGroupMore": "더 보기",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "폴더",
"LaunchProviderConfiguredShort": "공급자 설정됨",
"LaunchProviderSetupShort": "공급자 설정",
"LaunchMenuChangelog": "변경 이력",
"LaunchWorktreePrompt": "브랜치/워크트리 이름을 입력하거나, Enter를 누르면 자동으로 이름이 지정됩니다. Esc로 돌아갑니다.",
"LaunchWorktreeNeedsGit": "새 워크트리는 Git 저장소가 필요합니다.",
"LaunchWorktreeNameLabel": "워크트리 이름",
"LaunchHintMove": "이동",
"LaunchHintOpen": "열기",
"LaunchTipFlags": "팁: -w <경로>는 작업 공간을 열고, -r <세션 ID>는 바로 세션을 재개합니다",
"LaunchSavedSessionSingular": "저장된 세션 1개",
"LaunchSavedSessionsPlural": "저장된 세션 {count}개",
"LaunchCreatingWorktree": "워크트리 생성 중…",
"LaunchWorktreeFailed": "워크트리 생성 실패: {error}",
"LaunchWorktreeCreated": "새 워크트리 {path} (브랜치 {branch})",
"LaunchNoSavedSessions": "이 작업 공간에는 저장된 세션이 없습니다.",
"LaunchNoModelConnected": "연결된 모델 없음",
"DispatchNotSentNoModel": "연결된 모델이 없어 이 메시지를 보내지 않았습니다. 메시지는 입력창에 다시 들어 있습니다. F3 또는 /provider로 모델을 연결한 뒤 Enter를 눌러 보내세요.",
"DispatchNotSentSaveKey": "키 저장: {command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "이 컴퓨터에서 실행 중인 모델 {model}(Ollama)을 사용합니다. 다른 모델을 고르려면 F3를 누르세요.",
"ProviderPickerNotReopened": "제공자 목록을 다시 열지 못했습니다. F3를 눌러 여세요.",
"LaunchRunCommand": "{command} 실행",
"LaunchMcpConnectedOne": "MCP 서버 1개 연결됨",
"LaunchMcpConnectedMany": "MCP 서버 {count}개 연결됨",
"LaunchMcpNeedsSignInOne": "1개는 로그인 필요",
"LaunchMcpNeedsSignInMany": "{count}개는 로그인 필요",
"PhaseIdle": "유휴",
"PhaseDraft": "초안",
"PhaseWorking": "작업 중",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "마무리 중",
"ChipModeAct": "실행",
"ChipModePlan": "계획",
"ChipModeOperate": "운영",
"ChipPermissionReadOnly": "읽기 전용",
"ChipPermissionAsk": "확인",
"ChipPermissionAuto": "자동",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "허용 안 함",
"PermissionsChangedReceipt": "권한이 {label}(으)로 변경되었습니다",
"FooterHintKeys": "단축키",
"FooterHintOutput": "출력",
"FooterHintContext": "컨텍스트",
"InfoLineHelp": "도움말",
"InfoLineContext": "컨텍스트",
"InfoLineTtft": "ttft",
"InfoLinePeak": "피크",
"InfoLineOffPeak": "오프피크",
"InfoLineWhales": "고래",
"InfoLineAutomation": "자동화",
"InfoLineNotConnected": "연결 안 됨",
"InfoLineThinking": "사고: {level}",
"EmptyStateNoGit": "git 없음",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "모든 모델 검색",
"RoutePanelHeader": "라우트",
"RouteProviderLabel": "프로바이더",
"RouteModelFirstAtomic": "모델 우선 원자적 라우트",
"PickerActionMove": "이동",
"PickerActionSwitch": "전환",
"PickerActionApply": "적용",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "검색 지우기",
"PickerActionBrowseAll": "전체 보기",
"PickerActionCustom": "사용자 지정",
"PickerActionJump": "바로가기",
"PickerActionEditKey": "키 편집",
"PickerActionModels": "모델",
"PickerActionUnavailable": "사용 불가",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "그 로그인 사용 중지",
"ProviderExternalActionChoices": "다른 앱으로 로그인",
"ProviderExternalActionReuseGrok": "외부 Grok 자격 증명 재사용",
"ProviderExternalHintCodexReview": "{login} 후 Enter를 눌러 비활성화, 읽기 전용, 관리형 접근을 검토하세요.",
"ProviderExternalHintXaiReview": "Enter는 Codewhale 소유 기기 로그인, E는 기존 Grok CLI 자격 증명 재사용을 검토합니다.",
"ProviderExternalHintXaiApiKey": "또는 XAI_API_KEY를 사용한 뒤 이 선택기를 다시 여세요.",
"XaiAuthChoiceTitle": " xAI 인증 ",
"XaiAuthChoiceIntro": "명시적인 자격 증명 소스 하나를 선택하세요. 키 텍스트는 OAuth 토큰으로 처리되지 않습니다.",
"XaiAuthChoiceApiKeyOption": "xAI API 키 — 입력하거나 붙여 넣은 뒤 xAI 제공자 슬롯에 저장",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT / Codex 인증 ",
"ChatgptAuthChoiceIntro": "구독 로그인은 ChatGPT 플랜으로 청구됩니다. openai API 키 경로는 다른 청구 주체입니다.",
"ChatgptAuthChoicePkceOption": "ChatGPT로 로그인 — 브라우저 PKCE, Codewhale 소유 토큰, ChatGPT 구독 청구",
"ChatgptAuthChoiceImportOption": "Codex CLI 자격 증명 가져오기 — 명시적 읽기 전용 동의; 소유자는 계속 Codex CLI",
"ProviderExternalHintChatgptReview": "Enter로 ChatGPT 로그인, E로 기존 Codex CLI 재사용을 검토하세요.",
"ProviderExternalActionReuseCodex": "외부 Codex 재사용",
"ProviderExternalDetailScope": "외부: 접근={access} | 제공자={provider} | 소스={source} | 버전={version} | {state}",
"ProviderExternalDormant": "휴면",
"ProviderExternalOwnerPath": "소유자/경로: {owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "{workspace}에서 스냅샷과 /undo가 꺼져 있습니다: 홈 디렉터리나 루트 디렉터리는 범위가 너무 넓어 안전하게 스냅샷할 수 없습니다. 프로젝트 디렉터리에서 시작하면 켜집니다.",
"SnapshotsHistoryRepaired": "{workspace}의 실행 취소 기록이 손상되어(최신 복원 지점이 없음) 새로 시작했습니다. 이전 복원 지점은 더 이상 복원할 수 없지만, 새 턴은 다시 보호됩니다.",
"SnapshotsFailing": "{workspace}의 스냅샷이 실패하고 있어 /undo로 최근 턴을 복원할 수 없습니다: {limit}",
"SessionIdDivergedNotice": "이 창의 세션 ID가 바뀌었습니다. 엔진은 이제 {next}로 체크포인트를 저장합니다(이전: {previous}). 이전 체크포인트는 옛 ID 아래에 남습니다. `codewhale sessions`로 둘 다 확인하고 `codewhale resume {previous}`로 이전 세션을 다시 열 수 있습니다.",
"RuntimeStoreUnreadableNotice": "세션 런타임 저장소: {path}의 {record}을(를) 읽을 수 없습니다({reason}). 해당 파일을 옮기거나 삭제한 뒤 다시 시도하세요. 스레드의 다른 레코드는 그대로 유지됩니다.",
"RuntimeStoreUnwritableNotice": "세션 런타임 저장소: {path}의 {record}을(를) 쓸 수 없습니다({reason}). 해당 위치의 여유 공간과 권한을 확인한 뒤 다시 시도하세요. 아무것도 덮어쓰지 않았습니다.",
"ProviderExternalSemanticsRevoke": "{semantics} | 취소: {revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "설정",
"FleetRosterWorkers": "워커",
"FleetRosterMembersCount": "멤버 {count}명",
"FleetRosterOperatorFirst": "코디네이터가 이끎 · 세션 모델이 이 Fleet를 구동",
"FleetRosterOperatorRow": "코디네이터 · 리더",
"FleetRosterShadowBadgeProjectOverride": "이 프로젝트에 저장됨",
"FleetRosterShadowBadgePersonalIgnored": "저장된 사본 무시됨",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "현재 사용 중인 모델(팀의 operator 경로)입니다. 모델을 전환하거나 /fleet save로 변경하세요",
"FleetModelReasonAlreadyPresent": "이미 팀에 있습니다",
"FleetModelErrorNeedsRoute": "팀 모델에는 provider ID와 모델 ID가 모두 필요합니다",
"FleetModelErrorNeedsRole": "에이전트에는 역할 이름이 필요합니다(예: `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "선택된 팀이 없습니다. 현재 팀은 세션 모델뿐입니다",
"FleetModelErrorOperatorRoute": "{route}은(는) 팀 `{fleet}`의 operator 경로입니다. remove가 아니라 /fleet save로 변경하세요",
"FleetModelErrorNotInFleet": "{route}은(는) 팀 `{fleet}`에 없습니다",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ 첨부 · 일치 1개",
"FilePickerMatchesPlural": "@ 첨부 · 일치 {count}개",
"FilePickerScanning": "작업 공간 스캔 중…",
"BehavioralTipPlanning": "계획 중인가요? {key} 키로 Plan 모드로 전환합니다",
"BehavioralTipBackgroundReceipt": "영수증은 Work 패널에 있습니다 — {key} 키로 검사기를 엽니다",
"BehavioralTipClearedInput": "지움 · {chord} 키로 복원",
"BehavioralTipMcpValidation": "{command} 명령은 서버를 시작하고 원인을 보여 줍니다",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "모델과 사고",
"SettingSubjectProvider": "제공자",
"SettingSubjectPermissions": "권한",
"ThinkingControlledByAutoRouting": "사고는 자동 모델 라우팅이 제어합니다. 먼저 고정 모델을 선택하세요.",
"SavedAsStartupDefault": "시작 기본값으로 저장했습니다",
"ModeAlreadyActiveSavedAsDefault": "이미 {mode} 모드입니다 — 시작 기본값으로 저장했습니다.",
"StartupDefaultNotSaved": "{setting}을(를) 저장하지 못했습니다: {error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "사고 수준",
"StartupDefaultSubjectModel": "모델",
"StartupDefaultSubjectAll": "시작 기본값",
"SessionsRailTitle": "세션",
"SessionsRailEmpty": "이 작업 공간에는 아직 세션이 없습니다",
"SessionsRailBrowseAll": "모든 세션 보기",
"SessionsRailShowingCount": "{total}개 중 {shown}개 — 전체 보기",
"SessionsRailUnavailable": "세션을 불러올 수 없습니다: {error}",
"SessionsActionArchive": "보관",
"SessionsActionShowArchived": "보관됨",
"SessionsArchived": "세션 {id}을(를) 보관했습니다",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "에이전트",
"FooterHintToManage": "관리",
"AgentRailQueuedCount": "{count}개 대기",
"WorkbarSoFar": "지금까지 {done}/{total}",
"WorkbarLargeWorkflow": "대규모 워크플로",
"WorkbarMoreRuns": "+{count}개 더",
"WorkflowLineStarted": "시작됨",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "일부 누락된 채 완료됨",
"WorkflowLineFailed": "실패",
"WorkflowLineStopped": "중지됨",
"WorkflowLineAgents": "에이전트 {done}/{total}",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "쓰기 가능",
"AgentFocusPostureReadOnly": "읽기 전용",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "읽기 전용 셸",
"AgentFocusPostureShellNone": "셸 없음",
"GoalReceiptSet": "목표 설정: \"{objective}\" · /goal 로 진행 상황 확인 · /goal pause 또는 /goal clear 로 중지",
"GoalReceiptSetOperate": "◆ 목표 설정 · Operate는 검증될 때까지 계속 작업합니다 · 수정은 /goal",
"GoalControlAccepted": "목표 제어를 저장했습니다. 다음 안전한 경계에서 적용합니다.",
"GoalControlRuntimeUnavailable": "목표 제어는 저장되었지만 런타임을 사용할 수 없습니다. 다시 시작한 후 복원됩니다.",
"GoalStatusIdleHint": "지금은 실행 중이 아님 — 메시지를 보내거나 /goal resume 로 계속",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "목표 활성 · 다음 턴까지 {delay} · Esc, Ctrl+C 또는 /goal pause로 대기 중인 계속 실행 중지",
"GoalContinuationReady": "목표 계속 실행 준비 완료. 대기 중인 제어 작업을 다음 턴보다 먼저 실행합니다.",
"GoalContinuationStopped": "대기 중인 목표 계속 실행을 중지했습니다. 목표는 활성 상태로 유지됩니다.",
"McpCapabilitiesAdvertised": "공개된 기능: {capabilities}",
"McpCapabilitiesLegacyFallback": "공개된 기능: 제공되지 않음; 레거시 검색 대체 경로 사용",
"McpCapabilitiesNotObserved": "공개된 기능: 서버가 연결되지 않아 확인되지 않음",
"PickerActionTestConnection": "연결 테스트",
"ProviderCustomFormBaseUrl": "기본 URL",
"ProviderCustomFormModel": "기본 모델",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "간트 시간 →",
"ConfigCategoryAppearance": "모양",
"ConfigCategoryModelsProviders": "모델 및 제공자",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "작업",
"ConfigCategoryToolsMcp": "도구 및 MCP",
"ConfigCategoryTrust": "신뢰",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "읽기 전용",
"ConfigRowActionNote": "동작 · 저장되는 설정이 아님",
"ConfigRowDiagnosticNote": "관측 영수증 · 여기서 편집 불가",
"ConfigNavHint": "←/→ 또는 Tab 카테고리 · ↑/↓ 설정",
"ConfigActivateAgain": "Enter 또는 다시 클릭:",
"ConfigSearchLabel": " 검색: ",
"ConfigEditChooseLabel": "선택:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "허용 안 함",
"ConfigChoiceModeAct": "실행",
"ConfigChoiceModePlan": "계획 (읽기 전용)",
"ConfigChoiceModeOperate": "운영",
"ConfigChoicePlacementTop": "상단",
"ConfigChoicePlacementBottom": "하단 바",
"ConfigChoicePlacementLeft": "왼쪽 사이드바",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "도구 위험을 자동으로 검토하고 결정이 필요할 때만 묻습니다.",
"ConfigChoiceDetailUseTuiDefault": "루트 설정 재정의를 제거하고 저장된 TUI 권한 선택을 사용합니다.",
"ConfigChoiceDetailFullAccess": "도구가 묻지 않고 실행되고, 명령은 이 컴퓨터의 모든 것에 접근할 수 있어요.",
"ConfigChoiceDetailNever": "승인이 필요한 모든 도구를 차단합니다.",
"ConfigChoiceDetailModeAgent": "협업하고 도구를 사용할 준비 상태로 시작합니다.",
"ConfigChoiceDetailModePlan": "읽기 전용 계획 작업 공간에서 시작합니다.",
"ConfigChoiceDetailModeOperate": "운영은 최대 역량의 실행입니다. 실질적인 요청마다 목표가 되고, 워크플로와 병렬 워커를 거치며, 독립 검토자가 확인하고, 검증될 때까지 계속 진행합니다.",
"ConfigChoiceDetailPlacementTop": "작업, 할 일, 작업자를 대화 기록 위에 표시합니다.",
"ConfigChoiceDetailPlacementBottom": "작업, 할 일, 작업자를 작성기 아래에 표시합니다.",
"ConfigChoiceDetailPlacementLeft": "터미널이 충분히 넓을 때 작업, 할 일, 작업자를 왼쪽 사이드바에 표시합니다.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "모델 추론 배경을 채웁니다.",
"ConfigChoiceDetailThinkingHighlightOff": "배경을 채우지 않고 점선 추론선과 기울임 텍스트를 유지합니다.",
"ConfigHintModel": "이 세션의 실시간 경로 모델. Enter로 /model 열기",
"ConfigHintFastModel": "이 제공자에 알려진 형제 모델이 있을 때 Auto 라우팅과 에이전트의 model_strength=faster가 사용",
"ConfigHintProvider": "자격 증명, 모델, 엔드포인트가 함께 전환됨",
"ConfigHintApprovalMode": "이 세션만: 확인 | 자동 검토 | 전체 접근",
"ConfigHintPermissionPosture": "새 세션의 기본값: 확인 | 자동 검토 | 전체 접근",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "실행 (agent) | plan",
"ConfigHintMaxHistory": "정수 (0 허용) · 다시 불러오기와 기록 검색을 위해 보관하는 보낸 메시지 수",
"ConfigHintAutoCompactThreshold": "10..=100 · 압축 임계값: 자동 압축이 실행되는 사용 가능 컨텍스트 길이의 백분율",
"ConfigHintDefaultModel": "DeepSeek 전용 레거시 대체. 다른 제공자는 위의 제공자별 모델 사용",
"ConfigHintReasoningEffort": "default는 모델 자체 기본값으로 복원. 항상 사고하는 모델은 off가 없음",
"ConfigHintMcpOpen": "MCP 관리자 열기 · 연결 / 재연결 / 재인증 / 진단",
"ConfigHintMcpReconnect": "MCP 재연결 · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "패치 편집 도구의 읽기 전용 기능 플래그 상태",
"ConfigHintFeatureMcp": "MCP 도구의 읽기 전용 기능 플래그 상태",
"ConfigHintFeatureExecPolicy": "실행 정책 도구의 읽기 전용 기능 플래그 상태",
"ConfigHintFeatureVisionModel": "비전/모델 이미지 지원의 베타 기능 플래그",
"ConfigHintGoalCommand": "/goal은 목표, 예산, 작업 컨텍스트 상태를 설정",
"ConfigHintWorkflow": "/workflow는 팬아웃/팬인 실행 카드와 함께 스크립트화된 작업을 실행",
"LaunchMenuNewWorktree": "새 워크트리",
"LaunchMenuResume": "세션 재개",
"LaunchMenuQuit": "종료",
"LaunchNoticeClaude": "Claude Code가 감지되었습니다. /import-claude를 실행해 가져올 수 있는 항목(MCP 서버, 안전한 설정, 권한)을 검토하세요. 승인 없이는 아무것도 적용되지 않습니다.",
"LaunchNewSession": "새 세션",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ 눌러 재개",
"LaunchHelpLine": "명령은 /help · 작업 바는 {dock}",
"LaunchSeeAllSessions": "모든 세션 보기…",
"LaunchNoRecentSessions": "최근 세션이 아직 없습니다 — 아래에 입력하여 시작하세요.",
"LaunchResumeFailed": "다시 시작 실패: {error}",
"ReceiptSessionHooks": "훅 {count}",
"AutomationEditorNew": "자동화 만들기",
"AutomationEditorEdit": "자동화 편집",
"AutomationEditorSchedule": "일정",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} 완료",
"WorkflowPhaseCountOne": "{count}개 단계",
"WorkflowPhaseCountMany": "{count}개 단계",
"WorkflowPhaseOrdinal": "단계 {n}/{total}",
"ModelPickerPinned": "{route} 고정됨",
"ModelPickerUnpinned": "{route} 고정 해제됨",
"ModelPickerPinFailed": "고정을 업데이트하지 못했습니다: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "이전 Codewhale {provider} 로그인({account})을 대체했습니다.",
"AuthReplacedPreviousSignIn": "이전 Codewhale {provider} 로그인을 대체했습니다.",
"AuthSameAccountAsBefore": "이전과 같은 계정입니다. 다른 {provider} 계정을 사용하려면 브라우저에서 이 계정에서 로그아웃하거나 시크릿 창을 연 뒤 다시 로그인하세요.",
"AuthEnvTokenOutranksSignIn": "이 환경에 OPENAI_CODEX_ACCESS_TOKEN 또는 CODEX_ACCESS_TOKEN이 설정되어 있어 이 로그인보다 우선합니다. 설정을 해제할 때까지 요청은 해당 토큰의 계정을 계속 사용합니다.",
"PinnedPromptJumpToMessage": "이 메시지로 이동",
"PlanHandoffHeader": "계획 준비 완료",
"PlanHandoffQuestion": "어떻게 진행할까요?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Enter를 눌러 브라우저에서 로그인하세요. Esc를 누르면 돌아갑니다. API 키는 필요하지 않습니다.",
"PluginOAuthReady": "{provider}: 로그인했습니다. 모델을 선택하세요.",
"PluginOAuthLocalLogout": "{provider}: 이 기기의 로그인 정보를 삭제했습니다. 서버 권한은 유지됩니다.",
"CmdConnectDescription": "브라우저 로그인으로 플러그인 제공자를 연결합니다",
"CmdDisconnectDescription": "플러그인 제공자의 이 기기 로그인 정보를 삭제합니다",
"ExecAutoHelp": "더 엄격한 샌드박스가 설정되어 있지 않으면 자동 승인과 Full Access(셸 샌드박스 없음, 신뢰 모드 켜짐)로 도구를 활성화합니다. 파일 및 셸 쓰기를 제한하려면 --sandbox workspace-write를 사용하세요.",
"ExecSandboxHelp": "이번 실행의 샌드박스 정책입니다. danger-full-access 이외의 --sandbox(또는 설정의 동등한 sandbox_mode)는 신뢰 모드를 끕니다.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "O Runtime fechou o fluxo de eventos desta conversa; reabra a conversa",
"MobileStreamReconnecting": "Conexão perdida; reconectando",
"MobileStreamConnected": "Conectado",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Um habitat compartilhado",
"PetHabitatHints": "{back} voltar · {sound} som · {browser} aparência · {window} janela",
"PetHabitatQueued": "Enviado ao habitat compartilhado. /pet on mostra o pet e a caixa de mensagem.",
"PetWatchSoundOn": "Som ligado",
"PetWatchSoundOff": "Som desligado",
"PetWatchSoundPaused": "Som pausado",
"PetWatchSoundUnavailable": "O som do Codewhale parou. Verifique o FFmpeg (ffplay) e a saída de áudio e ligue o som novamente.",
"CmdPetDescription": "Use o pet animado como a visão principal do Codewhale",
"ConfigLabelPetMode": "Modo pet",
"ConfigHintPetMode": "Use o pet animado como visualização principal ao iniciar o Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "modo pet desligado",
"PetViewOpen": "habitat aberto",
"PetViewClosed": "habitat fechado",
"PetWatchRestored": "O /pet restaurou o habitat desta sessão. Aguardando nova telemetria.",
"PetWatchStorageUnavailable": "O Watch não conseguiu restaurar ou salvar este habitat. Os arquivos existentes foram mantidos. Use {command} para exportar esta execução.",
"PetWatchExported": "Gravação do Watch salva: {path}",
"PetWatchExportFailed": "Não foi possível salvar a gravação do Watch. Ela permanece na memória.",
"PetWatchExportQueued": "Salvando gravação do Watch…",
"PetWatchExportUnavailable": "Abra o /pet em uma sessão salva ou aguarde a exportação atual.",
"PetUnobserved": "sem observação",
"PetOffline": "offline — codewhale pet serve o acorda",
"PetDozing": "cochilando",
"PetWatchUnavailable": "A telemetria do pet foi pausada. /pet on tenta novamente.",
"ConversationChangedBeforeUndo": "A conversa mudou antes de concluir a ação de desfazer. Nada foi desfeito e nenhuma nova tentativa foi enviada. Revise a conversa atual antes de tentar novamente.",
"SessionArchiveExported": "Sessão exportada",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Editar",
"ExtensionsHooksAddLabel": "Adicionar um hook",
"ExtensionsHooksAddDescription": "Abre o arquivo de hooks deste projeto no seu editor",
"ExtensionsActionReload": "recarregar",
"ExtensionsActionConnect": "conectar",
"ExtensionsActionReconnect": "reconectar",
"ExtensionsActionReauth": "reautenticar",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "conectado",
"ExtensionsStateEnabled": "ativado",
"ExtensionsStateError": "erro",
"ExtensionsStateInactive": "inativo",
"ExtensionsStateInapplicable": "não aplicável",
"ExtensionsStateInvalid": "inválido",
"ExtensionsStateNotInspected": "não inspecionado",
"ExtensionsStateDisconnected": "desconectado",
"ExtensionsStateRejected": "rejeitado",
"ExtensionsStateReviewedCandidate": "candidato revisado",
"ExtensionsStateUnderEvaluation": "em avaliação",
"ExtensionsStateUnstaged": "não preparado",
"ExtensionsStateUnsupported": "sem suporte",
"ExtensionsStateWarning": "aviso",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ enviar nesta rodada",
"ComposerHintLongDraft": "{shortcut}: editor externo",
"PendingSendingIntoTurnPrefix": " ↳ Enviando nesta rodada: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Não foi possível enviar nesta rodada: ",
"PendingEditingFollowUpPrefix": " ↳ Editando o acompanhamento: ",
"PendingQueuedOnePrefix": "Na fila #1: ",
"PendingQueuedManyPrefix": "Na fila {count} · próximo: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Pensamento concluído",
"TranscriptThoughtFor": "Pensou por {duration}",
"TelemetryNoticeDefaultOn": "As estatísticas de uso estão ativadas por padrão. Compartilhar totais de versão, plataforma, sessões, funções e erros com Codewhale e o operador PostHog. Também conta provedores, modelos do catálogo público, totais de tokens e o uso de ferramentas integradas. Sem conteúdo ou IP. docs/TELEMETRY.md Desativar: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Estatísticas de uso do Codewhale",
"TelemetryNoticeBody": "O Codewhale conta: a versão em execução, a família do sistema operacional e da\nCPU, a duração e o resultado da sessão, e contagens agregadas de recursos e\nerros.\n\nTambém conta os provedores e modelos do catálogo público que você usa, seus totais de tokens e quantas vezes cada ferramenta integrada é executada.\n\nEle nunca coleta suas conversas, código, prompts, arquivos, nomes de\narquivos, repositórios ou ramos, conteúdo do modelo nem credenciais — e nunca\nenvia uma cronologia da atividade do agente por turno ou ferramenta.\n\nVocê é identificado apenas por um ID aleatório armazenado nesta máquina,\nsubstituído a cada 90 dias. Mude de ideia a qualquer momento:\n codewhale config set telemetry false\n\nEsquema completo, campo por campo: docs/TELEMETRY.md\n\nAs estatísticas de uso estão ativadas por padrão. Codewhale e PostHog processam esses totais quando o envio está configurado. Nenhum IP é coletado.",
"TelemetryNoticeCompactBody": "Conta: versão, OS/CPU, tempo/resultado, funções/erros.\nTambém: provedor/modelo, tokens, ferramentas.\nID local: rotação 90d.\nNunca: chat/código/prompts/arquivos/nomes; conteúdo do modelo/credenciais; turnos/ferramentas.\nEsquema: docs/TELEMETRY.md\nDesl.: codewhale config set telemetry false\nAs estatísticas de uso estão ativadas por padrão. Codewhale e PostHog processam esses totais quando o envio está configurado. Nenhum IP é coletado.",
"TelemetryNoticeChoiceKeep": "Sim, manter as contagens anônimas",
"TelemetryNoticeChoiceDisable": "Não, desativar o rastreamento",
"TelemetryNoticeActionChoose": "escolher",
"TelemetryNoticeActionConfirm": "confirmar",
"TelemetryNoticeActionExit": "sair",
"TelemetryNoticeReceiptEnabled": "A contagem anônima de uso está ativada. Conversas e código nunca são coletados. Altere em /settings; esquema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "A contagem anônima de uso está desligada. Não perguntaremos novamente.",
"TelemetryNoticeReceiptEnabledUnsaved": "A contagem anônima de uso está ativa nesta sessão. O Codewhale não conseguiu salvar este aviso e vai exibi-lo novamente. Altere em /settings; esquema: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "A contagem anônima de uso está desligada nesta sessão. O Codewhale não conseguiu salvar a escolha e perguntará novamente na próxima inicialização.",
"TelemetryPreferenceEnabledNextLaunch": "A contagem anônima de uso será ativada na próxima inicialização. Conversas e código nunca são coletados.",
"TelemetryPreferenceDisabled": "A contagem anônima de uso está desativada. Os dados locais de telemetria foram apagados.",
"TelemetryPreferenceDisabledWithWarning": "A contagem anônima de uso está desativada, mas parte da limpeza precisa de atenção: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Nenhuma ação da Hotbar disponível.",
"HotbarSetupRecommended": "rec",
"HotbarSetupEmptySlot": "vazio",
"HotbarSetupHelp": "Tab/Shift+Tab origem Up/Down ação 1-8 slot Enter atribuir Space alternar Delete limpar s salvar Esc cancelar",
"HotbarActionVoiceToggleName": "Entrada de voz",
"HotbarActionVoiceToggleDescription": "Alternar captura de voz pelo microfone do terminal.",
"HotbarActionSessionCompactName": "Compactar sessão",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Modo Work",
"HotbarActionModeAgentDescription": "Trabalhe diretamente na sessão atual.",
"HotbarActionModeYoloName": "Acesso total (Work)",
"HotbarActionModeYoloDescription": "Compatibilidade: Work com acesso total (não é um modo separado).",
"HotbarActionReasoningCycleName": "Alternar raciocínio",
"HotbarActionReasoningCycleDescription": "Alternar o esforço de raciocínio configurado para o provedor ativo.",
"HotbarActionReasoningCycleAutoDisabled": "O esforço de raciocínio é controlado pelo roteamento automático de modelo.",
"HotbarActionSidebarToggleName": "Alternar barra lateral",
"HotbarActionSidebarToggleDescription": "Mostrar ou ocultar a barra lateral.",
"HotbarActionFileTreeToggleName": "Alternar árvore de arquivos",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Nenhuma configuração disponível.",
"ConfigNoMatchesPrefix": " Nenhuma configuração corresponde a ",
"ConfigFilteredSettings": " Configurações filtradas",
"ConfigShowing": " Mostrando",
"ConfigFooterDefault": " digite=filtrar, Up/Down=selecionar, Enter=editar, Esc=fechar ",
"ConfigFooterScrollable": " digite=filtrar, Up/Down=selecionar, Enter=editar, PgUp/PgDn=rolar, Esc=fechar ",
"ConfigFooterFiltered": " digite=filtrar, Backspace=apagar, Ctrl+U/Esc=limpar, Enter=editar ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; as sugestões de texto fantasma são aplicadas após os próximos turnos)",
"ConfigNotificationsSetHint": "Defina com /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; aplica-se aos próximos alertas)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs deve ser um número inteiro",
"ConfigAuditSearchProvider": "Grava [search] provider; as próximas chamadas de web_search continuam respeitando substituições do ambiente.",
"ConfigAuditPromptSuggestion": "Grava prompt_suggestion no nível superior; as sugestões de texto fantasma continuam opcionais.",
"ConfigAuditNotifications": "Grava valores escalares de [notifications] e os aplica aos próximos alertas de fim de turno.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL da API do provedor",
"ConfigHintProviderUrl": "Endpoint atual do provedor; Xiaomi: plano de tokens | pagamento conforme o uso | URL personalizada",
"ConfigLabelModel": "Modelo ativo do provedor",
"ConfigLabelFastModel": "Modelo rápido (derivado)",
"ConfigLabelDefaultModel": "Modelo alternativo legado (somente rotas DeepSeek)",
"ConfigLabelReasoningEffort": "Nível de raciocínio",
"ConfigLabelApprovalMode": "Permissão desta sessão",
"ConfigLabelPermissionPosture": "Permissão de novas sessões",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Totais de versão, sessões, funções e erros para Codewhale e PostHog; nunca conteúdo ou IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Ativada",
"ConfigValueTelemetryOff": "Desativada",
"ConfigLabelStreamTimeout": "Tempo limite do fluxo",
"ConfigLabelTheme": "Tema",
"ConfigLabelLocale": "Idioma",
"ConfigLabelBackground": "Plano de fundo",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Destaque do fundo do raciocínio",
"ConfigLabelShowToolDetails": "Nível de detalhe das ferramentas",
"ConfigLabelInlineDiffs": "Alterações de arquivo em linha",
"ConfigLabelStatusIndicator": "Indicador de status",
"ConfigLabelSynchronizedOutput": "Ritmo da saída",
"ConfigLabelCostCurrency": "Moeda de custos",
"ConfigLabelTranscriptSpacing": "Espaçamento da conversa",
@@ -376,7 +408,16 @@
"ConfigLabelComposerDensity": "Densidade do editor",
"ConfigLabelComposerBorder": "Borda do editor",
"ConfigLabelComposerMultilineMode": "Modo multilinha do editor",
"ConfigLabelComposerVimMode": "Modo Vim do editor",
"ConfigLabelBracketedPaste": "Colagem entre colchetes",
"ConfigLabelPasteBurstDetection": "Detecção de colagem",
"ConfigLabelMentionMenuLimit": "Limite do menu de menções",
"ConfigLabelMentionMenuBehavior": "Comportamento do menu de menções",
"ConfigLabelMentionWalkDepth": "Profundidade de menções de arquivos",
"ConfigLabelWorkspaceFollowSymlinks": "Seguir links simbólicos",
"ConfigLabelContextPanel": "Painel de contexto",
"ConfigLabelSessionsRail": "Barra de trabalho de sessões",
"ConfigLabelSessionAutoResume": "Retomar a última sessão automaticamente",
"ConfigLabelAutoCompact": "Compactação automática",
"ConfigLabelAutoCompactThreshold": "Limite de compactação",
"ConfigLabelMaxHistory": "Histórico de entrada",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "Comando de objetivo",
"ConfigLabelWorkflow": "Fluxo de trabalho",
"ConfigLabelFeaturePrefix": "Recurso: {name}",
"ConfigColumnSetting": "Configuração",
"ConfigColumnValue": "Valor",
"ConfigColumnScope": "Escopo",
"ConfigActionOpenProvider": "Enter abre o seletor de provedor",
"ConfigActionOpenModel": "Enter abre o seletor de modelo",
"ConfigActionOpenMcp": "Enter abre o gerenciador MCP",
@@ -416,6 +459,7 @@
"HelpKeybindings": "Atalhos",
"HelpUserCommands": "Comandos do usuário",
"HelpSkills": "Habilidades",
"HelpFooterTypeFilter": " digite para filtrar ",
"HelpFooterMove": " Up/Down move ",
"HelpFooterJump": " PgUp/PgDn salta ",
"HelpFooterClose": " Esc fecha ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "Plugin sugerido: {name}",
"PluginCtaReview": "Revisar",
"PluginCtaInstall": "Instalar",
"PluginCtaReviewTrust": "Revisar confiança",
"PluginCtaEnable": "Ativar",
"PluginCtaDismiss": "Não sugerir novamente",
"PluginCtaDismissSaveFailed": "Oculto nesta sessão; não foi possível salvar a preferência do plugin.",
"PluginSuggestionReason": "Corresponde a “{trigger}”",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "Falha na ação do plugin: {error}",
"CmdPluginNoneFound": "Nenhuma ferramenta executável legada de plugin encontrada em {dir}",
"CmdPluginNotFound": "Plugin '{name}' não encontrado",
"CmdPluginListHeader": "Ferramentas executáveis legadas de plugins ({count}):",
"CmdPluginDetailDescription": "Descrição: {description}",
"CmdPluginDetailSchema": "Esquema:\n{schema}",
"CmdPluginDetailApproval": "Aprovação: {approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "Catálogo em cache; execute `codewhale models --update` para atualizar os provedores configurados.",
"ModelsUpdateSummary": "Catálogos de modelos: {updated} atualizados, {loaded} carregados do Codex, {failed} com falha, {skipped} ignorados.",
"ModelsUpdatePartial": "Não foi possível atualizar alguns catálogos. Os modelos anteriores e configurados continuam disponíveis.",
"ModelsCodexHint": "Os modelos do ChatGPT são carregados pelo Codex. O horário da consulta não confirma uma atualização do catálogo do provedor.",
"ModelsSourceFallback": "Modelos incluídos ou configurados; disponibilidade não verificada.",
"CmdModelDbDescription": "Navegar pelo banco de dados de modelos integrado",
"CmdNetworkDescription": "Gerenciar regras de rede permitidas e bloqueadas",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "Ver ou editar mensagens enfileiradas",
"CmdQueueUsage": "Uso: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "{count} mensagem(ns) enfileirada(s) de uma sessão anterior restaurada(s). Elas não são enviadas automaticamente: /queue send <n> envia uma, /queue clear as descarta.",
"CmdQueueDraftHeader": "Editando mensagem enfileirada:",
"CmdQueueNoMessages": "Nenhuma mensagem enfileirada",
"CmdQueueListHeader": "Mensagens enfileiradas ({count}):",
"CmdQueueTip": "Dica: /queue send <n> para enviar agora, /queue drop <n> para remover",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "{hit} hit / miss não reportado",
"CmdTokensCacheMissOnly": "hit não reportado / {miss} miss",
"CmdTokensCacheWriteTotal": "Tokens de escrita de cache (criação) nesta sessão: {write}. Cobrados acima da tarifa de entrada quando o provedor publica um adicional de escrita; veja /cache para o detalhamento por turno.",
"CmdTokensContextUnknownWindow": "~{estimated} / janela desconhecida",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 sub-agente",
"FooterAgentsPlural": "{count} sub-agentes",
"HeaderAgentsChip": "sub-agentes {count}",
"FooterPressCtrlCAgain": "Pressione Ctrl+C novamente para sair",
"FooterWorking": "trabalhando",
"FooterBalancePrefix": "saldo",
"HelpSectionActions": "Ações",
"HelpSectionClipboard": "Área de transferência",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "não reportado",
"CmdTokensReport": "Uso de tokens:\n─────────────────────────────\nContexto ativo: {active}\nÚltima entrada da API: {input} (telemetria por turno; pode contar o mesmo prefixo várias vezes em rodadas com ferramentas)\nÚltima saída da API: {output}\nHit/miss do cache: {cache} (apenas para telemetria/custo)\nTokens acumulados: {total} (telemetria de uso da sessão)\nValor precificado: {cost}\nMensagens da API: {api_messages}\nMensagens do chat: {chat_messages}\nModelo: {model}",
"KbScrollTranscript": "Rolar transcrição, navegar histórico de entrada ou selecionar anexos do compositor",
"KbNavigateHistory": "Navegar histórico de entrada",
"KbBrowseHistory": "Navegar histórico da conversa",
"KbScrollTranscriptAlt": "Rolar transcrição",
"KbScrollPage": "Rolar transcrição por página",
@@ -822,6 +875,7 @@
"KbCompactContext": "Compactar o contexto da conversa",
"KbLastMessagePager": "Abrir paginador para última mensagem (quando entrada vazia)",
"KbSelectedDetails": "Mostrar o detalhe bruto da ferramenta ou mensagem selecionada; Ctrl+Alt+O abre a visão geral de todo o turno",
"KbToolDetailsPager": "Mostrar o detalhe bruto do item selecionado (Alt+V)",
"KbExternalEditor": "Abrir rascunho no editor externo",
"KbLiveTranscript": "Abrir sobreposição de transcrição ao vivo (auto-scroll)",
"KbBacktrackMessage": "Retroceder para mensagem anterior do usuário (esquerda/direita, Enter para rebobinar)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "Abrir esta sobreposição de ajuda (quando entrada vazia)",
"KbCycleWorkDock": "Percorrer a barra de trabalho (tarefas, agentes, jobs, segundo plano) ou, no modo pet, as visões do pet",
"KbCycleWorkDockBack": "Percorrer a barra de trabalho ou as visões do pet para trás",
"KbToggleHelp": "Alternar sobreposição de ajuda",
"KbToggleHelpSlash": "Alternar sobreposição de ajuda",
"HelpUsageLabel": "Uso:",
"HelpAliasesLabel": "Apelidos:",
"SettingsTitle": "Configurações:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " /mode plan para pesquisar e apresentar um plano primeiro",
"HomeAgentModeYoloTip": " Shift+Tab cicla permissão: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + acesso total — ferramentas sem pedidos de aprovação",
"HomeYoloModeCaution": " Operações destrutivas podem rodar na hora; prefira Ask se duvidar",
"HomePlanModeTip": "Plan — pesquise e desenhe antes de implementar",
"HomePlanModeChecklistTip": " Apresente o plano e depois mude para Work",
"HomeGoalModeTip": "Rastreamento de Goal - Use /goal <objetivo> para rastrear um objetivo persistente",
"OnboardLanguageTitle": "Escolha o idioma",
"OnboardLanguageBlurb": "Escolha o idioma da interface. Você pode mudá-lo a qualquer momento com `/config locale <tag> --save`.",
"OnboardProviderTitle": "Escolha seu provedor de modelos",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "O StepFun cobra pagamento por uso e assinaturas Step Plan em endpoints diferentes. Escolha o que corresponde à sua chave.",
"StepfunBillingRoutePaygOption": "Pagamento por uso (preço por tokens)",
"StepfunBillingRoutePlanOption": "Assinatura Step Plan (cota do plano)",
"StepfunPlanApiKeyHint": "Para assinaturas Step Plan do StepFun, use a chave emitida para o seu Step Plan, não uma chave de pagamento por uso.",
"StepfunPlanRouteHint": "Esta rota usa {route} e é cobrada da cota do seu Step Plan.",
"OnboardApiKeyRejectedEnv": "A chave de API de {provider} obtida de {env} foi rejeitada. Cole uma chave válida para salvá-la em {path} ou atualize a variável de ambiente.",
"OnboardTrustTitle": "Conheça este workspace",
"OnboardTrustQuestion": "O Codewhale pode trabalhar com as instruções e os arquivos deste workspace?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "“Manter” deixa o mascaramento ativo neste lançamento; como a configuração ainda pede \"disabled\", o próximo lançamento perguntará de novo.",
"RedactionGateSaveFailed": "Não foi possível salvar a confirmação. O mascaramento continua ativo. Tente novamente ou mantenha-o ativado.",
"RedactionGateTitle": "Mascaramento de chaves na fronteira do modelo",
"OnboardOfflineOption": "Ctrl+O — explorar offline: olhe agora, conecte um provedor depois.",
"OnboardOfflineNotice": "Explorando offline. Nada conectado ainda — use /provider quando quiser conectar.",
"OnboardWelcomeTitle": "O Codewhale trabalha com você nesta pasta.",
"OnboardWelcomeLead": "Vamos deixar tudo pronto.",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "Explique o que este projeto faz e liste os principais pontos de entrada.",
"OnboardSeedFolder": "Veja esta pasta e sugira uma boa primeira tarefa.",
"SetupWizardTitle": "Setup",
"SetupWizardWhy": "Esta tela registra o progresso do setup em setup_state.json; mudanças de configuração só são aplicadas por ações explícitas de etapa.",
"SetupWizardProgress": "Etapa",
"SetupActionBack": "voltar",
"SetupActionContinue": "continuar",
"SetupActionSkip": "pular",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "rolar corpo",
"SetupActionGuided": "prévia/ratificar",
"SetupActionTuneGuided": "ajustar",
"SetupActionModelDraft": "rascunho do modelo",
"SetupActionFreeform": "suas palavras",
"SetupActionKeepExisting": "manter existente",
"SetupActionUseRecommended": "usar recomendado",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "rotas de modelo",
"SetupActionFleet": "configurar Fleet",
"SetupActionHotbar": "configurar Hotbar",
"SetupActionRemote": "entrada remota",
"SetupActionMode": "seletor de modo",
"SetupActionConfig": "visão de config",
"SetupActionRuntimePreset": "preset",
"SetupActionApplyRuntimePreset": "prévia/aplicar",
"SetupActionUseBundled": "usar embutido",
"SetupActionDefer": "adiar",
"SetupActionCancel": "cancelar",
"SetupStatusNotStarted": "não iniciado",
"SetupStatusRecommended": "recomendado",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "Idioma do setup registrado.",
"SetupConstitutionChoiceLabel": "Escolha:",
"SetupConstitutionSourceLabel": "Fonte:",
"SetupConstitutionValidityLabel": "Validade:",
"SetupConstitutionPreviewLabel": "Hash da prévia:",
"SetupConstitutionExistingLabel": "Arquivo existente:",
"SetupConstitutionExpertOverrideLabel": "Override especialista:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "Plugins:",
"SetupToolsMcpReviewHint": "Enter registra os fatos atuais de Tools/MCP. R mostra on-ramps seguros (sem execução automática).",
"SetupToolsMcpReviewed": "Prontidão de Tools/MCP registrada.",
"SetupRemoteCloudsLabel": "Destinos cloud:",
"SetupRemoteBridgesLabel": "Pontes de chat:",
"SetupRemoteProvidersLabel": "Provedores:",
"SetupRemoteModeLabel": "Modo remoto:",
"SetupRemoteModeLocalOnly": "Só nesta máquina:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "Copiar mensagem",
"CtxMenuCopyMessageDesc": "copiar célula da transcrição clicada",
"CtxMenuOpenInEditor": "Abrir no editor",
"CtxMenuOpenInEditorDesc": "abrir file:line no $EDITOR",
"CtxMenuShowCell": "Mostrar célula",
"CtxMenuShowCellDesc": "reexibir esta célula da transcrição",
"CtxMenuHideCell": "Ocultar célula",
@@ -1216,9 +1290,15 @@
"FanoutCounts": "{done} concluído · {running} em execução · {failed} falhou · {pending} pendente",
"AppModeAgent": "Work",
"AppModeAuto": "Automático",
"AppModeYolo": "Acesso total (rótulo obsoleto)",
"AppModePlan": "Plan",
"AppModeAgentHint": "Trabalho direto nesta sessão — edições e shell pedem aprovação",
"AppModeAutoHint": "Shell habilitado com revisão automática de risco",
"AppModePlanHint": "Pesquisa somente leitura primeiro — apresente um plano antes de agir",
"AppModeYoloHint": "Só compatibilidade — Work + acesso total, não um modo visível",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERIR --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Só leitura",
"ApprovalEffectChangesFiles": "Altera arquivos",
"ApprovalRiskDestructive": "Não pode ser desfeito",
@@ -1246,6 +1326,7 @@
"ApprovalSaveAskRuleHint": " · s permitir agora e sempre perguntar antes de repetir",
"ApprovalOptionDeny": "Não permitir",
"ApprovalOptionAbortTurn": "Parar este turno",
"ApprovalBlockTitle": "aprovação",
"ApprovalControlsHint": "Pg↑/↓ revisar · {details} mais opções · Esc parar",
"ApprovalOwnerHeader": "Agente: {agent} · {role}",
"ApprovalGoToAgent": "g ir para o agente",
@@ -1271,6 +1352,8 @@
"ApprovalTruncationHint": " … truncado · pressione {details} para ver todos os detalhes",
"ApprovalAsksWithoutGit": "Não há repositório Git aqui, então as edições pedem permissão antes.",
"ApprovalFullAccessPolicyBlocked": "{tool} bloqueado: Full Access não pode ignorar esta política",
"ApprovalChooseHint": "Escolha: ",
"ApprovalChooseAction": "Enter para selecionar, ou pressione y/a/d diretamente",
"ApprovalIntentLabel": "Intenção: ",
"ApprovalMoreLines": " … (+{count} linhas)",
"ApprovalProceedQuestion": "Deseja continuar?",
@@ -1310,10 +1393,12 @@
"ContextManualCompacting": "Compactando o contexto…",
"ContextCompactionQueued": "A compactação do contexto foi enfileirada; ela será executada após o turno ativo.",
"ContextCompactionAlreadyRunning": "A compactação do contexto já está em andamento.",
"ContextCompactionQueueFull": "Não foi possível enfileirar a compactação do contexto porque o mecanismo está ocupado; tente novamente após o término do turno.",
"ContextCompactionQueueClosed": "A compactação do contexto está indisponível porque o mecanismo não está mais em execução.",
"ContextCompactionRouteInvalid": "Não é possível compactar porque a rota do provedor ativo é inválida: {error}",
"ContextCompactionStoppedOnEngineSwitch": "A compactação do contexto foi interrompida; a conversa não foi alterada",
"ContextPurgeAbandonedOnEngineSwitch": "A limpeza da sessão foi abandonada com o mecanismo substituído; a conversa não foi alterada",
"CtxInspTitle": "Inspetor de contexto",
"CtxInspSessionContext": "Contexto da sessão",
"CtxInspSystemPrompt": "Estrutura do prompt do sistema",
"CtxInspReferences": "Referências",
@@ -1545,21 +1630,47 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills e Plugins — On-ramps seguros\n\n/setup só lê o inventário local. Não inicia servidores MCP, não instala skills, não executa plugins nem comandos não confiáveis.\n\nInventário atual:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (adaptadores compartilhados): {hotbar_result}\n\nCaminhos:\n- MCP: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nBootstrap seguro (execute você mesmo):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills\n- Plugins: /plugin · codewhale setup --plugins\n- Tools: codewhale setup --tools\n\nAções com efeitos colaterais sempre exigem confirmação explícita. Veja docs/MCP.md.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — conectado através do Codewhale, nunca um segundo agendador:\n- Estado: {dsh_result}\n- Detecção somente leitura; conectar/planejar/iniciar/remover: codewhale integrations dsh status · plan · connect · launch · remove\n- O Codewhale grava apenas em $CODEWHALE_HOME/integrations/dsh; nunca copia chaves de API nem edita arquivos do DSH.",
"HotbarActionModeOperateName": "Modo Operate",
"HotbarActionModeOperateDescription": "Trabalhe em uma solicitação duradoura em paralelo até que seja verificada.",
"HomeOperateModeTip": "Operate — coloque seu Fleet para trabalhar em paralelo",
"HomeOperateModeFleetTip": " Papéis integrados usam o modelo desta sessão; /fleet setup os personaliza",
"AppModeOperate": "Operate",
"AppModeOperateHint": "Work a pleno: meta, workers paralelos, verificado",
"HelpSubtitle": "Comandos, habilidades e atalhos",
"CommandPaletteTitle": "Comando",
"CommandPaletteSubtitle": "Encontre e execute uma ação",
"ConfigSubtitle": "Configurações primeiro; chaves brutas no detalhe avançado",
"LaunchStartTitle": "Comece aqui",
"LaunchResumeConfirm": "Retomar {title}? Clique novamente ou pressione Enter para confirmar.",
"LaunchResumeConfirmTitle": "Retomar sessão",
"LaunchResumeConfirmBody": "Isso substitui o contexto atual pelo histórico dessa sessão.",
"LaunchResumeConfirmResume": "retomar",
"LaunchResumeConfirmCancel": "cancelar",
"LaunchWorkDescription": "Use esta pasta com ferramentas locais; as alterações seguem sua política de aprovação.",
"LaunchChatDescription": "Somente conversa e planejamento; nenhum arquivo é alterado.",
"LaunchWorkspaceGitReady": "Workspace · {name} · workspace Git",
"LaunchWorkspaceFolderReady": "Workspace · {name} · pasta local",
"LaunchProviderConfigured": "Provedor · configurado",
"LaunchProviderSetupNeeded": "Provedor · requer configuração",
"LaunchGroupContinue": "Continuar",
"LaunchGroupMore": "Mais",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "pasta",
"LaunchProviderConfiguredShort": "provedor configurado",
"LaunchProviderSetupShort": "configurar provedor",
"LaunchMenuChangelog": "Changelog",
"LaunchWorktreePrompt": "Nomeie a branch/worktree ou pressione Enter para um nome automático. Esc para voltar.",
"LaunchWorktreeNeedsGit": "Novo worktree requer um repositório Git.",
"LaunchWorktreeNameLabel": "nome do worktree",
"LaunchHintMove": "mover",
"LaunchHintOpen": "abrir",
"LaunchTipFlags": "Dica: -w <path> abre um workspace; -r <session-id> retoma diretamente",
"LaunchSavedSessionSingular": "1 sessão salva",
"LaunchSavedSessionsPlural": "{count} sessões salvas",
"LaunchCreatingWorktree": "Criando worktree…",
"LaunchWorktreeFailed": "Falha no worktree: {error}",
"LaunchWorktreeCreated": "Novo worktree {path} na branch {branch}",
"LaunchNoSavedSessions": "Nenhuma sessão salva para este workspace.",
"LaunchNoModelConnected": "nenhum modelo conectado",
"DispatchNotSentNoModel": "Nenhum modelo está conectado, então esta mensagem não foi enviada. Ela voltou para a caixa de mensagem: conecte um modelo com F3 ou /provider e pressione Enter para enviá-la.",
"DispatchNotSentSaveKey": "Salve uma chave: {command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "Usando {model}, um modelo que roda neste computador (Ollama). Pressione F3 para escolher outro.",
"ProviderPickerNotReopened": "Não foi possível reabrir a lista de provedores. Pressione F3 para abri-la.",
"LaunchRunCommand": "execute {command}",
"LaunchMcpConnectedOne": "1 servidor MCP conectado",
"LaunchMcpConnectedMany": "{count} servidores MCP conectados",
"LaunchMcpNeedsSignInOne": "1 precisa de login",
"LaunchMcpNeedsSignInMany": "{count} precisam de login",
"PhaseIdle": "ocioso",
"PhaseDraft": "rascunho",
"PhaseWorking": "trabalhando",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "finalizando",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "só leitura",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "nunca",
"PermissionsChangedReceipt": "Permissões alteradas para {label}",
"FooterHintKeys": "teclas",
"FooterHintOutput": "saída",
"FooterHintContext": "contexto",
"InfoLineHelp": "ajuda",
"InfoLineContext": "contexto",
"InfoLineTtft": "ttft",
"InfoLinePeak": "pico",
"InfoLineOffPeak": "fora de pico",
"InfoLineWhales": "baleias",
"InfoLineAutomation": "automação",
"InfoLineNotConnected": "não conectado",
"InfoLineThinking": "raciocínio: {level}",
"EmptyStateNoGit": "sem git",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "buscar qualquer modelo",
"RoutePanelHeader": "rota",
"RouteProviderLabel": "provedor",
"RouteModelFirstAtomic": "rota atômica modelo-primeiro",
"PickerActionMove": "mover",
"PickerActionSwitch": "alternar",
"PickerActionApply": "aplicar",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "limpar busca",
"PickerActionBrowseAll": "ver todos",
"PickerActionCustom": "personalizado",
"PickerActionJump": "pular",
"PickerActionEditKey": "editar chave",
"PickerActionModels": "modelos",
"PickerActionUnavailable": "indisponível",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "parar de usar esse login",
"ProviderExternalActionChoices": "entrar por outro app",
"ProviderExternalActionReuseGrok": "reutilizar credencial externa do Grok",
"ProviderExternalHintCodexReview": "Após {login}, pressione Enter para revisar as opções desativada, somente leitura e gerenciada.",
"ProviderExternalHintXaiReview": "Pressione Enter para login de dispositivo próprio do Codewhale; pressione E para revisar a reutilização do Grok CLI.",
"ProviderExternalHintXaiApiKey": "Ou use XAI_API_KEY e reabra este seletor.",
"XaiAuthChoiceTitle": " Autenticação da xAI ",
"XaiAuthChoiceIntro": "Escolha uma fonte explícita de credenciais. O texto da chave nunca é tratado como token OAuth.",
"XaiAuthChoiceApiKeyOption": "Chave de API da xAI — digite ou cole e salve no espaço do provedor xAI",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " Autenticação ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "O login da assinatura cobra no seu plano ChatGPT. A rota de chave de API openai tem outro dono de faturamento.",
"ChatgptAuthChoicePkceOption": "Entrar com o ChatGPT — PKCE no navegador, tokens do Codewhale, faturamento da assinatura ChatGPT",
"ChatgptAuthChoiceImportOption": "Importar credenciais da CLI Codex — consentimento explícito somente leitura; a CLI Codex continua dona",
"ProviderExternalHintChatgptReview": "Pressione Enter para entrar com o ChatGPT; pressione E para revisar o reuso existente da CLI Codex.",
"ProviderExternalActionReuseCodex": "reuso externo do Codex",
"ProviderExternalDetailScope": "Externa: acesso={access} | provedor={provider} | origem={source} | versão={version} | {state}",
"ProviderExternalDormant": "inativo",
"ProviderExternalOwnerPath": "Proprietário/caminho: {owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "Snapshots e /undo estão desligados para {workspace}: um diretório raiz ou pessoal é amplo demais para um snapshot seguro. Comece em um diretório de projeto para ligá-los.",
"SnapshotsHistoryRepaired": "O histórico de desfazer de {workspace} estava danificado (faltava o ponto de restauração mais recente) e foi reiniciado. Os pontos de restauração anteriores não podem mais ser restaurados; os novos turnos voltam a ficar protegidos.",
"SnapshotsFailing": "Os snapshots estão falhando em {workspace}, então /undo não consegue restaurar os turnos recentes: {limit}",
"SessionIdDivergedNotice": "A identidade da sessão mudou nesta janela: o motor agora salva checkpoints como {next} (antes era {previous}). Os checkpoints anteriores ficam sob o id antigo; `codewhale sessions` lista os dois e `codewhale resume {previous}` reabre o anterior.",
"RuntimeStoreUnreadableNotice": "Armazenamento de execução da sessão: não foi possível ler {record} em {path} ({reason}). Afaste esse arquivo (ou exclua-o) e tente de novo; os demais registros da thread permanecem.",
"RuntimeStoreUnwritableNotice": "Armazenamento de execução da sessão: não foi possível gravar {record} em {path} ({reason}). Verifique o espaço livre e as permissões nesse local e tente de novo; nada foi sobrescrito.",
"ProviderExternalSemanticsRevoke": "{semantics} | revogar: {revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "setup",
"FleetRosterWorkers": "workers",
"FleetRosterMembersCount": "{count} membros",
"FleetRosterOperatorFirst": "O Coordenador lidera · o modelo da sessão dirige este Fleet",
"FleetRosterOperatorRow": "Coordenador · líder",
"FleetRosterShadowBadgeProjectOverride": "salvo neste projeto",
"FleetRosterShadowBadgePersonalIgnored": "cópia salva ignorada",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "este é o seu modelo atual (a rota do operador da equipe); troque de modelo ou use /fleet save para alterá-la",
"FleetModelReasonAlreadyPresent": "já está na equipe",
"FleetModelErrorNeedsRoute": "um modelo da equipe precisa de um id de provider e de um id de modelo",
"FleetModelErrorNeedsRole": "O agente precisa de um nome de função (por exemplo, `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "nenhuma equipe está selecionada; sua equipe é apenas o modelo da sessão",
"FleetModelErrorOperatorRoute": "{route} é a rota do operador da equipe `{fleet}`; altere-a com /fleet save, não com remove",
"FleetModelErrorNotInFleet": "{route} não está na equipe `{fleet}`",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ anexar · 1 resultado",
"FilePickerMatchesPlural": "@ anexar · {count} resultados",
"FilePickerScanning": "Varrendo o workspace…",
"BehavioralTipPlanning": "Planejando? {key} alterna para o modo Plan",
"BehavioralTipBackgroundReceipt": "Os recibos ficam no painel Work — {key} abre o inspetor",
"BehavioralTipClearedInput": "Limpo · {chord} restaura",
"BehavioralTipMcpValidation": "{command} inicia os servidores e mostra o motivo",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "O modelo e o raciocínio",
"SettingSubjectProvider": "O provedor",
"SettingSubjectPermissions": "As permissões",
"ThinkingControlledByAutoRouting": "O raciocínio é controlado pelo roteamento automático de modelos; escolha um modelo fixo primeiro.",
"SavedAsStartupDefault": "salvo como padrão de inicialização",
"ModeAlreadyActiveSavedAsDefault": "Já está no modo {mode} — salvo como padrão de inicialização.",
"StartupDefaultNotSaved": "Não foi possível salvar {setting}: {error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "o nível de raciocínio",
"StartupDefaultSubjectModel": "o modelo",
"StartupDefaultSubjectAll": "os padrões de inicialização",
"SessionsRailTitle": "Sessões",
"SessionsRailEmpty": "Ainda não há sessões neste workspace",
"SessionsRailBrowseAll": "Ver todas as sessões",
"SessionsRailShowingCount": "{shown} de {total} — ver todas",
"SessionsRailUnavailable": "Sessões indisponíveis: {error}",
"SessionsActionArchive": "arquivar",
"SessionsActionShowArchived": "arquivadas",
"SessionsArchived": "Sessão {id} arquivada",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "agentes",
"FooterHintToManage": "gerenciar",
"AgentRailQueuedCount": "{count} na fila",
"WorkbarSoFar": "{done}/{total} até agora",
"WorkbarLargeWorkflow": "Fluxo de trabalho grande",
"WorkbarMoreRuns": "+{count} a mais",
"WorkflowLineStarted": "iniciado",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "concluído com lacunas",
"WorkflowLineFailed": "falhou",
"WorkflowLineStopped": "interrompido",
"WorkflowLineAgents": "{done}/{total} agentes",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "escreve",
"AgentFocusPostureReadOnly": "somente leitura",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell somente leitura",
"AgentFocusPostureShellNone": "sem shell",
"GoalReceiptSet": "Meta definida: \"{objective}\" · /goal mostra o progresso · /goal pause ou /goal clear interrompe",
"GoalReceiptSetOperate": "◆ meta definida · Operate continua trabalhando até ser verificada · /goal para editar",
"GoalControlAccepted": "Controle da meta salvo; será aplicado no próximo limite seguro.",
"GoalControlRuntimeUnavailable": "O controle da meta está salvo, mas o runtime não está disponível. Ele será restaurado após reiniciar.",
"GoalStatusIdleHint": "parada no momento — envie uma mensagem ou /goal resume para continuar",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Objetivo ativo · próximo turno em {delay} · Esc, Ctrl+C ou /goal pause interrompe a continuação pendente",
"GoalContinuationReady": "Continuação do objetivo pronta; os controles na fila executam antes do próximo turno.",
"GoalContinuationStopped": "Continuação pendente interrompida; o objetivo permanece ativo.",
"McpCapabilitiesAdvertised": "Recursos anunciados: {capabilities}",
"McpCapabilitiesLegacyFallback": "Recursos anunciados: não informados; usando descoberta legada como alternativa",
"McpCapabilitiesNotObserved": "Recursos anunciados: não observados porque o servidor não está conectado",
"PickerActionTestConnection": "testar conexão",
"ProviderCustomFormBaseUrl": "URL base",
"ProviderCustomFormModel": "Modelo padrão",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt tempo →",
"ConfigCategoryAppearance": "Aparência",
"ConfigCategoryModelsProviders": "Modelos e provedores",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Trabalho",
"ConfigCategoryToolsMcp": "Ferramentas e MCP",
"ConfigCategoryTrust": "Confiança",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "somente leitura",
"ConfigRowActionNote": "ação · não é uma configuração persistida",
"ConfigRowDiagnosticNote": "recibo observado · não editável aqui",
"ConfigNavHint": "←/→ ou Tab categoria · ↑/↓ configuração",
"ConfigActivateAgain": "Enter ou clique de novo:",
"ConfigSearchLabel": " Buscar: ",
"ConfigEditChooseLabel": "Escolha:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Nunca",
"ConfigChoiceModeAct": "Agir",
"ConfigChoiceModePlan": "Planejar (somente leitura)",
"ConfigChoiceModeOperate": "Operar",
"ConfigChoicePlacementTop": "Topo",
"ConfigChoicePlacementBottom": "Barra inferior",
"ConfigChoicePlacementLeft": "Barra lateral esquerda",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Revisa o risco das ferramentas automaticamente e pergunta quando uma decisão precisa de você.",
"ConfigChoiceDetailUseTuiDefault": "Remove a sobreposição do config raiz e usa a escolha de permissão salva na TUI.",
"ConfigChoiceDetailFullAccess": "As ferramentas rodam sem perguntar, e os comandos podem acessar tudo neste computador.",
"ConfigChoiceDetailNever": "Bloqueia toda ferramenta que exige aprovação.",
"ConfigChoiceDetailModeAgent": "Começa pronto para colaborar e usar ferramentas.",
"ConfigChoiceDetailModePlan": "Começa em um espaço de planejamento somente leitura.",
"ConfigChoiceDetailModeOperate": "Operate é o Work com força total: cada solicitação substancial vira uma meta, passa por workflows e workers paralelos, é conferida por um revisor independente e continua até ser verificada.",
"ConfigChoiceDetailPlacementTop": "Mostra Tarefas, A fazer e Workers acima da transcrição.",
"ConfigChoiceDetailPlacementBottom": "Mostra Tarefas, A fazer e Workers abaixo do editor.",
"ConfigChoiceDetailPlacementLeft": "Mostra Tarefas, A fazer e Workers em uma barra lateral esquerda quando o terminal é largo o bastante.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Preenche o fundo do raciocínio do modelo.",
"ConfigChoiceDetailThinkingHighlightOff": "Mantém a linha de raciocínio tracejada e o texto em itálico sem fundo preenchido.",
"ConfigHintModel": "modelo da rota ao vivo desta sessão; Enter abre /model",
"ConfigHintFastModel": "usado pelo roteamento Auto e por model_strength=faster dos agentes quando este provedor tem um irmão conhecido",
"ConfigHintProvider": "credencial, modelo e endpoint mudam juntos",
"ConfigHintApprovalMode": "somente esta sessão: Perguntar | Revisão automática | Acesso total",
"ConfigHintPermissionPosture": "padrão para novas sessões: Perguntar | Revisão automática | Acesso total",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "inteiro (0 permitido) · quantidade de mensagens enviadas mantidas para recuperação e busca no histórico",
"ConfigHintAutoCompactThreshold": "10..=100 · limiar de compactação: porcentagem do comprimento de contexto utilizável em que a compactação automática dispara",
"ConfigHintDefaultModel": "fallback legado somente DeepSeek; outros provedores usam o modelo por provedor acima",
"ConfigHintReasoningEffort": "default restaura o padrão do próprio modelo; modelos que sempre raciocinam omitem off",
"ConfigHintMcpOpen": "abre o gerenciador MCP · Conectar / Reconectar / Reautenticar / Diagnosticar",
"ConfigHintMcpReconnect": "reconecta o MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "estado somente leitura do flag de recurso das ferramentas de edição por patch",
"ConfigHintFeatureMcp": "estado somente leitura do flag de recurso das ferramentas MCP",
"ConfigHintFeatureExecPolicy": "estado somente leitura do flag de recurso das ferramentas de política de execução",
"ConfigHintFeatureVisionModel": "flag beta para suporte a imagens de visão/modelo",
"ConfigHintGoalCommand": "/goal define objetivos, orçamentos e o status do contexto de Trabalho",
"ConfigHintWorkflow": "/workflow executa operações roteirizadas com cartões de execução de distribuição/consolidação",
"LaunchMenuNewWorktree": "Novo worktree",
"LaunchMenuResume": "Retomar sessão",
"LaunchMenuQuit": "Sair",
"LaunchNoticeClaude": "Claude Code detectado. Execute /import-claude para revisar o que pode ser trazido: servidores MCP, configurações seguras e permissões. Nada é aplicado sem a sua aprovação.",
"LaunchNewSession": "Nova sessão",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ para retomar",
"LaunchHelpLine": "/help para comandos · {dock} para a barra de trabalho",
"LaunchSeeAllSessions": "Ver todas as sessões…",
"LaunchNoRecentSessions": "Ainda não há sessões recentes — digite abaixo para começar.",
"LaunchResumeFailed": "Falha ao retomar: {error}",
"ReceiptSessionHooks": "hooks {count}",
"AutomationEditorNew": "Nova automação",
"AutomationEditorEdit": "Editar automação",
"AutomationEditorSchedule": "Agendamento",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} concluídos",
"WorkflowPhaseCountOne": "{count} fase",
"WorkflowPhaseCountMany": "{count} fases",
"WorkflowPhaseOrdinal": "fase {n}/{total}",
"ModelPickerPinned": "{route} fixado",
"ModelPickerUnpinned": "{route} desafixado",
"ModelPickerPinFailed": "Não foi possível atualizar a fixação: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Substituiu o login anterior do Codewhale no {provider} ({account}).",
"AuthReplacedPreviousSignIn": "Substituiu o login anterior do Codewhale no {provider}.",
"AuthSameAccountAsBefore": "Esta é a mesma conta de antes; para usar outra conta do {provider}, saia dela no navegador (ou use uma janela privada) e entre novamente.",
"AuthEnvTokenOutranksSignIn": "OPENAI_CODEX_ACCESS_TOKEN ou CODEX_ACCESS_TOKEN está definido neste ambiente e tem prioridade sobre este login; as solicitações continuam usando a conta desse token até você removê-lo.",
"PinnedPromptJumpToMessage": "Ir para esta mensagem",
"PlanHandoffHeader": "Plano pronto",
"PlanHandoffQuestion": "Como você quer continuar?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Pressione Enter para entrar pelo navegador ou Esc para voltar. Não é necessária uma chave de API.",
"PluginOAuthReady": "{provider}: sessão iniciada. Escolha um modelo.",
"PluginOAuthLocalLogout": "{provider}: sessão local removida. O acesso remoto não foi alterado.",
"CmdConnectDescription": "Conecta um provedor de plugin com login pelo navegador",
"CmdDisconnectDescription": "Remove o login local de um provedor de plugin",
"ExecAutoHelp": "Ativa ferramentas com aprovação automática e Full Access (sem sandbox do shell, modo de confiança ativado), salvo se houver um sandbox mais restritivo configurado; use --sandbox workspace-write para restringir gravações de arquivos e do shell.",
"ExecSandboxHelp": "Política de sandbox desta execução; qualquer --sandbox diferente de danger-full-access (ou sandbox_mode equivalente na configuração) desativa o modo de confiança.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime закрыл поток событий этой беседы; откройте её заново",
"MobileStreamReconnecting": "Соединение потеряно; переподключение",
"MobileStreamConnected": "Подключено",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Общая среда обитания",
"PetHabitatHints": "{back} назад · {sound} звук · {browser} внешний вид · {window} окно",
"PetHabitatQueued": "Отправлено в общую среду обитания. /pet on показывает питомца и поле сообщения.",
"PetWatchSoundOn": "Звук включён",
"PetWatchSoundOff": "Звук выключен",
"PetWatchSoundPaused": "Звук приостановлен",
"PetWatchSoundUnavailable": "Звук Codewhale остановлен. Проверьте FFmpeg (ffplay) и аудиовыход, затем снова включите звук.",
"CmdPetDescription": "Сделать анимированного питомца главным экраном Codewhale",
"ConfigLabelPetMode": "Режим питомца",
"ConfigHintPetMode": "Показывать анимированного питомца на главном экране при запуске Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "режим питомца выключен",
"PetViewOpen": "среда открыта",
"PetViewClosed": "среда закрыта",
"PetWatchRestored": "/pet восстановил среду этой сессии. Ожидание новой телеметрии.",
"PetWatchStorageUnavailable": "Watch не удалось восстановить или сохранить эту среду. Существующие файлы сохранены. Используйте {command}, чтобы экспортировать этот запуск.",
"PetWatchExported": "Запись Watch сохранена: {path}",
"PetWatchExportFailed": "Не удалось сохранить запись Watch. Она остаётся в памяти.",
"PetWatchExportQueued": "Сохранение записи Watch…",
"PetWatchExportUnavailable": "Откройте /pet в сохранённой сессии или дождитесь завершения текущего экспорта.",
"PetUnobserved": "нет наблюдений",
"PetOffline": "не в сети — codewhale pet serve разбудит его",
"PetDozing": "дремлет",
"PetWatchUnavailable": "Телеметрия питомца приостановлена. /pet on повторит попытку.",
"ConversationChangedBeforeUndo": "Разговор изменился до завершения отмены. Ничего не отменено, повторный запрос не отправлен. Проверьте текущий разговор, прежде чем повторять попытку.",
"SessionArchiveExported": "Сеанс экспортирован",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Изменить",
"ExtensionsHooksAddLabel": "Добавить хук",
"ExtensionsHooksAddDescription": "Открыть файл хуков этого проекта в вашем редакторе",
"ExtensionsActionReload": "перезагрузить",
"ExtensionsActionConnect": "подключить",
"ExtensionsActionReconnect": "переподключить",
"ExtensionsActionReauth": "повторно войти",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "подключён",
"ExtensionsStateEnabled": "включён",
"ExtensionsStateError": "ошибка",
"ExtensionsStateInactive": "неактивен",
"ExtensionsStateInapplicable": "не применим",
"ExtensionsStateInvalid": "недействителен",
"ExtensionsStateNotInspected": "не проверено",
"ExtensionsStateDisconnected": "отключён",
"ExtensionsStateRejected": "отклонён",
"ExtensionsStateReviewedCandidate": "проверенный кандидат",
"ExtensionsStateUnderEvaluation": "оценивается",
"ExtensionsStateUnstaged": "не подготовлен",
"ExtensionsStateUnsupported": "не поддерживается",
"ExtensionsStateWarning": "предупреждение",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ отправить в этот ход",
"ComposerHintLongDraft": "{shortcut}: внешний редактор",
"PendingSendingIntoTurnPrefix": " ↳ Отправка в этот ход: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Не удалось отправить в этот ход: ",
"PendingEditingFollowUpPrefix": " ↳ Редактируется следующее сообщение: ",
"PendingQueuedOnePrefix": "В очереди #1: ",
"PendingQueuedManyPrefix": "В очереди {count} · далее: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Обдумывание завершено",
"TranscriptThoughtFor": "Обдумывание заняло {duration}",
"TelemetryNoticeDefaultOn": "Отправка статистики использования включена по умолчанию. Передавать сводные счётчики версий, платформ, сеансов, функций и ошибок Codewhale и обработчику PostHog. Также считает провайдеров, модели из публичного каталога, суммы токенов и использование встроенных инструментов. Без содержимого и IP. docs/TELEMETRY.md Отключить: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Статистика использования Codewhale",
"TelemetryNoticeBody": "Codewhale считает: версию, операционную систему и семейство процессора,\nдлительность и результат сеанса, а также сводные счётчики функций и ошибок.\n\nТакже считает провайдеров и модели из публичного каталога, которые вы используете, суммы их токенов и то, как часто запускается каждый встроенный инструмент.\n\nОн никогда не собирает ваши разговоры, код, запросы, файлы, имена файлов,\nрепозиториев или веток, содержимое модели и учётные данные — и никогда не\nотправляет хронологию действий агента по отдельным ходам или инструментам.\n\nДля идентификации служит только случайный идентификатор на этом устройстве,\nкоторый заменяется каждые 90 дней. Передумать можно в любое время:\n codewhale config set telemetry false\n\nПолная схема по полям: docs/TELEMETRY.md\n\nОтправка статистики использования включена по умолчанию. Codewhale и PostHog обрабатывают эти счётчики, если отправка настроена. IP не собираются.",
"TelemetryNoticeCompactBody": "Счёт: версия, ОС/CPU, время/итог сеанса, функции/ошибки. Также: провайдер/модель, токены, инструменты. Локальный случайный ID меняется каждые 90 дней. Никогда: чаты/код/запросы/файлы/имена, данные модели/учётные данные, ходы/инструменты. Схема: docs/TELEMETRY.md Выкл.: codewhale config set telemetry false\nОтправка статистики использования включена по умолчанию. Codewhale и PostHog обрабатывают эти счётчики, если отправка настроена. IP не собираются.",
"TelemetryNoticeChoiceKeep": "Да, оставить анонимный подсчёт",
"TelemetryNoticeChoiceDisable": "Нет, отключить отслеживание",
"TelemetryNoticeActionChoose": "выбрать",
"TelemetryNoticeActionConfirm": "подтвердить",
"TelemetryNoticeActionExit": "выйти",
"TelemetryNoticeReceiptEnabled": "Анонимный подсчёт использования включён. Разговоры и код никогда не собираются. Изменить в /settings; схема: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Анонимный подсчёт использования отключён. Повторного вопроса не будет.",
"TelemetryNoticeReceiptEnabledUnsaved": "Анонимный подсчёт использования включён для этого сеанса. Codewhale не удалось сохранить уведомление, поэтому оно появится снова. Изменить в /settings; схема: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Анонимный подсчёт использования отключён для этого сеанса. Codewhale не удалось сохранить выбор, поэтому при следующем запуске вопрос повторится.",
"TelemetryPreferenceEnabledNextLaunch": "Анонимный подсчёт использования включится при следующем запуске. Разговоры и код никогда не собираются.",
"TelemetryPreferenceDisabled": "Анонимный подсчёт использования отключён. Локальные данные телеметрии удалены.",
"TelemetryPreferenceDisabledWithWarning": "Анонимный подсчёт использования отключён, но часть очистки требует внимания: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Нет доступных действий для Hotbar.",
"HotbarSetupRecommended": "рек",
"HotbarSetupEmptySlot": "пусто",
"HotbarSetupHelp": "Tab/Shift+Tab источник Up/Down действие 1-8 слот Enter назначить Space перекл. Delete очистить s сохранить Esc отмена",
"HotbarActionVoiceToggleName": "Голосовой ввод",
"HotbarActionVoiceToggleDescription": "Включает/выключает захват голоса с микрофона терминала.",
"HotbarActionSessionCompactName": "Сжать сессию",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Режим Work",
"HotbarActionModeAgentDescription": "Прямая работа в текущей сессии.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Совместимость: Work с правами Full Access (не отдельный режим).",
"HotbarActionReasoningCycleName": "Переключение рассуждений",
"HotbarActionReasoningCycleDescription": "Перебирает уровень рассуждений активного провайдера.",
"HotbarActionReasoningCycleAutoDisabled": "Уровень рассуждений задаётся автомаршрутизацией модели.",
"HotbarActionSidebarToggleName": "Боковая панель",
"HotbarActionSidebarToggleDescription": "Показать или скрыть боковую панель.",
"HotbarActionFileTreeToggleName": "Дерево файлов",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Настройки недоступны.",
"ConfigNoMatchesPrefix": " Нет совпадений для ",
"ConfigFilteredSettings": " Отфильтрованные настройки",
"ConfigShowing": " Показано",
"ConfigFooterDefault": " ввод=фильтр, Up/Down=выбор, Enter=изменить, Esc=закрыть ",
"ConfigFooterScrollable": " ввод=фильтр, Up/Down=выбор, Enter=изменить, PgUp/PgDn=прокрутка, Esc=закрыть ",
"ConfigFooterFiltered": " ввод=фильтр, Backspace=удалить, Ctrl+U/Esc=очистить, Enter=изменить ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; подсказки-призраки применяются после последующих ходов)",
"ConfigNotificationsSetHint": "Задайте через /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; применяется к последующим уведомлениям)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs должно быть целым числом",
"ConfigAuditSearchProvider": "Записывает [search] provider; последующие вызовы web_search по-прежнему учитывают переменные среды.",
"ConfigAuditPromptSuggestion": "Записывает prompt_suggestion верхнего уровня; подсказки-призраки остаются опциональными.",
"ConfigAuditNotifications": "Записывает скалярные значения [notifications] и применяет их к последующим уведомлениям о завершении хода.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL API провайдера",
"ConfigHintProviderUrl": "Текущая конечная точка провайдера; Xiaomi: пакет токенов | оплата по мере использования | пользовательский URL",
"ConfigLabelModel": "Модель текущего провайдера",
"ConfigLabelFastModel": "Быстрая модель (производная)",
"ConfigLabelDefaultModel": "Резервная модель (только маршруты DeepSeek)",
"ConfigLabelReasoningEffort": "Уровень рассуждений",
"ConfigLabelApprovalMode": "Разрешение этой сессии",
"ConfigLabelPermissionPosture": "Разрешение новых сессий",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Сводные счётчики версий, сеансов, функций и ошибок для Codewhale и PostHog; никогда содержимое или IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Вкл.",
"ConfigValueTelemetryOff": "Выкл.",
"ConfigLabelStreamTimeout": "Тайм-аут потока",
"ConfigLabelTheme": "Тема",
"ConfigLabelLocale": "Язык",
"ConfigLabelBackground": "Фон",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Подсветка фона рассуждений",
"ConfigLabelShowToolDetails": "Детализация инструментов",
"ConfigLabelInlineDiffs": "Встроенные изменения файлов",
"ConfigLabelStatusIndicator": "Индикатор статуса",
"ConfigLabelSynchronizedOutput": "Темп вывода",
"ConfigLabelCostCurrency": "Валюта стоимости",
"ConfigLabelTranscriptSpacing": "Интервалы в ленте",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "Плотность поля ввода",
"ConfigLabelComposerBorder": "Рамка поля ввода",
"ConfigLabelComposerMultilineMode": "Многострочный режим поля ввода",
"ConfigLabelComposerVimMode": "Режим Vim в поле ввода",
"ConfigLabelBracketedPaste": "Режим bracketed paste",
"ConfigLabelPasteBurstDetection": "Определение вставки",
"ConfigLabelMentionMenuLimit": "Лимит меню упоминаний",
"ConfigLabelMentionMenuBehavior": "Поведение меню упоминаний",
"ConfigLabelMentionWalkDepth": "Глубина упоминаний файлов",
"ConfigLabelWorkspaceFollowSymlinks": "Следовать симлинкам",
"ConfigLabelContextPanel": "Панель контекста",
"ConfigLabelAutoCompact": "Автосжатие",
"ConfigLabelAutoCompactThreshold": "Порог сжатия",
"ConfigLabelMaxHistory": "История ввода",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "Команда цели",
"ConfigLabelWorkflow": "Воркфлоу",
"ConfigLabelFeaturePrefix": "Функция: {name}",
"ConfigColumnSetting": "Настройка",
"ConfigColumnValue": "Значение",
"ConfigColumnScope": "Область",
"ConfigActionOpenProvider": "Enter — выбор провайдера",
"ConfigActionOpenModel": "Enter — выбор модели",
"ConfigActionOpenMcp": "Enter открывает менеджер MCP",
@@ -415,6 +456,7 @@
"HelpKeybindings": "Сочетания клавиш",
"HelpUserCommands": "Пользовательские команды",
"HelpSkills": "Навыки",
"HelpFooterTypeFilter": " введите для фильтра ",
"HelpFooterMove": " Up/Down перемещение ",
"HelpFooterJump": " PgUp/PgDn переход ",
"HelpFooterClose": " Esc закрыть ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "Рекомендуемый плагин: {name}",
"PluginCtaReview": "Проверить",
"PluginCtaInstall": "Установить",
"PluginCtaReviewTrust": "Проверить доверие",
"PluginCtaEnable": "Включить",
"PluginCtaDismiss": "Больше не предлагать",
"PluginCtaDismissSaveFailed": "Скрыто на время сеанса; не удалось сохранить настройку плагина.",
"PluginSuggestionReason": "Совпадение с «{trigger}»",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "Действие с плагином не удалось: {error}",
"CmdPluginNoneFound": "Устаревшие исполняемые плагины в {dir} не найдены",
"CmdPluginNotFound": "Плагин '{name}' не найден",
"CmdPluginListHeader": "Устаревшие исполняемые плагины ({count}):",
"CmdPluginDetailDescription": "Описание: {description}",
"CmdPluginDetailSchema": "Схема:\n{schema}",
"CmdPluginDetailApproval": "Одобрение: {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "Сохранённый каталог; выполните `codewhale models --update`, чтобы обновить настроенных провайдеров.",
"ModelsUpdateSummary": "Каталоги моделей: обновлено {updated}, загружено из Codex {loaded}, ошибок {failed}, пропущено {skipped}.",
"ModelsUpdatePartial": "Не удалось обновить некоторые каталоги. Предыдущие и настроенные модели остаются доступны.",
"ModelsCodexHint": "Модели ChatGPT загружаются через Codex. Время запроса не подтверждает обновление каталога у провайдера.",
"ModelsSourceFallback": "Встроенные или настроенные модели; доступность не проверена.",
"CmdModelDbDescription": "Просмотр встроенной базы моделей",
"CmdNetworkDescription": "Управление правилами разрешения и запрета сети",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "Просмотр и редактирование сообщений в очереди",
"CmdQueueUsage": "Использование: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "Восстановлено сообщений в очереди из прошлого сеанса: {count}. Они не отправляются автоматически: /queue send <n> отправит одно, /queue clear удалит их.",
"CmdQueueDraftHeader": "Редактирование сообщения из очереди:",
"CmdQueueNoMessages": "Нет сообщений в очереди",
"CmdQueueListHeader": "Сообщения в очереди ({count}):",
"CmdQueueTip": "Совет: /queue send <n> — отправить сейчас, /queue drop <n> — удалить",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} попад. / {miss} промах.",
"CmdTokensCacheHitOnly": "{hit} попад. / промахи не сообщены",
"CmdTokensCacheMissOnly": "попадания не сообщены / {miss} промах.",
"CmdTokensContextUnknownWindow": "~{estimated} / окно неизвестно",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 агент",
"FooterAgentsPlural": "{count} агентов",
"HeaderAgentsChip": "агентов {count}",
"FooterPressCtrlCAgain": "Нажмите Ctrl+C ещё раз, чтобы выйти",
"FooterWorking": "в работе",
"FooterBalancePrefix": "баланс",
"HelpSectionActions": "Действия",
"HelpSectionClipboard": "Буфер обмена",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "не сообщено",
"CmdTokensReport": "Использование токенов:\n ─────────────────────────────\n Активный контекст: {active}\n Последний ввод API: {input} (телеметрия хода; повторный префикс может считаться в каждом раунде инструментов)\n Последний вывод API: {output}\n Попадания/промахи кэша: {cache} (только телеметрия/стоимость)\n Всего токенов: {total} (телеметрия использования сессии)\n Примерная стоимость: {cost}\n Сообщений API: {api_messages}\n Сообщений чата: {chat_messages}\n Модель: {model}",
"KbScrollTranscript": "Прокрутка ленты, навигация по истории ввода или выбор вложений",
"KbNavigateHistory": "Навигация по истории ввода",
"KbBrowseHistory": "Просмотр истории диалога",
"KbScrollTranscriptAlt": "Прокрутка ленты",
"KbScrollPage": "Прокрутка ленты постранично",
@@ -807,6 +858,7 @@
"KbCompactContext": "Сжать контекст разговора",
"KbLastMessagePager": "Открыть последнее сообщение в пейджере (при пустом вводе)",
"KbSelectedDetails": "Показать сырые детали выбранного инструмента или сообщения; Ctrl+Alt+O — обзор всего хода",
"KbToolDetailsPager": "Показать сырые детали выбранного элемента (Alt+V)",
"KbExternalEditor": "Открыть черновик во внешнем редакторе",
"KbLiveTranscript": "Открыть живую ленту поверх (Ctrl+Shift+T; автопрокрутка с привязкой к концу)",
"KbBacktrackMessage": "Вернуться к предыдущему сообщению пользователя (Left/Right — шаг, Enter — откат)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "Открыть эту справку поверх (при пустом вводе)",
"KbCycleWorkDock": "Переключать рабочую панель (задачи, агенты, задания, фон), а в режиме питомца — виды питомца",
"KbCycleWorkDockBack": "Переключать рабочую панель или виды питомца назад",
"KbToggleHelp": "Переключить справку поверх",
"KbToggleHelpSlash": "Переключить справку поверх",
"HelpUsageLabel": "Использование:",
"HelpAliasesLabel": "Псевдонимы:",
"SettingsTitle": "Настройки:",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan — сначала исследовать и представить план",
"HomeAgentModeYoloTip": " Shift+Tab переключает разрешения: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — инструменты работают без запросов на одобрение",
"HomeYoloModeCaution": " Деструктивные операции могут выполниться сразу; если сомневаетесь, выбирайте Ask",
"HomePlanModeTip": "Plan — исследование и проектирование до реализации",
"HomePlanModeChecklistTip": " Представьте план и прогресс To-do, затем переключитесь в Work",
"HomeGoalModeTip": "Отслеживание цели - задайте /goal <objective> для достижения целей",
"OnboardLanguageTitle": "Выберите язык",
"OnboardLanguageBlurb": "Выберите язык интерфейса. Его можно сменить в любой момент командой `/config locale <tag> --save`.",
"OnboardProviderTitle": "Выберите провайдера модели",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "«Оставить» включает маскирование на этот запуск; конфигурация всё ещё требует \"disabled\", поэтому следующий запуск спросит снова.",
"RedactionGateSaveFailed": "Не удалось сохранить подтверждение. Маскирование остаётся включённым. Повторите попытку или оставьте его включённым.",
"RedactionGateTitle": "Маскирование ключей на границе модели",
"OnboardOfflineOption": "Ctrl+O — посмотреть офлайн: осмотритесь сейчас, провайдера подключите позже.",
"OnboardOfflineNotice": "Смотрите офлайн. Пока ничего не подключено — выполните /provider, когда захотите подключиться.",
"OnboardWelcomeTitle": "Codewhale работает с вами в этой папке.",
"OnboardWelcomeLead": "Давайте подготовимся.",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "Объясни, что делает этот проект, и перечисли основные точки входа.",
"OnboardSeedFolder": "Посмотри эту папку и предложи хорошую первую задачу.",
"SetupWizardTitle": "Настройка",
"SetupWizardWhy": "Эта оболочка записывает прогресс настройки в setup_state.json; изменения конфигурации применяются только явными действиями шагов.",
"SetupWizardProgress": "Шаг",
"SetupActionBack": "назад",
"SetupActionContinue": "продолжить",
"SetupActionSkip": "пропустить",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "прокрутка текста",
"SetupActionGuided": "предпросмотр/утвердить",
"SetupActionTuneGuided": "настроить",
"SetupActionModelDraft": "черновик модели",
"SetupActionFreeform": "свои слова",
"SetupActionKeepExisting": "оставить текущее",
"SetupActionUseRecommended": "принять рекомендацию",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "маршруты модели",
"SetupActionFleet": "настройка Fleet",
"SetupActionHotbar": "настройка Hotbar",
"SetupActionRemote": "удалённое подключение",
"SetupActionMode": "выбор режима",
"SetupActionConfig": "просмотр конфигурации",
"SetupActionRuntimePreset": "пресет",
"SetupActionApplyRuntimePreset": "предпросмотр/применить",
"SetupActionUseBundled": "использовать встроенное",
"SetupActionDefer": "отложить",
"SetupActionCancel": "отмена",
"SetupStatusNotStarted": "не начато",
"SetupStatusRecommended": "рекомендуется",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "Язык настройки записан.",
"SetupConstitutionChoiceLabel": "Выбор:",
"SetupConstitutionSourceLabel": "Источник:",
"SetupConstitutionValidityLabel": "Действительность:",
"SetupConstitutionPreviewLabel": "Хэш предпросмотра:",
"SetupConstitutionExistingLabel": "Текущий файл:",
"SetupConstitutionExpertOverrideLabel": "Экспертное переопределение:",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "Плагины:",
"SetupToolsMcpReviewHint": "Enter записывает этот снимок настройки. Нажмите R для безопасного подключения (без автозапуска).",
"SetupToolsMcpReviewed": "Готовность Tools/MCP записана.",
"SetupRemoteCloudsLabel": "Облачные цели:",
"SetupRemoteBridgesLabel": "Чат-мосты:",
"SetupRemoteProvidersLabel": "Провайдеры:",
"SetupRemoteModeLabel": "Удалённый режим:",
"SetupRemoteModeLocalOnly": "Только этот компьютер:",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "Копировать сообщение",
"CtxMenuCopyMessageDesc": "записать выбранную ячейку транскрипта",
"CtxMenuOpenInEditor": "Открыть в редакторе",
"CtxMenuOpenInEditorDesc": "открыть файл:строку в $EDITOR",
"CtxMenuShowCell": "Показать ячейку",
"CtxMenuShowCellDesc": "раскрыть эту ячейку транскрипта",
"CtxMenuHideCell": "Скрыть ячейку",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} готово · {running} выполняется · {failed} ошибок · {pending} в очереди",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (устаревшее название режима)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Прямая работа в этой сессии — правки и shell запрашивают одобрение",
"AppModeAutoHint": "Shell включён с автоматической проверкой рисков",
"AppModePlanHint": "Сначала исследование только для чтения — план до начала действий",
"AppModeYoloHint": "Только для совместимости — Work + Full Access, не видимый режим",
"AppModeOperateHint": "Work на полную: цель, параллельные агенты, проверка",
"VimModeNormal": "-- ОБЫЧНЫЙ --",
"VimModeInsert": "-- ВСТАВКА --",
"VimModeVisual": "-- ВЫДЕЛЕНИЕ --",
"ApprovalEffectReadsOnly": "Только чтение",
"ApprovalEffectChangesFiles": "Изменяет файлы",
"ApprovalRiskDestructive": "Нельзя отменить",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s разрешить сейчас и всегда спрашивать в следующий раз",
"ApprovalOptionDeny": "Не разрешать",
"ApprovalOptionAbortTurn": "Остановить этот ход",
"ApprovalBlockTitle": "одобрение",
"ApprovalControlsHint": "Pg↑/↓ просмотр · {details} другие варианты · Esc стоп",
"ApprovalOwnerHeader": "Агент: {agent} · {role}",
"ApprovalGoToAgent": "g перейти к агенту",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … обрезано · нажмите {details} для полных деталей",
"ApprovalAsksWithoutGit": "Здесь нет репозитория Git, поэтому перед правками запрашивается подтверждение.",
"ApprovalFullAccessPolicyBlocked": "{tool} заблокирован: Full Access не может обойти эту политику",
"ApprovalChooseHint": "Выбор: ",
"ApprovalChooseAction": "Enter — выбранный вариант, или нажмите y/a/d напрямую",
"ApprovalIntentLabel": "Намерение: ",
"ApprovalMoreLines": " … (ещё {count} строк)",
"ApprovalProceedQuestion": "Продолжить?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "Контекст сжимается…",
"ContextCompactionQueued": "Сжатие контекста поставлено в очередь; оно запустится после активного хода.",
"ContextCompactionAlreadyRunning": "Сжатие контекста уже выполняется.",
"ContextCompactionQueueFull": "Не удалось поставить сжатие контекста в очередь, потому что движок занят; повторите попытку после завершения хода.",
"ContextCompactionQueueClosed": "Сжатие контекста недоступно, потому что движок больше не работает.",
"ContextCompactionRouteInvalid": "Невозможно выполнить сжатие, потому что активный маршрут провайдера недействителен: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Сжатие контекста остановлено; разговор не изменён",
"ContextPurgeAbandonedOnEngineSwitch": "Очистка сессии прервана вместе с заменённым движком; разговор не изменён",
"CtxInspTitle": "Инспектор контекста",
"CtxInspSessionContext": "Контекст сессии",
"CtxInspSystemPrompt": "Структура системного промпта",
"CtxInspReferences": "Ссылки",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Инструменты, MCP, навыки и плагины — безопасное начало\n\n/setup только читает локальный инвентарь. Он никогда не запускает серверы MCP, не устанавливает навыки, не запускает плагины и не выполняет недоверенные команды.\n\nТекущий инвентарь:\n- MCP: {mcp_result}\n- Навыки: {skills_result}\n- Каталог инструментов: {tools_result}\n- Плагины: {plugins_result}\n- Hotbar (общие адаптеры): {hotbar_result}\n\nПути (домашний каталог скрыт):\n- Конфигурация MCP: {mcp_path}\n- Навыки: {skills_path}\n- Плагины: {plugins_path}\n\nБезопасная инициализация (выполните сами в обычном терминале или командой TUI):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Навыки: /skills · codewhale setup --skills · /skills install <spec>\n- Плагины: /plugin · codewhale setup --plugins\n- Каталог инструментов: codewhale setup --tools\n\nДействия с побочными эффектами всегда требуют явного подтверждения. Команды плагинов отличаются от slash-команд; источник плагинов Hotbar отложен до появления барьеров одобрения.\n\nСм. docs/MCP.md и docs/skills/README.md о том, что ещё требует ручной внешней настройки.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — подключён через Codewhale, никогда не второй планировщик:\n- Состояние: {dsh_result}\n- Обнаружение только для чтения; подключить/план/запуск/удалить: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale пишет только в $CODEWHALE_HOME/integrations/dsh; никогда не копирует API-ключи и не изменяет файлы DSH.",
"HotbarActionModeOperateName": "Режим Operate",
"HotbarActionModeOperateDescription": "Выполнять долгий запрос параллельно, пока он не будет проверен.",
"HomeOperateModeTip": "Operate — параллельная работа Fleet",
"HomeOperateModeFleetTip": " Встроенные роли используют модель этой сессии; /fleet setup настраивает их",
"HelpSubtitle": "Команды, навыки и сочетания клавиш",
"CommandPaletteTitle": "Команда",
"CommandPaletteSubtitle": "Найти и выполнить одно действие",
"ConfigSubtitle": "Сначала настройки; сырые ключи — в расширенных деталях",
"LaunchStartTitle": "Начните здесь",
"LaunchResumeConfirm": "Возобновить {title}? Нажмите ещё раз или Enter для подтверждения.",
"LaunchResumeConfirmTitle": "Возобновить сессию",
"LaunchResumeConfirmBody": "Текущий контекст будет заменён историей той сессии.",
"LaunchResumeConfirmResume": "возобновить",
"LaunchResumeConfirmCancel": "отмена",
"LaunchWorkDescription": "Используйте локальные инструменты в этой папке; изменения подчиняются политике подтверждений.",
"LaunchChatDescription": "Только разговор и планирование; файлы не изменяются.",
"LaunchWorkspaceGitReady": "Рабочая область · {name} · область Git",
"LaunchWorkspaceFolderReady": "Рабочая область · {name} · локальная папка",
"LaunchProviderConfigured": "Провайдер · настроен",
"LaunchProviderSetupNeeded": "Провайдер · требуется настройка",
"LaunchGroupContinue": "Продолжить",
"LaunchGroupMore": "Ещё",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "папка",
"LaunchProviderConfiguredShort": "провайдер настроен",
"LaunchProviderSetupShort": "настройка провайдера",
"LaunchMenuChangelog": "Список изменений",
"LaunchWorktreePrompt": "Назовите ветку/worktree или нажмите Enter для автоматического имени. Esc — назад.",
"LaunchWorktreeNeedsGit": "Новый worktree требует репозиторий Git.",
"LaunchWorktreeNameLabel": "имя worktree",
"LaunchHintMove": "перемещение",
"LaunchHintOpen": "открыть",
"LaunchTipFlags": "Совет: -w <path> открывает рабочую область; -r <session-id> возобновляет напрямую",
"LaunchSavedSessionSingular": "1 сохранённая сессия",
"LaunchSavedSessionsPlural": "сохранённых сессий: {count}",
"LaunchCreatingWorktree": "Создание worktree…",
"LaunchWorktreeFailed": "Ошибка worktree: {error}",
"LaunchWorktreeCreated": "Новый worktree {path} в ветке {branch}",
"LaunchNoSavedSessions": "Нет сохранённых сессий для этой рабочей области.",
"LaunchNoModelConnected": "модель не подключена",
"DispatchNotSentNoModel": "Модель не подключена, поэтому сообщение не отправлено. Оно снова в поле ввода: подключите модель через F3 или /provider, затем нажмите Enter, чтобы отправить его.",
"DispatchNotSentSaveKey": "Сохранить ключ: {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "Используется {model} — модель, работающая на этом компьютере (Ollama). Нажмите F3, чтобы выбрать другую.",
"ProviderPickerNotReopened": "Не удалось снова открыть список провайдеров. Нажмите F3, чтобы открыть его.",
"LaunchRunCommand": "выполните {command}",
"LaunchMcpConnectedOne": "подключён 1 сервер MCP",
"LaunchMcpConnectedMany": "подключено серверов MCP: {count}",
"LaunchMcpNeedsSignInOne": "1 требует входа",
"LaunchMcpNeedsSignInMany": "{count} требуют входа",
"PhaseIdle": "простой",
"PhaseDraft": "черновик",
"PhaseWorking": "работа",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "завершение",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "только чтение",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "никогда",
"PermissionsChangedReceipt": "Разрешения изменены: {label}",
"FooterHintKeys": "клавиши",
"FooterHintOutput": "вывод",
"FooterHintContext": "контекст",
"InfoLineHelp": "справка",
"InfoLineContext": "контекст",
"InfoLineTtft": "ttft",
"InfoLinePeak": "пик",
"InfoLineOffPeak": "непиковое",
"InfoLineWhales": "киты",
"InfoLineAutomation": "автоматизация",
"InfoLineNotConnected": "не подключено",
"InfoLineThinking": "размышление: {level}",
"EmptyStateNoGit": "нет git",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "искать любую модель",
"RoutePanelHeader": "маршрут",
"RouteProviderLabel": "провайдер",
"RouteModelFirstAtomic": "атомарный маршрут с приоритетом модели",
"PickerActionMove": "перемещение",
"PickerActionSwitch": "переключить",
"PickerActionApply": "применить",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "очистить поиск",
"PickerActionBrowseAll": "показать все",
"PickerActionCustom": "свой",
"PickerActionJump": "перейти",
"PickerActionEditKey": "изменить ключ",
"PickerActionModels": "модели",
"PickerActionUnavailable": "недоступно",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "больше не использовать этот вход",
"ProviderExternalActionChoices": "войти через другое приложение",
"ProviderExternalActionReuseGrok": "повторное использование внешнего Grok",
"ProviderExternalHintCodexReview": "После {login} нажмите Enter, чтобы просмотреть варианты доступа: отключён/только чтение/управляемый.",
"ProviderExternalHintXaiReview": "Enter — вход через устройство от Codewhale; E — просмотр существующего использования Grok CLI.",
"ProviderExternalHintXaiApiKey": "Или используйте XAI_API_KEY и откройте этот выбор заново.",
"XaiAuthChoiceTitle": " Аутентификация xAI ",
"XaiAuthChoiceIntro": "Выберите один явный источник учётных данных. Текст ключа никогда не считается токеном OAuth.",
"XaiAuthChoiceApiKeyOption": "Ключ API xAI — введите или вставьте, затем сохраните в слоте провайдера xAI",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " Аутентификация ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "Вход по подписке списывается с вашего плана ChatGPT. Маршрут API-ключа openai принадлежит другому плательщику.",
"ChatgptAuthChoicePkceOption": "Войти через ChatGPT — PKCE в браузере, токены Codewhale, оплата подписки ChatGPT",
"ChatgptAuthChoiceImportOption": "Импортировать учётные данные CLI Codex — явное согласие только на чтение; владельцем остаётся CLI Codex",
"ProviderExternalHintChatgptReview": "Нажмите Enter, чтобы войти через ChatGPT; нажмите E, чтобы проверить существующее повторное использование CLI Codex.",
"ProviderExternalActionReuseCodex": "внешнее повторное использование Codex",
"ProviderExternalDetailScope": "Внешний: доступ={access} | провайдер={provider} | источник={source} | версия={version} | {state}",
"ProviderExternalDormant": "неактивен",
"ProviderExternalOwnerPath": "Владелец/путь: {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "Снимки и /undo отключены для {workspace}: домашний или корневой каталог слишком широк для безопасного снимка. Начните в каталоге проекта, чтобы включить их.",
"SnapshotsHistoryRepaired": "История отмены для {workspace} была повреждена (не хватало последней точки восстановления) и начата заново. Более ранние точки восстановления больше нельзя восстановить; новые ходы снова защищены.",
"SnapshotsFailing": "Снимки для {workspace} не создаются, поэтому /undo не может восстановить последние ходы: {limit}",
"SessionIdDivergedNotice": "Идентификатор сеанса в этом окне изменился: движок теперь сохраняет контрольные точки как {next} (было {previous}). Прежние точки остаются под старым id; `codewhale sessions` показывает оба, а `codewhale resume {previous}` открывает прежний сеанс.",
"RuntimeStoreUnreadableNotice": "Хранилище среды выполнения сессии: не удалось прочитать {record} в {path} ({reason}). Отложите этот файл (или удалите его) и повторите попытку; остальные записи потока сохраняются.",
"RuntimeStoreUnwritableNotice": "Хранилище среды выполнения сессии: не удалось записать {record} в {path} ({reason}). Проверьте свободное место и права доступа там и повторите попытку; ничего не было перезаписано.",
"ProviderExternalSemanticsRevoke": "{semantics} | отзыв: {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "настройка",
"FleetRosterWorkers": "воркеры",
"FleetRosterMembersCount": "участников: {count}",
"FleetRosterOperatorFirst": "Координатор ведёт · модель сессии управляет этим Fleet",
"FleetRosterOperatorRow": "Координатор · лидер",
"FleetRosterShadowBadgeProjectOverride": "сохранено для этого проекта",
"FleetRosterShadowBadgePersonalIgnored": "сохранённая копия игнорируется",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "это ваша текущая модель (маршрут оператора команды); переключите модель или измените его через /fleet save",
"FleetModelReasonAlreadyPresent": "уже в команде",
"FleetModelErrorNeedsRoute": "модели команды нужны и id провайдера, и id модели",
"FleetModelErrorNeedsRole": "Агенту нужно имя роли (например, `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "команда не выбрана; ваша команда — только модель сессии",
"FleetModelErrorOperatorRoute": "{route} — маршрут оператора команды `{fleet}`; меняйте его через /fleet save, а не remove",
"FleetModelErrorNotInFleet": "{route} нет в команде `{fleet}`",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ прикрепить · 1 совпадение",
"FilePickerMatchesPlural": "@ прикрепить · совпадений: {count}",
"FilePickerScanning": "Сканирование рабочей области…",
"BehavioralTipPlanning": "Планирование? {key} переключает в режим Plan",
"BehavioralTipBackgroundReceipt": "Подтверждения — в панели «Работа», {key} открывает инспектор",
"BehavioralTipClearedInput": "Очищено · {chord} восстанавливает",
"BehavioralTipMcpValidation": "{command} запускает серверы и показывает причину",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "Модель и thinking",
"SettingSubjectProvider": "Провайдер",
"SettingSubjectPermissions": "Права",
"ThinkingControlledByAutoRouting": "Thinking управляется автоматической маршрутизацией моделей; сначала выберите фиксированную модель.",
"SavedAsStartupDefault": "сохранено как значение по умолчанию при запуске",
"ModeAlreadyActiveSavedAsDefault": "Режим {mode} уже активен — сохранён как значение по умолчанию при запуске.",
"StartupDefaultNotSaved": "{setting} не сохранено: {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun выставляет счета за pay-as-you-go и подписки Step Plan на разных конечных точках. Выберите ту, к которой относится ваш ключ.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (потокенная оплата)",
"StepfunBillingRoutePlanOption": "Подписка Step Plan (лимит плана)",
"StepfunPlanApiKeyHint": "Для подписок StepFun Step Plan используйте ключ, выданный для вашего Step Plan, а не ключ pay-as-you-go.",
"StepfunPlanRouteHint": "Этот маршрут использует {route} и списывается из лимита вашего Step Plan.",
"ConfigLabelSessionsRail": "Панель сеансов",
"ConfigLabelSessionAutoResume": "Автовозобновление последнего сеанса",
"SessionsRailTitle": "Сеансы",
"SessionsRailEmpty": "В этом рабочем пространстве пока нет сеансов",
"SessionsRailBrowseAll": "Все сеансы",
"SessionsRailShowingCount": "{shown} из {total} — показать все",
"SessionsRailUnavailable": "Сеансы недоступны: {error}",
"SessionsActionArchive": "архивировать",
"SessionsActionShowArchived": "архив",
"SessionsArchived": "Сеанс {id} архивирован",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "агенты",
"FooterHintToManage": "управление",
"AgentRailQueuedCount": "{count} в очереди",
"WorkbarSoFar": "пока {done}/{total}",
"WorkbarLargeWorkflow": "Крупный рабочий процесс",
"WorkbarMoreRuns": "ещё {count}",
"WorkflowLineStarted": "запущен",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "завершён с пробелами",
"WorkflowLineFailed": "сбой",
"WorkflowLineStopped": "остановлен",
"WorkflowLineAgents": "агентов: {done}/{total}",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "пишет",
"AgentFocusPostureReadOnly": "только чтение",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell только чтение",
"AgentFocusPostureShellNone": "без shell",
"GoalReceiptSet": "Цель задана: «{objective}» · /goal показывает прогресс · /goal pause или /goal clear останавливает",
"GoalReceiptSetOperate": "◆ цель задана · Operate работает, пока она не будет проверена · /goal для правки",
"GoalControlAccepted": "Команда цели сохранена и будет применена на следующей безопасной границе.",
"GoalControlRuntimeUnavailable": "Команда цели сохранена, но среда выполнения недоступна. Она будет восстановлена после перезапуска.",
"GoalStatusIdleHint": "сейчас не выполняется — отправьте сообщение или /goal resume, чтобы продолжить",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Цель активна · следующий ход через {delay} · Esc, Ctrl+C или /goal pause останавливает ожидающее продолжение",
"GoalContinuationReady": "Продолжение цели готово; команды в очереди выполнятся перед следующим ходом.",
"GoalContinuationStopped": "Ожидающее продолжение цели остановлено; цель остаётся активной.",
"McpCapabilitiesAdvertised": "Заявленные возможности: {capabilities}",
"McpCapabilitiesLegacyFallback": "Заявленные возможности: не указаны; используется резервное устаревшее обнаружение",
"McpCapabilitiesNotObserved": "Заявленные возможности: не определены, так как сервер не подключён",
"PickerActionTestConnection": "проверить соединение",
"ProviderCustomFormBaseUrl": "Базовый URL",
"ProviderCustomFormModel": "Модель по умолчанию",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "гант время →",
"ConfigCategoryAppearance": "Оформление",
"ConfigCategoryModelsProviders": "Модели и провайдеры",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Работа",
"ConfigCategoryToolsMcp": "Инструменты и MCP",
"ConfigCategoryTrust": "Доверие",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "только чтение",
"ConfigRowActionNote": "действие · не сохраняемая настройка",
"ConfigRowDiagnosticNote": "наблюдаемая квитанция · здесь не редактируется",
"ConfigNavHint": "←/→ или Tab — категория · ↑/↓ — настройка",
"ConfigActivateAgain": "Enter или щёлкните ещё раз:",
"ConfigSearchLabel": " Поиск: ",
"ConfigEditChooseLabel": "Выбор:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Никогда",
"ConfigChoiceModeAct": "Действовать",
"ConfigChoiceModePlan": "Планировать (только чтение)",
"ConfigChoiceModeOperate": "Управлять",
"ConfigChoicePlacementTop": "Сверху",
"ConfigChoicePlacementBottom": "Нижняя панель",
"ConfigChoicePlacementLeft": "Левая боковая панель",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Автоматически оценивает риск инструментов и спрашивает, когда решение за вами.",
"ConfigChoiceDetailUseTuiDefault": "Снимает переопределение корневого config и использует сохранённый выбор разрешения TUI.",
"ConfigChoiceDetailFullAccess": "Инструменты будут запускаться без вопросов, а команды получат доступ ко всему на этом компьютере.",
"ConfigChoiceDetailNever": "Блокирует каждый инструмент, требующий одобрения.",
"ConfigChoiceDetailModeAgent": "Начинает в готовности сотрудничать и использовать инструменты.",
"ConfigChoiceDetailModePlan": "Начинает в пространстве планирования только для чтения.",
"ConfigChoiceDetailModeOperate": "Operate — это Work на полную мощность: каждый существенный запрос становится целью, проходит через workflow и параллельных агентов, проверяется независимым ревьюером и выполняется, пока не будет проверен.",
"ConfigChoiceDetailPlacementTop": "Показывает задачи, список дел и исполнителей над стенограммой.",
"ConfigChoiceDetailPlacementBottom": "Показывает задачи, список дел и исполнителей под полем ввода.",
"ConfigChoiceDetailPlacementLeft": "Показывает задачи, список дел и исполнителей в левой боковой панели, когда терминал достаточно широк.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Заливает фон рассуждений модели.",
"ConfigChoiceDetailThinkingHighlightOff": "Сохраняет пунктирную линию и курсив без заливки фона.",
"ConfigHintModel": "модель живого маршрута этой сессии; Enter открывает /model",
"ConfigHintFastModel": "используется маршрутизацией Auto и model_strength=faster агентов, когда у провайдера есть известная родственная модель",
"ConfigHintProvider": "учётные данные, модель и адрес переключаются вместе",
"ConfigHintApprovalMode": "только эта сессия: Спрашивать | Автопроверка | Полный доступ",
"ConfigHintPermissionPosture": "по умолчанию для новых сессий: Спрашивать | Автопроверка | Полный доступ",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "целое число (0 допускается) · сколько отправленных сообщений хранить для повтора и поиска по истории",
"ConfigHintAutoCompactThreshold": "10..=100 · порог сжатия: процент используемой длины контекста, при котором срабатывает автосжатие",
"ConfigHintDefaultModel": "устаревший запасной вариант только для DeepSeek; другие провайдеры используют свою модель выше",
"ConfigHintReasoningEffort": "default возвращает собственное значение модели по умолчанию; у моделей, которые всегда рассуждают, нет off",
"ConfigHintMcpOpen": "открыть менеджер MCP · подключить / переподключить / повторно войти / диагностика",
"ConfigHintMcpReconnect": "переподключить MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "состояние флага функции только для чтения для инструментов правки патчами",
"ConfigHintFeatureMcp": "состояние флага функции только для чтения для инструментов MCP",
"ConfigHintFeatureExecPolicy": "состояние флага функции только для чтения для инструментов политики выполнения",
"ConfigHintFeatureVisionModel": "бета-флаг поддержки изображений для зрения/модели",
"ConfigHintGoalCommand": "/goal задаёт цели, бюджеты и состояние рабочего контекста",
"ConfigHintWorkflow": "/workflow выполняет сценарные операции с карточками запуска распараллеливания/слияния",
"LaunchMenuNewWorktree": "Новый worktree",
"LaunchMenuResume": "Продолжить сессию",
"LaunchMenuQuit": "Выход",
"LaunchNoticeClaude": "Обнаружен Claude Code. Выполните /import-claude, чтобы посмотреть, что можно перенести: MCP-серверы, безопасные настройки и разрешения. Ничего не применяется без вашего согласия.",
"LaunchNewSession": "Новая сессия",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ — продолжить",
"LaunchHelpLine": "/help — команды · {dock} — рабочая панель",
"LaunchSeeAllSessions": "Показать все сессии…",
"LaunchNoRecentSessions": "Пока нет недавних сессий — введите ниже, чтобы начать.",
"LaunchResumeFailed": "Не удалось возобновить: {error}",
"ReceiptSessionHooks": "хуков: {count}",
"AutomationEditorNew": "Новая автоматизация",
"AutomationEditorEdit": "Изменить автоматизацию",
"AutomationEditorSchedule": "Расписание",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} готово",
"WorkflowPhaseCountOne": "фаз: {count}",
"WorkflowPhaseCountMany": "фаз: {count}",
"WorkflowPhaseOrdinal": "фаза {n}/{total}",
"ModelPickerPinned": "{route} закреплено",
"ModelPickerUnpinned": "{route} откреплено",
"ModelPickerPinFailed": "Не удалось обновить закрепление: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Предыдущий вход Codewhale в {provider} ({account}) заменён.",
"AuthReplacedPreviousSignIn": "Предыдущий вход Codewhale в {provider} заменён.",
"AuthSameAccountAsBefore": "Это тот же аккаунт, что и раньше; чтобы использовать другой аккаунт {provider}, выйдите из него в браузере (или откройте приватное окно) и войдите снова.",
"AuthEnvTokenOutranksSignIn": "В этой среде задана переменная OPENAI_CODEX_ACCESS_TOKEN или CODEX_ACCESS_TOKEN, и она важнее этого входа; запросы будут использовать аккаунт этого токена, пока вы её не удалите.",
"PinnedPromptJumpToMessage": "Перейти к этому сообщению",
"PlanHandoffHeader": "План готов",
"PlanHandoffQuestion": "Как вы хотите продолжить?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Нажмите Enter для входа через браузер или Esc для возврата. Ключ API не нужен.",
"PluginOAuthReady": "{provider}: вход выполнен. Выберите модель.",
"PluginOAuthLocalLogout": "{provider}: локальные данные входа удалены. Удалённый доступ не изменён.",
"CmdConnectDescription": "Подключить провайдера плагина через вход в браузере",
"CmdDisconnectDescription": "Удалить локальные данные входа провайдера плагина",
"ExecAutoHelp": "Включить инструменты с автоматическим одобрением и Full Access (без песочницы оболочки, режим доверия включён), если не настроена более строгая песочница; --sandbox workspace-write ограничивает запись через файловые инструменты и оболочку.",
"ExecSandboxHelp": "Политика песочницы для этого запуска; любое значение --sandbox, кроме danger-full-access (или соответствующее значение sandbox_mode в конфигурации), отключает режим доверия.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime закрив потік подій цієї розмови; відкрийте її знову",
"MobileStreamReconnecting": "З’єднання втрачено; повторне підключення",
"MobileStreamConnected": "Підключено",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Спільне середовище",
"PetHabitatHints": "{back} назад · {sound} звук · {browser} вигляд · {window} вікно",
"PetHabitatQueued": "Надіслано до спільного середовища. /pet on показує улюбленця й поле повідомлення.",
"PetWatchSoundOn": "Звук увімкнено",
"PetWatchSoundOff": "Звук вимкнено",
"PetWatchSoundPaused": "Звук призупинено",
"PetWatchSoundUnavailable": "Звук Codewhale зупинено. Перевірте FFmpeg (ffplay) та аудіовихід, а потім знову ввімкніть звук.",
"CmdPetDescription": "Зробити анімованого улюбленця головним екраном Codewhale",
"ConfigLabelPetMode": "Режим улюбленця",
"ConfigHintPetMode": "Показувати анімованого улюбленця на головному екрані під час запуску Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "режим улюбленця вимкнено",
"PetViewOpen": "середовище відкрите",
"PetViewClosed": "середовище закрите",
"PetWatchRestored": "/pet відновив середовище цієї сесії. Очікування нової телеметрії.",
"PetWatchStorageUnavailable": "Watch не вдалося відновити або зберегти це середовище. Наявні файли збережено. Скористайтеся {command}, щоб експортувати цей запуск.",
"PetWatchExported": "Запис Watch збережено: {path}",
"PetWatchExportFailed": "Не вдалося зберегти запис Watch. Він залишається в пам’яті.",
"PetWatchExportQueued": "Збереження запису Watch…",
"PetWatchExportUnavailable": "Відкрийте /pet у збереженій сесії або дочекайтеся завершення поточного експорту.",
"PetUnobserved": "немає спостережень",
"PetOffline": "не в мережі — codewhale pet serve розбудить його",
"PetDozing": "дрімає",
"PetWatchUnavailable": "Телеметрію улюбленця призупинено. /pet on повторить спробу.",
"ConversationChangedBeforeUndo": "Розмова змінилася до завершення скасування. Нічого не скасовано, повторний запит не надіслано. Перевірте поточну розмову, перш ніж спробувати знову.",
"SessionArchiveExported": "Сеанс експортовано",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Змінити",
"ExtensionsHooksAddLabel": "Додати хук",
"ExtensionsHooksAddDescription": "Відкрити файл хуків цього проєкту у вашому редакторі",
"ExtensionsActionReload": "перезавантажити",
"ExtensionsActionConnect": "підключити",
"ExtensionsActionReconnect": "перепідключити",
"ExtensionsActionReauth": "повторно увійти",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "підключено",
"ExtensionsStateEnabled": "увімкнено",
"ExtensionsStateError": "помилка",
"ExtensionsStateInactive": "неактивний",
"ExtensionsStateInapplicable": "не застосовується",
"ExtensionsStateInvalid": "недійсний",
"ExtensionsStateNotInspected": "не перевірено",
"ExtensionsStateDisconnected": "відключено",
"ExtensionsStateRejected": "відхилено",
"ExtensionsStateReviewedCandidate": "перевірений кандидат",
"ExtensionsStateUnderEvaluation": "оцінюється",
"ExtensionsStateUnstaged": "не підготовлено",
"ExtensionsStateUnsupported": "не підтримується",
"ExtensionsStateWarning": "попередження",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ надіслати в цей хід",
"ComposerHintLongDraft": "{shortcut}: зовнішній редактор",
"PendingSendingIntoTurnPrefix": " ↳ Надсилання в цей хід: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Не вдалося надіслати в цей хід: ",
"PendingEditingFollowUpPrefix": " ↳ Редагується наступне повідомлення: ",
"PendingQueuedOnePrefix": "У черзі #1: ",
"PendingQueuedManyPrefix": "У черзі {count} · далі: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Обмірковування завершено",
"TranscriptThoughtFor": "Обмірковування тривало {duration}",
"TelemetryNoticeDefaultOn": "Надсилання статистики використання ввімкнено за замовчуванням. Передавати зведені лічильники версій, платформ, сеансів, функцій і помилок Codewhale та обробнику PostHog. Також рахує провайдерів, моделі з публічного каталогу, суми токенів і використання вбудованих інструментів. Без вмісту та IP. docs/TELEMETRY.md Вимкнути: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Статистика використання Codewhale",
"TelemetryNoticeBody": "Codewhale рахує: версію, операційну систему й сімейство процесора,\nтривалість і результат сеансу, а також зведені лічильники функцій і помилок.\n\nТакож рахує провайдерів і моделі з публічного каталогу, якими ви користуєтеся, суми їхніх токенів і те, як часто запускається кожен вбудований інструмент.\n\nВін ніколи не збирає ваші розмови, код, запити, файли, назви файлів,\nсховищ або гілок, вміст моделі чи облікові дані — і ніколи не надсилає\nхронологію дій агента за окремими ходами або інструментами.\n\nДля розпізнавання використовується лише випадковий ідентифікатор на цьому\nпристрої, який замінюють кожні 90 днів. Передумати можна будь-коли:\n codewhale config set telemetry false\n\nПовна схема за полями: docs/TELEMETRY.md\n\nНадсилання статистики використання ввімкнено за замовчуванням. Codewhale і PostHog обробляють ці лічильники, якщо надсилання налаштовано. IP не збираються.",
"TelemetryNoticeCompactBody": "Лічба: версія, ОС/CPU, час/результат сеансу, функції/помилки. Також: провайдер/модель, токени, інструменти. Випадковий локальний ID змінюється кожні 90 днів. Ніколи: чати/код/запити/файли/назви, дані моделі/облікові дані, ходи/інструменти. Схема: docs/TELEMETRY.md Вимк.: codewhale config set telemetry false\nНадсилання статистики використання ввімкнено за замовчуванням. Codewhale і PostHog обробляють ці лічильники, якщо надсилання налаштовано. IP не збираються.",
"TelemetryNoticeChoiceKeep": "Так, лишити анонімний підрахунок",
"TelemetryNoticeChoiceDisable": "Ні, вимкнути відстеження",
"TelemetryNoticeActionChoose": "вибрати",
"TelemetryNoticeActionConfirm": "підтвердити",
"TelemetryNoticeActionExit": "вийти",
"TelemetryNoticeReceiptEnabled": "Анонімний підрахунок використання ввімкнено. Розмови та код ніколи не збираються. Змінити в /settings; схема: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Анонімний підрахунок використання вимкнено. Повторного запитання не буде.",
"TelemetryNoticeReceiptEnabledUnsaved": "Анонімний підрахунок використання ввімкнено для цього сеансу. Codewhale не вдалося зберегти повідомлення, тому воно з'явиться знову. Змінити в /settings; схема: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Анонімний підрахунок використання вимкнено для цього сеансу. Codewhale не вдалося зберегти вибір, тому під час наступного запуску запитання повториться.",
"TelemetryPreferenceEnabledNextLaunch": "Анонімний підрахунок використання ввімкнеться під час наступного запуску. Розмови та код ніколи не збираються.",
"TelemetryPreferenceDisabled": "Анонімний підрахунок використання вимкнено. Локальні дані телеметрії видалено.",
"TelemetryPreferenceDisabledWithWarning": "Анонімний підрахунок використання вимкнено, але частина очищення потребує уваги: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Немає доступних дій Hotbar.",
"HotbarSetupRecommended": "рек",
"HotbarSetupEmptySlot": "порожньо",
"HotbarSetupHelp": "Tab/Shift+Tab джерело Up/Down дія 1-8 слот Enter призначити Space перемкнути Delete очистити s зберегти Esc скасувати",
"HotbarActionVoiceToggleName": "Голосове введення",
"HotbarActionVoiceToggleDescription": "Перемкнути захоплення голосу з мікрофона термінала.",
"HotbarActionSessionCompactName": "Стиснути сеанс",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Режим Work",
"HotbarActionModeAgentDescription": "Безпосередня робота в поточному сеансі.",
"HotbarActionModeYoloName": "Full Access (Work)",
"HotbarActionModeYoloDescription": "Сумісність: Work із дозволами Full Access (не окремий режим).",
"HotbarActionReasoningCycleName": "Перемикання міркувань",
"HotbarActionReasoningCycleDescription": "Перемкнути налаштований рівень міркувань для активного провайдера.",
"HotbarActionReasoningCycleAutoDisabled": "Рівень міркувань керується автоматичним маршрутизуванням моделі.",
"HotbarActionSidebarToggleName": "Перемкнути бічну панель",
"HotbarActionSidebarToggleDescription": "Показати або приховати бічну панель.",
"HotbarActionFileTreeToggleName": "Перемкнути дерево файлів",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Немає доступних налаштувань.",
"ConfigNoMatchesPrefix": " Немає налаштувань за фільтром ",
"ConfigFilteredSettings": " Відфільтровані налаштування",
"ConfigShowing": " Показано",
"ConfigFooterDefault": " ввід=фільтр, Up/Down=вибір, Enter=редагувати, Esc=закрити ",
"ConfigFooterScrollable": " ввід=фільтр, Up/Down=вибір, Enter=редагувати, PgUp/PgDn=прокрутити, Esc=закрити ",
"ConfigFooterFiltered": " ввід=фільтр, Backspace=видалити, Ctrl+U/Esc=очистити, Enter=редагувати ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; підказки-привиди застосовуються після наступних ходів)",
"ConfigNotificationsSetHint": "Задайте через /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; застосовується до наступних сповіщень)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs має бути цілим числом",
"ConfigAuditSearchProvider": "Записує [search] provider; наступні виклики web_search і надалі враховують змінні середовища.",
"ConfigAuditPromptSuggestion": "Записує prompt_suggestion верхнього рівня; підказки-привиди залишаються необов’язковими.",
"ConfigAuditNotifications": "Записує скалярні значення [notifications] і застосовує їх до наступних сповіщень про завершення ходу.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL API провайдера",
"ConfigHintProviderUrl": "Поточна кінцева точка провайдера; Xiaomi: пакет токенів | оплата за використання | власна URL-адреса",
"ConfigLabelModel": "Модель активного провайдера",
"ConfigLabelFastModel": "Швидка модель (похідна)",
"ConfigLabelDefaultModel": "Резервна застаріла модель (лише маршрути DeepSeek)",
"ConfigLabelReasoningEffort": "Рівень міркувань",
"ConfigLabelApprovalMode": "Дозволи цього сеансу",
"ConfigLabelPermissionPosture": "Дозволи нових сеансів",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Зведені лічильники версій, сеансів, функцій і помилок для Codewhale та PostHog; ніколи вміст чи IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Увімк.",
"ConfigValueTelemetryOff": "Вимк.",
"ConfigLabelStreamTimeout": "Тайм-аут потоку",
"ConfigLabelTheme": "Тема",
"ConfigLabelLocale": "Мова",
"ConfigLabelBackground": "Тло",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Підсвічування тла міркувань",
"ConfigLabelShowToolDetails": "Рівень деталізації інструментів",
"ConfigLabelInlineDiffs": "Вбудовані зміни файлів",
"ConfigLabelStatusIndicator": "Індикатор стану",
"ConfigLabelSynchronizedOutput": "Темп виводу",
"ConfigLabelCostCurrency": "Валюта вартості",
"ConfigLabelTranscriptSpacing": "Інтервали транскрипту",
@@ -376,7 +408,14 @@
"ConfigLabelComposerDensity": "Щільність композера",
"ConfigLabelComposerBorder": "Рамка композера",
"ConfigLabelComposerMultilineMode": "Багаторядковий режим композера",
"ConfigLabelComposerVimMode": "Режим Vim у композері",
"ConfigLabelBracketedPaste": "Дужкове вставлення",
"ConfigLabelPasteBurstDetection": "Виявлення вставлення",
"ConfigLabelMentionMenuLimit": "Ліміт меню згадок",
"ConfigLabelMentionMenuBehavior": "Поведінка меню згадок",
"ConfigLabelMentionWalkDepth": "Глибина згадок файлів",
"ConfigLabelWorkspaceFollowSymlinks": "Переходити за симпосиланнями",
"ConfigLabelContextPanel": "Панель контексту",
"ConfigLabelAutoCompact": "Автостиснення",
"ConfigLabelAutoCompactThreshold": "Поріг стиснення",
"ConfigLabelMaxHistory": "Історія вводу",
@@ -389,7 +428,9 @@
"ConfigLabelGoalCommand": "Команда цілі",
"ConfigLabelWorkflow": "Робочий процес",
"ConfigLabelFeaturePrefix": "Функція: {name}",
"ConfigColumnSetting": "Налаштування",
"ConfigColumnValue": "Значення",
"ConfigColumnScope": "Область",
"ConfigActionOpenProvider": "Enter відкриває вибір провайдера",
"ConfigActionOpenModel": "Enter відкриває вибір моделі",
"ConfigActionOpenMcp": "Enter відкриває менеджер MCP",
@@ -415,6 +456,7 @@
"HelpKeybindings": "Комбінації клавіш",
"HelpUserCommands": "Команди користувача",
"HelpSkills": "Навички",
"HelpFooterTypeFilter": " вводьте для фільтра ",
"HelpFooterMove": " Up/Down рух ",
"HelpFooterJump": " PgUp/PgDn стрибок ",
"HelpFooterClose": " Esc закрити ",
@@ -569,6 +611,8 @@
"PluginCtaInstallPrompt": "Рекомендований плагін: {name}",
"PluginCtaReview": "Перевірити",
"PluginCtaInstall": "Встановити",
"PluginCtaReviewTrust": "Перевірити довіру",
"PluginCtaEnable": "Увімкнути",
"PluginCtaDismiss": "Більше не пропонувати",
"PluginCtaDismissSaveFailed": "Приховано на час сеансу; не вдалося зберегти налаштування плагіна.",
"PluginSuggestionReason": "Збіг із «{trigger}»",
@@ -578,6 +622,7 @@
"CmdPluginActionFailed": "Дія плагіна не вдалася: {error}",
"CmdPluginNoneFound": "Застарілих виконуваних інструментів-плагінів у {dir} не знайдено",
"CmdPluginNotFound": "Плагін '{name}' не знайдено",
"CmdPluginListHeader": "Застарілі виконувані інструменти-плагіни ({count}):",
"CmdPluginDetailDescription": "Опис: {description}",
"CmdPluginDetailSchema": "Схема:\n{schema}",
"CmdPluginDetailApproval": "Схвалення: {approval}",
@@ -627,6 +672,7 @@
"ModelsListHint": "Збережений каталог; виконайте `codewhale models --update`, щоб оновити налаштованих провайдерів.",
"ModelsUpdateSummary": "Каталоги моделей: оновлено {updated}, завантажено з Codex {loaded}, помилок {failed}, пропущено {skipped}.",
"ModelsUpdatePartial": "Не вдалося оновити деякі каталоги. Попередні та налаштовані моделі залишаються доступними.",
"ModelsCodexHint": "Моделі ChatGPT завантажуються через Codex. Час запиту не підтверджує оновлення каталогу постачальника.",
"ModelsSourceFallback": "Вбудовані або налаштовані моделі; доступність не перевірено.",
"CmdModelDbDescription": "Переглянути вбудовану базу моделей",
"CmdNetworkDescription": "Керувати мережевими правилами дозволу та заборони",
@@ -639,6 +685,7 @@
"CmdQueueDescription": "Переглянути або редагувати повідомлення в черзі",
"CmdQueueUsage": "Використання: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "Відновлено повідомлень у черзі з попереднього сеансу: {count}. Вони не надсилаються автоматично: /queue send <n> надішле одне, /queue clear видалить їх.",
"CmdQueueDraftHeader": "Редагування повідомлення з черги:",
"CmdQueueNoMessages": "Немає повідомлень у черзі",
"CmdQueueListHeader": "Повідомлення в черзі ({count}):",
"CmdQueueTip": "Порада: /queue send <n> — надіслати зараз, /queue drop <n> — видалити",
@@ -758,10 +805,13 @@
"CmdTokensCacheBoth": "{hit} влуч. / {miss} пром.",
"CmdTokensCacheHitOnly": "{hit} влуч. / промахи не повідомлено",
"CmdTokensCacheMissOnly": "влучання не повідомлено / {miss} пром.",
"CmdTokensContextUnknownWindow": "~{estimated} / невідоме вікно",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 агент",
"FooterAgentsPlural": "{count} агентів",
"HeaderAgentsChip": "агенти {count}",
"FooterPressCtrlCAgain": "Натисніть Ctrl+C ще раз, щоб вийти",
"FooterWorking": "робота",
"FooterBalancePrefix": "баланс",
"HelpSectionActions": "Дії",
"HelpSectionClipboard": "Буфер обміну",
@@ -774,6 +824,7 @@
"CmdTokensNotReported": "не повідомлено",
"CmdTokensReport": "Використання токенів:\n ─────────────────────────────\n Активний контекст: {active}\n Останній ввід API: {input} (телеметрія ходу; може враховувати повторений префікс між раундами інструментів)\n Останній вивід API: {output}\n Кеш влуч./пром.: {cache} (лише телеметрія/вартість)\n Сукупні токени: {total} (телеметрія використання сеансу)\n Приблизна вартість: {cost}\n Повідомлення API: {api_messages}\n Повідомлення чату: {chat_messages}\n Модель: {model}",
"KbScrollTranscript": "Прокручування транскрипту, навігація історією вводу або вибір вкладень композера",
"KbNavigateHistory": "Навігація історією вводу",
"KbBrowseHistory": "Перегляд історії розмови",
"KbScrollTranscriptAlt": "Прокручування транскрипту",
"KbScrollPage": "Прокручування транскрипту посторінково",
@@ -807,6 +858,7 @@
"KbCompactContext": "Стиснути контекст розмови",
"KbLastMessagePager": "Відкрити пейджер для останнього повідомлення (коли ввід порожній)",
"KbSelectedDetails": "Показати необроблені деталі вибраного інструмента або повідомлення; Ctrl+Alt+O відкриває огляд усього ходу",
"KbToolDetailsPager": "Показати необроблені деталі вибраного елемента (Alt+V)",
"KbExternalEditor": "Відкрити чернетку композера у зовнішньому редакторі",
"KbLiveTranscript": "Відкрити накладення живого транскрипту (Ctrl+Shift+T; автопрокручування до кінця)",
"KbBacktrackMessage": "Повернутися до попереднього повідомлення користувача (Left/Right — крок, Enter — перемотати)",
@@ -845,6 +897,8 @@
"KbHelpOverlay": "Відкрити це накладення довідки (коли ввід порожній)",
"KbCycleWorkDock": "Перемикати робочу панель (задачі, агенти, завдання, фон), а в режимі улюбленця — вигляди улюбленця",
"KbCycleWorkDockBack": "Перемикати робочу панель або вигляди улюбленця назад",
"KbToggleHelp": "Перемкнути накладення довідки",
"KbToggleHelpSlash": "Перемкнути накладення довідки",
"HelpUsageLabel": "Використання:",
"HelpAliasesLabel": "Псевдоніми:",
"SettingsTitle": "Налаштування:",
@@ -945,8 +999,10 @@
"HomeAgentModeReviewTip": " /mode plan, щоб спершу дослідити й подати план",
"HomeAgentModeYoloTip": " Shift+Tab перемикає дозволи: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + Full Access — інструменти виконуються без запитів на схвалення",
"HomeYoloModeCaution": " Руйнівні операції можуть виконатися одразу; якщо сумніваєтеся — використовуйте Ask",
"HomePlanModeTip": "Plan — дослідження та проєктування перед реалізацією",
"HomePlanModeChecklistTip": " Подайте план і прогрес To-do, потім перейдіть до Work",
"HomeGoalModeTip": "Відстеження цілей - задайте /goal <objective>, щоб досягати цілей",
"OnboardLanguageTitle": "Оберіть мову",
"OnboardLanguageBlurb": "Оберіть мову інтерфейсу. Її можна змінити будь-коли командою `/config locale <tag> --save`.",
"OnboardProviderTitle": "Оберіть провайдера моделі",
@@ -976,6 +1032,7 @@
"RedactionGateRollbackHint": "«Залишити» вмикає маскування на цей запуск; конфігурація все ще вимагає \"disabled\", тож наступний запуск запитає знову.",
"RedactionGateSaveFailed": "Не вдалося зберегти підтвердження. Маскування залишається ввімкненим. Спробуйте ще раз або залиште його ввімкненим.",
"RedactionGateTitle": "Маскування ключів на межі моделі",
"OnboardOfflineOption": "Ctrl+O — оглянути офлайн: подивіться зараз, провайдера підключіть пізніше.",
"OnboardOfflineNotice": "Оглядаєте офлайн. Поки нічого не підключено — виконайте /provider, коли захочете підключитися.",
"OnboardWelcomeTitle": "Codewhale працює з вами у цій теці.",
"OnboardWelcomeLead": "Готуємось до початку.",
@@ -997,6 +1054,8 @@
"OnboardSeedCodeProject": "Поясни, що робить цей проєкт, і перелічи основні точки входу.",
"OnboardSeedFolder": "Подивись цю теку і запропонуй гарне перше завдання.",
"SetupWizardTitle": "Налаштування",
"SetupWizardWhy": "Ця оболонка записує прогрес налаштування в setup_state.json; зміни конфігурації застосовуються лише явними діями кроків.",
"SetupWizardProgress": "Крок",
"SetupActionBack": "назад",
"SetupActionContinue": "продовжити",
"SetupActionSkip": "пропустити",
@@ -1004,6 +1063,7 @@
"SetupActionScrollBody": "прокрутити текст",
"SetupActionGuided": "перегляд/ратифікація",
"SetupActionTuneGuided": "налаштувати",
"SetupActionModelDraft": "типовий проєкт",
"SetupActionFreeform": "своїми словами",
"SetupActionKeepExisting": "залишити наявне",
"SetupActionUseRecommended": "прийняти рекомендацію",
@@ -1012,7 +1072,13 @@
"SetupActionModel": "маршрути моделей",
"SetupActionFleet": "налаштування Fleet",
"SetupActionHotbar": "налаштування Hotbar",
"SetupActionRemote": "віддалений запуск",
"SetupActionMode": "вибір режиму",
"SetupActionConfig": "перегляд конфігурації",
"SetupActionRuntimePreset": "пресет",
"SetupActionApplyRuntimePreset": "перегляд/застосування",
"SetupActionUseBundled": "використати вбудоване",
"SetupActionDefer": "відкласти",
"SetupActionCancel": "скасувати",
"SetupStatusNotStarted": "не розпочато",
"SetupStatusRecommended": "рекомендовано",
@@ -1052,6 +1118,7 @@
"SetupLanguageReviewed": "Мову налаштування записано.",
"SetupConstitutionChoiceLabel": "Вибір:",
"SetupConstitutionSourceLabel": "Джерело:",
"SetupConstitutionValidityLabel": "Чинність:",
"SetupConstitutionPreviewLabel": "Хеш перегляду:",
"SetupConstitutionExistingLabel": "Наявний файл:",
"SetupConstitutionExpertOverrideLabel": "Експертне перевизначення:",
@@ -1092,6 +1159,8 @@
"SetupToolsMcpPluginsLabel": "Плагіни:",
"SetupToolsMcpReviewHint": "Enter фіксує цей знімок налаштування. Натисніть R для безпечного старту (без автозапуску).",
"SetupToolsMcpReviewed": "Готовність інструментів/MCP зафіксовано.",
"SetupRemoteCloudsLabel": "Хмарні цілі:",
"SetupRemoteBridgesLabel": "Чат-мости:",
"SetupRemoteProvidersLabel": "Провайдери:",
"SetupRemoteModeLabel": "Віддалений режим:",
"SetupRemoteModeLocalOnly": "Лише цей комп'ютер:",
@@ -1163,6 +1232,7 @@
"CtxMenuCopyMessage": "Копіювати повідомлення",
"CtxMenuCopyMessageDesc": "записати клітинку стенограми, по якій клікнули",
"CtxMenuOpenInEditor": "Відкрити в редакторі",
"CtxMenuOpenInEditorDesc": "відкрити файл:рядок у $EDITOR",
"CtxMenuShowCell": "Показати клітинку",
"CtxMenuShowCellDesc": "відобразити цю клітинку стенограми",
"CtxMenuHideCell": "Сховати клітинку",
@@ -1197,9 +1267,17 @@
"FanoutCounts": "{done} готово · {running} виконується · {failed} невдало · {pending} очікує",
"AppModeAgent": "Work",
"AppModeAuto": "Auto",
"AppModeYolo": "Full Access (застаріла назва режиму)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Пряма робота в цій сесії — редагування й shell запитують схвалення",
"AppModeAutoHint": "Shell увімкнено з автоматичною перевіркою ризиків",
"AppModePlanHint": "Спочатку дослідження лише для читання — подайте план перед діями",
"AppModeYoloHint": "Лише для сумісності — Work + Full Access, не видимий режим",
"AppModeOperateHint": "Work на повну: ціль, паралельні агенти, перевірка",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERT --",
"VimModeVisual": "-- VISUAL --",
"ApprovalEffectReadsOnly": "Лише читання",
"ApprovalEffectChangesFiles": "Змінює файли",
"ApprovalRiskDestructive": "Не можна скасувати",
@@ -1227,6 +1305,7 @@
"ApprovalSaveAskRuleHint": " · s дозволити зараз і завжди питати наступного разу",
"ApprovalOptionDeny": "Не дозволяти",
"ApprovalOptionAbortTurn": "Зупинити цей хід",
"ApprovalBlockTitle": "схвалення",
"ApprovalControlsHint": "Pg↑/↓ перегляд · {details} інші варіанти · Esc зупинити",
"ApprovalOwnerHeader": "Агент: {agent} · {role}",
"ApprovalGoToAgent": "g перейти до агента",
@@ -1252,6 +1331,8 @@
"ApprovalTruncationHint": " … обрізано · натисніть {details} для повних деталей",
"ApprovalAsksWithoutGit": "Тут немає репозиторію Git, тому перед змінами запитується підтвердження.",
"ApprovalFullAccessPolicyBlocked": "Заблоковано {tool}: Full Access не може обійти цю політику",
"ApprovalChooseHint": "Виберіть: ",
"ApprovalChooseAction": "Enter — вибрати опцію, або натисніть y/a/d напряму",
"ApprovalIntentLabel": "Намір: ",
"ApprovalMoreLines": " … (+{count} рядків)",
"ApprovalProceedQuestion": "Продовжити?",
@@ -1291,10 +1372,12 @@
"ContextManualCompacting": "Контекст стискається…",
"ContextCompactionQueued": "Стиснення контексту поставлено в чергу; воно запуститься після активного ходу.",
"ContextCompactionAlreadyRunning": "Стиснення контексту вже виконується.",
"ContextCompactionQueueFull": "Не вдалося поставити стиснення контексту в чергу, оскільки рушій зайнятий; повторіть спробу після завершення ходу.",
"ContextCompactionQueueClosed": "Стиснення контексту недоступне, оскільки рушій більше не працює.",
"ContextCompactionRouteInvalid": "Неможливо виконати стиснення, оскільки активний маршрут провайдера недійсний: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Стиснення контексту зупинено; розмову не змінено",
"ContextPurgeAbandonedOnEngineSwitch": "Очищення сеансу скасовано разом із заміненим рушієм; розмову не змінено",
"CtxInspTitle": "Інспектор контексту",
"CtxInspSessionContext": "Контекст сесії",
"CtxInspSystemPrompt": "Структура системного промпту",
"CtxInspReferences": "Посилання",
@@ -1526,21 +1609,45 @@
"SetupToolsMcpOnRampText": "Інструменти, MCP, навички й плагіни — безпечний старт\n\n/setup лише читає локальний інвентар. Він ніколи не запускає сервери MCP, не встановлює навички, не запускає плагіни й не виконує недовірені команди.\n\nПоточний інвентар:\n- MCP: {mcp_result}\n- Навички: {skills_result}\n- Каталог інструментів: {tools_result}\n- Плагіни: {plugins_result}\n- Hotbar (спільні адаптери): {hotbar_result}\n\nШляхи (домівка прихована):\n- Конфігурація MCP: {mcp_path}\n- Навички: {skills_path}\n- Плагіни: {plugins_path}\n\nБезпечне початкове налаштування (виконайте самі у звичайному терміналі або командою TUI):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Навички: /skills · codewhale setup --skills · /skills install <spec>\n- Плагіни: /plugin · codewhale setup --plugins\n- Каталог інструментів: codewhale setup --tools\n\nДії з побічними ефектами завжди потребують явного підтвердження. Команди плагінів залишаються відмінними від слеш-команд; джерело плагінів Hotbar відкладено, доки не з'являться ворота схвалення.\n\nДивіться docs/MCP.md і docs/skills/README.md про те, що ще потребує ручного зовнішнього налаштування.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — під'єднано через Codewhale, ніколи не другий планувальник:\n- Стан: {dsh_result}\n- Виявлення лише для читання; під'єднати/план/запуск/вилучити: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale пише лише в $CODEWHALE_HOME/integrations/dsh; ніколи не копіює API-ключі й не змінює файли DSH.",
"HotbarActionModeOperateName": "Режим Operate",
"HotbarActionModeOperateDescription": "Виконувати тривалий запит паралельно, доки його не буде перевірено.",
"HomeOperateModeTip": "Operate — паралельна робота Fleet",
"HomeOperateModeFleetTip": " Вбудовані ролі використовують модель цієї сесії; /fleet setup налаштовує їх",
"HelpSubtitle": "Команди, навички та комбінації клавіш",
"CommandPaletteTitle": "Команда",
"CommandPaletteSubtitle": "Знайдіть і виконайте одну дію",
"ConfigSubtitle": "Спочатку налаштування; сирі ключі — в розширених деталях",
"LaunchStartTitle": "Почніть тут",
"LaunchResumeConfirm": "Відновити {title}? Натисніть ще раз або Enter для підтвердження.",
"LaunchResumeConfirmTitle": "Відновити сесію",
"LaunchResumeConfirmBody": "Поточний контекст буде замінено історією тієї сесії.",
"LaunchResumeConfirmResume": "відновити",
"LaunchResumeConfirmCancel": "скасувати",
"LaunchWorkDescription": "Використовуйте локальні інструменти в цій папці; зміни підпорядковуються політиці схвалення.",
"LaunchChatDescription": "Лише розмова й планування; файли не змінюються.",
"LaunchWorkspaceGitReady": "Робочий простір · {name} · простір Git",
"LaunchWorkspaceFolderReady": "Робочий простір · {name} · локальна папка",
"LaunchProviderConfigured": "Провайдер · налаштований",
"LaunchProviderSetupNeeded": "Провайдер · потрібне налаштування",
"LaunchGroupContinue": "Продовжити",
"LaunchGroupMore": "Ще",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "папка",
"LaunchProviderConfiguredShort": "провайдер налаштований",
"LaunchProviderSetupShort": "налаштувати провайдера",
"LaunchMenuChangelog": "Журнал змін",
"LaunchWorktreePrompt": "Назвіть гілку/worktree або натисніть Enter для автоматичної назви. Esc — назад.",
"LaunchWorktreeNeedsGit": "Новий worktree потребує репозиторію Git.",
"LaunchWorktreeNameLabel": "назва worktree",
"LaunchHintMove": "рухатися",
"LaunchHintOpen": "відкрити",
"LaunchTipFlags": "Порада: -w <path> відкриває робочий простір; -r <session-id> відновлює напряму",
"LaunchSavedSessionSingular": "1 збережена сесія",
"LaunchSavedSessionsPlural": "{count} збережених сесій",
"LaunchCreatingWorktree": "Створення worktree…",
"LaunchWorktreeFailed": "Worktree не вдався: {error}",
"LaunchWorktreeCreated": "Новий worktree {path} у гілці {branch}",
"LaunchNoSavedSessions": "Немає збережених сесій для цього робочого простору.",
"LaunchNoModelConnected": "модель не підключено",
"DispatchNotSentNoModel": "Модель не підключено, тому повідомлення не надіслано. Воно знову в полі введення: підключіть модель через F3 або /provider, потім натисніть Enter, щоб надіслати його.",
"DispatchNotSentSaveKey": "Зберегти ключ: {command}",
@@ -1553,6 +1660,10 @@
"LocalModelAdopted": "Використовується {model} — модель, що працює на цьому комп'ютері (Ollama). Натисніть F3, щоб вибрати іншу.",
"ProviderPickerNotReopened": "Не вдалося знову відкрити список провайдерів. Натисніть F3, щоб відкрити його.",
"LaunchRunCommand": "виконайте {command}",
"LaunchMcpConnectedOne": "підключено 1 сервер MCP",
"LaunchMcpConnectedMany": "підключено серверів MCP: {count}",
"LaunchMcpNeedsSignInOne": "1 потребує входу",
"LaunchMcpNeedsSignInMany": "{count} потребують входу",
"PhaseIdle": "очікування",
"PhaseDraft": "чернетка",
"PhaseWorking": "робота",
@@ -1567,6 +1678,7 @@
"PhaseFinishing": "завершення",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "лише читання",
"ChipPermissionAsk": "питати",
"ChipPermissionAuto": "авто",
@@ -1574,12 +1686,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "ніколи",
"PermissionsChangedReceipt": "Дозволи змінено: {label}",
"FooterHintKeys": "клавіші",
"FooterHintOutput": "вивід",
"FooterHintContext": "контекст",
"InfoLineHelp": "довідка",
"InfoLineContext": "контекст",
"InfoLineTtft": "ttft",
"InfoLinePeak": "пік",
"InfoLineOffPeak": "непіковий",
"InfoLineWhales": "кити",
"InfoLineAutomation": "автоматизація",
"InfoLineNotConnected": "не підключено",
"InfoLineThinking": "міркування: {level}",
"EmptyStateNoGit": "немає git",
@@ -1675,6 +1791,7 @@
"RouteActionSearchAnyModel": "пошук будь-якої моделі",
"RoutePanelHeader": "маршрут",
"RouteProviderLabel": "провайдер",
"RouteModelFirstAtomic": "атомарний маршрут model-first",
"PickerActionMove": "рухатися",
"PickerActionSwitch": "перемкнути",
"PickerActionApply": "застосувати",
@@ -1691,6 +1808,7 @@
"PickerActionClearSearch": "очистити пошук",
"PickerActionBrowseAll": "переглянути все",
"PickerActionCustom": "власний",
"PickerActionJump": "перейти",
"PickerActionEditKey": "редагувати ключ",
"PickerActionModels": "моделі",
"PickerActionUnavailable": "недоступно",
@@ -1706,6 +1824,9 @@
"ProviderExternalActionRevoke": "більше не використовувати цей вхід",
"ProviderExternalActionChoices": "увійти через інший застосунок",
"ProviderExternalActionReuseGrok": "повторне використання зовнішнього Grok",
"ProviderExternalHintCodexReview": "Після {login} натисніть Enter, щоб переглянути варіанти доступу: вимкнено/лише читання/керований.",
"ProviderExternalHintXaiReview": "Натисніть Enter для входу з пристрою від Codewhale; натисніть E, щоб переглянути наявне повторне використання Grok CLI.",
"ProviderExternalHintXaiApiKey": "Або використайте XAI_API_KEY і знову відкрийте цей вибір.",
"XaiAuthChoiceTitle": " Автентифікація xAI ",
"XaiAuthChoiceIntro": "Виберіть одне явне джерело облікових даних. Текст ключа ніколи не вважається токеном OAuth.",
"XaiAuthChoiceApiKeyOption": "Ключ API xAI — введіть або вставте, потім збережіть у слоті провайдера xAI",
@@ -1717,6 +1838,9 @@
"ChatgptAuthChoiceTitle": " Автентифікація ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "Вхід за підпискою списується з вашого плану ChatGPT. Маршрут API-ключа openai має іншого платника.",
"ChatgptAuthChoicePkceOption": "Увійти через ChatGPT — PKCE в браузері, токени Codewhale, оплата підписки ChatGPT",
"ChatgptAuthChoiceImportOption": "Імпортувати облікові дані CLI Codex — явна згода лише на читання; власником лишається CLI Codex",
"ProviderExternalHintChatgptReview": "Натисніть Enter, щоб увійти через ChatGPT; натисніть E, щоб переглянути наявне повторне використання CLI Codex.",
"ProviderExternalActionReuseCodex": "зовнішнє повторне використання Codex",
"ProviderExternalDetailScope": "Зовнішній: доступ={access} | провайдер={provider} | джерело={source} | версія={version} | {state}",
"ProviderExternalDormant": "неактивний",
"ProviderExternalOwnerPath": "Власник/шлях: {owner} | {path}",
@@ -1727,6 +1851,7 @@
"SnapshotsDisabledUnsafeLocation": "Знімки та /undo вимкнено для {workspace}: домашній або кореневий каталог надто широкий для безпечного знімка. Почніть у каталозі проєкту, щоб увімкнути їх.",
"SnapshotsHistoryRepaired": "Історію скасування для {workspace} було пошкоджено (бракувало останньої точки відновлення), тож її розпочато заново. Попередні точки відновлення більше не можна відновити; нові ходи знову захищені.",
"SnapshotsFailing": "Знімки для {workspace} не створюються, тому /undo не може відновити останні ходи: {limit}",
"SessionIdDivergedNotice": "Ідентифікатор сеансу в цьому вікні змінився: рушій тепер зберігає контрольні точки як {next} (було {previous}). Попередні точки лишаються під старим id; `codewhale sessions` показує обидва, а `codewhale resume {previous}` відкриває попередній сеанс.",
"RuntimeStoreUnreadableNotice": "Сховище середовища виконання сесії: не вдалося прочитати {record} у {path} ({reason}). Відкладіть цей файл (або видаліть його) і повторіть спробу; інші записи потоку залишаються.",
"RuntimeStoreUnwritableNotice": "Сховище середовища виконання сесії: не вдалося записати {record} у {path} ({reason}). Перевірте вільне місце та права доступу там і повторіть спробу; нічого не було перезаписано.",
"ProviderExternalSemanticsRevoke": "{semantics} | відкликання: {revoke}",
@@ -1765,6 +1890,7 @@
"FleetRosterTabSetup": "налаштування",
"FleetRosterWorkers": "воркери",
"FleetRosterMembersCount": "{count} учасників",
"FleetRosterOperatorFirst": "Координатор веде · модель сесії керує цим Fleet",
"FleetRosterOperatorRow": "Координатор · лідер",
"FleetRosterShadowBadgeProjectOverride": "збережено для цього проєкту",
"FleetRosterShadowBadgePersonalIgnored": "збережену копію проігноровано",
@@ -1787,6 +1913,7 @@
"FleetModelReasonOperatorRoute": "це ваша поточна модель (маршрут оператора команди); перемкніть модель або змініть його через /fleet save",
"FleetModelReasonAlreadyPresent": "уже у команді",
"FleetModelErrorNeedsRoute": "моделі команди потрібні і id провайдера, і id моделі",
"FleetModelErrorNeedsRole": "Агенту потрібна назва ролі (наприклад, `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "команда не вибрана; ваша команда — лише модель сесії",
"FleetModelErrorOperatorRoute": "{route} — маршрут оператора команди `{fleet}`; змінюйте його через /fleet save, а не remove",
"FleetModelErrorNotInFleet": "{route} немає у команді `{fleet}`",
@@ -1905,6 +2032,7 @@
"FilePickerMatchSingular": "@ прикріпити · 1 збіг",
"FilePickerMatchesPlural": "@ прикріпити · {count} збігів",
"FilePickerScanning": "Сканування робочого простору…",
"BehavioralTipPlanning": "Плануєте? {key} перемикає в режим Plan",
"BehavioralTipBackgroundReceipt": "Підтвердження — у панелі «Робота» — {key} відкриває інспектор",
"BehavioralTipClearedInput": "Очищено · {chord} відновлює",
"BehavioralTipMcpValidation": "{command} запускає сервери й показує причину",
@@ -1918,6 +2046,7 @@
"SettingSubjectModelAndThinking": "Модель і міркування",
"SettingSubjectProvider": "Провайдер",
"SettingSubjectPermissions": "Дозволи",
"ThinkingControlledByAutoRouting": "Міркування керується автоматичною маршрутизацією моделей; спочатку виберіть фіксовану модель.",
"SavedAsStartupDefault": "збережено як типове для запуску",
"ModeAlreadyActiveSavedAsDefault": "Режим {mode} уже активний — збережено як типовий для запуску.",
"StartupDefaultNotSaved": "{setting} не збережено: {error}",
@@ -1956,6 +2085,15 @@
"StepfunBillingRouteIntro": "StepFun виставляє рахунки за pay-as-you-go і підписки Step Plan на різних кінцевих точках. Оберіть ту, до якої належить ваш ключ.",
"StepfunBillingRoutePaygOption": "Pay-as-you-go (потокенна оплата)",
"StepfunBillingRoutePlanOption": "Підписка Step Plan (ліміт плану)",
"StepfunPlanApiKeyHint": "Для підписок StepFun Step Plan використовуйте ключ, виданий для вашого Step Plan, а не ключ pay-as-you-go.",
"StepfunPlanRouteHint": "Цей маршрут використовує {route} і списується з ліміту вашого Step Plan.",
"ConfigLabelSessionsRail": "Панель сеансів",
"ConfigLabelSessionAutoResume": "Автовідновлення останнього сеансу",
"SessionsRailTitle": "Сеанси",
"SessionsRailEmpty": "У цьому робочому просторі ще немає сеансів",
"SessionsRailBrowseAll": "Усі сеанси",
"SessionsRailShowingCount": "{shown} з {total} — показати всі",
"SessionsRailUnavailable": "Сеанси недоступні: {error}",
"SessionsActionArchive": "архівувати",
"SessionsActionShowArchived": "архів",
"SessionsArchived": "Сеанс {id} заархівовано",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "агенти",
"FooterHintToManage": "керування",
"AgentRailQueuedCount": "{count} у черзі",
"WorkbarSoFar": "поки {done}/{total}",
"WorkbarLargeWorkflow": "Великий робочий процес",
"WorkbarMoreRuns": "ще {count}",
"WorkflowLineStarted": "запущено",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "завершено з прогалинами",
"WorkflowLineFailed": "збій",
"WorkflowLineStopped": "зупинено",
"WorkflowLineAgents": "агентів: {done}/{total}",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "пише",
"AgentFocusPostureReadOnly": "лише читання",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell лише читання",
"AgentFocusPostureShellNone": "без shell",
"GoalReceiptSet": "Ціль задано: «{objective}» · /goal показує прогрес · /goal pause або /goal clear зупиняє",
"GoalReceiptSetOperate": "◆ ціль задано · Operate працює, доки її не буде перевірено · /goal для редагування",
"GoalControlAccepted": "Команду цілі збережено; її буде застосовано на наступній безпечній межі.",
"GoalControlRuntimeUnavailable": "Команду цілі збережено, але середовище виконання недоступне. Її буде відновлено після перезапуску.",
"GoalStatusIdleHint": "зараз не виконується — надішліть повідомлення або /goal resume, щоб продовжити",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Ціль активна · наступний хід через {delay} · Esc, Ctrl+C або /goal pause зупиняє очікуване продовження",
"GoalContinuationReady": "Продовження цілі готове; команди в черзі виконаються перед наступним ходом.",
"GoalContinuationStopped": "Очікуване продовження цілі зупинено; ціль залишається активною.",
"McpCapabilitiesAdvertised": "Заявлені можливості: {capabilities}",
"McpCapabilitiesLegacyFallback": "Заявлені можливості: не вказані; використовується резервне застаріле виявлення",
"McpCapabilitiesNotObserved": "Заявлені можливості: не визначені, оскільки сервер не підключено",
"PickerActionTestConnection": "перевірити з’єднання",
"ProviderCustomFormBaseUrl": "Базовий URL",
"ProviderCustomFormModel": "Типова модель",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "гант час →",
"ConfigCategoryAppearance": "Оформлення",
"ConfigCategoryModelsProviders": "Моделі та провайдери",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Робота",
"ConfigCategoryToolsMcp": "Інструменти та MCP",
"ConfigCategoryTrust": "Довіра",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "лише читання",
"ConfigRowActionNote": "дія · не збережене налаштування",
"ConfigRowDiagnosticNote": "спостережувана квитанція · тут не редагується",
"ConfigNavHint": "←/→ або Tab — категорія · ↑/↓ — налаштування",
"ConfigActivateAgain": "Enter або клацніть ще раз:",
"ConfigSearchLabel": " Пошук: ",
"ConfigEditChooseLabel": "Вибір:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Ніколи",
"ConfigChoiceModeAct": "Діяти",
"ConfigChoiceModePlan": "Планувати (лише читання)",
"ConfigChoiceModeOperate": "Керувати",
"ConfigChoicePlacementTop": "Угорі",
"ConfigChoicePlacementBottom": "Нижня панель",
"ConfigChoicePlacementLeft": "Ліва бічна панель",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Автоматично оцінює ризик інструментів і запитує, коли рішення за вами.",
"ConfigChoiceDetailUseTuiDefault": "Знімає перевизначення кореневого config і використовує збережений вибір дозволу TUI.",
"ConfigChoiceDetailFullAccess": "Інструменти запускатимуться без запитань, а команди матимуть доступ до всього на цьому комп’ютері.",
"ConfigChoiceDetailNever": "Блокує кожен інструмент, який потребує схвалення.",
"ConfigChoiceDetailModeAgent": "Починає в готовності співпрацювати та використовувати інструменти.",
"ConfigChoiceDetailModePlan": "Починає в просторі планування лише для читання.",
"ConfigChoiceDetailModeOperate": "Operate — це Work на повну потужність: кожен суттєвий запит стає ціллю, проходить через workflow і паралельних агентів, перевіряється незалежним рецензентом і виконується, доки його не буде перевірено.",
"ConfigChoiceDetailPlacementTop": "Показує завдання, список справ і виконавців над стенограмою.",
"ConfigChoiceDetailPlacementBottom": "Показує завдання, список справ і виконавців під композером.",
"ConfigChoiceDetailPlacementLeft": "Показує завдання, список справ і виконавців у лівій бічній панелі, коли термінал достатньо широкий.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Заливає тло міркувань моделі.",
"ConfigChoiceDetailThinkingHighlightOff": "Зберігає пунктирну лінію та курсив без заливки тла.",
"ConfigHintModel": "модель живого маршруту цього сеансу; Enter відкриває /model",
"ConfigHintFastModel": "використовується маршрутизацією Auto та model_strength=faster агентів, коли провайдер має відому споріднену модель",
"ConfigHintProvider": "облікові дані, модель і адреса перемикаються разом",
"ConfigHintApprovalMode": "лише цей сеанс: Запитувати | Автоперевірка | Повний доступ",
"ConfigHintPermissionPosture": "типово для нових сеансів: Запитувати | Автоперевірка | Повний доступ",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "ціле число (0 допускається) · скільки надісланих повідомлень зберігати для повторення та пошуку в історії",
"ConfigHintAutoCompactThreshold": "10..=100 · поріг стиснення: відсоток використовуваної довжини контексту, за якого спрацьовує автостиснення",
"ConfigHintDefaultModel": "застарілий запасний варіант лише для DeepSeek; інші провайдери використовують свою модель вище",
"ConfigHintReasoningEffort": "default повертає власне типове значення моделі; у моделей, які завжди міркують, немає off",
"ConfigHintMcpOpen": "відкрити менеджер MCP · підключити / перепідключити / повторно ввійти / діагностика",
"ConfigHintMcpReconnect": "перепідключити MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "стан прапорця функції лише для читання для інструментів правки патчами",
"ConfigHintFeatureMcp": "стан прапорця функції лише для читання для інструментів MCP",
"ConfigHintFeatureExecPolicy": "стан прапорця функції лише для читання для інструментів політики виконання",
"ConfigHintFeatureVisionModel": "бета-прапорець підтримки зображень для зору/моделі",
"ConfigHintGoalCommand": "/goal задає цілі, бюджети та стан робочого контексту",
"ConfigHintWorkflow": "/workflow виконує сценарні операції з картками запуску розпаралелення/злиття",
"LaunchMenuNewWorktree": "Новий worktree",
"LaunchMenuResume": "Відновити сесію",
"LaunchMenuQuit": "Вихід",
"LaunchNoticeClaude": "Виявлено Claude Code. Виконайте /import-claude, щоб переглянути, що можна перенести: MCP-сервери, безпечні налаштування та дозволи. Нічого не застосовується без вашої згоди.",
"LaunchNewSession": "Нова сесія",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ — продовжити",
"LaunchHelpLine": "/help — команди · {dock} — робоча панель",
"LaunchSeeAllSessions": "Показати всі сесії…",
"LaunchNoRecentSessions": "Поки немає нещодавніх сесій — введіть нижче, щоб почати.",
"LaunchResumeFailed": "Не вдалося відновити: {error}",
"ReceiptSessionHooks": "гачків: {count}",
"AutomationEditorNew": "Нова автоматизація",
"AutomationEditorEdit": "Редагувати автоматизацію",
"AutomationEditorSchedule": "Розклад",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} готово",
"WorkflowPhaseCountOne": "фаз: {count}",
"WorkflowPhaseCountMany": "фаз: {count}",
"WorkflowPhaseOrdinal": "фаза {n}/{total}",
"ModelPickerPinned": "{route} закріплено",
"ModelPickerUnpinned": "{route} відкріплено",
"ModelPickerPinFailed": "Не вдалося оновити закріплення: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Попередній вхід Codewhale у {provider} ({account}) замінено.",
"AuthReplacedPreviousSignIn": "Попередній вхід Codewhale у {provider} замінено.",
"AuthSameAccountAsBefore": "Це той самий обліковий запис, що й раніше; щоб використати інший обліковий запис {provider}, вийдіть із нього в браузері (або відкрийте приватне вікно) й увійдіть знову.",
"AuthEnvTokenOutranksSignIn": "У цьому середовищі задано OPENAI_CODEX_ACCESS_TOKEN або CODEX_ACCESS_TOKEN, і ця змінна має пріоритет над цим входом; запити й далі використовуватимуть обліковий запис цього токена, доки ви її не видалите.",
"PinnedPromptJumpToMessage": "Перейти до цього повідомлення",
"PlanHandoffHeader": "План готовий",
"PlanHandoffQuestion": "Як ви хочете продовжити?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Натисніть Enter для входу через браузер або Esc для повернення. Ключ API не потрібен.",
"PluginOAuthReady": "{provider}: вхід виконано. Виберіть модель.",
"PluginOAuthLocalLogout": "{provider}: локальні дані входу видалено. Віддалений доступ не змінено.",
"CmdConnectDescription": "Підключити провайдера плагіна через вхід у браузері",
"CmdDisconnectDescription": "Видалити локальні дані входу провайдера плагіна",
"ExecAutoHelp": "Увімкнути інструменти з автоматичним схваленням і Full Access (без пісочниці оболонки, режим довіри ввімкнено), якщо не налаштовано суворішу пісочницю; --sandbox workspace-write обмежує запис через файлові інструменти й оболонку.",
"ExecSandboxHelp": "Політика пісочниці для цього запуску; будь-яке значення --sandbox, крім danger-full-access (або відповідне значення sandbox_mode у конфігурації), вимикає режим довіри.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime đã đóng luồng sự kiện của cuộc trò chuyện này; hãy mở lại cuộc trò chuyện",
"MobileStreamReconnecting": "Mất kết nối; đang kết nối lại",
"MobileStreamConnected": "Đã kết nối",
"PetHabitatTitle": "CODEWHALE / WHALESONG · Một môi trường sống chung",
"PetHabitatHints": "{back} quay lại · {sound} âm thanh · {browser} giao diện · {window} cửa sổ",
"PetHabitatQueued": "Đã gửi đến môi trường sống chung. /pet on hiển thị thú cưng và ô tin nhắn.",
"PetWatchSoundOn": "Âm thanh bật",
"PetWatchSoundOff": "Âm thanh tắt",
"PetWatchSoundPaused": "Âm thanh tạm dừng",
"PetWatchSoundUnavailable": "Âm thanh Codewhale đã dừng. Hãy kiểm tra FFmpeg (ffplay) và đầu ra âm thanh, rồi bật lại âm thanh.",
"CmdPetDescription": "Dùng thú cưng hoạt hình làm giao diện chính của Codewhale",
"ConfigLabelPetMode": "Chế độ thú cưng",
"ConfigHintPetMode": "Dùng thú cưng hoạt hình làm giao diện chính khi khởi động Codewhale.",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "chế độ thú cưng tắt",
"PetViewOpen": "môi trường sống đang mở",
"PetViewClosed": "môi trường sống đã đóng",
"PetWatchRestored": "/pet đã khôi phục môi trường của phiên này. Đang chờ dữ liệu đo mới.",
"PetWatchStorageUnavailable": "Watch không thể khôi phục hoặc lưu môi trường này. Các tệp hiện có được giữ nguyên. Dùng {command} để xuất lần chạy này.",
"PetWatchExported": "Đã lưu bản ghi Watch: {path}",
"PetWatchExportFailed": "Không thể lưu bản ghi Watch. Bản ghi vẫn còn trong bộ nhớ.",
"PetWatchExportQueued": "Đang lưu bản ghi Watch…",
"PetWatchExportUnavailable": "Mở /pet trong một phiên đã lưu hoặc đợi quá trình xuất hiện tại hoàn tất.",
"PetUnobserved": "chưa quan sát",
"PetOffline": "ngoại tuyến — codewhale pet serve sẽ đánh thức nó",
"PetDozing": "ngủ gật",
"PetWatchUnavailable": "Đã tạm dừng dữ liệu thú cưng. /pet on sẽ thử lại.",
"ConversationChangedBeforeUndo": "Cuộc trò chuyện đã thay đổi trước khi hoàn tất hoàn tác. Không có nội dung nào bị hoàn tác và không gửi yêu cầu thử lại. Hãy kiểm tra cuộc trò chuyện hiện tại trước khi thử lại.",
"SessionArchiveExported": "Đã xuất phiên",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "Sửa",
"ExtensionsHooksAddLabel": "Thêm hook",
"ExtensionsHooksAddDescription": "Mở tệp hook của dự án này trong trình soạn thảo",
"ExtensionsActionReload": "tải lại",
"ExtensionsActionConnect": "kết nối",
"ExtensionsActionReconnect": "kết nối lại",
"ExtensionsActionReauth": "xác thực lại",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "đã kết nối",
"ExtensionsStateEnabled": "đã bật",
"ExtensionsStateError": "lỗi",
"ExtensionsStateInactive": "không hoạt động",
"ExtensionsStateInapplicable": "không áp dụng",
"ExtensionsStateInvalid": "không hợp lệ",
"ExtensionsStateNotInspected": "chưa kiểm tra",
"ExtensionsStateDisconnected": "đã ngắt kết nối",
"ExtensionsStateRejected": "bị từ chối",
"ExtensionsStateReviewedCandidate": "ứng viên đã xem xét",
"ExtensionsStateUnderEvaluation": "đang đánh giá",
"ExtensionsStateUnstaged": "chưa chuẩn bị",
"ExtensionsStateUnsupported": "không được hỗ trợ",
"ExtensionsStateWarning": "cảnh báo",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ gửi vào lượt này",
"ComposerHintLongDraft": "{shortcut}: trình sửa ngoài",
"PendingSendingIntoTurnPrefix": " ↳ Đang gửi vào lượt này: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ Không gửi được vào lượt này: ",
"PendingEditingFollowUpPrefix": " ↳ Đang sửa tin theo sau: ",
"PendingQueuedOnePrefix": "Đang chờ #1: ",
"PendingQueuedManyPrefix": "Đang chờ {count} · tiếp: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "Đã suy nghĩ xong",
"TranscriptThoughtFor": "Đã suy nghĩ trong {duration}",
"TelemetryNoticeDefaultOn": "Báo cáo sử dụng được bật theo mặc định. Chia sẻ tổng số phiên bản, nền tảng, phiên, tính năng và lỗi với Codewhale và bên xử lý PostHog. Cũng đếm nhà cung cấp, mô hình trong danh mục công khai, tổng token và mức dùng công cụ tích hợp. Không thu thập nội dung hay IP. docs/TELEMETRY.md Tắt: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Báo cáo sử dụng Codewhale",
"TelemetryNoticeBody": "Codewhale đếm: phiên bản bạn chạy, hệ điều hành và họ CPU, thời lượng và kết\nquả phiên, cùng số liệu tổng hợp về tính năng và lỗi.\n\nCũng đếm các nhà cung cấp và mô hình trong danh mục công khai bạn dùng, tổng token của chúng và số lần mỗi công cụ tích hợp chạy.\n\nHệ thống không bao giờ thu thập cuộc trò chuyện, mã nguồn, prompt, tệp, tên\ntệp, kho mã hoặc nhánh, nội dung mô hình hay thông tin đăng nhập của bạn — và\nkhông bao giờ gửi dòng thời gian hoạt động của tác nhân theo lượt hoặc công cụ.\n\nBạn chỉ được nhận diện bằng một ID ngẫu nhiên lưu trên máy này, được thay\nmới sau mỗi 90 ngày. Đổi ý bất cứ lúc nào:\n codewhale config set telemetry false\n\nLược đồ đầy đủ theo từng trường: docs/TELEMETRY.md\n\nBáo cáo sử dụng được bật theo mặc định. Codewhale và PostHog xử lý các số liệu này khi việc gửi được cấu hình. Không thu thập IP.",
"TelemetryNoticeCompactBody": "Số liệu: phiên bản, hệ thống/CPU, thời lượng/kết quả và tổng tính năng/lỗi.\nThêm: nhà cung cấp/mô hình, token, công cụ.\nID cục bộ ngẫu nhiên đổi mỗi 90 ngày.\nKhông bao giờ: trò chuyện/mã/prompt/tệp/tên, nội dung mô hình/thông tin đăng nhập, lượt/công cụ.\nLược đồ: docs/TELEMETRY.md\nTắt: codewhale config set telemetry false\nBáo cáo sử dụng được bật theo mặc định. Codewhale và PostHog xử lý các số liệu này khi việc gửi được cấu hình. Không thu thập IP.",
"TelemetryNoticeChoiceKeep": "Có, tiếp tục đếm ẩn danh",
"TelemetryNoticeChoiceDisable": "Không, tắt theo dõi",
"TelemetryNoticeActionChoose": "chọn",
"TelemetryNoticeActionConfirm": "xác nhận",
"TelemetryNoticeActionExit": "thoát",
"TelemetryNoticeReceiptEnabled": "Thống kê sử dụng ẩn danh đang bật. Hội thoại và mã nguồn không bao giờ được thu thập. Thay đổi trong /settings; lược đồ: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "Đếm lượt sử dụng ẩn danh đã tắt. Hệ thống sẽ không hỏi lại.",
"TelemetryNoticeReceiptEnabledUnsaved": "Thống kê sử dụng ẩn danh đang bật cho phiên này. Codewhale không thể lưu thông báo nên sẽ hiển thị lại. Thay đổi trong /settings; lược đồ: docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "Đếm lượt sử dụng ẩn danh đang tắt cho phiên này. Codewhale không thể lưu lựa chọn nên sẽ hỏi lại vào lần khởi động tới.",
"TelemetryPreferenceEnabledNextLaunch": "Thống kê sử dụng ẩn danh sẽ bật vào lần khởi động tới. Hội thoại và mã nguồn không bao giờ được thu thập.",
"TelemetryPreferenceDisabled": "Thống kê sử dụng ẩn danh đã tắt. Dữ liệu đo từ xa cục bộ đã được xóa.",
"TelemetryPreferenceDisabledWithWarning": "Thống kê sử dụng ẩn danh đã tắt, nhưng một phần dọn dẹp cần được chú ý: {detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "Không có thao tác Hotbar nào khả dụng.",
"HotbarSetupRecommended": "gợi ý",
"HotbarSetupEmptySlot": "trống",
"HotbarSetupHelp": "Tab/Shift+Tab nguồn Up/Down thao tác 1-8 ô Enter gán Space bật/tắt Delete xoá s lưu Esc huỷ",
"HotbarActionVoiceToggleName": "Nhập giọng nói",
"HotbarActionVoiceToggleDescription": "Bật/tắt ghi âm từ micrô của terminal.",
"HotbarActionSessionCompactName": "Nén phiên",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Chế độ Work",
"HotbarActionModeAgentDescription": "Làm việc trực tiếp trong phiên hiện tại.",
"HotbarActionModeYoloName": "Toàn quyền (Work)",
"HotbarActionModeYoloDescription": "Tương thích: Work + toàn quyền (không phải chế độ riêng).",
"HotbarActionReasoningCycleName": "Đổi mức suy luận",
"HotbarActionReasoningCycleDescription": "Luân phiên mức suy luận đã cấu hình cho nhà cung cấp đang hoạt động.",
"HotbarActionReasoningCycleAutoDisabled": "Mức suy luận do định tuyến mô hình tự động kiểm soát.",
"HotbarActionSidebarToggleName": "Bật/tắt thanh bên",
"HotbarActionSidebarToggleDescription": "Hiển thị hoặc ẩn thanh bên.",
"HotbarActionFileTreeToggleName": "Bật/tắt cây tệp",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " Không có cài đặt nào khả dụng.",
"ConfigNoMatchesPrefix": " Không có cài đặt nào khớp với ",
"ConfigFilteredSettings": " Cài đặt đã lọc",
"ConfigShowing": " Đang hiển thị",
"ConfigFooterDefault": " gõ=lọc, Lên/Xuống=chọn, Enter=sửa, Esc=đóng ",
"ConfigFooterScrollable": " gõ=lọc, Lên/Xuống=chọn, Enter=sửa, PgUp/PgDn=cuộn, Esc=đóng ",
"ConfigFooterFiltered": " gõ=lọc, Backspace=xóa, Ctrl+U/Esc=xóa sạch, Enter=sửa ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; gợi ý văn bản mờ được áp dụng sau các lượt tiếp theo)",
"ConfigNotificationsSetHint": "Đặt bằng /config notifications <key> <value> [--save].",
"ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; áp dụng cho các cảnh báo tiếp theo)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs phải là số nguyên",
"ConfigAuditSearchProvider": "Ghi [search] provider; các lệnh web_search tiếp theo vẫn tuân theo biến môi trường.",
"ConfigAuditPromptSuggestion": "Ghi prompt_suggestion ở cấp cao nhất; gợi ý văn bản mờ vẫn cần bật riêng.",
"ConfigAuditNotifications": "Ghi các giá trị vô hướng [notifications] và áp dụng cho cảnh báo hoàn tất lượt tiếp theo.",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "URL API nhà cung cấp",
"ConfigHintProviderUrl": "Điểm cuối hiện tại của nhà cung cấp; Xiaomi: gói token | trả theo mức dùng | URL tùy chỉnh",
"ConfigLabelModel": "Mô hình đang dùng của nhà cung cấp",
"ConfigLabelFastModel": "Mô hình nhanh (suy ra)",
"ConfigLabelDefaultModel": "Mô hình dự phòng cũ (chỉ tuyến DeepSeek)",
"ConfigLabelReasoningEffort": "Mức suy luận",
"ConfigLabelApprovalMode": "Quyền của phiên này",
"ConfigLabelPermissionPosture": "Quyền của phiên mới",
@@ -346,6 +376,7 @@
"ConfigHintTelemetry": "Tổng số phiên bản, phiên, tính năng và lỗi gửi tới Codewhale và PostHog; không bao giờ gửi nội dung hay IP. docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "Bật",
"ConfigValueTelemetryOff": "Tắt",
"ConfigLabelStreamTimeout": "Thời gian chờ luồng",
"ConfigLabelTheme": "Chủ đề",
"ConfigLabelLocale": "Ngôn ngữ",
"ConfigLabelBackground": "Nền",
@@ -369,6 +400,7 @@
"ConfigLabelThinkingHighlight": "Tô nền phần suy luận",
"ConfigLabelShowToolDetails": "Mức chi tiết công cụ",
"ConfigLabelInlineDiffs": "Thay đổi tệp nội dòng",
"ConfigLabelStatusIndicator": "Chỉ báo trạng thái",
"ConfigLabelSynchronizedOutput": "Nhịp đầu ra",
"ConfigLabelCostCurrency": "Đơn vị tiền chi phí",
"ConfigLabelTranscriptSpacing": "Khoảng cách bản ghi",
@@ -376,7 +408,16 @@
"ConfigLabelComposerDensity": "Mật độ ô soạn thảo",
"ConfigLabelComposerBorder": "Viền ô soạn thảo",
"ConfigLabelComposerMultilineMode": "Chế độ nhiều dòng của ô soạn thảo",
"ConfigLabelComposerVimMode": "Chế độ Vim của ô soạn thảo",
"ConfigLabelBracketedPaste": "Dán có dấu ngoặc",
"ConfigLabelPasteBurstDetection": "Phát hiện thao tác dán",
"ConfigLabelMentionMenuLimit": "Giới hạn menu đề cập",
"ConfigLabelMentionMenuBehavior": "Hành vi menu đề cập",
"ConfigLabelMentionWalkDepth": "Độ sâu đề cập tệp",
"ConfigLabelWorkspaceFollowSymlinks": "Theo liên kết tượng trưng",
"ConfigLabelContextPanel": "Bảng ngữ cảnh",
"ConfigLabelSessionsRail": "Thanh phiên",
"ConfigLabelSessionAutoResume": "Tự động tiếp tục phiên gần nhất",
"ConfigLabelAutoCompact": "Tự động thu gọn",
"ConfigLabelAutoCompactThreshold": "Ngưỡng thu gọn",
"ConfigLabelMaxHistory": "Lịch sử nhập",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "Lệnh mục tiêu",
"ConfigLabelWorkflow": "Quy trình làm việc",
"ConfigLabelFeaturePrefix": "Tính năng: {name}",
"ConfigColumnSetting": "Cài đặt",
"ConfigColumnValue": "Giá trị",
"ConfigColumnScope": "Phạm vi",
"ConfigActionOpenProvider": "Enter mở bộ chọn nhà cung cấp",
"ConfigActionOpenModel": "Enter mở bộ chọn mô hình",
"ConfigActionOpenMcp": "Enter mở trình quản lý MCP",
@@ -416,6 +459,7 @@
"HelpKeybindings": "Phím tắt",
"HelpUserCommands": "Lệnh người dùng",
"HelpSkills": "Kỹ năng",
"HelpFooterTypeFilter": " nhập để lọc ",
"HelpFooterMove": " Lên/Xuống để di chuyển ",
"HelpFooterJump": " PgUp/PgDn để nhảy trang ",
"HelpFooterClose": " Esc để đóng ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "Plugin gợi ý: {name}",
"PluginCtaReview": "Xem lại",
"PluginCtaInstall": "Cài",
"PluginCtaReviewTrust": "Xem lại tin cậy",
"PluginCtaEnable": "Bật",
"PluginCtaDismiss": "Không gợi ý nữa",
"PluginCtaDismissSaveFailed": "Đã ẩn trong phiên này; không thể lưu tùy chọn plugin.",
"PluginSuggestionReason": "Khớp với “{trigger}”",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "Thao tác plugin thất bại: {error}",
"CmdPluginNoneFound": "Không tìm thấy công cụ plugin thực thi cũ trong {dir}",
"CmdPluginNotFound": "Không tìm thấy plugin '{name}'",
"CmdPluginListHeader": "Công cụ plugin thực thi cũ ({count}):",
"CmdPluginDetailDescription": "Mô tả: {description}",
"CmdPluginDetailSchema": "Lược đồ:\n{schema}",
"CmdPluginDetailApproval": "Phê duyệt: {approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "Danh mục đã lưu; chạy `codewhale models --update` để cập nhật các nhà cung cấp đã cấu hình.",
"ModelsUpdateSummary": "Danh mục mô hình: {updated} đã cập nhật, {loaded} đã tải từ Codex, {failed} thất bại, {skipped} đã bỏ qua.",
"ModelsUpdatePartial": "Không thể cập nhật một số danh mục. Các mô hình trước đó và đã cấu hình vẫn có sẵn.",
"ModelsCodexHint": "Các mô hình ChatGPT được tải qua Codex. Thời điểm truy vấn không xác nhận danh mục của nhà cung cấp đã được cập nhật.",
"ModelsSourceFallback": "Mô hình đi kèm hoặc đã cấu hình; chưa xác minh tính khả dụng.",
"CmdModelDbDescription": "Duyệt cơ sở dữ liệu mô hình tích hợp",
"CmdNetworkDescription": "Quản lý các quy tắc cho phép và từ chối mạng",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "Xem hoặc chỉnh sửa các tin nhắn đang chờ xử lý",
"CmdQueueUsage": "Cách dùng: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "Đã khôi phục {count} tin nhắn đang chờ từ phiên trước. Chúng không được gửi tự động: /queue send <n> gửi một tin, /queue clear để hủy chúng.",
"CmdQueueDraftHeader": "Đang chỉnh sửa tin nhắn đang chờ:",
"CmdQueueNoMessages": "Không có tin nhắn đang chờ",
"CmdQueueListHeader": "Tin nhắn đang chờ ({count}):",
"CmdQueueTip": "Mẹo: /queue send <n> để gửi ngay, /queue drop <n> để xóa",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "{hit} hit / không báo cáo miss",
"CmdTokensCacheMissOnly": "không báo cáo hit / {miss} miss",
"CmdTokensCacheWriteTotal": "Token ghi cache (tạo cache) trong phiên này: {write}. Bị tính cao hơn giá đầu vào ở những nhà cung cấp công bố phụ phí ghi; xem /cache để biết chi tiết theo lượt.",
"CmdTokensContextUnknownWindow": "~{estimated} / không rõ cửa sổ ngữ cảnh",
"CmdTokensContextWithWindow": "~{used} / {window} ({percent}%)",
"FooterAgentSingular": "1 tác nhân",
"FooterAgentsPlural": "{count} tác nhân",
"HeaderAgentsChip": "tác nhân {count}",
"FooterPressCtrlCAgain": "Nhấn Ctrl+C một lần nữa để thoát",
"FooterWorking": "đang xử lý",
"FooterBalancePrefix": "số dư",
"HelpSectionActions": "Hành động",
"HelpSectionClipboard": "Bộ nhớ tạm",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "không được báo cáo",
"CmdTokensReport": "Lượng Token Sử Dụng:\n─────────────────────────────\nNgữ cảnh hoạt động: {active}\nĐầu vào API gần nhất: {input} (viễn trắc theo lượt; có thể đếm lặp lại tiền tố qua các vòng công cụ)\nĐầu ra API gần nhất: {output}\nHit/miss bộ nhớ đệm: {cache} (chỉ dành cho viễn trắc/chi phí)\nToken tích lũy: {total} (dữ liệu viễn trắc sử dụng của phiên)\nSố tiền đã định giá: {cost}\nTin nhắn API: {api_messages}\nTin nhắn trò chuyện: {chat_messages}\nMô hình: {model}",
"KbScrollTranscript": "Cuộn bản ghi trò chuyện, điều hướng lịch sử nhập hoặc chọn tệp đính kèm",
"KbNavigateHistory": "Điều hướng lịch sử nhập",
"KbBrowseHistory": "Duyệt lịch sử cuộc trò chuyện",
"KbScrollTranscriptAlt": "Cuộn bản ghi trò chuyện",
"KbScrollPage": "Cuộn bản ghi trò chuyện theo trang",
@@ -822,6 +875,7 @@
"KbCompactContext": "Nén ngữ cảnh hội thoại",
"KbLastMessagePager": "Mở trang xem cho tin nhắn cuối cùng (khi khung nhập trống)",
"KbSelectedDetails": "Hiển thị chi tiết thô của công cụ hoặc tin nhắn đã chọn; Ctrl+Alt+O mở tổng quan cả lượt",
"KbToolDetailsPager": "Hiển thị chi tiết thô của mục đã chọn (Alt+V)",
"KbExternalEditor": "Mở bản nháp trong trình soạn thảo bên ngoài",
"KbLiveTranscript": "Mở lớp phủ bản ghi trực tiếp (tự động cuộn theo đuôi)",
"KbBacktrackMessage": "Quay lại tin nhắn trước đó của người dùng (nhấn Trái/Phải để chuyển bước, Enter để lùi lại)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "Mở lớp phủ trợ giúp này (khi khung nhập trống)",
"KbCycleWorkDock": "Chuyển thanh làm việc (todo, tác nhân, job, nền), hoặc chế độ xem thú cưng khi ở chế độ thú cưng",
"KbCycleWorkDockBack": "Chuyển thanh làm việc hoặc chế độ xem thú cưng ngược lại",
"KbToggleHelp": "Bật/Tắt lớp phủ trợ giúp",
"KbToggleHelpSlash": "Bật/Tắt lớp phủ trợ giúp",
"HelpUsageLabel": "Sử dụng:",
"HelpAliasesLabel": "Bí danh:",
"SettingsTitle": "Cài đặt:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " /mode plan để nghiên cứu và trình kế hoạch trước",
"HomeAgentModeYoloTip": " Shift+Tab xoay quyền: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + toàn quyền — công cụ chạy không cần phê duyệt",
"HomeYoloModeCaution": " Thao tác phá hủy có thể chạy ngay; dùng Ask khi không chắc",
"HomePlanModeTip": "Plan — nghiên cứu và thiết kế trước khi triển khai",
"HomePlanModeChecklistTip": " Trình kế hoạch rồi chuyển sang Work",
"HomeGoalModeTip": "Theo dõi mục tiêu - Dùng /goal <mục_tiêu> để đặt mục tiêu làm việc",
"OnboardLanguageTitle": "Chọn ngôn ngữ của bạn",
"OnboardLanguageBlurb": "Chọn ngôn ngữ hiển thị. Bạn có thể thay đổi bất kỳ lúc nào bằng lệnh `/config locale <tag> --save`.",
"OnboardProviderTitle": "Chọn nhà cung cấp mô hình",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "StepFun tính phí trả theo mức dùng và gói đăng ký Step Plan trên các endpoint khác nhau. Hãy chọn tuyến khớp với khóa của bạn.",
"StepfunBillingRoutePaygOption": "Trả theo mức dùng (giá theo token)",
"StepfunBillingRoutePlanOption": "Gói đăng ký Step Plan (hạn mức gói)",
"StepfunPlanApiKeyHint": "Với gói đăng ký Step Plan của StepFun, hãy dùng khóa được cấp cho Step Plan, không phải khóa trả theo mức dùng.",
"StepfunPlanRouteHint": "Tuyến này dùng {route} và được tính vào hạn mức Step Plan của bạn.",
"OnboardApiKeyRejectedEnv": "Khóa API {provider} từ {env} đã bị từ chối. Hãy dán khóa hợp lệ để lưu vào {path}, hoặc cập nhật biến môi trường.",
"OnboardTrustTitle": "Hiểu workspace này",
"OnboardTrustQuestion": "Codewhale có được làm việc với hướng dẫn và tệp trong workspace này không?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "Chọn “giữ” sẽ bật che trong lần khởi động này; vì cấu hình vẫn yêu cầu \"disabled\", lần khởi động sau sẽ hỏi lại.",
"RedactionGateSaveFailed": "Không thể lưu xác nhận. Tính năng che giấu vẫn bật. Thử lại hoặc tiếp tục bật tính năng này.",
"RedactionGateTitle": "Che khóa tại ranh giới mô hình",
"OnboardOfflineOption": "Ctrl+O — xem ngoại tuyến: xem trước, kết nối nhà cung cấp sau.",
"OnboardOfflineNotice": "Đang xem ngoại tuyến. Chưa kết nối gì — chạy /provider khi bạn muốn kết nối.",
"OnboardWelcomeTitle": "Codewhale làm việc cùng bạn trong thư mục này.",
"OnboardWelcomeLead": "Hãy cùng chuẩn bị.",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "Giải thích dự án này làm gì và liệt kê các điểm vào chính.",
"OnboardSeedFolder": "Xem thư mục này và gợi ý một tác vụ đầu tiên phù hợp.",
"SetupWizardTitle": "Thiết lập",
"SetupWizardWhy": "Màn hình này ghi tiến độ thiết lập vào setup_state.json; thay đổi cấu hình chỉ được áp dụng bằng hành động bước rõ ràng.",
"SetupWizardProgress": "Bước",
"SetupActionBack": "quay lại",
"SetupActionContinue": "tiếp tục",
"SetupActionSkip": "bỏ qua",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "cuộn nội dung",
"SetupActionGuided": "xem trước/phê chuẩn",
"SetupActionTuneGuided": "tinh chỉnh",
"SetupActionModelDraft": "bản nháp model",
"SetupActionFreeform": "lời của bạn",
"SetupActionKeepExisting": "giữ hiện có",
"SetupActionUseRecommended": "dùng đề xuất",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "tuyến model",
"SetupActionFleet": "thiết lập Fleet",
"SetupActionHotbar": "thiết lập Hotbar",
"SetupActionRemote": "mở lối từ xa",
"SetupActionMode": "chọn chế độ",
"SetupActionConfig": "xem cấu hình",
"SetupActionRuntimePreset": "preset",
"SetupActionApplyRuntimePreset": "xem trước/áp dụng",
"SetupActionUseBundled": "dùng mặc định",
"SetupActionDefer": "để sau",
"SetupActionCancel": "hủy",
"SetupStatusNotStarted": "chưa bắt đầu",
"SetupStatusRecommended": "khuyến nghị",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "Đã ghi ngôn ngữ setup.",
"SetupConstitutionChoiceLabel": "Lựa chọn:",
"SetupConstitutionSourceLabel": "Nguồn:",
"SetupConstitutionValidityLabel": "Hiệu lực:",
"SetupConstitutionPreviewLabel": "Hash xem trước:",
"SetupConstitutionExistingLabel": "Tệp hiện có:",
"SetupConstitutionExpertOverrideLabel": "Ghi đè chuyên gia:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "Plugin:",
"SetupToolsMcpReviewHint": "Enter ghi thông tin Tools/MCP hiện tại. R xem on-ramp an toàn (không tự chạy).",
"SetupToolsMcpReviewed": "Đã ghi mức sẵn sàng Tools/MCP.",
"SetupRemoteCloudsLabel": "Đích cloud:",
"SetupRemoteBridgesLabel": "Cầu nối chat:",
"SetupRemoteProvidersLabel": "Nhà cung cấp:",
"SetupRemoteModeLabel": "Chế độ từ xa:",
"SetupRemoteModeLocalOnly": "Chỉ máy này:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "Sao chép tin nhắn",
"CtxMenuCopyMessageDesc": "ghi ô transcript đã bấm",
"CtxMenuOpenInEditor": "Mở trong trình soạn thảo",
"CtxMenuOpenInEditorDesc": "mở file:line trong $EDITOR",
"CtxMenuShowCell": "Hiển thị ô",
"CtxMenuShowCellDesc": "hiển thị lại ô transcript này",
"CtxMenuHideCell": "Ẩn ô",
@@ -1216,9 +1290,15 @@
"FanoutCounts": "{done} hoàn thành · {running} đang chạy · {failed} thất bại · {pending} chờ",
"AppModeAgent": "Work",
"AppModeAuto": "Tự động",
"AppModeYolo": "Toàn quyền (nhãn cũ)",
"AppModePlan": "Plan",
"AppModeAgentHint": "Làm việc trực tiếp phiên này — sửa file và shell cần phê duyệt",
"AppModeAutoHint": "Bật shell với rà soát rủi ro tự động",
"AppModePlanHint": "Nghiên cứu chỉ-đọc trước — trình kế hoạch trước khi hành động",
"AppModeYoloHint": "Chỉ tương thích — Work + toàn quyền, không phải chế độ hiển thị",
"VimModeNormal": "-- BÌNH THƯỜNG --",
"VimModeInsert": "-- CHÈN --",
"VimModeVisual": "-- TRỰC QUAN --",
"ApprovalEffectReadsOnly": "Chỉ đọc",
"ApprovalEffectChangesFiles": "Thay đổi tệp",
"ApprovalRiskDestructive": "Không thể hoàn tác",
@@ -1246,6 +1326,7 @@
"ApprovalSaveAskRuleHint": " · s cho phép lần này và luôn hỏi trước ở lần sau",
"ApprovalOptionDeny": "Không cho phép",
"ApprovalOptionAbortTurn": "Dừng lượt này",
"ApprovalBlockTitle": "phê duyệt",
"ApprovalControlsHint": "Pg↑/↓ xem lại · {details} thêm lựa chọn · Esc dừng",
"ApprovalOwnerHeader": "Agent: {agent} · {role}",
"ApprovalGoToAgent": "g tới agent",
@@ -1271,6 +1352,8 @@
"ApprovalTruncationHint": " … đã rút gọn · nhấn {details} để xem đầy đủ",
"ApprovalAsksWithoutGit": "Ở đây không có kho Git nên các chỉnh sửa sẽ hỏi trước.",
"ApprovalFullAccessPolicyBlocked": "Đã chặn {tool}: Full Access không thể bỏ qua chính sách này",
"ApprovalChooseHint": "Chọn: ",
"ApprovalChooseAction": "Enter để chọn, hoặc nhấn y/a/d trực tiếp",
"ApprovalIntentLabel": "Ý định: ",
"ApprovalMoreLines": " … (+{count} dòng)",
"ApprovalProceedQuestion": "Bạn có muốn tiếp tục không?",
@@ -1310,10 +1393,12 @@
"ContextManualCompacting": "Đang nén ngữ cảnh…",
"ContextCompactionQueued": "Đã đưa việc nén ngữ cảnh vào hàng đợi; tác vụ sẽ chạy sau khi lượt hiện tại kết thúc.",
"ContextCompactionAlreadyRunning": "Việc nén ngữ cảnh đang được tiến hành.",
"ContextCompactionQueueFull": "Không thể đưa việc nén ngữ cảnh vào hàng đợi vì bộ máy đang bận; hãy thử lại sau khi lượt này kết thúc.",
"ContextCompactionQueueClosed": "Tính năng nén ngữ cảnh không khả dụng vì bộ máy không còn chạy.",
"ContextCompactionRouteInvalid": "Không thể nén vì tuyến của nhà cung cấp đang hoạt động không hợp lệ: {error}",
"ContextCompactionStoppedOnEngineSwitch": "Đã dừng nén ngữ cảnh; cuộc trò chuyện không bị thay đổi",
"ContextPurgeAbandonedOnEngineSwitch": "Đã bỏ dở việc dọn dẹp phiên cùng bộ máy bị thay thế; cuộc trò chuyện không bị thay đổi",
"CtxInspTitle": "Trình kiểm tra ngữ cảnh",
"CtxInspSessionContext": "Ngữ cảnh phiên",
"CtxInspSystemPrompt": "Cấu trúc lời nhắc hệ thống",
"CtxInspReferences": "Tham chiếu",
@@ -1545,21 +1630,47 @@
"SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — On-ramp an toàn\n\n/setup chỉ đọc kho cục bộ. Không khởi động máy chủ MCP, không cài skill, không chạy plugin hay lệnh không tin cậy.\n\nKho hiện tại:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (adapter dùng chung): {hotbar_result}\n\nĐường dẫn:\n- MCP: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nBootstrap an toàn (bạn tự chạy):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills\n- Plugins: /plugin · codewhale setup --plugins\n- Tools: codewhale setup --tools\n\nMọi thao tác có tác dụng phụ luôn cần xác nhận rõ ràng. Xem docs/MCP.md.",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — kết nối thông qua Codewhale, không bao giờ là bộ lập lịch thứ hai:\n- Trạng thái: {dsh_result}\n- Phát hiện chỉ đọc; kết nối/lập kế hoạch/khởi chạy/gỡ bỏ: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale chỉ ghi vào $CODEWHALE_HOME/integrations/dsh; không bao giờ sao chép khóa API hay sửa tệp của DSH.",
"HotbarActionModeOperateName": "Chế độ Operate",
"HotbarActionModeOperateDescription": "Xử lý một yêu cầu dài hạn song song cho đến khi được xác minh.",
"HomeOperateModeTip": "Operate — cho Fleet của bạn làm việc song song",
"HomeOperateModeFleetTip": " Vai trò tích hợp dùng mô hình của phiên này; /fleet setup để tùy chỉnh",
"AppModeOperate": "Operate",
"AppModeOperateHint": "Work hết sức: mục tiêu, worker song song, xác minh",
"HelpSubtitle": "Lệnh, kỹ năng và phím tắt",
"CommandPaletteTitle": "Lệnh",
"CommandPaletteSubtitle": "Tìm và chạy một thao tác",
"ConfigSubtitle": "Cài đặt trước; khóa thô ở chi tiết nâng cao",
"LaunchStartTitle": "Bắt đầu tại đây",
"LaunchResumeConfirm": "Tiếp tục {title}? Nhấp lại hoặc nhấn Enter để xác nhận.",
"LaunchResumeConfirmTitle": "Tiếp tục phiên",
"LaunchResumeConfirmBody": "Thao tác này thay ngữ cảnh hiện tại bằng lịch sử của phiên đó.",
"LaunchResumeConfirmResume": "tiếp tục",
"LaunchResumeConfirmCancel": "huỷ",
"LaunchWorkDescription": "Dùng công cụ cục bộ trong thư mục này; mọi thay đổi tuân theo chính sách phê duyệt của bạn.",
"LaunchChatDescription": "Chỉ trò chuyện và lập kế hoạch; không thay đổi tệp.",
"LaunchWorkspaceGitReady": "Không gian làm việc · {name} · không gian Git",
"LaunchWorkspaceFolderReady": "Không gian làm việc · {name} · thư mục cục bộ",
"LaunchProviderConfigured": "Nhà cung cấp · đã cấu hình",
"LaunchProviderSetupNeeded": "Nhà cung cấp · cần thiết lập",
"LaunchGroupContinue": "Tiếp tục",
"LaunchGroupMore": "Thêm",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "thư mục",
"LaunchProviderConfiguredShort": "đã đặt nhà cung cấp",
"LaunchProviderSetupShort": "thiết lập nhà cung cấp",
"LaunchMenuChangelog": "Nhật ký thay đổi",
"LaunchWorktreePrompt": "Đặt tên cho nhánh/worktree, hoặc nhấn Enter để dùng tên tự động. Esc để quay lại.",
"LaunchWorktreeNeedsGit": "Worktree mới yêu cầu một kho Git.",
"LaunchWorktreeNameLabel": "tên worktree",
"LaunchHintMove": "di chuyển",
"LaunchHintOpen": "mở",
"LaunchTipFlags": "Mẹo: -w <đường_dẫn> mở một workspace; -r <id_phiên> tiếp tục phiên trực tiếp",
"LaunchSavedSessionSingular": "1 phiên đã lưu",
"LaunchSavedSessionsPlural": "{count} phiên đã lưu",
"LaunchCreatingWorktree": "Đang tạo worktree…",
"LaunchWorktreeFailed": "Worktree thất bại: {error}",
"LaunchWorktreeCreated": "Worktree mới {path} trên nhánh {branch}",
"LaunchNoSavedSessions": "Không có phiên đã lưu cho workspace này.",
"LaunchNoModelConnected": "chưa kết nối mô hình",
"DispatchNotSentNoModel": "Chưa kết nối mô hình nào nên tin nhắn này chưa được gửi. Tin nhắn đã quay lại ô nhập: kết nối mô hình bằng F3 hoặc /provider, rồi nhấn Enter để gửi.",
"DispatchNotSentSaveKey": "Lưu khóa: {command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "Đang dùng {model}, một mô hình chạy trên máy tính này (Ollama). Nhấn F3 để chọn mô hình khác.",
"ProviderPickerNotReopened": "Không mở lại được danh sách nhà cung cấp. Nhấn F3 để mở.",
"LaunchRunCommand": "chạy {command}",
"LaunchMcpConnectedOne": "1 máy chủ MCP đã kết nối",
"LaunchMcpConnectedMany": "{count} máy chủ MCP đã kết nối",
"LaunchMcpNeedsSignInOne": "1 cần đăng nhập",
"LaunchMcpNeedsSignInMany": "{count} cần đăng nhập",
"PhaseIdle": "rảnh",
"PhaseDraft": "nháp",
"PhaseWorking": "đang xử lý",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "đang hoàn tất",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "chỉ đọc",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "Quyền đã đổi thành {label}",
"FooterHintKeys": "phím",
"FooterHintOutput": "đầu ra",
"FooterHintContext": "ngữ cảnh",
"InfoLineHelp": "trợ giúp",
"InfoLineContext": "ngữ cảnh",
"InfoLineTtft": "ttft",
"InfoLinePeak": "cao điểm",
"InfoLineOffPeak": "thấp điểm",
"InfoLineWhales": "cá voi",
"InfoLineAutomation": "tự động hóa",
"InfoLineNotConnected": "chưa kết nối",
"InfoLineThinking": "suy nghĩ: {level}",
"EmptyStateNoGit": "không có git",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "tìm mô hình bất kỳ",
"RoutePanelHeader": "tuyến",
"RouteProviderLabel": "nhà cung cấp",
"RouteModelFirstAtomic": "tuyến nguyên tử ưu tiên model",
"PickerActionMove": "di chuyển",
"PickerActionSwitch": "chuyển",
"PickerActionApply": "áp dụng",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "xóa tìm kiếm",
"PickerActionBrowseAll": "xem tất cả",
"PickerActionCustom": "tùy chỉnh",
"PickerActionJump": "nhảy",
"PickerActionEditKey": "sửa khóa",
"PickerActionModels": "mô hình",
"PickerActionUnavailable": "không khả dụng",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "ngừng dùng đăng nhập đó",
"ProviderExternalActionChoices": "đăng nhập qua ứng dụng khác",
"ProviderExternalActionReuseGrok": "dùng lại thông tin Grok bên ngoài",
"ProviderExternalHintCodexReview": "Sau {login}, nhấn Enter để xem các lựa chọn tắt, chỉ đọc và được quản lý.",
"ProviderExternalHintXaiReview": "Nhấn Enter để đăng nhập thiết bị do Codewhale sở hữu; nhấn E để xem việc dùng lại Grok CLI hiện có.",
"ProviderExternalHintXaiApiKey": "Hoặc dùng XAI_API_KEY rồi mở lại trình chọn này.",
"XaiAuthChoiceTitle": " Xác thực xAI ",
"XaiAuthChoiceIntro": "Chọn một nguồn thông tin xác thực rõ ràng. Nội dung khóa không bao giờ được xem là mã thông báo OAuth.",
"XaiAuthChoiceApiKeyOption": "Khóa API xAI — nhập hoặc dán, rồi lưu vào vị trí nhà cung cấp xAI",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " Xác thực ChatGPT / Codex ",
"ChatgptAuthChoiceIntro": "Đăng nhập gói đăng ký sẽ tính vào gói ChatGPT của bạn. Tuyến khóa API openai thuộc chủ thể thanh toán khác.",
"ChatgptAuthChoicePkceOption": "Đăng nhập bằng ChatGPT — PKCE trình duyệt, token do Codewhale sở hữu, thanh toán gói ChatGPT",
"ChatgptAuthChoiceImportOption": "Nhập thông tin Codex CLI — đồng ý chỉ đọc tường minh; Codex CLI vẫn là chủ sở hữu",
"ProviderExternalHintChatgptReview": "Nhấn Enter để đăng nhập bằng ChatGPT; nhấn E để xem lại việc tái sử dụng Codex CLI hiện có.",
"ProviderExternalActionReuseCodex": "tái sử dụng Codex bên ngoài",
"ProviderExternalDetailScope": "Bên ngoài: truy cập={access} | nhà cung cấp={provider} | nguồn={source} | phiên bản={version} | {state}",
"ProviderExternalDormant": "không hoạt động",
"ProviderExternalOwnerPath": "Chủ sở hữu/đường dẫn: {owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "Ảnh chụp nhanh và /undo đang tắt cho {workspace}: thư mục nhà hoặc thư mục gốc quá rộng để chụp an toàn. Hãy bắt đầu trong một thư mục dự án để bật lại.",
"SnapshotsHistoryRepaired": "Lịch sử hoàn tác của {workspace} bị hỏng (thiếu điểm khôi phục mới nhất) và đã được bắt đầu lại. Các điểm khôi phục trước đó không thể khôi phục nữa; các lượt mới lại được bảo vệ.",
"SnapshotsFailing": "Snapshot đang lỗi cho {workspace}, nên /undo không thể khôi phục các lượt gần đây: {limit}",
"SessionIdDivergedNotice": "Danh tính phiên trong cửa sổ này đã thay đổi: engine hiện lưu checkpoint dưới {next} (trước đó là {previous}). Các checkpoint cũ vẫn nằm dưới id cũ; `codewhale sessions` liệt kê cả hai và `codewhale resume {previous}` mở lại phiên cũ.",
"RuntimeStoreUnreadableNotice": "Kho lưu trữ runtime của phiên: không đọc được {record} tại {path} ({reason}). Hãy dời tệp đó sang chỗ khác (hoặc xóa) rồi thử lại; các bản ghi khác của luồng vẫn được giữ nguyên.",
"RuntimeStoreUnwritableNotice": "Kho lưu trữ runtime của phiên: không ghi được {record} tại {path} ({reason}). Hãy kiểm tra dung lượng trống và quyền truy cập ở đó rồi thử lại; không có gì bị ghi đè.",
"ProviderExternalSemanticsRevoke": "{semantics} | thu hồi: {revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "thiết lập",
"FleetRosterWorkers": "worker",
"FleetRosterMembersCount": "{count} thành viên",
"FleetRosterOperatorFirst": "Coordinator dẫn đầu · mô hình phiên điều phối Fleet này",
"FleetRosterOperatorRow": "Coordinator · trưởng nhóm",
"FleetRosterShadowBadgeProjectOverride": "đã lưu cho dự án này",
"FleetRosterShadowBadgePersonalIgnored": "bản sao đã lưu bị bỏ qua",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "đây là mô hình hiện tại của bạn (tuyến operator của nhóm); hãy đổi mô hình hoặc dùng /fleet save để thay đổi",
"FleetModelReasonAlreadyPresent": "đã có trong nhóm",
"FleetModelErrorNeedsRoute": "một mô hình trong nhóm cần cả id provider lẫn id mô hình",
"FleetModelErrorNeedsRole": "Tác tử cần tên vai trò (ví dụ `/fleet add {route} scout`).",
"FleetModelErrorNoSelection": "chưa chọn nhóm nào; nhóm của bạn chỉ gồm mô hình của phiên",
"FleetModelErrorOperatorRoute": "{route} là tuyến operator của nhóm `{fleet}`; hãy thay đổi bằng /fleet save, không phải remove",
"FleetModelErrorNotInFleet": "{route} không có trong nhóm `{fleet}`",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ đính kèm · 1 kết quả",
"FilePickerMatchesPlural": "@ đính kèm · {count} kết quả",
"FilePickerScanning": "Đang quét không gian làm việc…",
"BehavioralTipPlanning": "Đang lập kế hoạch? {key} chuyển sang chế độ Plan",
"BehavioralTipBackgroundReceipt": "Biên nhận nằm trong bảng Work — {key} mở trình kiểm tra",
"BehavioralTipClearedInput": "Đã xóa · {chord} để khôi phục",
"BehavioralTipMcpValidation": "{command} khởi động máy chủ và cho biết nguyên nhân",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "Mô hình và suy nghĩ",
"SettingSubjectProvider": "Nhà cung cấp",
"SettingSubjectPermissions": "Quyền",
"ThinkingControlledByAutoRouting": "Suy nghĩ do định tuyến mô hình tự động điều khiển; hãy chọn một mô hình cố định trước.",
"SavedAsStartupDefault": "đã lưu làm mặc định khi khởi động",
"ModeAlreadyActiveSavedAsDefault": "Đang ở chế độ {mode} — đã lưu làm mặc định khi khởi động.",
"StartupDefaultNotSaved": "Không lưu được {setting}: {error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "mức suy nghĩ",
"StartupDefaultSubjectModel": "mô hình",
"StartupDefaultSubjectAll": "các mặc định khi khởi động",
"SessionsRailTitle": "Phiên",
"SessionsRailEmpty": "Chưa có phiên nào trong workspace này",
"SessionsRailBrowseAll": "Xem tất cả phiên",
"SessionsRailShowingCount": "{shown} trên {total} — xem tất cả",
"SessionsRailUnavailable": "Không đọc được phiên: {error}",
"SessionsActionArchive": "lưu trữ",
"SessionsActionShowArchived": "đã lưu trữ",
"SessionsArchived": "Đã lưu trữ phiên {id}",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "agent",
"FooterHintToManage": "quản lý",
"AgentRailQueuedCount": "{count} đang chờ",
"WorkbarSoFar": "{done}/{total} cho đến nay",
"WorkbarLargeWorkflow": "Quy trình lớn",
"WorkbarMoreRuns": "+{count} nữa",
"WorkflowLineStarted": "đã bắt đầu",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "xong nhưng còn thiếu",
"WorkflowLineFailed": "thất bại",
"WorkflowLineStopped": "đã dừng",
"WorkflowLineAgents": "{done}/{total} tác tử",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "được ghi",
"AgentFocusPostureReadOnly": "chỉ đọc",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "shell chỉ đọc",
"AgentFocusPostureShellNone": "không shell",
"GoalReceiptSet": "Đã đặt mục tiêu: \"{objective}\" · /goal hiển thị tiến độ · /goal pause hoặc /goal clear để dừng",
"GoalReceiptSetOperate": "◆ đã đặt mục tiêu · Operate tiếp tục làm việc cho đến khi được xác minh · /goal để sửa",
"GoalControlAccepted": "Đã lưu điều khiển mục tiêu; sẽ áp dụng tại ranh giới an toàn tiếp theo.",
"GoalControlRuntimeUnavailable": "Điều khiển mục tiêu đã được lưu nhưng runtime hiện không khả dụng. Trạng thái sẽ được khôi phục sau khi khởi động lại.",
"GoalStatusIdleHint": "hiện không chạy — gửi tin nhắn hoặc /goal resume để tiếp tục",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "Mục tiêu đang hoạt động · lượt tiếp theo sau {delay} · Esc, Ctrl+C hoặc /goal pause sẽ dừng lượt tiếp tục đang chờ",
"GoalContinuationReady": "Lượt tiếp tục mục tiêu đã sẵn sàng; các lệnh điều khiển trong hàng đợi chạy trước lượt tiếp theo.",
"GoalContinuationStopped": "Đã dừng lượt tiếp tục mục tiêu đang chờ; mục tiêu vẫn hoạt động.",
"McpCapabilitiesAdvertised": "Khả năng đã công bố: {capabilities}",
"McpCapabilitiesLegacyFallback": "Khả năng đã công bố: không được cung cấp; dùng cơ chế khám phá cũ",
"McpCapabilitiesNotObserved": "Khả năng đã công bố: chưa quan sát được vì máy chủ chưa kết nối",
"PickerActionTestConnection": "kiểm tra kết nối",
"ProviderCustomFormBaseUrl": "URL cơ sở",
"ProviderCustomFormModel": "Mô hình mặc định",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "gantt thời gian →",
"ConfigCategoryAppearance": "Giao diện",
"ConfigCategoryModelsProviders": "Mô hình & nhà cung cấp",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "Công việc",
"ConfigCategoryToolsMcp": "Công cụ & MCP",
"ConfigCategoryTrust": "Tin cậy",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "chỉ đọc",
"ConfigRowActionNote": "hành động · không phải cài đặt được lưu",
"ConfigRowDiagnosticNote": "biên nhận quan sát · không chỉnh sửa ở đây",
"ConfigNavHint": "←/→ hoặc Tab: danh mục · ↑/↓: cài đặt",
"ConfigActivateAgain": "Nhấn Enter hoặc nhấp lần nữa:",
"ConfigSearchLabel": " Tìm kiếm: ",
"ConfigEditChooseLabel": "Chọn:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "Không bao giờ",
"ConfigChoiceModeAct": "Hành động",
"ConfigChoiceModePlan": "Lập kế hoạch (chỉ đọc)",
"ConfigChoiceModeOperate": "Vận hành",
"ConfigChoicePlacementTop": "Trên cùng",
"ConfigChoicePlacementBottom": "Thanh dưới",
"ConfigChoicePlacementLeft": "Thanh bên trái",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "Tự động xem xét rủi ro của công cụ và chỉ hỏi khi cần bạn quyết định.",
"ConfigChoiceDetailUseTuiDefault": "Bỏ ghi đè của config gốc và dùng lựa chọn quyền đã lưu trong TUI.",
"ConfigChoiceDetailFullAccess": "Công cụ sẽ chạy mà không hỏi trước, và lệnh có thể truy cập mọi thứ trên máy tính này.",
"ConfigChoiceDetailNever": "Chặn mọi công cụ cần phê duyệt.",
"ConfigChoiceDetailModeAgent": "Bắt đầu ở trạng thái sẵn sàng cộng tác và dùng công cụ.",
"ConfigChoiceDetailModePlan": "Bắt đầu trong không gian lập kế hoạch chỉ đọc.",
"ConfigChoiceDetailModeOperate": "Operate là Work hết công suất: mỗi yêu cầu thực chất trở thành một mục tiêu, chạy qua workflow và worker song song, được một người duyệt độc lập kiểm tra, và tiếp tục đến khi được xác minh.",
"ConfigChoiceDetailPlacementTop": "Hiện Tác vụ, Việc cần làm và Worker phía trên bản ghi.",
"ConfigChoiceDetailPlacementBottom": "Hiện Tác vụ, Việc cần làm và Worker dưới ô soạn thảo.",
"ConfigChoiceDetailPlacementLeft": "Hiện Tác vụ, Việc cần làm và Worker ở thanh bên trái khi terminal đủ rộng.",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "Tô nền cho suy luận của mô hình.",
"ConfigChoiceDetailThinkingHighlightOff": "Giữ đường suy luận nét đứt và chữ nghiêng mà không tô nền.",
"ConfigHintModel": "mô hình của tuyến trực tiếp trong phiên này; Enter mở /model",
"ConfigHintFastModel": "được định tuyến Auto và model_strength=faster của tác nhân dùng khi nhà cung cấp này có mô hình anh em đã biết",
"ConfigHintProvider": "thông tin xác thực, mô hình và endpoint chuyển cùng nhau",
"ConfigHintApprovalMode": "chỉ phiên này: Hỏi | Tự động xem xét | Toàn quyền",
"ConfigHintPermissionPosture": "mặc định cho phiên mới: Hỏi | Tự động xem xét | Toàn quyền",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "số nguyên (cho phép 0) · số tin nhắn đã gửi được giữ lại để gọi lại và tìm kiếm lịch sử",
"ConfigHintAutoCompactThreshold": "10..=100 · ngưỡng nén: phần trăm độ dài ngữ cảnh khả dụng mà tại đó tự động nén được kích hoạt",
"ConfigHintDefaultModel": "dự phòng cũ chỉ cho DeepSeek; nhà cung cấp khác dùng mô hình theo nhà cung cấp ở trên",
"ConfigHintReasoningEffort": "default khôi phục mặc định của chính mô hình; mô hình luôn suy luận không có off",
"ConfigHintMcpOpen": "mở trình quản lý MCP · Kết nối / Kết nối lại / Xác thực lại / Chẩn đoán",
"ConfigHintMcpReconnect": "kết nối lại MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "trạng thái cờ tính năng chỉ đọc cho công cụ chỉnh sửa bằng patch",
"ConfigHintFeatureMcp": "trạng thái cờ tính năng chỉ đọc cho công cụ MCP",
"ConfigHintFeatureExecPolicy": "trạng thái cờ tính năng chỉ đọc cho công cụ chính sách thực thi",
"ConfigHintFeatureVisionModel": "cờ tính năng beta cho hỗ trợ hình ảnh thị giác/mô hình",
"ConfigHintGoalCommand": "/goal đặt mục tiêu, ngân sách và trạng thái ngữ cảnh Công việc",
"ConfigHintWorkflow": "/workflow chạy các thao tác theo kịch bản với thẻ chạy phân tán/gộp",
"LaunchMenuNewWorktree": "Worktree mới",
"LaunchMenuResume": "Tiếp tục phiên",
"LaunchMenuQuit": "Thoát",
"LaunchNoticeClaude": "Đã phát hiện Claude Code. Chạy /import-claude để xem những gì có thể chuyển sang: máy chủ MCP, cài đặt an toàn và quyền. Không có gì được áp dụng nếu bạn chưa duyệt.",
"LaunchNewSession": "Phiên mới",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ để tiếp tục",
"LaunchHelpLine": "/help để xem lệnh · {dock} để mở thanh làm việc",
"LaunchSeeAllSessions": "Xem tất cả các phiên…",
"LaunchNoRecentSessions": "Chưa có phiên gần đây — nhập bên dưới để bắt đầu.",
"LaunchResumeFailed": "Tiếp tục thất bại: {error}",
"ReceiptSessionHooks": "hook {count}",
"AutomationEditorNew": "Tạo tự động hóa",
"AutomationEditorEdit": "Sửa tự động hóa",
"AutomationEditorSchedule": "Lịch chạy",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} xong",
"WorkflowPhaseCountOne": "{count} giai đoạn",
"WorkflowPhaseCountMany": "{count} giai đoạn",
"WorkflowPhaseOrdinal": "giai đoạn {n}/{total}",
"ModelPickerPinned": "Đã ghim {route}",
"ModelPickerUnpinned": "Đã bỏ ghim {route}",
"ModelPickerPinFailed": "Không thể cập nhật ghim: {error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "Đã thay thế lần đăng nhập {provider} trước đó của Codewhale ({account}).",
"AuthReplacedPreviousSignIn": "Đã thay thế lần đăng nhập {provider} trước đó của Codewhale.",
"AuthSameAccountAsBefore": "Đây vẫn là tài khoản cũ; để dùng tài khoản {provider} khác, hãy đăng xuất tài khoản này trong trình duyệt (hoặc dùng cửa sổ riêng tư) rồi đăng nhập lại.",
"AuthEnvTokenOutranksSignIn": "Môi trường này đã đặt OPENAI_CODEX_ACCESS_TOKEN hoặc CODEX_ACCESS_TOKEN, và biến đó được ưu tiên hơn lần đăng nhập này; các yêu cầu vẫn dùng tài khoản của token đó cho đến khi bạn bỏ đặt nó.",
"PinnedPromptJumpToMessage": "Nhảy đến tin nhắn này",
"PlanHandoffHeader": "Kế hoạch đã sẵn sàng",
"PlanHandoffQuestion": "Bạn muốn tiếp tục thế nào?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "Nhấn Enter để đăng nhập bằng trình duyệt hoặc Esc để quay lại. Không cần khóa API.",
"PluginOAuthReady": "{provider}: đã đăng nhập. Hãy chọn mô hình.",
"PluginOAuthLocalLogout": "{provider}: đã xóa thông tin đăng nhập cục bộ. Quyền truy cập từ xa không đổi.",
"CmdConnectDescription": "Kết nối nhà cung cấp plugin bằng đăng nhập qua trình duyệt",
"CmdDisconnectDescription": "Xóa đăng nhập cục bộ của nhà cung cấp plugin",
"ExecAutoHelp": "Bật công cụ với phê duyệt tự động và Full Access (không có sandbox shell, bật chế độ tin cậy), trừ khi đã cấu hình sandbox chặt chẽ hơn; dùng --sandbox workspace-write để hạn chế việc ghi bằng công cụ tệp và shell.",
"ExecSandboxHelp": "Chính sách sandbox cho lần chạy này; mọi --sandbox khác danger-full-access (hoặc sandbox_mode tương đương trong cấu hình) đều tắt chế độ tin cậy.",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime 已关闭此对话的事件流;请重新打开会话",
"MobileStreamReconnecting": "连接已断开;正在重新连接",
"MobileStreamConnected": "已连接",
"PetHabitatTitle": "CODEWHALE / WHALESONG · 共享栖息地",
"PetHabitatHints": "{back} 返回 · {sound} 声音 · {browser} 外观 · {window} 窗口",
"PetHabitatQueued": "已发送到共享栖息地。/pet on 显示宠物与消息框。",
"PetWatchSoundOn": "声音已开启",
"PetWatchSoundOff": "声音已关闭",
"PetWatchSoundPaused": "声音已暂停",
"PetWatchSoundUnavailable": "Codewhale 声音已停止。请检查 FFmpeg (ffplay) 和音频输出,然后重新开启声音。",
"CmdPetDescription": "将动画宠物设为 Codewhale 主视图",
"ConfigLabelPetMode": "宠物模式",
"ConfigHintPetMode": "启动 Codewhale 时,将动画宠物设为主界面。",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "宠物模式已关闭",
"PetViewOpen": "栖息地已打开",
"PetViewClosed": "栖息地已关闭",
"PetWatchRestored": "/pet 已恢复此会话的栖息地,正在等待新的遥测数据。",
"PetWatchStorageUnavailable": "Watch 无法恢复或保存此栖息地。现有文件已保留。使用 {command} 导出本次运行。",
"PetWatchExported": "Watch 回放已保存:{path}",
"PetWatchExportFailed": "无法保存 Watch 回放,记录仍保留在内存中。",
"PetWatchExportQueued": "正在保存 Watch 回放…",
"PetWatchExportUnavailable": "请在已保存的会话中打开 /pet,或等待当前导出完成。",
"PetUnobserved": "休息中",
"PetOffline": "离线 — 运行 codewhale pet serve 唤醒它",
"PetDozing": "打盹",
"PetWatchUnavailable": "宠物遥测已暂停。/pet on 重试。",
"ConversationChangedBeforeUndo": "撤销完成前,会话已发生变化。未撤销任何内容,也未发送重试请求。请先检查当前会话,再重试。",
"SessionArchiveExported": "会话已导出",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "编辑",
"ExtensionsHooksAddLabel": "添加钩子",
"ExtensionsHooksAddDescription": "在你的编辑器中打开本项目的钩子文件",
"ExtensionsActionReload": "重新加载",
"ExtensionsActionConnect": "连接",
"ExtensionsActionReconnect": "重新连接",
"ExtensionsActionReauth": "重新登录",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "已连接",
"ExtensionsStateEnabled": "已启用",
"ExtensionsStateError": "错误",
"ExtensionsStateInactive": "未激活",
"ExtensionsStateInapplicable": "不适用",
"ExtensionsStateInvalid": "无效",
"ExtensionsStateNotInspected": "尚未检查",
"ExtensionsStateDisconnected": "已断开",
"ExtensionsStateRejected": "已拒绝",
"ExtensionsStateReviewedCandidate": "已审核候选",
"ExtensionsStateUnderEvaluation": "评估中",
"ExtensionsStateUnstaged": "尚未暂存",
"ExtensionsStateUnsupported": "不支持",
"ExtensionsStateWarning": "警告",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ 发进本回合",
"ComposerHintLongDraft": "{shortcut}:外部编辑器",
"PendingSendingIntoTurnPrefix": " ↳ 正在发进本回合: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ 留待下一回合: ",
"PendingEditingFollowUpPrefix": " ↳ 正在编辑后续消息: ",
"PendingQueuedOnePrefix": "已排队 #1: ",
"PendingQueuedManyPrefix": "已排队 {count} · 下一条: ",
@@ -216,6 +227,18 @@
"TranscriptThought": "思考完毕",
"TranscriptThoughtFor": "思考用时 {duration}",
"TelemetryNoticeDefaultOn": "使用统计默认开启。向 Codewhale 和数据处理方 PostHog 分享版本/平台、会话、功能和错误的汇总计数。还统计提供商、公开目录中的模型、token 总数和内置工具的使用次数。不收集内容或 IP。docs/TELEMETRY.md 关闭:codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale 使用统计",
"TelemetryNoticeBody": "Codewhale 只统计:你运行的版本、操作系统和 CPU 系列、会话时长和结果,\n以及汇总的功能和错误计数。\n\n还统计你使用的提供商和公开目录中的模型、其 token 总数,以及每个内置工具的运行次数。\n\n它绝不会收集你的对话、代码、提示词、文件、仓库名或分支名、模型内容\n或凭据,也绝不会发送按回合或按工具记录的智能体活动。\n\n系统只使用存储在本机上的随机 ID 来识别你,该 ID 每 90 天更换一次。\n你可以随时更改:\n codewhale config set telemetry false\n\n逐字段完整架构:docs/TELEMETRY.md\n\n使用统计默认开启。配置发送后,Codewhale 和 PostHog 会处理这些计数。不收集 IP。",
"TelemetryNoticeCompactBody": "统计:版本、系统/处理器、会话时长/结果、功能/错误总数。\n另计:提供商/模型、token、工具使用。\n随机本地标识每 90 天更换。\n绝不收集:对话/代码/提示词/文件/名称、模型内容/凭据、按回合/工具记录的活动。\n架构:docs/TELEMETRY.md\n关闭:codewhale config set telemetry false\n使用统计默认开启。配置发送后,Codewhale 和 PostHog 会处理这些计数。不收集 IP。",
"TelemetryNoticeChoiceKeep": "是,保留匿名统计",
"TelemetryNoticeChoiceDisable": "不,关闭匿名统计",
"TelemetryNoticeActionChoose": "选择",
"TelemetryNoticeActionConfirm": "确认",
"TelemetryNoticeActionExit": "退出",
"TelemetryNoticeReceiptEnabled": "匿名使用统计已开启。绝不收集对话或代码。可在 /settings 中更改;完整结构:docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "匿名使用统计已关闭。以后不会再次询问。",
"TelemetryNoticeReceiptEnabledUnsaved": "本次会话已开启匿名使用统计。Codewhale 无法保存此提示,因此会再次显示。可在 /settings 中更改;完整结构:docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "本次会话已关闭匿名使用统计。Codewhale 无法保存此选择,因此下次启动时会再次询问。",
"TelemetryPreferenceEnabledNextLaunch": "匿名使用统计将在下次启动时开启。绝不收集对话或代码。",
"TelemetryPreferenceDisabled": "匿名使用统计已关闭。本地遥测数据已清除。",
"TelemetryPreferenceDisabledWithWarning": "匿名使用统计已关闭,但部分清理需要注意:{detail}",
@@ -260,6 +283,7 @@
"HotbarSetupNoActions": "没有可用的 Hotbar 操作。",
"HotbarSetupRecommended": "荐",
"HotbarSetupEmptySlot": "空",
"HotbarSetupHelp": "Tab/Shift+Tab 来源 Up/Down 操作 1-8 槽位 Enter 分配 Space 切换 Delete 清除 s 保存 Esc 取消",
"HotbarActionVoiceToggleName": "语音输入",
"HotbarActionVoiceToggleDescription": "切换终端麦克风语音采集。",
"HotbarActionSessionCompactName": "压缩会话",
@@ -269,8 +293,10 @@
"HotbarActionModeAgentName": "Work 模式",
"HotbarActionModeAgentDescription": "在当前会话中直接工作。",
"HotbarActionModeYoloName": "完全访问 (Work)",
"HotbarActionModeYoloDescription": "兼容项:Work 模式 + 完全访问权限(不是独立模式)。",
"HotbarActionReasoningCycleName": "切换思考强度",
"HotbarActionReasoningCycleDescription": "轮换当前提供商配置的思考强度。",
"HotbarActionReasoningCycleAutoDisabled": "思考强度由自动模型路由控制。",
"HotbarActionSidebarToggleName": "切换侧边栏",
"HotbarActionSidebarToggleDescription": "显示或隐藏侧边栏。",
"HotbarActionFileTreeToggleName": "切换文件树",
@@ -287,6 +313,7 @@
"ConfigNoSettings": " 没有可用设置。",
"ConfigNoMatchesPrefix": " 没有匹配设置:",
"ConfigFilteredSettings": " 已筛选设置",
"ConfigShowing": " 显示",
"ConfigFooterDefault": " 输入=筛选, Up/Down=选择, Enter=编辑, Esc=关闭 ",
"ConfigFooterScrollable": " 输入=筛选, Up/Down=选择, Enter=编辑, PgUp/PgDn=滚动, Esc=关闭 ",
"ConfigFooterFiltered": " 输入=筛选, Backspace=删除, Ctrl+U/Esc=清除, Enter=编辑 ",
@@ -312,6 +339,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value}({scope};输入建议从下一回合起生效)",
"ConfigNotificationsSetHint": "使用 /config notifications <key> <value> [--save] 设置。",
"ConfigNotificationUpdated": "notifications.{key} = {value}({scope};应用于后续提醒)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs 必须是整数",
"ConfigAuditSearchProvider": "写入 [search] provider;后续 web_search 仍会遵循环境变量覆盖。",
"ConfigAuditPromptSuggestion": "写入顶层 prompt_suggestion;幽灵文本提示仍需主动启用。",
"ConfigAuditNotifications": "写入 [notifications] 标量,并应用于后续的回合完成提醒。",
@@ -334,6 +362,8 @@
"ConfigLabelProviderUrl": "提供商 API 地址",
"ConfigHintProviderUrl": "当前提供商端点;Xiaomi:token 套餐 | 按量付费 | 自定义 URL",
"ConfigLabelModel": "当前提供商模型",
"ConfigLabelFastModel": "快速模型(派生)",
"ConfigLabelDefaultModel": "旧版后备模型(仅 DeepSeek 路由)",
"ConfigLabelReasoningEffort": "思考强度",
"ConfigLabelFleetSpawnDepth": "智能体嵌套深度",
"ConfigLabelApprovalMode": "本会话权限",
@@ -347,6 +377,7 @@
"ConfigHintTelemetry": "仅向 Codewhale 和 PostHog 发送版本、会话、功能和错误的汇总计数;绝不发送内容或 IP。docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "开启",
"ConfigValueTelemetryOff": "关闭",
"ConfigLabelStreamTimeout": "流式超时",
"ConfigLabelTheme": "主题",
"ConfigLabelLocale": "语言",
"ConfigLabelBackground": "背景",
@@ -370,6 +401,7 @@
"ConfigLabelThinkingHighlight": "思考背景高亮",
"ConfigLabelShowToolDetails": "工具详情级别",
"ConfigLabelInlineDiffs": "内联文件更改",
"ConfigLabelStatusIndicator": "状态指示器",
"ConfigLabelSynchronizedOutput": "输出节奏",
"ConfigLabelCostCurrency": "费用币种",
"ConfigLabelTranscriptSpacing": "对话间距",
@@ -377,7 +409,16 @@
"ConfigLabelComposerDensity": "输入框密度",
"ConfigLabelComposerBorder": "输入框边框",
"ConfigLabelComposerMultilineMode": "输入框多行模式",
"ConfigLabelComposerVimMode": "输入框 Vim 模式",
"ConfigLabelBracketedPaste": "括号粘贴",
"ConfigLabelPasteBurstDetection": "粘贴检测",
"ConfigLabelMentionMenuLimit": "提及菜单上限",
"ConfigLabelMentionMenuBehavior": "提及菜单行为",
"ConfigLabelMentionWalkDepth": "文件提及深度",
"ConfigLabelWorkspaceFollowSymlinks": "跟随符号链接",
"ConfigLabelContextPanel": "上下文面板",
"ConfigLabelSessionsRail": "会话栏",
"ConfigLabelSessionAutoResume": "自动恢复上次会话",
"ConfigLabelAutoCompact": "自动压缩",
"ConfigLabelAutoCompactThreshold": "压缩阈值",
"ConfigLabelMaxHistory": "输入历史",
@@ -389,7 +430,9 @@
"ConfigLabelGoalCommand": "目标命令",
"ConfigLabelWorkflow": "工作流",
"ConfigLabelFeaturePrefix": "功能:{name}",
"ConfigColumnSetting": "设置",
"ConfigColumnValue": "值",
"ConfigColumnScope": "范围",
"ConfigActionOpenProvider": "按 Enter 打开提供商选择器",
"ConfigActionOpenModel": "按 Enter 打开模型选择器",
"ConfigActionOpenMcp": "Enter 打开 MCP 管理器",
@@ -416,6 +459,7 @@
"HelpKeybindings": "快捷键",
"HelpUserCommands": "用户命令",
"HelpSkills": "技能",
"HelpFooterTypeFilter": " 输入以筛选 ",
"HelpFooterMove": " Up/Down 移动 ",
"HelpFooterJump": " PgUp/PgDn 跳转 ",
"HelpFooterClose": " Esc 关闭 ",
@@ -570,6 +614,8 @@
"PluginCtaInstallPrompt": "建议的插件:{name}",
"PluginCtaReview": "审查",
"PluginCtaInstall": "安装",
"PluginCtaReviewTrust": "审查信任",
"PluginCtaEnable": "启用",
"PluginCtaDismiss": "不再建议",
"PluginCtaDismissSaveFailed": "已在本次会话中隐藏,但无法保存插件偏好设置。",
"PluginSuggestionReason": "匹配“{trigger}”",
@@ -579,6 +625,7 @@
"CmdPluginActionFailed": "插件操作失败:{error}",
"CmdPluginNoneFound": "在 {dir} 未发现旧版可执行插件工具",
"CmdPluginNotFound": "未找到插件「{name}」",
"CmdPluginListHeader": "旧版可执行插件工具({count}):",
"CmdPluginDetailDescription": "描述:{description}",
"CmdPluginDetailSchema": "架构:\n{schema}",
"CmdPluginDetailApproval": "审批:{approval}",
@@ -628,6 +675,7 @@
"ModelsListHint": "已缓存的目录;运行 `codewhale models --update` 可更新已配置的提供商。",
"ModelsUpdateSummary": "模型目录:{updated} 个已更新,{loaded} 个从 Codex 加载,{failed} 个失败,{skipped} 个已跳过。",
"ModelsUpdatePartial": "部分目录无法更新。此前的模型和已配置的模型仍然可用。",
"ModelsCodexHint": "ChatGPT 模型通过 Codex 加载。查询时间并不代表提供商已刷新模型目录。",
"ModelsSourceFallback": "内置或已配置的模型;尚未验证可用性。",
"CmdModelDbDescription": "参考:浏览内置的模型数据库",
"CmdNetworkDescription": "管理网络允许和拒绝规则",
@@ -640,6 +688,7 @@
"CmdQueueDescription": "查看或编辑已排队的消息",
"CmdQueueUsage": "用法:/queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "已恢复上一会话中的 {count} 条排队消息。它们不会自动发送:/queue send <n> 发送其中一条,/queue clear 将其丢弃。",
"CmdQueueDraftHeader": "正在编辑已排队的消息:",
"CmdQueueNoMessages": "没有已排队的消息",
"CmdQueueListHeader": "已排队的消息 ({count}):",
"CmdQueueTip": "提示:/queue send <n> 立即发送,/queue drop <n> 删除",
@@ -773,10 +822,13 @@
"CmdTokensCacheHitOnly": "命中 {hit} / 未命中未上报",
"CmdTokensCacheMissOnly": "命中未上报 / 未命中 {miss}",
"CmdTokensCacheWriteTotal": "本次会话的缓存写入(创建)token:{write}。在公布写入加价的提供商处按高于输入价计费;逐回合明细见 /cache。",
"CmdTokensContextUnknownWindow": "~{estimated} / 窗口未知",
"CmdTokensContextWithWindow": "~{used} / {window}({percent}%)",
"FooterAgentSingular": "1 个智能体",
"FooterAgentsPlural": "{count} 个智能体",
"HeaderAgentsChip": "智能体 {count}",
"FooterPressCtrlCAgain": "再次按 Ctrl+C 退出",
"FooterWorking": "工作中",
"FooterBalancePrefix": "余额",
"HelpSectionActions": "操作",
"HelpSectionClipboard": "剪贴板",
@@ -789,6 +841,7 @@
"CmdTokensNotReported": "未上报",
"CmdTokensReport": "token 用量:\n─────────────────────────────\n活动上下文: {active}\n上次 API 输入: {input}(来自回合遥测;多轮工具调用中相同前缀可能被重复计入)\n上次 API 输出: {output}\n缓存命中/未命中: {cache}(仅用于遥测/计费)\n累计 token: {total}(会话用量遥测)\n已定价金额: {cost}\nAPI 消息数: {api_messages}\n聊天消息数: {chat_messages}\n模型: {model}",
"KbScrollTranscript": "滚动对话记录、浏览输入历史或选择附件",
"KbNavigateHistory": "浏览输入历史",
"KbBrowseHistory": "浏览对话历史",
"KbScrollTranscriptAlt": "滚动对话记录",
"KbScrollPage": "按页滚动对话记录",
@@ -822,6 +875,7 @@
"KbCompactContext": "压缩对话上下文",
"KbLastMessagePager": "打开最后一条消息的分页器(输入框为空时)",
"KbSelectedDetails": "显示所选工具或消息的原始详情;Ctrl+Alt+O 打开整回合概览",
"KbToolDetailsPager": "显示所选项的原始详情(Alt+V)",
"KbExternalEditor": "在外部编辑器中打开撰写中的草稿",
"KbLiveTranscript": "打开实时对话覆盖层(Ctrl+Shift+T;尾部自动滚动)",
"KbBacktrackMessage": "回退到之前的用户消息(左右键步进,Enter 回退)",
@@ -860,6 +914,8 @@
"KbHelpOverlay": "打开此帮助覆盖层(输入框为空时)",
"KbCycleWorkDock": "切换任务面板(待办、智能体、作业、后台),宠物模式下切换宠物视图",
"KbCycleWorkDockBack": "反向切换任务面板或宠物视图",
"KbToggleHelp": "切换帮助覆盖层",
"KbToggleHelpSlash": "切换帮助覆盖层",
"HelpUsageLabel": "用法:",
"HelpAliasesLabel": "别名:",
"SettingsTitle": "设置:",
@@ -960,8 +1016,10 @@
"HomeAgentModeReviewTip": " 用 /mode plan 先调研并提出计划",
"HomeAgentModeYoloTip": " Shift+Tab 循环权限:Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + 完全访问 — 工具无需先询问即可运行",
"HomeYoloModeCaution": " 破坏性操作可能立即执行;不确定时用 Ask",
"HomePlanModeTip": "Plan — 实现前先调研与设计",
"HomePlanModeChecklistTip": " 提交计划和待办进度,然后切换到 Work",
"HomeGoalModeTip": "Goal 跟踪 - 设置 /goal <目标> 以跟踪持久目标",
"OnboardLanguageTitle": "选择语言",
"OnboardLanguageBlurb": "选择界面语言。可随时使用 `/config locale <tag> --save` 修改。",
"OnboardProviderTitle": "选择模型提供商",
@@ -973,6 +1031,8 @@
"StepfunBillingRouteIntro": "StepFun 的按量付费与 Step Plan 订阅使用不同的端点。请选择与你的密钥匹配的一项。",
"StepfunBillingRoutePaygOption": "按量付费(按 token 计价)",
"StepfunBillingRoutePlanOption": "Step Plan 订阅(套餐额度)",
"StepfunPlanApiKeyHint": "使用 StepFun Step Plan 订阅时,请使用为 Step Plan 签发的密钥,而不是按量付费密钥。",
"StepfunPlanRouteHint": "此路由使用 {route},并从你的 Step Plan 额度中扣除。",
"OnboardApiKeyRejectedEnv": "来自 {env} 的 {provider} API 密钥被拒绝。请粘贴有效密钥并保存到 {path},或更新该环境变量。",
"OnboardTrustTitle": "了解此工作区",
"OnboardTrustQuestion": "是否允许 Codewhale 使用此工作区中的指令和文件开展工作?",
@@ -995,6 +1055,7 @@
"RedactionGateRollbackHint": "选择“保持开启”后,本次启动仍开启脱敏;由于配置仍为 \"disabled\",下次启动会再次询问。",
"RedactionGateSaveFailed": "无法保存确认。脱敏仍然开启。请重试或选择保持脱敏。",
"RedactionGateTitle": "模型边界密钥脱敏",
"OnboardOfflineOption": "Ctrl+O — 离线浏览:先随便看看,之后再连接提供商。",
"OnboardOfflineNotice": "正在离线浏览。尚未连接 — 想连接时请运行 /provider。",
"OnboardWelcomeTitle": "Codewhale 在这个文件夹里与你协作。",
"OnboardWelcomeLead": "我们来做好准备。",
@@ -1016,6 +1077,8 @@
"OnboardSeedCodeProject": "说明这个项目是做什么的,并列出主要入口。",
"OnboardSeedFolder": "看看这个文件夹,建议一个合适的第一个任务。",
"SetupWizardTitle": "设置",
"SetupWizardWhy": "此向导把设置进度记录到 setup_state.json;只有明确的步骤操作才会应用配置变更。",
"SetupWizardProgress": "步骤",
"SetupActionBack": "返回",
"SetupActionContinue": "继续",
"SetupActionSkip": "跳过",
@@ -1023,6 +1086,7 @@
"SetupActionScrollBody": "滚动正文",
"SetupActionGuided": "预览/确认",
"SetupActionTuneGuided": "调整",
"SetupActionModelDraft": "模型生成草案",
"SetupActionFreeform": "自定义准则",
"SetupActionKeepExisting": "保留现有",
"SetupActionUseRecommended": "使用推荐设置",
@@ -1031,7 +1095,13 @@
"SetupActionModel": "模型路由",
"SetupActionFleet": "Fleet 设置",
"SetupActionHotbar": "Hotbar 设置",
"SetupActionRemote": "远程入口",
"SetupActionMode": "模式选择",
"SetupActionConfig": "配置视图",
"SetupActionRuntimePreset": "预设",
"SetupActionApplyRuntimePreset": "预览/应用",
"SetupActionUseBundled": "使用内置",
"SetupActionDefer": "稍后",
"SetupActionCancel": "取消",
"SetupStatusNotStarted": "未开始",
"SetupStatusRecommended": "建议",
@@ -1071,6 +1141,7 @@
"SetupLanguageReviewed": "已记录设置语言。",
"SetupConstitutionChoiceLabel": "选择:",
"SetupConstitutionSourceLabel": "来源:",
"SetupConstitutionValidityLabel": "有效性:",
"SetupConstitutionPreviewLabel": "预览哈希:",
"SetupConstitutionExistingLabel": "现有文件:",
"SetupConstitutionExpertOverrideLabel": "专家覆盖:",
@@ -1111,6 +1182,8 @@
"SetupToolsMcpPluginsLabel": "插件:",
"SetupToolsMcpReviewHint": "按 Enter 记录当前工具/MCP 事实。按 R 查看安全引导(不会自动执行)。",
"SetupToolsMcpReviewed": "已记录工具/MCP 就绪状态。",
"SetupRemoteCloudsLabel": "云目标:",
"SetupRemoteBridgesLabel": "聊天桥:",
"SetupRemoteProvidersLabel": "提供商:",
"SetupRemoteModeLabel": "远程模式:",
"SetupRemoteModeLocalOnly": "仅本机:",
@@ -1182,6 +1255,7 @@
"CtxMenuCopyMessage": "复制消息",
"CtxMenuCopyMessageDesc": "将点击的记录条目写入剪贴板",
"CtxMenuOpenInEditor": "在编辑器中打开",
"CtxMenuOpenInEditorDesc": "在 $EDITOR 中打开 file:line",
"CtxMenuShowCell": "显示条目",
"CtxMenuShowCellDesc": "取消隐藏此记录条目",
"CtxMenuHideCell": "隐藏条目",
@@ -1216,9 +1290,17 @@
"FanoutCounts": "{done} 已完成 · {running} 运行中 · {failed} 失败 · {pending} 等待中",
"AppModeAgent": "Work",
"AppModeAuto": "自动",
"AppModeYolo": "完全访问(已弃用标签)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "在本会话直接工作 — 编辑与 shell 需批准",
"AppModeAutoHint": "启用 shell,并自动进行风险审查",
"AppModePlanHint": "先只读调研,行动前给出计划",
"AppModeYoloHint": "仅为兼容保留 — Work + 完全访问,不是可见模式",
"AppModeOperateHint": "全力版 Work:设目标、并行智能体,验证后才停",
"VimModeNormal": "-- 普通 --",
"VimModeInsert": "-- 插入 --",
"VimModeVisual": "-- 可视 --",
"ApprovalEffectReadsOnly": "只读",
"ApprovalEffectChangesFiles": "修改文件",
"ApprovalRiskDestructive": "无法撤销",
@@ -1246,6 +1328,7 @@
"ApprovalSaveAskRuleHint": " · s 本次允许,以后每次先询问",
"ApprovalOptionDeny": "不允许",
"ApprovalOptionAbortTurn": "停止本回合",
"ApprovalBlockTitle": "审批",
"ApprovalControlsHint": "Pg↑/↓ 回看 · {details} 更多选项 · Esc 停止",
"ApprovalOwnerHeader": "智能体:{agent} · {role}",
"ApprovalGoToAgent": "g 前往智能体",
@@ -1271,6 +1354,8 @@
"ApprovalTruncationHint": " … 已截断 · 按 {details} 查看完整内容",
"ApprovalAsksWithoutGit": "此文件夹没有 Git 仓库,因此编辑前会先询问。",
"ApprovalFullAccessPolicyBlocked": "已阻止 {tool}:Full Access 无法绕过此策略",
"ApprovalChooseHint": "选择: ",
"ApprovalChooseAction": "Enter 执行选中项,或直接按 y/a/d",
"ApprovalIntentLabel": "意图: ",
"ApprovalMoreLines": " … (还有 {count} 行)",
"ApprovalProceedQuestion": "是否继续?",
@@ -1310,10 +1395,12 @@
"ContextManualCompacting": "正在压缩上下文…",
"ContextCompactionQueued": "上下文压缩已排队,将在本回合结束后运行。",
"ContextCompactionAlreadyRunning": "上下文压缩已在进行中。",
"ContextCompactionQueueFull": "上下文压缩需要等待:引擎正忙。请在本回合结束后重试。",
"ContextCompactionQueueClosed": "无法压缩上下文:引擎已停止。",
"ContextCompactionRouteInvalid": "无法压缩,因为当前提供商路由无效:{error}",
"ContextCompactionStoppedOnEngineSwitch": "已停止压缩上下文;对话未被更改",
"ContextPurgeAbandonedOnEngineSwitch": "会话清理已随被替换的引擎一同放弃;对话未被更改",
"CtxInspTitle": "上下文检查器",
"CtxInspSessionContext": "会话上下文",
"CtxInspSystemPrompt": "系统提示结构",
"CtxInspReferences": "引用",
@@ -1545,21 +1632,45 @@
"SetupToolsMcpOnRampText": "工具、MCP、技能与插件 — 安全引导\n\n/setup 只读取本地清单。不会启动 MCP 服务器、安装技能、运行插件或自动执行不受信任的命令。\n\n当前清单:\n- MCP:{mcp_result}\n- 技能:{skills_result}\n- 工具目录:{tools_result}\n- 插件:{plugins_result}\n- 快捷栏(共享适配器):{hotbar_result}\n\n路径:\n- MCP:{mcp_path}\n- 技能:{skills_path}\n- 插件:{plugins_path}\n\n安全引导(请自行在终端或 TUI 中执行):\n- MCP:/mcp · codewhale mcp init · codewhale doctor\n- 技能:/skills · codewhale setup --skills\n- 插件:/plugin · codewhale setup --plugins\n- 工具:codewhale setup --tools\n\n有副作用的操作始终需要明确确认。详见 docs/MCP.md。",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — 通过 Codewhale 连接,绝不是第二个调度器:\n- 状态:{dsh_result}\n- 只读检测;连接/计划/启动/移除:codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale 只写入 $CODEWHALE_HOME/integrations/dsh,绝不复制 API 密钥或修改 DSH 文件。",
"HotbarActionModeOperateName": "Operate 模式",
"HotbarActionModeOperateDescription": "把一项持续的请求并行推进,直到通过验证。",
"HomeOperateModeTip": "Operate — 让 Fleet 并行开展工作",
"HomeOperateModeFleetTip": " 内置角色使用本会话的模型;/fleet setup 可自定义",
"HelpSubtitle": "命令、技能与快捷键",
"CommandPaletteTitle": "命令",
"CommandPaletteSubtitle": "查找并执行一个操作",
"ConfigSubtitle": "设置优先;原始键在高级详情",
"LaunchStartTitle": "从这里开始",
"LaunchResumeConfirm": "恢复 {title}?再次点击或按 Enter 确认。",
"LaunchResumeConfirmTitle": "恢复会话",
"LaunchResumeConfirmBody": "这会用该会话的历史替换当前上下文。",
"LaunchResumeConfirmResume": "恢复",
"LaunchResumeConfirmCancel": "取消",
"LaunchWorkDescription": "在此文件夹中工作;更改遵循你的权限设置。",
"LaunchChatDescription": "仅对话和规划;不会更改文件。",
"LaunchWorkspaceGitReady": "工作区 · {name} · Git 工作区",
"LaunchWorkspaceFolderReady": "工作区 · {name} · 本地文件夹",
"LaunchProviderConfigured": "提供商 · 已配置",
"LaunchProviderSetupNeeded": "提供商 · 需要设置",
"LaunchGroupContinue": "继续",
"LaunchGroupMore": "更多",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "文件夹",
"LaunchProviderConfiguredShort": "提供商已配置",
"LaunchProviderSetupShort": "设置提供商",
"LaunchMenuChangelog": "更新日志",
"LaunchWorktreePrompt": "为分支/工作树命名,或按 Enter 使用自动名称。 Esc 返回。",
"LaunchWorktreeNeedsGit": "新建工作树需要 Git 仓库。",
"LaunchWorktreeNameLabel": "工作树名称",
"LaunchHintMove": "移动",
"LaunchHintOpen": "打开",
"LaunchTipFlags": "提示:-w <path> 打开工作区;-r <session-id> 直接恢复",
"LaunchSavedSessionSingular": "已保存 1 个会话",
"LaunchSavedSessionsPlural": "已保存 {count} 个会话",
"LaunchCreatingWorktree": "正在创建工作树…",
"LaunchWorktreeFailed": "工作树创建失败:{error}",
"LaunchWorktreeCreated": "新工作树 {path},分支 {branch}",
"LaunchNoSavedSessions": "此工作区没有已保存的会话。",
"LaunchNoModelConnected": "未连接模型",
"DispatchNotSentNoModel": "尚未连接模型,因此这条消息没有发送。消息已放回输入框:用 F3 或 /provider 连接模型,然后按 Enter 发送。",
"DispatchNotSentSaveKey": "保存密钥:{command}",
@@ -1572,6 +1683,10 @@
"LocalModelAdopted": "正在使用 {model},这是在本机运行的模型(Ollama)。按 F3 可选择其他模型。",
"ProviderPickerNotReopened": "无法重新打开提供商列表。按 F3 打开。",
"LaunchRunCommand": "运行 {command}",
"LaunchMcpConnectedOne": "已连接 1 个 MCP 服务器",
"LaunchMcpConnectedMany": "已连接 {count} 个 MCP 服务器",
"LaunchMcpNeedsSignInOne": "1 个需要登录",
"LaunchMcpNeedsSignInMany": "{count} 个需要登录",
"PhaseIdle": "空闲",
"PhaseDraft": "草稿",
"PhaseWorking": "工作中",
@@ -1586,6 +1701,7 @@
"PhaseFinishing": "收尾中",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "只读",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1593,12 +1709,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "权限已更改为 {label}",
"FooterHintKeys": "快捷键",
"FooterHintOutput": "输出",
"FooterHintContext": "上下文",
"InfoLineHelp": "帮助",
"InfoLineContext": "上下文",
"InfoLineTtft": "ttft",
"InfoLinePeak": "高峰",
"InfoLineOffPeak": "错峰",
"InfoLineWhales": "鲸鱼",
"InfoLineAutomation": "自动化",
"InfoLineNotConnected": "未连接",
"InfoLineThinking": "思考:{level}",
"EmptyStateNoGit": "无 git",
@@ -1694,6 +1814,7 @@
"RouteActionSearchAnyModel": "搜索任意模型",
"RoutePanelHeader": "路由",
"RouteProviderLabel": "提供商",
"RouteModelFirstAtomic": "模型优先的原子路由",
"PickerActionMove": "移动",
"PickerActionSwitch": "切换",
"PickerActionApply": "应用",
@@ -1710,6 +1831,7 @@
"PickerActionClearSearch": "清除搜索",
"PickerActionBrowseAll": "浏览全部",
"PickerActionCustom": "自定义",
"PickerActionJump": "跳转",
"PickerActionEditKey": "编辑密钥",
"PickerActionModels": "模型",
"PickerActionUnavailable": "不可用",
@@ -1725,6 +1847,9 @@
"ProviderExternalActionRevoke": "停止使用该登录",
"ProviderExternalActionChoices": "通过其他应用登录",
"ProviderExternalActionReuseGrok": "复用外部Grok凭据",
"ProviderExternalHintCodexReview": "完成 {login} 后,按Enter查看禁用、只读和托管访问选项。",
"ProviderExternalHintXaiReview": "按Enter使用Codewhale自有的设备登录;按E查看现有Grok CLI凭据复用。",
"ProviderExternalHintXaiApiKey": "也可以使用XAI_API_KEY,然后重新打开此选择器。",
"XaiAuthChoiceTitle": " xAI 身份验证 ",
"XaiAuthChoiceIntro": "请选择一个明确的凭据来源。密钥文本绝不会被当作 OAuth 令牌。",
"XaiAuthChoiceApiKeyOption": "xAI API 密钥 — 输入或粘贴,然后保存到 xAI 提供商槽位",
@@ -1736,6 +1861,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT / Codex 身份验证 ",
"ChatgptAuthChoiceIntro": "订阅登录计入你的 ChatGPT 套餐。openai API 密钥路径属于另一计费主体。",
"ChatgptAuthChoicePkceOption": "使用 ChatGPT 登录 — 浏览器 PKCE、Codewhale 自有令牌、ChatGPT 订阅计费",
"ChatgptAuthChoiceImportOption": "导入 Codex CLI 凭据 — 显式只读授权;所有者仍是 Codex CLI",
"ProviderExternalHintChatgptReview": "按 Enter 使用 ChatGPT 登录;按 E 查看现有 Codex CLI 复用。",
"ProviderExternalActionReuseCodex": "外部 Codex 复用",
"ProviderExternalDetailScope": "外部凭据:访问={access} | 提供商={provider} | 来源={source} | 版本={version} | {state}",
"ProviderExternalDormant": "休眠",
"ProviderExternalOwnerPath": "所有者/路径:{owner} | {path}",
@@ -1746,6 +1874,7 @@
"SnapshotsDisabledUnsafeLocation": "此工作区 {workspace} 的快照与 /undo 已关闭:主目录或根目录范围过大,无法安全快照。请在项目目录中启动即可开启。",
"SnapshotsHistoryRepaired": "{workspace} 的撤销历史已损坏(缺少最新的恢复点),已重新开始记录。之前的恢复点无法再恢复;新的回合重新受到保护。",
"SnapshotsFailing": "{workspace} 的快照持续失败,因此 /undo 无法恢复最近的回合:{limit}",
"SessionIdDivergedNotice": "此窗口下的会话身份已更改:引擎现在以 {next} 保存检查点(之前为 {previous})。较早的检查点仍保留在旧 ID 下;`codewhale sessions` 会列出两者,`codewhale resume {previous}` 可重新打开较早的会话。",
"RuntimeStoreUnreadableNotice": "会话运行时存储:无法读取 {path} 处的 {record}({reason})。请将该文件移开(或删除)后重试;线程的其他记录保持不变。",
"RuntimeStoreUnwritableNotice": "会话运行时存储:无法写入 {path} 处的 {record}({reason})。请检查该位置的可用空间和权限后重试;没有任何内容被覆盖。",
"ProviderExternalSemanticsRevoke": "{semantics} | 撤销:{revoke}",
@@ -1784,6 +1913,7 @@
"FleetRosterTabSetup": "设置",
"FleetRosterWorkers": "智能体",
"FleetRosterMembersCount": "{count} 个成员",
"FleetRosterOperatorFirst": "协调者统领 · 会话模型驱动此 Fleet",
"FleetRosterOperatorRow": "协调者 · 你",
"FleetRosterShadowBadgeProjectOverride": "已保存到本项目",
"FleetRosterShadowBadgePersonalIgnored": "已保存副本被忽略",
@@ -1806,6 +1936,7 @@
"FleetModelReasonOperatorRoute": "这是你当前的模型(Fleet 的协调者路由);请切换模型或使用 /fleet save 更改",
"FleetModelReasonAlreadyPresent": "已在 Fleet 中",
"FleetModelErrorNeedsRoute": "Fleet 模型必须同时指定提供商 ID 和模型 ID",
"FleetModelErrorNeedsRole": "智能体需要一个角色名称(例如 `/fleet add {route} scout`)。",
"FleetModelErrorNoSelection": "未选择 Fleet;你的 Fleet 仅包含会话模型",
"FleetModelErrorOperatorRoute": "{route} 是 Fleet `{fleet}` 的协调者路由;请用 /fleet save 更改,不能直接移除",
"FleetModelErrorNotInFleet": "{route} 不在 Fleet `{fleet}` 中",
@@ -1924,6 +2055,7 @@
"FilePickerMatchSingular": "@ 附加 · 1 个匹配",
"FilePickerMatchesPlural": "@ 附加 · {count} 个匹配",
"FilePickerScanning": "正在扫描工作区…",
"BehavioralTipPlanning": "在规划?按 {key} 可切换到 Plan 模式",
"BehavioralTipBackgroundReceipt": "回执在 Work 面板中 — 按 {key} 打开检查器",
"BehavioralTipClearedInput": "已清空 · 按 {chord} 恢复",
"BehavioralTipMcpValidation": "{command} 会启动服务器并显示原因",
@@ -1937,6 +2069,7 @@
"SettingSubjectModelAndThinking": "模型与思考",
"SettingSubjectProvider": "提供商",
"SettingSubjectPermissions": "权限",
"ThinkingControlledByAutoRouting": "思考由自动模型路由控制;请先选择固定模型。",
"SavedAsStartupDefault": "已保存为启动默认值",
"ModeAlreadyActiveSavedAsDefault": "已处于 {mode} 模式 — 已保存为启动默认值。",
"StartupDefaultNotSaved": "{setting}未能保存:{error}",
@@ -1956,6 +2089,11 @@
"StartupDefaultSubjectThinking": "思考级别",
"StartupDefaultSubjectModel": "模型",
"StartupDefaultSubjectAll": "启动默认值",
"SessionsRailTitle": "会话",
"SessionsRailEmpty": "此工作区尚无会话",
"SessionsRailBrowseAll": "浏览所有会话",
"SessionsRailShowingCount": "{total} 个中的 {shown} 个 — 浏览全部",
"SessionsRailUnavailable": "无法读取会话:{error}",
"SessionsActionArchive": "归档",
"SessionsActionShowArchived": "已归档",
"SessionsArchived": "已归档会话 {id}",
@@ -2143,6 +2281,7 @@
"FooterHintForAgents": "智能体",
"FooterHintToManage": "管理",
"AgentRailQueuedCount": "{count} 条排队",
"WorkbarSoFar": "目前 {done}/{total}",
"WorkbarLargeWorkflow": "大型工作流",
"WorkbarMoreRuns": "还有 {count} 个",
"WorkflowLineStarted": "已开始",
@@ -2150,6 +2289,7 @@
"WorkflowLineFinishedWithGaps": "已完成但有缺口",
"WorkflowLineFailed": "失败",
"WorkflowLineStopped": "已停止",
"WorkflowLineAgents": "{done}/{total} 个智能体",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "可写入",
"AgentFocusPostureReadOnly": "只读",
@@ -2159,6 +2299,7 @@
"AgentFocusPostureShellReadOnly": "只读 shell",
"AgentFocusPostureShellNone": "无 shell",
"GoalReceiptSet": "已设置目标:“{objective}” · /goal 查看进度 · /goal pause 或 /goal clear 停止",
"GoalReceiptSetOperate": "◆ 已设置目标 · Operate 会持续工作直到验证完成 · /goal 可编辑",
"GoalControlAccepted": "目标控制已保存;将在下一个安全边界应用。",
"GoalControlRuntimeUnavailable": "目标控制已保存,但运行时当前不可用。重启后将恢复该状态。",
"GoalStatusIdleHint": "当前未运行 — 发送消息或 /goal resume 以继续",
@@ -2168,6 +2309,9 @@
"GoalContinuationWaiting": "目标运行中 · {delay} 后开始下一回合 · 按 Esc、Ctrl+C 或使用 /goal pause 可停止待执行的继续操作",
"GoalContinuationReady": "目标继续操作已就绪;队列中的控制命令会在下一回合之前执行。",
"GoalContinuationStopped": "已停止待执行的目标继续操作;目标仍保持运行状态。",
"McpCapabilitiesAdvertised": "已声明的能力:{capabilities}",
"McpCapabilitiesLegacyFallback": "已声明的能力:未提供;使用旧版发现回退",
"McpCapabilitiesNotObserved": "已声明的能力:服务器未连接,尚未观测",
"PickerActionTestConnection": "测试连接",
"ProviderCustomFormBaseUrl": "基础 URL",
"ProviderCustomFormModel": "默认模型",
@@ -2187,6 +2331,7 @@
"OperateBoardGantt": "甘特图 时间 →",
"ConfigCategoryAppearance": "外观",
"ConfigCategoryModelsProviders": "模型与提供商",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "工作",
"ConfigCategoryToolsMcp": "工具与 MCP",
"ConfigCategoryTrust": "信任",
@@ -2222,6 +2367,7 @@
"ConfigKindReadOnly": "只读",
"ConfigRowActionNote": "操作 · 非持久化设置",
"ConfigRowDiagnosticNote": "观测回执 · 此处不可编辑",
"ConfigNavHint": "←/→ 或 Tab 切换类别 · ↑/↓ 切换设置",
"ConfigActivateAgain": "按 Enter 或再次点击:",
"ConfigSearchLabel": " 搜索:",
"ConfigEditChooseLabel": "选择:",
@@ -2244,6 +2390,7 @@
"ConfigChoiceNever": "从不",
"ConfigChoiceModeAct": "Work",
"ConfigChoiceModePlan": "Plan(只读)",
"ConfigChoiceModeOperate": "Operate",
"ConfigChoicePlacementTop": "顶部",
"ConfigChoicePlacementBottom": "底部栏",
"ConfigChoicePlacementLeft": "左侧边栏",
@@ -2260,8 +2407,10 @@
"ConfigChoiceDetailAutoReview": "自动审核工具风险,需要你决定时才询问。",
"ConfigChoiceDetailUseTuiDefault": "移除根配置覆盖,使用已保存的 TUI 权限选择。",
"ConfigChoiceDetailFullAccess": "工具会不经询问直接运行,命令可以访问这台电脑上的任何内容。",
"ConfigChoiceDetailNever": "阻止所有需要审批的工具。",
"ConfigChoiceDetailModeAgent": "以可协作并使用工具的状态开始。",
"ConfigChoiceDetailModePlan": "在只读的规划工作区中开始。",
"ConfigChoiceDetailModeOperate": "Operate 是全力版的 Work:每个实质性请求都会变成目标,交给工作流和并行智能体推进,由独立审核者检查,直到通过验证才停止。",
"ConfigChoiceDetailPlacementTop": "在对话记录上方显示任务、待办和智能体。",
"ConfigChoiceDetailPlacementBottom": "在输入框下方显示任务、待办和智能体。",
"ConfigChoiceDetailPlacementLeft": "终端足够宽时,在左侧任务面板中显示任务、待办和智能体。",
@@ -2279,6 +2428,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "填充模型推理的背景。",
"ConfigChoiceDetailThinkingHighlightOff": "保留虚线推理边栏和斜体文字,不填充背景。",
"ConfigHintModel": "本会话实时路由的模型;按 Enter 打开 /model",
"ConfigHintFastModel": "当提供商有已知的同系模型时,供 Auto 路由和 model_strength=faster 使用",
"ConfigHintProvider": "凭据、模型和端点一起切换",
"ConfigHintApprovalMode": "仅本会话:询问 | 自动审核 | 完全访问",
"ConfigHintPermissionPosture": "新会话的默认值:询问 | 自动审核 | 完全访问",
@@ -2313,6 +2463,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "整数(允许 0) · 保留的已发送消息数,用于调出和历史搜索",
"ConfigHintAutoCompactThreshold": "10..=100 · 压缩阈值:触发自动压缩时占可用上下文长度的百分比",
"ConfigHintDefaultModel": "仅 DeepSeek 的旧版回退;其他提供商使用上方按提供商划分的模型",
"ConfigHintReasoningEffort": "default 恢复该模型自身的默认值;常开思考模型没有 off",
"ConfigHintMcpOpen": "打开 MCP 管理器 · 连接 / 重连 / 重新认证 / 诊断",
"ConfigHintMcpReconnect": "重连 MCP · /mcp reload",
@@ -2325,8 +2476,11 @@
"ConfigHintFeatureApplyPatch": "补丁编辑工具的只读功能开关状态",
"ConfigHintFeatureMcp": "MCP 工具的只读功能开关状态",
"ConfigHintFeatureExecPolicy": "执行策略工具的只读功能开关状态",
"ConfigHintFeatureVisionModel": "视觉/模型图像支持的测试版功能开关",
"ConfigHintGoalCommand": "/goal 设置目标、预算和工作上下文状态",
"ConfigHintWorkflow": "/workflow 运行带扇出/扇入运行卡片的脚本化操作",
"LaunchMenuNewWorktree": "新建工作树",
"LaunchMenuResume": "恢复会话",
"LaunchMenuQuit": "退出",
"LaunchNoticeClaude": "检测到 Claude Code。用 /import-claude 复核;每项更改都需你确认。",
"LaunchNewSession": "新建会话",
@@ -2334,7 +2488,9 @@
"LaunchRecentResumeHint": "↑ 恢复",
"LaunchHelpLine": "/help 查看命令 · {dock} 打开任务面板",
"LaunchSeeAllSessions": "查看全部会话…",
"LaunchNoRecentSessions": "暂无最近会话 — 在下方输入以开始。",
"LaunchResumeFailed": "恢复失败:{error}",
"ReceiptSessionHooks": "钩子 {count}",
"AutomationEditorNew": "新建自动化",
"AutomationEditorEdit": "编辑自动化",
"AutomationEditorSchedule": "运行计划",
@@ -2490,6 +2646,7 @@
"WorkflowSettledOfTotal": "{done}/{total} 已完成",
"WorkflowPhaseCountOne": "{count} 个阶段",
"WorkflowPhaseCountMany": "{count} 个阶段",
"WorkflowPhaseOrdinal": "阶段 {n}/{total}",
"ModelPickerPinned": "已固定 {route}",
"ModelPickerUnpinned": "已取消固定 {route}",
"ModelPickerPinFailed": "无法更新固定:{error}",
@@ -2503,6 +2660,7 @@
"AuthReplacedPreviousSignInAs": "已替换之前的 Codewhale {provider} 登录({account})。",
"AuthReplacedPreviousSignIn": "已替换之前的 Codewhale {provider} 登录。",
"AuthSameAccountAsBefore": "这与之前是同一个账户;如需使用其他 {provider} 账户,请先在浏览器中退出该账户(或使用无痕窗口),然后重新登录。",
"AuthEnvTokenOutranksSignIn": "此环境中设置了 OPENAI_CODEX_ACCESS_TOKEN 或 CODEX_ACCESS_TOKEN,其优先级高于本次登录;在取消设置之前,请求将继续使用该令牌对应的账户。",
"PinnedPromptJumpToMessage": "跳转到这条消息",
"PlanHandoffHeader": "计划已就绪",
"PlanHandoffQuestion": "你想如何继续?",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "按 Enter 打开浏览器登录,按 Esc 返回。不需要 API Key。",
"PluginOAuthReady": "{provider}:已登录,请选择模型。",
"PluginOAuthLocalLogout": "{provider}:已删除本机登录凭据,未撤销服务端授权。",
"CmdConnectDescription": "通过浏览器登录连接插件提供方",
"CmdDisconnectDescription": "删除插件提供方的本机登录凭据",
"ExecAutoHelp": "启用工具,自动批准并使用 Full Access(无 shell 沙盒,开启信任模式),除非已配置更严格的沙盒;使用 --sandbox workspace-write 可限制文件和 shell 写入。",
"ExecSandboxHelp": "本次运行的沙盒策略;danger-full-access 以外的任何 --sandbox(或配置中等效的 sandbox_mode)都会关闭信任模式。",
+159
View File
@@ -41,10 +41,13 @@
"MobileStreamClosed": "Runtime 已關閉此對話的事件串流;請重新開啟對話",
"MobileStreamReconnecting": "連線已中斷;正在重新連線",
"MobileStreamConnected": "已連線",
"PetHabitatTitle": "CODEWHALE / WHALESONG · 共享棲息地",
"PetHabitatHints": "{back} 返回 · {sound} 聲音 · {browser} 外觀 · {window} 視窗",
"PetHabitatQueued": "已傳送到共享棲息地。/pet on 顯示寵物與訊息框。",
"PetWatchSoundOn": "聲音已開啟",
"PetWatchSoundOff": "聲音已關閉",
"PetWatchSoundPaused": "聲音已暫停",
"PetWatchSoundUnavailable": "Codewhale 聲音已停止。請檢查 FFmpeg (ffplay) 和音訊輸出,然後重新開啟聲音。",
"CmdPetDescription": "將動畫寵物設為 Codewhale 主檢視",
"ConfigLabelPetMode": "寵物模式",
"ConfigHintPetMode": "啟動 Codewhale 時,將動畫寵物設為主介面。",
@@ -77,11 +80,15 @@
"PetModeOffLabel": "寵物模式已關閉",
"PetViewOpen": "棲息地已開啟",
"PetViewClosed": "棲息地已關閉",
"PetWatchRestored": "/pet 已還原此工作階段的棲息地,正在等待新的遙測資料。",
"PetWatchStorageUnavailable": "Watch 無法還原或儲存此棲息地。現有檔案已保留。使用 {command} 匯出本次執行。",
"PetWatchExported": "Watch 重播已儲存:{path}",
"PetWatchExportFailed": "無法儲存 Watch 重播,記錄仍保留在記憶體中。",
"PetWatchExportQueued": "正在儲存 Watch 重播…",
"PetWatchExportUnavailable": "請在已儲存的工作階段中開啟 /pet,或等待目前的匯出完成。",
"PetUnobserved": "休息中",
"PetOffline": "離線 — 執行 codewhale pet serve 喚醒它",
"PetDozing": "打盹",
"PetWatchUnavailable": "寵物遙測已暫停。/pet on 重試。",
"ConversationChangedBeforeUndo": "復原完成前,對話已發生變更。未復原任何內容,也未送出重試請求。請先檢查目前的對話,再重試。",
"SessionArchiveExported": "工作階段已匯出",
@@ -93,6 +100,7 @@
"ExtensionsActionEdit": "編輯",
"ExtensionsHooksAddLabel": "新增掛鉤",
"ExtensionsHooksAddDescription": "在你的編輯器中開啟本專案的掛鉤檔案",
"ExtensionsActionReload": "重新載入",
"ExtensionsActionConnect": "連線",
"ExtensionsActionReconnect": "重新連線",
"ExtensionsActionReauth": "重新登入",
@@ -151,12 +159,14 @@
"ExtensionsStateConnected": "已連線",
"ExtensionsStateEnabled": "已啟用",
"ExtensionsStateError": "錯誤",
"ExtensionsStateInactive": "未啟用",
"ExtensionsStateInapplicable": "不適用",
"ExtensionsStateInvalid": "無效",
"ExtensionsStateNotInspected": "尚未檢查",
"ExtensionsStateDisconnected": "已中斷",
"ExtensionsStateRejected": "已拒絕",
"ExtensionsStateReviewedCandidate": "已審查候選",
"ExtensionsStateUnderEvaluation": "評估中",
"ExtensionsStateUnstaged": "尚未暫存",
"ExtensionsStateUnsupported": "不支援",
"ExtensionsStateWarning": "警告",
@@ -187,6 +197,7 @@
"ComposerHintSendIntoTurn": "↵ 送進本回合",
"ComposerHintLongDraft": "{shortcut}:外部編輯器",
"PendingSendingIntoTurnPrefix": " ↳ 正在送進本回合: ",
"PendingCouldNotSendIntoTurnPrefix": " ↳ 留待下一回合: ",
"PendingEditingFollowUpPrefix": " ↳ 正在編輯後續訊息: ",
"PendingQueuedOnePrefix": "已排隊 #1: ",
"PendingQueuedManyPrefix": "已排隊 {count} · 下一則: ",
@@ -214,6 +225,18 @@
"HistoryNoMatches": " 無相符",
"TranscriptReasoningExpand": "展開",
"TelemetryNoticeDefaultOn": "使用統計預設開啟。 向 Codewhale 和資料處理方 PostHog 分享版本/平台、工作階段、功能和錯誤的彙總計數。也統計服務商、公開目錄中的模型、Token 總數和內建工具的使用次數。不收集內容或 IP。docs/TELEMETRY.md 關閉: codewhale config set telemetry false",
"TelemetryNoticeHeadline": "Codewhale 使用統計",
"TelemetryNoticeBody": "Codewhale 只統計:您執行的版本、作業系統和 CPU 系列、工作階段時間和結果,\n以及彙總的功能和錯誤計數。\n\n也統計你使用的服務商和公開目錄中的模型、其 Token 總數,以及每個內建工具的執行次數。\n\n它絕不會收集您的對話、程式碼、提示詞、檔案、儲存庫名稱或分支名稱、\n模型內容或憑證,也絕不會傳送逐回合或逐工具記錄的代理活動。\n\n系統只使用儲存在此機器上的隨機 ID 來識別您,該 ID 每 90 天更換一次。\n您可以隨時更改:\n codewhale config set telemetry false\n\n逐欄位完整結構:docs/TELEMETRY.md\n\n使用統計預設開啟。 設定傳送後,Codewhale 和 PostHog 會處理這些計數。不收集 IP。",
"TelemetryNoticeCompactBody": "統計:版本、系統/處理器、工作階段時間/結果、功能/錯誤總數。\n另計:服務商/模型、Token、工具使用。\n隨機本機識別碼每 90 天更換。\n絕不收集:對話/程式碼/提示詞/檔案/名稱、模型內容/憑證、逐回合/工具記錄的活動。\n結構:docs/TELEMETRY.md\n關閉:codewhale config set telemetry false\n使用統計預設開啟。 設定傳送後,Codewhale 和 PostHog 會處理這些計數。不收集 IP。",
"TelemetryNoticeChoiceKeep": "是,保留匿名使用統計",
"TelemetryNoticeChoiceDisable": "不,關閉匿名統計",
"TelemetryNoticeActionChoose": "選擇",
"TelemetryNoticeActionConfirm": "確認",
"TelemetryNoticeActionExit": "離開",
"TelemetryNoticeReceiptEnabled": "匿名使用統計已開啟。絕不收集對話或程式碼。可在 /settings 中更改;完整結構:docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabled": "匿名使用統計已關閉。之後不會再次詢問。",
"TelemetryNoticeReceiptEnabledUnsaved": "此工作階段已開啟匿名使用統計。Codewhale 無法儲存此提示,因此會再次顯示。可在 /settings 中更改;完整結構:docs/TELEMETRY.md",
"TelemetryNoticeReceiptDisabledUnsaved": "此工作階段已關閉匿名使用統計。Codewhale 無法儲存此選擇,因此下次啟動時會再次詢問。",
"TelemetryPreferenceEnabledNextLaunch": "匿名使用統計將在下次啟動時開啟。絕不收集對話或程式碼。",
"TelemetryPreferenceDisabled": "匿名使用統計已關閉。本機遙測資料已清除。",
"TelemetryPreferenceDisabledWithWarning": "匿名使用統計已關閉,但部分清理需要注意:{detail}",
@@ -258,6 +281,7 @@
"HotbarSetupNoActions": "沒有可用的 Hotbar 操作。",
"HotbarSetupRecommended": "薦",
"HotbarSetupEmptySlot": "空",
"HotbarSetupHelp": "Tab/Shift+Tab 來源 Up/Down 操作 1-8 槽位 Enter 分配 Space 切換 Delete 清除 s 儲存 Esc 取消",
"HotbarActionVoiceToggleName": "語音輸入",
"HotbarActionVoiceToggleDescription": "切換終端麥克風語音擷取。",
"HotbarActionSessionCompactName": "壓縮工作階段",
@@ -267,8 +291,10 @@
"HotbarActionModeAgentName": "Work 模式",
"HotbarActionModeAgentDescription": "在目前工作階段直接工作。",
"HotbarActionModeYoloName": "完整存取 (Work)",
"HotbarActionModeYoloDescription": "相容項:Work 模式 + 完整存取權限(不是獨立模式)。",
"HotbarActionReasoningCycleName": "切換思考強度",
"HotbarActionReasoningCycleDescription": "輪換目前供應商設定的思考強度。",
"HotbarActionReasoningCycleAutoDisabled": "思考強度由自動模型路由控制。",
"HotbarActionSidebarToggleName": "切換側邊欄",
"HotbarActionSidebarToggleDescription": "顯示或隱藏側邊欄。",
"HotbarActionFileTreeToggleName": "切換檔案樹",
@@ -285,6 +311,7 @@
"ConfigNoSettings": " 沒有可用設定。",
"ConfigNoMatchesPrefix": " 沒有相符設定: ",
"ConfigFilteredSettings": " 已篩選設定",
"ConfigShowing": " 顯示",
"ConfigFooterDefault": " 輸入=篩選, Up/Down=選擇, Enter=編輯, Esc=關閉 ",
"ConfigFooterScrollable": " 輸入=篩選, Up/Down=選擇, Enter=編輯, PgUp/PgDn=捲動, Esc=關閉 ",
"ConfigFooterFiltered": " 輸入=篩選, Backspace=刪除, Ctrl+U/Esc=清除, Enter=編輯 ",
@@ -310,6 +337,7 @@
"ConfigPromptSuggestionUpdated": "prompt_suggestion = {value}({scope};輸入建議從下一回合起生效)",
"ConfigNotificationsSetHint": "使用 /config notifications <key> <value> [--save] 設定。",
"ConfigNotificationUpdated": "notifications.{key} = {value}({scope};套用於後續通知)",
"ConfigNotificationsWholeNumber": "notifications.threshold_secs 必須是整數",
"ConfigAuditSearchProvider": "寫入 [search] provider;後續 web_search 仍會遵循環境變數覆寫。",
"ConfigAuditPromptSuggestion": "寫入頂層 prompt_suggestion;幽靈文字提示仍須主動啟用。",
"ConfigAuditNotifications": "寫入 [notifications] 純量值,並套用於後續的回合完成通知。",
@@ -332,6 +360,8 @@
"ConfigLabelProviderUrl": "供應商 API 地址",
"ConfigHintProviderUrl": "目前的供應商端點;Xiaomi:token 方案 | 按量付費 | 自訂 URL",
"ConfigLabelModel": "目前供應商模型",
"ConfigLabelFastModel": "快速模型(派生)",
"ConfigLabelDefaultModel": "舊版後備模型(僅 DeepSeek 路由)",
"ConfigLabelReasoningEffort": "思考強度",
"ConfigLabelFleetSpawnDepth": "代理巢狀深度",
"ConfigLabelApprovalMode": "本工作階段權限",
@@ -345,6 +375,7 @@
"ConfigHintTelemetry": "僅向 Codewhale 和 PostHog 傳送版本、工作階段、功能和錯誤的彙總計數;絕不傳送內容或 IP。docs/TELEMETRY.md",
"ConfigValueTelemetryOn": "開啟",
"ConfigValueTelemetryOff": "關閉",
"ConfigLabelStreamTimeout": "流式逾時",
"ConfigLabelTheme": "主題",
"ConfigLabelLocale": "語言",
"ConfigLabelBackground": "背景",
@@ -368,6 +399,7 @@
"ConfigLabelThinkingHighlight": "思考背景醒目提示",
"ConfigLabelShowToolDetails": "工具詳情級別",
"ConfigLabelInlineDiffs": "內聯檔案更改",
"ConfigLabelStatusIndicator": "狀態指示器",
"ConfigLabelSynchronizedOutput": "輸出節奏",
"ConfigLabelCostCurrency": "費用幣別",
"ConfigLabelTranscriptSpacing": "對話間距",
@@ -375,7 +407,16 @@
"ConfigLabelComposerDensity": "輸入框密度",
"ConfigLabelComposerBorder": "輸入框邊框",
"ConfigLabelComposerMultilineMode": "輸入框多行模式",
"ConfigLabelComposerVimMode": "輸入框 Vim 模式",
"ConfigLabelBracketedPaste": "括號粘貼",
"ConfigLabelPasteBurstDetection": "粘貼檢測",
"ConfigLabelMentionMenuLimit": "提及選單上限",
"ConfigLabelMentionMenuBehavior": "提及選單行為",
"ConfigLabelMentionWalkDepth": "檔案提及深度",
"ConfigLabelWorkspaceFollowSymlinks": "跟隨符號鏈接",
"ConfigLabelContextPanel": "上下文面板",
"ConfigLabelSessionsRail": "工作階段欄",
"ConfigLabelSessionAutoResume": "自動還原上次工作階段",
"ConfigLabelAutoCompact": "自動壓縮",
"ConfigLabelAutoCompactThreshold": "壓縮閾值",
"ConfigLabelMaxHistory": "輸入歷史",
@@ -387,7 +428,9 @@
"ConfigLabelGoalCommand": "目標指令",
"ConfigLabelWorkflow": "工作流程",
"ConfigLabelFeaturePrefix": "功能:{name}",
"ConfigColumnSetting": "設定",
"ConfigColumnValue": "值",
"ConfigColumnScope": "範圍",
"ConfigActionOpenProvider": "按 Enter 開啟供應商選擇器",
"ConfigActionOpenModel": "按 Enter 開啟模型選擇器",
"ConfigActionOpenMcp": "Enter 開啟 MCP 管理員",
@@ -414,6 +457,7 @@
"HelpKeybindings": "快捷鍵",
"HelpUserCommands": "使用者指令",
"HelpSkills": "技能",
"HelpFooterTypeFilter": " 輸入以篩選 ",
"HelpFooterMove": " Up/Down 移動 ",
"HelpFooterJump": " PgUp/PgDn 跳轉 ",
"HelpFooterClose": " Esc 關閉 ",
@@ -568,6 +612,8 @@
"PluginCtaInstallPrompt": "建議的外掛:{name}",
"PluginCtaReview": "審查",
"PluginCtaInstall": "安裝",
"PluginCtaReviewTrust": "審查信任",
"PluginCtaEnable": "啟用",
"PluginCtaDismiss": "不再建議",
"PluginCtaDismissSaveFailed": "已在本次工作階段中隱藏,但無法儲存外掛偏好設定。",
"PluginSuggestionReason": "符合「{trigger}」",
@@ -577,6 +623,7 @@
"CmdPluginActionFailed": "外掛操作失敗:{error}",
"CmdPluginNoneFound": "在 {dir} 未發現舊版可執行外掛工具",
"CmdPluginNotFound": "未找到外掛「{name}」",
"CmdPluginListHeader": "舊版可執行外掛工具({count}):",
"CmdPluginDetailDescription": "描述:{description}",
"CmdPluginDetailSchema": "架構:\n{schema}",
"CmdPluginDetailApproval": "核准:{approval}",
@@ -626,6 +673,7 @@
"ModelsListHint": "已快取的目錄;執行 `codewhale models --update` 可更新已設定的供應商。",
"ModelsUpdateSummary": "模型目錄:{updated} 個已更新,{loaded} 個從 Codex 載入,{failed} 個失敗,{skipped} 個已略過。",
"ModelsUpdatePartial": "部分目錄無法更新。先前的模型和已設定的模型仍然可用。",
"ModelsCodexHint": "ChatGPT 模型透過 Codex 載入。查詢時間並不代表供應商已重新整理模型目錄。",
"ModelsSourceFallback": "內建或已設定的模型;尚未驗證可用性。",
"CmdModelDbDescription": "參考:瀏覽內置的模型資料庫",
"CmdNetworkDescription": "管理網路允許和拒絕規則",
@@ -638,6 +686,7 @@
"CmdQueueDescription": "檢視或編輯已排隊的訊息",
"CmdQueueUsage": "用法: /queue [list|send <n>|edit <n>|drop <n>|clear]",
"QueueRestoredFromPreviousSession": "已還原上一個工作階段中的 {count} 則排隊訊息。它們不會自動送出:/queue send <n> 送出其中一則,/queue clear 將其捨棄。",
"CmdQueueDraftHeader": "正在編輯已排隊的訊息:",
"CmdQueueNoMessages": "沒有已排隊的訊息",
"CmdQueueListHeader": "已排隊的訊息 ({count}):",
"CmdQueueTip": "提示: /queue send <n> 立即傳送, /queue drop <n> 刪除",
@@ -771,10 +820,13 @@
"CmdTokensCacheHitOnly": "命中 {hit} / 未命中未上報",
"CmdTokensCacheMissOnly": "命中未上報 / 未命中 {miss}",
"CmdTokensCacheWriteTotal": "本工作階段的快取寫入(建立)token:{write}。在公佈寫入加價的供應商處按高於輸入價計費;逐回合明細見 /cache。",
"CmdTokensContextUnknownWindow": "~{estimated} / 視窗未知",
"CmdTokensContextWithWindow": "~{used} / {window}({percent}%)",
"FooterAgentSingular": "1 個代理",
"FooterAgentsPlural": "{count} 個代理",
"HeaderAgentsChip": "代理 {count}",
"FooterPressCtrlCAgain": "再次按 Ctrl+C 退出",
"FooterWorking": "工作中",
"FooterBalancePrefix": "餘額",
"HelpSectionActions": "操作",
"HelpSectionClipboard": "剪貼板",
@@ -787,6 +839,7 @@
"CmdTokensNotReported": "未上報",
"CmdTokensReport": "token 用量:\n─────────────────────────────\n使用中上下文: {active}\n上次 API 輸入: {input}(回合遙測;工具往返可能重複計入相同前綴)\n上次 API 輸出: {output}\n快取命中/未命中: {cache}(僅用於遙測/費用)\n累計 token: {total}(工作階段用量遙測)\n已定價金額: {cost}\nAPI 訊息數: {api_messages}\n聊天訊息數: {chat_messages}\n模型: {model}",
"KbScrollTranscript": "捲動對話記錄、瀏覽輸入歷史或選擇附件",
"KbNavigateHistory": "瀏覽輸入歷史",
"KbBrowseHistory": "瀏覽對話歷史",
"KbScrollTranscriptAlt": "捲動對話記錄",
"KbScrollPage": "按頁捲動對話記錄",
@@ -820,6 +873,7 @@
"KbCompactContext": "壓縮對話上下文",
"KbLastMessagePager": "開啟最後一條訊息的分頁器(輸入框為空時)",
"KbSelectedDetails": "顯示所選工具或訊息的原始詳情;Ctrl+Alt+O 開啟整回合概覽",
"KbToolDetailsPager": "顯示所選項的原始詳情(Alt+V)",
"KbExternalEditor": "在外部編輯器中開啟撰寫中的草稿",
"KbLiveTranscript": "開啟實時對話涵蓋層(Ctrl+Shift+T;尾部自動捲動)",
"KbBacktrackMessage": "回退到之前的使用者訊息(左右鍵步進,Enter 回退)",
@@ -858,6 +912,8 @@
"KbHelpOverlay": "開啟此說明涵蓋層(輸入框為空時)",
"KbCycleWorkDock": "切換任務面板(待辦、代理、作業、背景),寵物模式下切換寵物檢視",
"KbCycleWorkDockBack": "反向切換任務面板或寵物檢視",
"KbToggleHelp": "切換說明涵蓋層",
"KbToggleHelpSlash": "切換說明涵蓋層",
"HelpUsageLabel": "用法:",
"HelpAliasesLabel": "別名:",
"SettingsTitle": "設定:",
@@ -958,8 +1014,10 @@
"HomeAgentModeReviewTip": " 用 /mode plan 先調研並提出計畫",
"HomeAgentModeYoloTip": " Shift+Tab 循環權限: Ask → Accept Edits → Plan → Auto-Review → Full Access",
"HomeYoloModeTip": "Work + 完整存取 — 工具無需先詢問即可執行",
"HomeYoloModeCaution": " 破壞性操作可能立即執行;不確定時用 Ask",
"HomePlanModeTip": "Plan — 實現前先調研與設計",
"HomePlanModeChecklistTip": " 提交計畫與待辦進度,然後切換到 Work",
"HomeGoalModeTip": "Goal 跟蹤 - 設定 /goal <目標> 以跟蹤持久目標",
"OnboardLanguageTitle": "選擇語言",
"OnboardLanguageBlurb": "選擇介面語言。可隨時使用 `/config locale <tag> --save` 修改。",
"OnboardProviderTitle": "選擇模型供應商",
@@ -971,6 +1029,8 @@
"StepfunBillingRouteIntro": "StepFun 的按量付費與 Step Plan 訂閱使用不同的端點。請選擇與你的金鑰相符的一項。",
"StepfunBillingRoutePaygOption": "按量付費(按 token 計價)",
"StepfunBillingRoutePlanOption": "Step Plan 訂閱(套餐額度)",
"StepfunPlanApiKeyHint": "使用 StepFun Step Plan 訂閱時,請使用為 Step Plan 簽發的金鑰,而不是按量付費金鑰。",
"StepfunPlanRouteHint": "此路由使用 {route},並從你的 Step Plan 額度中扣除。",
"OnboardApiKeyRejectedEnv": "來自 {env} 的 {provider} API 金鑰被拒絕。請粘貼有效金鑰並儲存到 {path},或更新該環境變數。",
"OnboardTrustTitle": "了解此工作區",
"OnboardTrustQuestion": "是否允許 Codewhale 使用此工作區中的指令和檔案開展工作?",
@@ -993,6 +1053,7 @@
"RedactionGateRollbackHint": "選擇「保持開啟」後,本次啟動仍開啟脫敏;由於設定仍為 \"disabled\",下次啟動會再次詢問。",
"RedactionGateSaveFailed": "無法儲存確認。遮罩仍然開啟。請重試或選擇保持遮罩。",
"RedactionGateTitle": "模型邊界金鑰脫敏",
"OnboardOfflineOption": "Ctrl+O — 離線瀏覽:先隨便看看,之後再連線供應商。",
"OnboardOfflineNotice": "正在離線瀏覽。尚未連線 — 想連線時請執行 /provider。",
"OnboardWelcomeTitle": "Codewhale 在這個資料夾裡與你協作。",
"OnboardWelcomeLead": "我們來做好準備。",
@@ -1014,6 +1075,8 @@
"OnboardSeedCodeProject": "說明這個專案在做什麼,並列出主要進入點。",
"OnboardSeedFolder": "看看這個資料夾,建議一個合適的第一個任務。",
"SetupWizardTitle": "設定",
"SetupWizardWhy": "此介面會將設定進度記錄到 setup_state.json;只有明確的步驟操作才會套用設定變更。",
"SetupWizardProgress": "步驟",
"SetupActionBack": "返回",
"SetupActionContinue": "繼續",
"SetupActionSkip": "略過",
@@ -1021,6 +1084,7 @@
"SetupActionScrollBody": "捲動正文",
"SetupActionGuided": "預覽/確認",
"SetupActionTuneGuided": "調整",
"SetupActionModelDraft": "模型草稿",
"SetupActionFreeform": "自己的話",
"SetupActionKeepExisting": "保留現有",
"SetupActionUseRecommended": "使用建議設定",
@@ -1029,7 +1093,13 @@
"SetupActionModel": "模型路由",
"SetupActionFleet": "Fleet 設定",
"SetupActionHotbar": "Hotbar 設定",
"SetupActionRemote": "遠端入口",
"SetupActionMode": "模式選擇",
"SetupActionConfig": "設定檢視",
"SetupActionRuntimePreset": "預設",
"SetupActionApplyRuntimePreset": "預覽/套用",
"SetupActionUseBundled": "使用內建",
"SetupActionDefer": "延後",
"SetupActionCancel": "取消",
"SetupStatusNotStarted": "尚未開始",
"SetupStatusRecommended": "建議",
@@ -1069,6 +1139,7 @@
"SetupLanguageReviewed": "已記錄設定語言。",
"SetupConstitutionChoiceLabel": "選擇:",
"SetupConstitutionSourceLabel": "來源:",
"SetupConstitutionValidityLabel": "有效性:",
"SetupConstitutionPreviewLabel": "預覽雜湊:",
"SetupConstitutionExistingLabel": "現有檔案:",
"SetupConstitutionExpertOverrideLabel": "專家覆寫:",
@@ -1109,6 +1180,8 @@
"SetupToolsMcpPluginsLabel": "外掛:",
"SetupToolsMcpReviewHint": "按 Enter 記錄目前工具/MCP 事實。按 R 查看安全引導(不會自動執行)。",
"SetupToolsMcpReviewed": "工具/MCP 就緒狀態已記錄。",
"SetupRemoteCloudsLabel": "雲端目標:",
"SetupRemoteBridgesLabel": "聊天橋接:",
"SetupRemoteProvidersLabel": "供應商:",
"SetupRemoteModeLabel": "遠端模式:",
"SetupRemoteModeLocalOnly": "僅本機:",
@@ -1180,6 +1253,7 @@
"CtxMenuCopyMessage": "複製訊息",
"CtxMenuCopyMessageDesc": "將點擊的記錄條目寫入剪貼板",
"CtxMenuOpenInEditor": "在編輯器中開啟",
"CtxMenuOpenInEditorDesc": "在 $EDITOR 中開啟 file:line",
"CtxMenuShowCell": "顯示條目",
"CtxMenuShowCellDesc": "取消隱藏此記錄條目",
"CtxMenuHideCell": "隱藏條目",
@@ -1214,9 +1288,17 @@
"FanoutCounts": "{done} 已完成 · {running} 運行中 · {failed} 失敗 · {pending} 等待中",
"AppModeAgent": "Work",
"AppModeAuto": "自動",
"AppModeYolo": "完整存取(已棄用標籤)",
"AppModePlan": "Plan",
"AppModeOperate": "Operate",
"AppModeAgentHint": "在本工作階段直接工作 — 編輯與 shell 需核准",
"AppModeAutoHint": "啟用 shell,並自動進行風險審查",
"AppModePlanHint": "先唯讀調研,行動前提出計畫",
"AppModeYoloHint": "僅為相容保留 — Work + 完整存取,不是可見模式",
"AppModeOperateHint": "全力版 Work:設目標、並行代理,驗證後才停",
"VimModeNormal": "-- 一般 --",
"VimModeInsert": "-- 插入 --",
"VimModeVisual": "-- 可視 --",
"ApprovalEffectReadsOnly": "唯讀",
"ApprovalEffectChangesFiles": "修改檔案",
"ApprovalRiskDestructive": "無法復原",
@@ -1244,6 +1326,7 @@
"ApprovalSaveAskRuleHint": " · s 本次允許,以後每次先詢問",
"ApprovalOptionDeny": "不允許",
"ApprovalOptionAbortTurn": "停止本回合",
"ApprovalBlockTitle": "核准",
"ApprovalControlsHint": "Pg↑/↓ 回看 · {details} 更多選項 · Esc 停止",
"ApprovalOwnerHeader": "代理:{agent} · {role}",
"ApprovalGoToAgent": "g 前往代理",
@@ -1269,6 +1352,8 @@
"ApprovalTruncationHint": " … 已截斷 · 按 {details} 查看完整內容",
"ApprovalAsksWithoutGit": "此資料夾沒有 Git 儲存庫,因此編輯前會先詢問。",
"ApprovalFullAccessPolicyBlocked": "已阻止 {tool}:Full Access 無法繞過此政策",
"ApprovalChooseHint": "選擇: ",
"ApprovalChooseAction": "Enter 執行選中項,或直接按 y/a/d",
"ApprovalIntentLabel": "意圖: ",
"ApprovalMoreLines": " … (還有 {count} 行)",
"ApprovalProceedQuestion": "是否繼續?",
@@ -1308,10 +1393,12 @@
"ContextManualCompacting": "正在壓縮上下文…",
"ContextCompactionQueued": "上下文壓縮已排入佇列,將在本回合結束後執行。",
"ContextCompactionAlreadyRunning": "上下文壓縮已在進行中。",
"ContextCompactionQueueFull": "上下文壓縮需要等待:引擎忙碌中。請在本回合結束後再試一次。",
"ContextCompactionQueueClosed": "無法壓縮上下文:引擎已停止。",
"ContextCompactionRouteInvalid": "無法壓縮,因為目前的供應商路由無效:{error}",
"ContextCompactionStoppedOnEngineSwitch": "已停止壓縮上下文;對話未被變更",
"ContextPurgeAbandonedOnEngineSwitch": "工作階段清理已隨被替換的引擎一併放棄;對話未被變更",
"CtxInspTitle": "上下文檢查器",
"CtxInspSessionContext": "工作階段上下文",
"CtxInspSystemPrompt": "系統提示結構",
"CtxInspReferences": "引用",
@@ -1543,21 +1630,45 @@
"SetupToolsMcpOnRampText": "工具、MCP、技能與外掛 — 安全引導\n\n/setup 只讀取本機清單。它不會啟動 MCP 伺服器、安裝技能、執行外掛或執行不受信任的指令。\n\n目前清單:\n- MCP:{mcp_result}\n- 技能:{skills_result}\n- 工具目錄:{tools_result}\n- 外掛:{plugins_result}\n- 快捷列(共用轉接器):{hotbar_result}\n\n路徑(家目錄已遮蔽):\n- MCP 設定:{mcp_path}\n- 技能:{skills_path}\n- 外掛:{plugins_path}\n\n安全初始設定(請自行在一般終端機或 TUI 指令中執行):\n- MCP:/mcp · codewhale mcp init · codewhale doctor\n- 技能:/skills · codewhale setup --skills · /skills install <spec>\n- 外掛:/plugin · codewhale setup --plugins\n- 工具目錄:codewhale setup --tools\n\n有副作用的操作一律需要明確確認。外掛指令與斜線指令仍保持區別;快捷列的外掛來源會等核准機制到位後才啟用。\n\n仍需手動完成的外部設定,請參閱 docs/MCP.md 和 docs/skills/README.md。",
"SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):",
"SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — 透過 Codewhale 連接,絕不是第二個排程器:\n- 狀態:{dsh_result}\n- 唯讀偵測;連接/計畫/啟動/移除:codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale 只寫入 $CODEWHALE_HOME/integrations/dsh,絕不複製 API 金鑰或修改 DSH 檔案。",
"HotbarActionModeOperateName": "Operate 模式",
"HotbarActionModeOperateDescription": "把一項持續的請求並行推進,直到通過驗證。",
"HomeOperateModeTip": "Operate — 讓 Fleet 並行展開工作",
"HomeOperateModeFleetTip": " 內置角色使用本工作階段的模型;/fleet setup 可自定義",
"HelpSubtitle": "指令、技能與快捷鍵",
"CommandPaletteTitle": "指令",
"CommandPaletteSubtitle": "查找並執行一個操作",
"ConfigSubtitle": "設定優先;原始鍵在高級詳情",
"LaunchStartTitle": "從這裡開始",
"LaunchResumeConfirm": "恢復 {title}?再次點擊或按 Enter 確認。",
"LaunchResumeConfirmTitle": "恢復工作階段",
"LaunchResumeConfirmBody": "這會以該工作階段的歷史取代目前的上下文。",
"LaunchResumeConfirmResume": "恢復",
"LaunchResumeConfirmCancel": "取消",
"LaunchWorkDescription": "在此資料夾中工作;變更遵循你的權限設定。",
"LaunchChatDescription": "僅對話和規劃;不會變更檔案。",
"LaunchWorkspaceGitReady": "工作區 · {name} · Git 工作區",
"LaunchWorkspaceFolderReady": "工作區 · {name} · 本機資料夾",
"LaunchProviderConfigured": "供應商 · 已設定",
"LaunchProviderSetupNeeded": "供應商 · 需要設定",
"LaunchGroupContinue": "繼續",
"LaunchGroupMore": "更多",
"LaunchWorkspaceGitShort": "Git",
"LaunchWorkspaceFolderShort": "資料夾",
"LaunchProviderConfiguredShort": "供應商已設定",
"LaunchProviderSetupShort": "設定供應商",
"LaunchMenuChangelog": "更新日誌",
"LaunchWorktreePrompt": "為分支/工作樹命名,或按 Enter 使用自動名稱。 Esc 返回。",
"LaunchWorktreeNeedsGit": "新建工作樹需要 Git 儲存庫。",
"LaunchWorktreeNameLabel": "工作樹名稱",
"LaunchHintMove": "移動",
"LaunchHintOpen": "開啟",
"LaunchTipFlags": "提示:-w <path> 開啟工作區;-r <session-id> 直接還原",
"LaunchSavedSessionSingular": "已儲存 1 個工作階段",
"LaunchSavedSessionsPlural": "已儲存 {count} 個工作階段",
"LaunchCreatingWorktree": "正在建立工作樹…",
"LaunchWorktreeFailed": "工作樹建立失敗:{error}",
"LaunchWorktreeCreated": "新工作樹 {path},分支 {branch}",
"LaunchNoSavedSessions": "此工作區沒有已儲存的工作階段。",
"LaunchNoModelConnected": "未連線模型",
"DispatchNotSentNoModel": "尚未連接模型,因此這則訊息沒有送出。訊息已放回輸入框:用 F3 或 /provider 連接模型,然後按 Enter 送出。",
"DispatchNotSentSaveKey": "儲存金鑰:{command}",
@@ -1570,6 +1681,10 @@
"LocalModelAdopted": "正在使用 {model},這是在本機執行的模型(Ollama)。按 F3 可選擇其他模型。",
"ProviderPickerNotReopened": "無法重新開啟供應商清單。按 F3 開啟。",
"LaunchRunCommand": "執行 {command}",
"LaunchMcpConnectedOne": "已連線 1 個 MCP 伺服器",
"LaunchMcpConnectedMany": "已連線 {count} 個 MCP 伺服器",
"LaunchMcpNeedsSignInOne": "1 個需要登入",
"LaunchMcpNeedsSignInMany": "{count} 個需要登入",
"PhaseIdle": "閒置",
"PhaseDraft": "草稿",
"PhaseWorking": "工作中",
@@ -1584,6 +1699,7 @@
"PhaseFinishing": "收尾中",
"ChipModeAct": "work",
"ChipModePlan": "plan",
"ChipModeOperate": "operate",
"ChipPermissionReadOnly": "唯讀",
"ChipPermissionAsk": "ask",
"ChipPermissionAuto": "auto",
@@ -1591,12 +1707,16 @@
"ChipPermissionFullAccess": "Full Access",
"ChipPermissionNever": "never",
"PermissionsChangedReceipt": "權限已變更為 {label}",
"FooterHintKeys": "快捷鍵",
"FooterHintOutput": "輸出",
"FooterHintContext": "上下文",
"InfoLineHelp": "幫助",
"InfoLineContext": "上下文",
"InfoLineTtft": "ttft",
"InfoLinePeak": "尖峰",
"InfoLineOffPeak": "離峰",
"InfoLineWhales": "鯨魚",
"InfoLineAutomation": "自動化",
"InfoLineNotConnected": "未連線",
"InfoLineThinking": "思考:{level}",
"EmptyStateNoGit": "無 git",
@@ -1692,6 +1812,7 @@
"RouteActionSearchAnyModel": "搜尋任意模型",
"RoutePanelHeader": "路由",
"RouteProviderLabel": "供應商",
"RouteModelFirstAtomic": "模型優先的原子路由",
"PickerActionMove": "移動",
"PickerActionSwitch": "切換",
"PickerActionApply": "套用",
@@ -1708,6 +1829,7 @@
"PickerActionClearSearch": "清除搜尋",
"PickerActionBrowseAll": "瀏覽全部",
"PickerActionCustom": "自定義",
"PickerActionJump": "跳轉",
"PickerActionEditKey": "編輯金鑰",
"PickerActionModels": "模型",
"PickerActionUnavailable": "無法使用",
@@ -1723,6 +1845,9 @@
"ProviderExternalActionRevoke": "停止使用該登入",
"ProviderExternalActionChoices": "透過其他應用程式登入",
"ProviderExternalActionReuseGrok": "重用外部 Grok 憑證",
"ProviderExternalHintCodexReview": "完成 {login} 後,按 Enter 檢視停用、唯讀及受管存取選項。",
"ProviderExternalHintXaiReview": "按 Enter 使用 Codewhale 自有的裝置登入;按 E 檢視重用現有 Grok CLI 憑證的選項。",
"ProviderExternalHintXaiApiKey": "也可以使用XAI_API_KEY,然後重新開啟此選擇器。",
"XaiAuthChoiceTitle": " xAI 身份驗證 ",
"XaiAuthChoiceIntro": "請選擇一個明確的憑證來源。金鑰文字絕不會被當作 OAuth 權杖。",
"XaiAuthChoiceApiKeyOption": "xAI API 金鑰 — 輸入或貼上,然後儲存至 xAI 供應商欄位",
@@ -1734,6 +1859,9 @@
"ChatgptAuthChoiceTitle": " ChatGPT / Codex 身分驗證 ",
"ChatgptAuthChoiceIntro": "訂閱登入會計入你的 ChatGPT 方案。openai API 金鑰路徑屬於另一計費主體。",
"ChatgptAuthChoicePkceOption": "以 ChatGPT 登入 — 瀏覽器 PKCE、Codewhale 自有權杖、ChatGPT 訂閱計費",
"ChatgptAuthChoiceImportOption": "匯入 Codex CLI 憑證 — 明確唯讀授權;擁有者仍是 Codex CLI",
"ProviderExternalHintChatgptReview": "按 Enter 以 ChatGPT 登入;按 E 檢視既有 Codex CLI 重用。",
"ProviderExternalActionReuseCodex": "外部 Codex 重用",
"ProviderExternalDetailScope": "外部憑證:存取={access} | 供應商={provider} | 來源={source} | 版本={version} | {state}",
"ProviderExternalDormant": "休眠",
"ProviderExternalOwnerPath": "所有者/路徑:{owner} | {path}",
@@ -1744,6 +1872,7 @@
"SnapshotsDisabledUnsafeLocation": "此工作區 {workspace} 的快照與 /undo 已關閉:主目錄或根目錄範圍過大,無法安全快照。請在專案目錄中啟動即可開啟。",
"SnapshotsHistoryRepaired": "{workspace} 的復原歷史已損壞(缺少最新的還原點),已重新開始記錄。先前的還原點無法再還原;新的回合重新受到保護。",
"SnapshotsFailing": "{workspace} 的快照持續失敗,因此 /undo 無法還原最近的回合:{limit}",
"SessionIdDivergedNotice": "此視窗下的工作階段身分已更改:引擎現在以 {next} 儲存檢查點(之前為 {previous})。較早的檢查點仍保留在舊 ID 下;`codewhale sessions` 會列出兩者,`codewhale resume {previous}` 可重新開啟較早的工作階段。",
"RuntimeStoreUnreadableNotice": "工作階段執行階段儲存區:無法讀取 {path} 的 {record}({reason})。請將該檔案移開(或刪除)後重試;執行緒的其他記錄保持不變。",
"RuntimeStoreUnwritableNotice": "工作階段執行階段儲存區:無法寫入 {path} 的 {record}({reason})。請檢查該位置的可用空間與權限後重試;沒有任何內容被覆寫。",
"ProviderExternalSemanticsRevoke": "{semantics} | 復原:{revoke}",
@@ -1782,6 +1911,7 @@
"FleetRosterTabSetup": "設定",
"FleetRosterWorkers": "代理",
"FleetRosterMembersCount": "{count} 個成員",
"FleetRosterOperatorFirst": "協調者統領 · 工作階段模型驅動此 Fleet",
"FleetRosterOperatorRow": "協調者 · 你",
"FleetRosterShadowBadgeProjectOverride": "已儲存到此專案",
"FleetRosterShadowBadgePersonalIgnored": "已儲存副本被忽略",
@@ -1804,6 +1934,7 @@
"FleetModelReasonOperatorRoute": "這是你目前的模型(Fleet 的協調者路由);請切換模型或使用 /fleet save 變更",
"FleetModelReasonAlreadyPresent": "已在 Fleet 中",
"FleetModelErrorNeedsRoute": "Fleet 模型需要同時提供供應商 ID 和模型 ID",
"FleetModelErrorNeedsRole": "代理需要一個角色名稱(例如 `/fleet add {route} scout`)。",
"FleetModelErrorNoSelection": "未選取 Fleet;你的 Fleet 僅包含工作階段模型",
"FleetModelErrorOperatorRoute": "{route} 是 Fleet `{fleet}` 的協調者路由;請用 /fleet save 變更,不能直接移除",
"FleetModelErrorNotInFleet": "{route} 不在 Fleet `{fleet}` 中",
@@ -1922,6 +2053,7 @@
"FilePickerMatchSingular": "@ 附加 · 1 個相符",
"FilePickerMatchesPlural": "@ 附加 · {count} 個相符",
"FilePickerScanning": "正在掃描工作區…",
"BehavioralTipPlanning": "在規劃?按 {key} 可切換到 Plan 模式",
"BehavioralTipBackgroundReceipt": "回執在 Work 面板中 — 按 {key} 開啟檢查器",
"BehavioralTipClearedInput": "已清空 · 按 {chord} 還原",
"BehavioralTipMcpValidation": "{command} 會啟動伺服器並顯示原因",
@@ -1935,6 +2067,7 @@
"SettingSubjectModelAndThinking": "模型與思考",
"SettingSubjectProvider": "供應商",
"SettingSubjectPermissions": "權限",
"ThinkingControlledByAutoRouting": "思考由自動模型路由控制;請先選擇固定模型。",
"SavedAsStartupDefault": "已儲存為啟動預設值",
"ModeAlreadyActiveSavedAsDefault": "已處於 {mode} 模式 — 已儲存為啟動預設值。",
"StartupDefaultNotSaved": "{setting}未能儲存:{error}",
@@ -1954,6 +2087,11 @@
"StartupDefaultSubjectThinking": "思考級別",
"StartupDefaultSubjectModel": "模型",
"StartupDefaultSubjectAll": "啟動預設值",
"SessionsRailTitle": "工作階段",
"SessionsRailEmpty": "此工作區尚無工作階段",
"SessionsRailBrowseAll": "瀏覽所有工作階段",
"SessionsRailShowingCount": "{total} 個中的 {shown} 個 — 瀏覽全部",
"SessionsRailUnavailable": "無法讀取工作階段:{error}",
"SessionsActionArchive": "封存",
"SessionsActionShowArchived": "已封存",
"SessionsArchived": "已封存工作階段 {id}",
@@ -2141,6 +2279,7 @@
"FooterHintForAgents": "代理",
"FooterHintToManage": "管理",
"AgentRailQueuedCount": "{count} 則排隊",
"WorkbarSoFar": "目前 {done}/{total}",
"WorkbarLargeWorkflow": "大型工作流程",
"WorkbarMoreRuns": "還有 {count} 個",
"WorkflowLineStarted": "已開始",
@@ -2148,6 +2287,7 @@
"WorkflowLineFinishedWithGaps": "已完成但有缺口",
"WorkflowLineFailed": "失敗",
"WorkflowLineStopped": "已停止",
"WorkflowLineAgents": "{done}/{total} 個代理",
"AgentFocusPosture": "{role} · {write} · {network} · {shell}",
"AgentFocusPostureWrites": "可寫入",
"AgentFocusPostureReadOnly": "唯讀",
@@ -2157,6 +2297,7 @@
"AgentFocusPostureShellReadOnly": "唯讀 shell",
"AgentFocusPostureShellNone": "無 shell",
"GoalReceiptSet": "已設定目標:「{objective}」 · /goal 查看進度 · /goal pause 或 /goal clear 停止",
"GoalReceiptSetOperate": "◆ 已設定目標 · Operate 會持續工作直到驗證完成 · /goal 可編輯",
"GoalControlAccepted": "目標控制已儲存;將在下一個安全邊界套用。",
"GoalControlRuntimeUnavailable": "目標控制已儲存,但執行階段目前無法使用。重新啟動後將還原此狀態。",
"GoalStatusIdleHint": "目前未執行 — 傳送訊息或 /goal resume 以繼續",
@@ -2166,6 +2307,9 @@
"GoalContinuationWaiting": "目標執行中 · {delay} 後開始下一回合 · 按 Esc、Ctrl+C 或使用 /goal pause 可停止待執行的繼續操作",
"GoalContinuationReady": "目標繼續操作已就緒;佇列中的控制指令會在下一回合之前執行。",
"GoalContinuationStopped": "已停止待執行的目標繼續操作;目標仍保持執行狀態。",
"McpCapabilitiesAdvertised": "已宣告的能力:{capabilities}",
"McpCapabilitiesLegacyFallback": "已宣告的能力:未提供;使用舊版探索後援",
"McpCapabilitiesNotObserved": "已宣告的能力:伺服器未連線,尚未觀測",
"PickerActionTestConnection": "測試連線",
"ProviderCustomFormBaseUrl": "基礎 URL",
"ProviderCustomFormModel": "預設模型",
@@ -2185,6 +2329,7 @@
"OperateBoardGantt": "甘特圖 時間 →",
"ConfigCategoryAppearance": "外觀",
"ConfigCategoryModelsProviders": "模型與供應商",
"ConfigCategoryFleet": "Fleet",
"ConfigCategoryWork": "工作",
"ConfigCategoryToolsMcp": "工具與 MCP",
"ConfigCategoryTrust": "信任",
@@ -2220,6 +2365,7 @@
"ConfigKindReadOnly": "唯讀",
"ConfigRowActionNote": "動作 · 非持久化設定",
"ConfigRowDiagnosticNote": "觀測回條 · 此處不可編輯",
"ConfigNavHint": "←/→ 或 Tab 切換類別 · ↑/↓ 切換設定",
"ConfigActivateAgain": "按 Enter 或再次點選:",
"ConfigSearchLabel": " 搜尋: ",
"ConfigEditChooseLabel": "選擇:",
@@ -2242,6 +2388,7 @@
"ConfigChoiceNever": "永不",
"ConfigChoiceModeAct": "Work",
"ConfigChoiceModePlan": "Plan(唯讀)",
"ConfigChoiceModeOperate": "Operate",
"ConfigChoicePlacementTop": "頂部",
"ConfigChoicePlacementBottom": "底部欄",
"ConfigChoicePlacementLeft": "左側欄",
@@ -2258,8 +2405,10 @@
"ConfigChoiceDetailAutoReview": "自動審核工具風險,需要你決定時才詢問。",
"ConfigChoiceDetailUseTuiDefault": "移除根設定覆寫,使用已儲存的 TUI 權限選擇。",
"ConfigChoiceDetailFullAccess": "工具會不經詢問直接執行,指令可以存取這台電腦上的任何內容。",
"ConfigChoiceDetailNever": "封鎖所有需要核准的工具。",
"ConfigChoiceDetailModeAgent": "以可協作並使用工具的狀態開始。",
"ConfigChoiceDetailModePlan": "在唯讀的規劃工作區中開始。",
"ConfigChoiceDetailModeOperate": "Operate 是全力版的 Work:每個實質性請求都會變成目標,交給工作流程和並行代理推進,由獨立審核者檢查,直到通過驗證才停止。",
"ConfigChoiceDetailPlacementTop": "在對話記錄上方顯示任務、待辦和代理。",
"ConfigChoiceDetailPlacementBottom": "在輸入框下方顯示任務、待辦和代理。",
"ConfigChoiceDetailPlacementLeft": "終端機夠寬時,在左側任務面板中顯示任務、待辦和代理。",
@@ -2277,6 +2426,7 @@
"ConfigChoiceDetailThinkingHighlightOn": "填滿模型推理的背景。",
"ConfigChoiceDetailThinkingHighlightOff": "保留虛線推理側欄和斜體文字,不填滿背景。",
"ConfigHintModel": "本工作階段即時路由的模型;按 Enter 開啟 /model",
"ConfigHintFastModel": "當供應商有已知的同系模型時,供 Auto 路由和 model_strength=faster 使用",
"ConfigHintProvider": "憑證、模型和端點一起切換",
"ConfigHintApprovalMode": "僅本工作階段:詢問 | 自動審核 | 完整存取",
"ConfigHintPermissionPosture": "新工作階段的預設值:詢問 | 自動審核 | 完整存取",
@@ -2311,6 +2461,7 @@
"ConfigHintDefaultMode": "work (agent) | plan",
"ConfigHintMaxHistory": "整數(允許 0) · 保留的已傳送訊息數,用於叫出和歷史搜尋",
"ConfigHintAutoCompactThreshold": "10..=100 · 壓縮門檻:觸發自動壓縮時占可用上下文長度的百分比",
"ConfigHintDefaultModel": "僅 DeepSeek 的舊版後備;其他供應商使用上方按供應商劃分的模型",
"ConfigHintReasoningEffort": "default 會恢復該模型自身的預設值;常開思考模型沒有 off",
"ConfigHintMcpOpen": "開啟 MCP 管理器 · 連線 / 重新連線 / 重新驗證 / 診斷",
"ConfigHintMcpReconnect": "重新連線 MCP · /mcp reload",
@@ -2323,8 +2474,11 @@
"ConfigHintFeatureApplyPatch": "修補程式編輯工具的唯讀功能開關狀態",
"ConfigHintFeatureMcp": "MCP 工具的唯讀功能開關狀態",
"ConfigHintFeatureExecPolicy": "執行政策工具的唯讀功能開關狀態",
"ConfigHintFeatureVisionModel": "視覺/模型影像支援的測試版功能開關",
"ConfigHintGoalCommand": "/goal 追蹤目標、預算及狀態",
"ConfigHintWorkflow": "/workflow 執行帶扇出/扇入執行卡片的腳本化操作",
"LaunchMenuNewWorktree": "新增工作樹",
"LaunchMenuResume": "恢復工作階段",
"LaunchMenuQuit": "結束",
"LaunchNoticeClaude": "偵測到 Claude Code。用 /import-claude 檢視;每項變更都需你確認。",
"LaunchNewSession": "新增工作階段",
@@ -2332,7 +2486,9 @@
"LaunchRecentResumeHint": "↑ 恢復",
"LaunchHelpLine": "/help 檢視指令 · {dock} 開啟任務面板",
"LaunchSeeAllSessions": "查看全部工作階段…",
"LaunchNoRecentSessions": "暫無最近工作階段 — 在下方輸入以開始。",
"LaunchResumeFailed": "恢復失敗:{error}",
"ReceiptSessionHooks": "掛鉤 {count}",
"AutomationEditorNew": "新增自動化",
"AutomationEditorEdit": "編輯自動化",
"AutomationEditorSchedule": "執行排程",
@@ -2488,6 +2644,7 @@
"WorkflowSettledOfTotal": "{done}/{total} 已完成",
"WorkflowPhaseCountOne": "{count} 個階段",
"WorkflowPhaseCountMany": "{count} 個階段",
"WorkflowPhaseOrdinal": "階段 {n}/{total}",
"ModelPickerPinned": "已釘選 {route}",
"ModelPickerUnpinned": "已取消釘選 {route}",
"ModelPickerPinFailed": "無法更新釘選:{error}",
@@ -2501,6 +2658,7 @@
"AuthReplacedPreviousSignInAs": "已取代先前的 Codewhale {provider} 登入({account})。",
"AuthReplacedPreviousSignIn": "已取代先前的 Codewhale {provider} 登入。",
"AuthSameAccountAsBefore": "這與先前是同一個帳戶;若要使用其他 {provider} 帳戶,請先在瀏覽器中登出該帳戶(或使用無痕視窗),然後重新登入。",
"AuthEnvTokenOutranksSignIn": "此環境已設定 OPENAI_CODEX_ACCESS_TOKEN 或 CODEX_ACCESS_TOKEN,其優先順序高於本次登入;在取消設定之前,請求會繼續使用該權杖的帳戶。",
"TranscriptThought": "思考完畢",
"TranscriptThoughtFor": "思考耗時 {duration}",
"PinnedPromptJumpToMessage": "跳轉到這則訊息",
@@ -2520,6 +2678,7 @@
"PluginOAuthBrowser": "按 Enter 開啟瀏覽器登入,按 Esc 返回。不需要 API Key。",
"PluginOAuthReady": "{provider}:已登入,請選擇模型。",
"PluginOAuthLocalLogout": "{provider}:已刪除本機登入憑證,未撤銷伺服器授權。",
"CmdConnectDescription": "透過瀏覽器登入連接外掛提供者",
"CmdDisconnectDescription": "刪除外掛提供者的本機登入憑證",
"ExecAutoHelp": "啟用工具,自動核准並使用 Full Access(無 shell 沙盒,開啟信任模式),除非已設定更嚴格的沙盒;使用 --sandbox workspace-write 可限制檔案與 shell 寫入。",
"ExecSandboxHelp": "本次執行的沙盒原則;danger-full-access 以外的任何 --sandbox(或設定中等效的 sandbox_mode)都會關閉信任模式。",
File diff suppressed because it is too large. Load diff
+6 -51
View File
@@ -255,12 +255,11 @@ impl StdioLspTransport {
let child = Arc::new(AsyncMutex::new(Some(child)));
let dispatcher_child = child.clone();
let dispatcher_pending = pending.clone();
let dispatcher_outbound = tx_outbound.clone();
let dispatcher_task = spawn_supervised(
"lsp-dispatcher",
std::panic::Location::caller(),
async move {
dispatcher_task(rx_inbound, tx_diag, dispatcher_outbound, dispatcher_pending).await;
dispatcher_task(rx_inbound, tx_diag, dispatcher_pending).await;
// EOF, malformed frames, or an overflowing diagnostics queue
// terminate the producer too, so its pipes cannot stay stuck.
if let Some(mut child) = dispatcher_child.lock().await.take() {
@@ -537,19 +536,15 @@ impl LspTransport for StdioLspTransport {
/// Send a JSON value as one Content-Length-framed JSON-RPC message.
async fn send_message(tx: &mpsc::Sender<Vec<u8>>, value: &Value) -> Result<()> {
tx.send(frame_message(value)?)
.await
.map_err(|_| anyhow!("LSP outbound channel closed"))?;
Ok(())
}
fn frame_message(value: &Value) -> Result<Vec<u8>> {
let body = serde_json::to_vec(value).context("serialize LSP message")?;
let header = format!("Content-Length: {}\r\n\r\n", body.len());
let mut frame = Vec::with_capacity(header.len() + body.len());
frame.extend_from_slice(header.as_bytes());
frame.extend_from_slice(&body);
Ok(frame)
tx.send(frame)
.await
.map_err(|_| anyhow!("LSP outbound channel closed"))?;
Ok(())
}
/// Background task that drains the outbound queue and writes each frame to
@@ -643,7 +638,6 @@ fn parse_header(buf: &[u8]) -> Result<Option<(usize, usize)>> {
async fn dispatcher_task(
mut rx: mpsc::Receiver<Value>,
tx_diag: mpsc::Sender<DiagnosticMessage>,
tx_outbound: mpsc::Sender<Vec<u8>>,
pending: Arc<AsyncMutex<HashMap<i64, oneshot::Sender<Value>>>>,
) {
while let Some(value) = rx.recv().await {
@@ -660,19 +654,6 @@ async fn dispatcher_task(
}
continue;
}
if let Some(method) = method {
if let Some(id) = value.get("id") {
let reply = json!({
"jsonrpc": "2.0",
"id": id,
"error": {"code": -32601, "message": format!("unsupported method {method}")},
});
if let Ok(frame) = frame_message(&reply) {
let _ = tx_outbound.try_send(frame);
}
}
continue;
}
// Replies have an `id` and a `result` or `error`.
if let Some(id) = value.get("id").and_then(|v| v.as_i64()) {
let mut map = pending.lock().await;
@@ -799,31 +780,6 @@ pub(super) mod tests {
assert_eq!(diags[0].message, "missing semicolon");
}
#[tokio::test]
async fn server_request_sharing_a_pending_id_is_answered_not_taken_as_the_reply() {
let (tx_in, rx_in) = mpsc::channel(4);
let (tx_out, mut rx_out) = mpsc::channel::<Vec<u8>>(4);
let (tx_diag, _rx_diag) = mpsc::channel(4);
let pending = Arc::new(AsyncMutex::new(HashMap::new()));
let (reply_tx, reply_rx) = oneshot::channel();
pending.lock().await.insert(2, reply_tx);
let dispatcher = tokio::spawn(dispatcher_task(rx_in, tx_diag, tx_out, pending));
tx_in
.send(json!({"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[]}}))
.await
.unwrap();
tx_in
.send(json!({"jsonrpc":"2.0","id":2,"result":"definition"}))
.await
.unwrap();
assert_eq!(reply_rx.await.unwrap()["result"], "definition");
let answer = next_document(&mut rx_out).await;
assert_eq!(answer["id"], 2);
assert_eq!(answer["error"]["code"], -32601);
drop(tx_in);
dispatcher.await.unwrap();
}
#[test]
fn round_trips_uri_path() {
let path = fixture_path("example/foo.rs");
@@ -1353,12 +1309,11 @@ while True:
let (mut producer, reader) = tokio::io::duplex(MAX_LSP_HEADER_BYTES * 2);
let (tx, rx) = mpsc::channel(8);
let (diag, _diagnostics) = mpsc::channel(8);
let (outbound, _outbound_rx) = mpsc::channel(8);
let pending = Arc::new(AsyncMutex::new(HashMap::new()));
let (reply, receiver) = oneshot::channel();
pending.lock().await.insert(1, reply);
let read_task = tokio::spawn(reader_task(reader, tx));
let dispatch = tokio::spawn(dispatcher_task(rx, diag, outbound, pending.clone()));
let dispatch = tokio::spawn(dispatcher_task(rx, diag, pending.clone()));
producer.write_all(&frame).await.unwrap();
assert!(
timeout(Duration::from_secs(1), receiver)
-2
View File
@@ -11,8 +11,6 @@ pub struct AutoRouteDecisionEvidence {
pub probabilities_bp: BTreeMap<String, u16>,
pub confidence_bp: u16,
pub min_confidence_bp: u16,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub abstained_questions: Vec<String>,
/// `[auto] cost_saving` kept the fast tier because the strong tier's
/// probability was below the cost-saving floor.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
+1 -1
View File
@@ -16,7 +16,7 @@ test-thread-scoped-state = ["test-support"]
[dependencies]
codewhale-config = { path = "../config", version = "0.10.3" }
codewhale-sanitize = { path = "../sanitize", version = "0.10.3" }
codewhale-secrets = { path = "../secrets", version = "0.10.3" }
regex = "1.11"
tempfile.workspace = true
tracing.workspace = true
+1 -1
View File
@@ -289,7 +289,7 @@ pub fn sanitize_field(text: &str) -> String {
// drops the ESC byte but leaves the parameter tail behind — good
// enough for a terminal that will never re-interpret it, wrong for a
// notification banner that would render a literal `[31m`.
codewhale_sanitize::sanitize::sanitize_text(&strip_escape_sequences(text))
codewhale_secrets::sanitize::sanitize_text(&strip_escape_sequences(text))
.lines()
.map(|line| {
let redacted = redact_structured(line.trim());
+3
View File
@@ -10,6 +10,9 @@ description = "Codewhale sandboxed Python REPL runtime"
[lints]
workspace = true
[features]
test-support = []
[dependencies]
codewhale-dependencies = { path = "../dependencies", version = "0.10.3" }
codewhale-runtime = { path = "../runtime", version = "0.10.3" }
Loaded 100 of 191 files, more files were not shown because too many files have changed in this diff. Show more