mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-18 00:23:25 -06:00
fix(exec-approval): stop misattributing Allow Always unavailability to policy (#97740)
* fix(exec-approval): stop misattributing Allow Always unavailability to policy Allow Always is dropped both when policy ask=always AND when a command is non-persistable (e.g. shell redirect `2>&1` -> one-shot), but the prompt always claimed 'effective approval policy requires approval every time'. That's misleading for the non-persistable case (#97069). Reword to reason-neutral 'Allow Always is unavailable for this command.' across all approval surfaces, update en + 20 locale bundles, refresh i18n meta, and the matching tests. Closes #97069 * fix(exec-approval): stop misattributing Allow Always unavailability to policy * test(ui): await exec approval render updates * chore(ui): sync approval i18n metadata --------- Co-authored-by: saju01 <saju01@users.noreply.github.com> Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com> Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
This commit is contained in:
@@ -403,9 +403,7 @@ export function buildApprovalPendingMessage(params: {
|
||||
);
|
||||
lines.push(`Reply with: /approve ${params.approvalSlug} ${decisionText}`);
|
||||
if (!allowedDecisions.includes("allow-always")) {
|
||||
lines.push(
|
||||
"The effective approval policy requires approval every time, so Allow Always is unavailable.",
|
||||
);
|
||||
lines.push("Allow Always is unavailable for this command.");
|
||||
}
|
||||
lines.push("If the short code is ambiguous, use the full id in /approve.");
|
||||
return lines.join("\n");
|
||||
|
||||
@@ -480,8 +480,7 @@ export function createExecApprovalHandlers(
|
||||
return allowedDecisions.includes(decision)
|
||||
? null
|
||||
: {
|
||||
message:
|
||||
"allow-always is unavailable because the effective policy requires approval every time",
|
||||
message: "allow-always is unavailable for this command",
|
||||
details: APPROVAL_ALLOW_ALWAYS_UNAVAILABLE_DETAILS,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -3716,8 +3716,7 @@ describe("exec approval handlers", () => {
|
||||
expect(mockCallArg(resolveRespond)).toBe(false);
|
||||
expect(mockCallArg(resolveRespond, 0, 1)).toBeUndefined();
|
||||
expectRecordFields(mockCallArg(resolveRespond, 0, 2), {
|
||||
message:
|
||||
"allow-always is unavailable because the effective policy requires approval every time",
|
||||
message: "allow-always is unavailable for this command",
|
||||
});
|
||||
|
||||
const denyRespond = vi.fn();
|
||||
@@ -3759,8 +3758,7 @@ describe("exec approval handlers", () => {
|
||||
expect(mockCallArg(resolveRespond)).toBe(false);
|
||||
expect(mockCallArg(resolveRespond, 0, 1)).toBeUndefined();
|
||||
expectRecordFields(mockCallArg(resolveRespond, 0, 2), {
|
||||
message:
|
||||
"allow-always is unavailable because the effective policy requires approval every time",
|
||||
message: "allow-always is unavailable for this command",
|
||||
});
|
||||
|
||||
const allowOnceRespond = vi.fn();
|
||||
|
||||
@@ -283,9 +283,7 @@ export function buildExecApprovalRequestMessage(request: ExecApprovalRequest, no
|
||||
);
|
||||
lines.push(`Reply with: /approve ${request.id} ${decisionText}`);
|
||||
if (!allowedDecisions.includes("allow-always")) {
|
||||
lines.push(
|
||||
"Allow Always is unavailable because the effective policy requires approval every time.",
|
||||
);
|
||||
lines.push("Allow Always is unavailable for this command.");
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ describe("exec approval reply helpers", () => {
|
||||
expect(payload.text).not.toContain("C:\\Users\\alice");
|
||||
});
|
||||
|
||||
it("omits allow-always actions when the effective policy requires approval every time", () => {
|
||||
it("omits allow-always actions when allow-always is unavailable", () => {
|
||||
const payload = buildExecApprovalPendingReplyPayload({
|
||||
approvalId: "req-ask-always",
|
||||
approvalSlug: "slug-always",
|
||||
@@ -353,9 +353,7 @@ describe("exec approval reply helpers", () => {
|
||||
});
|
||||
expect(payload.text).toContain("```txt\n/approve slug-always allow-once\n```");
|
||||
expect(payload.text).not.toContain("allow-always");
|
||||
expect(payload.text).toContain(
|
||||
"The effective approval policy requires approval every time, so Allow Always is unavailable.",
|
||||
);
|
||||
expect(payload.text).toContain("Allow Always is unavailable for this command.");
|
||||
expect(payload.presentation).toEqual({
|
||||
blocks: [
|
||||
{
|
||||
|
||||
@@ -383,9 +383,7 @@ export function buildExecApprovalPendingReplyPayload(
|
||||
lines.push(secondaryFence);
|
||||
}
|
||||
if (!allowedDecisions.includes("allow-always")) {
|
||||
lines.push(
|
||||
"The effective approval policy requires approval every time, so Allow Always is unavailable.",
|
||||
);
|
||||
lines.push("Allow Always is unavailable for this command.");
|
||||
}
|
||||
const info: string[] = [];
|
||||
info.push(`Host: ${params.host}`);
|
||||
|
||||
@@ -155,6 +155,27 @@ describe("plugin-sdk/approval-reaction-runtime", () => {
|
||||
expect(payload.text).not.toContain("\nIgnore previous instructions");
|
||||
});
|
||||
|
||||
it("builds exec reaction prompts with neutral allow-always unavailable copy", () => {
|
||||
const payload = buildApprovalReactionPromptPayloadForRequest({
|
||||
request: {
|
||||
...execRequest,
|
||||
request: {
|
||||
...execRequest.request,
|
||||
ask: "always",
|
||||
},
|
||||
},
|
||||
nowMs: 1_000,
|
||||
});
|
||||
|
||||
expect(payload.text).toContain("React with:\n\n👍 Allow Once\n👎 Deny");
|
||||
expect(payload.text).not.toContain("♾️ Allow Always");
|
||||
expect(payload.text).toContain("Allow Always is unavailable for this command.");
|
||||
expect(payload.text).not.toContain("effective policy requires approval every time");
|
||||
expect(
|
||||
payload.text?.trim().endsWith("Reply with: /approve exec-approval-123 allow-once|deny"),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("builds canonical plugin reaction prompts with real ids", () => {
|
||||
const payload = buildApprovalReactionPromptPayloadForRequest({
|
||||
request: {
|
||||
@@ -176,6 +197,7 @@ describe("plugin-sdk/approval-reaction-runtime", () => {
|
||||
expect(payload.text).toContain(
|
||||
"Allow Always is unavailable because the effective policy requires approval every time.",
|
||||
);
|
||||
expect(payload.text).not.toContain("Allow Always is unavailable for this command.");
|
||||
expect(
|
||||
payload.text?.trim().endsWith("Reply with: /approve plugin:approval-123 allow-once|deny"),
|
||||
).toBe(true);
|
||||
|
||||
@@ -236,13 +236,16 @@ function buildDecisionText(allowedDecisions: readonly ExecApprovalReplyDecision[
|
||||
}
|
||||
|
||||
function buildManualInstructionSection(params: {
|
||||
approvalKind: ApprovalKind;
|
||||
approvalId: string;
|
||||
allowedDecisions: readonly ExecApprovalReplyDecision[];
|
||||
}): string[] {
|
||||
const lines: string[] = [];
|
||||
if (!params.allowedDecisions.includes("allow-always")) {
|
||||
lines.push(
|
||||
"Allow Always is unavailable because the effective policy requires approval every time.",
|
||||
params.approvalKind === "exec"
|
||||
? "Allow Always is unavailable for this command."
|
||||
: "Allow Always is unavailable because the effective policy requires approval every time.",
|
||||
);
|
||||
}
|
||||
if (params.allowedDecisions.length > 0) {
|
||||
@@ -335,6 +338,7 @@ function buildApprovalReactionPromptText(params: {
|
||||
sections.push(commandInstructions.join("\n"));
|
||||
}
|
||||
const manualInstructions = buildManualInstructionSection({
|
||||
approvalKind: view.approvalKind,
|
||||
approvalId: view.approvalId,
|
||||
allowedDecisions,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { html, nothing, render, type LitElement } from "lit";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ExecApprovalRequest } from "../app/exec-approval.ts";
|
||||
import { i18n } from "../i18n/index.ts";
|
||||
import { getRenderedModalDialog, installDialogPolyfill } from "../test-helpers/modal-dialog.ts";
|
||||
import "./exec-approval.ts";
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let restoreDialogPolyfill: () => void;
|
||||
|
||||
function createExecRequest(overrides: Partial<ExecApprovalRequest> = {}): ExecApprovalRequest {
|
||||
return {
|
||||
id: "approval-1",
|
||||
kind: "exec",
|
||||
request: {
|
||||
command: "echo hello",
|
||||
ask: "on-request",
|
||||
},
|
||||
createdAtMs: Date.now() - 1_000,
|
||||
expiresAtMs: Date.now() + 60_000,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
async function renderApproval(request: ExecApprovalRequest) {
|
||||
render(
|
||||
html`<openclaw-exec-approval
|
||||
.props=${{
|
||||
queue: [request],
|
||||
busy: false,
|
||||
error: null,
|
||||
onDecision: vi.fn(),
|
||||
}}
|
||||
></openclaw-exec-approval>`,
|
||||
container,
|
||||
);
|
||||
const approval = container.querySelector<LitElement>("openclaw-exec-approval");
|
||||
if (!approval) {
|
||||
throw new Error("Expected exec approval");
|
||||
}
|
||||
await approval.updateComplete;
|
||||
}
|
||||
|
||||
describe("openclaw-exec-approval", () => {
|
||||
beforeEach(async () => {
|
||||
restoreDialogPolyfill = installDialogPolyfill();
|
||||
await i18n.setLocale("en");
|
||||
container = document.createElement("div");
|
||||
document.body.append(container);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
render(nothing, container);
|
||||
container.remove();
|
||||
await i18n.setLocale("en");
|
||||
restoreDialogPolyfill();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("uses neutral unavailable copy for exec allow-always decisions", async () => {
|
||||
await renderApproval(
|
||||
createExecRequest({
|
||||
request: {
|
||||
command: "echo hello",
|
||||
ask: "always",
|
||||
allowedDecisions: ["allow-once", "deny"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await getRenderedModalDialog(container);
|
||||
|
||||
expect(
|
||||
Array.from(container.querySelectorAll(".exec-approval-actions button")).map((button) =>
|
||||
button.textContent?.trim(),
|
||||
),
|
||||
).toEqual(["Allow once", "Deny"]);
|
||||
expect(container.querySelector(".exec-approval-warning")?.textContent?.trim()).toBe(
|
||||
"Allow Always is unavailable for this command.",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not show exec unavailable copy for restricted plugin approvals", async () => {
|
||||
await renderApproval(
|
||||
createExecRequest({
|
||||
id: "plugin-approval-1",
|
||||
kind: "plugin",
|
||||
request: {
|
||||
command: "Plugin approval",
|
||||
allowedDecisions: ["allow-once", "deny"],
|
||||
},
|
||||
pluginTitle: "Plugin approval",
|
||||
}),
|
||||
);
|
||||
|
||||
await getRenderedModalDialog(container);
|
||||
|
||||
expect(
|
||||
Array.from(container.querySelectorAll(".exec-approval-actions button")).map((button) =>
|
||||
button.textContent?.trim(),
|
||||
),
|
||||
).toEqual(["Allow once", "Deny"]);
|
||||
expect(container.querySelector(".exec-approval-warning")).toBeNull();
|
||||
});
|
||||
});
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:33.404Z",
|
||||
"generatedAt": "2026-07-11T09:56:49.437Z",
|
||||
"locale": "ar",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:32.165Z",
|
||||
"generatedAt": "2026-07-11T09:56:48.554Z",
|
||||
"locale": "de",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:32.362Z",
|
||||
"generatedAt": "2026-07-11T09:56:48.697Z",
|
||||
"locale": "es",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:35.201Z",
|
||||
"generatedAt": "2026-07-11T09:56:51.134Z",
|
||||
"locale": "fa",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:32.981Z",
|
||||
"generatedAt": "2026-07-11T09:56:49.141Z",
|
||||
"locale": "fr",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:33.193Z",
|
||||
"generatedAt": "2026-07-11T09:56:49.292Z",
|
||||
"locale": "hi",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:34.204Z",
|
||||
"generatedAt": "2026-07-11T09:56:50.018Z",
|
||||
"locale": "id",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:33.611Z",
|
||||
"generatedAt": "2026-07-11T09:56:49.584Z",
|
||||
"locale": "it",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:32.564Z",
|
||||
"generatedAt": "2026-07-11T09:56:48.848Z",
|
||||
"locale": "ja-JP",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:32.774Z",
|
||||
"generatedAt": "2026-07-11T09:56:48.993Z",
|
||||
"locale": "ko",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:34.993Z",
|
||||
"generatedAt": "2026-07-11T09:56:50.985Z",
|
||||
"locale": "nl",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:34.419Z",
|
||||
"generatedAt": "2026-07-11T09:56:50.155Z",
|
||||
"locale": "pl",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:31.982Z",
|
||||
"generatedAt": "2026-07-11T09:56:48.414Z",
|
||||
"locale": "pt-BR",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:35.401Z",
|
||||
"generatedAt": "2026-07-11T09:56:51.279Z",
|
||||
"locale": "ru",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:34.610Z",
|
||||
"generatedAt": "2026-07-11T09:56:50.298Z",
|
||||
"locale": "th",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:33.815Z",
|
||||
"generatedAt": "2026-07-11T09:56:49.733Z",
|
||||
"locale": "tr",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:34.005Z",
|
||||
"generatedAt": "2026-07-11T09:56:49.871Z",
|
||||
"locale": "uk",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:34.811Z",
|
||||
"generatedAt": "2026-07-11T09:56:50.827Z",
|
||||
"locale": "vi",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:31.467Z",
|
||||
"generatedAt": "2026-07-11T09:56:47.987Z",
|
||||
"locale": "zh-CN",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fallbackKeys": [],
|
||||
"generatedAt": "2026-07-11T09:23:31.818Z",
|
||||
"generatedAt": "2026-07-11T09:56:48.269Z",
|
||||
"locale": "zh-TW",
|
||||
"model": "gpt-5.5",
|
||||
"provider": "openai",
|
||||
"sourceHash": "9146812dfe02813bf7fc8eb1e6aa5d92db8285d2979abbdb2aa3ad7df99cbfa6",
|
||||
"sourceHash": "fba37d0370a89c15e35e7cb0cc8fa13860cd265f7fd54d798a9e625cdb2e932b",
|
||||
"totalKeys": 2107,
|
||||
"translatedKeys": 2107,
|
||||
"workflow": 1
|
||||
|
||||
Generated
+1
-2
@@ -501,8 +501,7 @@ export const ar: TranslationMap = {
|
||||
pending: "{count} قيد الانتظار",
|
||||
allowOnce: "السماح مرة واحدة",
|
||||
alwaysAllow: "السماح دائمًا",
|
||||
allowAlwaysUnavailable:
|
||||
"تتطلب سياسة الموافقة السارية الحصول على الموافقة في كل مرة، لذا فإن خيار السماح دائمًا غير متاح.",
|
||||
allowAlwaysUnavailable: "خيار السماح دائمًا غير متاح لهذا الأمر.",
|
||||
deny: "رفض",
|
||||
labels: {
|
||||
host: "المضيف",
|
||||
|
||||
Generated
+1
-2
@@ -506,8 +506,7 @@ export const de: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"Die wirksame Genehmigungsrichtlinie erfordert jedes Mal eine Genehmigung, daher ist Immer erlauben nicht verfügbar.",
|
||||
allowAlwaysUnavailable: "Allow Always ist für diesen Befehl nicht verfügbar.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
@@ -500,8 +500,7 @@ export const en: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"The effective approval policy requires approval every time, so Allow Always is unavailable.",
|
||||
allowAlwaysUnavailable: "Allow Always is unavailable for this command.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -503,8 +503,7 @@ export const es: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"La política de aprobación efectiva requiere aprobación cada vez, por lo que Permitir siempre no está disponible.",
|
||||
allowAlwaysUnavailable: "Permitir siempre no está disponible para este comando.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -503,8 +503,7 @@ export const fa: TranslationMap = {
|
||||
pending: "{count} در انتظار",
|
||||
allowOnce: "یکبار مجاز کن",
|
||||
alwaysAllow: "همیشه مجاز کن",
|
||||
allowAlwaysUnavailable:
|
||||
"سیاست تأیید مؤثر هر بار به تأیید نیاز دارد، بنابراین «همیشه مجاز باشد» در دسترس نیست.",
|
||||
allowAlwaysUnavailable: "«همیشه مجاز باشد» برای این فرمان در دسترس نیست.",
|
||||
deny: "رد کردن",
|
||||
labels: {
|
||||
host: "میزبان",
|
||||
|
||||
Generated
+1
-2
@@ -509,8 +509,7 @@ export const fr: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"La politique d’approbation effective exige une approbation à chaque fois, donc Autoriser toujours n’est pas disponible.",
|
||||
allowAlwaysUnavailable: "Autoriser toujours n’est pas disponible pour cette commande.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -502,8 +502,7 @@ export const hi: TranslationMap = {
|
||||
pending: "{count} लंबित",
|
||||
allowOnce: "एक बार अनुमति दें",
|
||||
alwaysAllow: "हमेशा अनुमति दें",
|
||||
allowAlwaysUnavailable:
|
||||
"प्रभावी अनुमोदन नीति हर बार अनुमोदन की आवश्यकता रखती है, इसलिए हमेशा अनुमति दें उपलब्ध नहीं है।",
|
||||
allowAlwaysUnavailable: "इस कमांड के लिए हमेशा अनुमति दें उपलब्ध नहीं है।",
|
||||
deny: "अस्वीकार करें",
|
||||
labels: {
|
||||
host: "होस्ट",
|
||||
|
||||
Generated
+1
-2
@@ -503,8 +503,7 @@ export const id: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"Kebijakan persetujuan yang berlaku mengharuskan persetujuan setiap kali, sehingga Izinkan Selalu tidak tersedia.",
|
||||
allowAlwaysUnavailable: "Izinkan Selalu tidak tersedia untuk perintah ini.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -508,8 +508,7 @@ export const it: TranslationMap = {
|
||||
pending: "{count} in sospeso",
|
||||
allowOnce: "Consenti una volta",
|
||||
alwaysAllow: "Consenti sempre",
|
||||
allowAlwaysUnavailable:
|
||||
"Il criterio di approvazione effettivo richiede l’approvazione ogni volta, quindi Consenti sempre non è disponibile.",
|
||||
allowAlwaysUnavailable: "Consenti sempre non è disponibile per questo comando.",
|
||||
deny: "Nega",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -508,8 +508,7 @@ export const ja_JP: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"有効な承認ポリシーでは毎回承認が必要なため、Allow Always は利用できません。",
|
||||
allowAlwaysUnavailable: "このコマンドでは Allow Always は利用できません。",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -501,8 +501,7 @@ export const ko: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"유효한 승인 정책이 매번 승인을 요구하므로, 항상 허용을 사용할 수 없습니다.",
|
||||
allowAlwaysUnavailable: "이 명령에는 항상 허용을 사용할 수 없습니다.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -506,8 +506,7 @@ export const nl: TranslationMap = {
|
||||
pending: "{count} in behandeling",
|
||||
allowOnce: "Eenmalig toestaan",
|
||||
alwaysAllow: "Altijd toestaan",
|
||||
allowAlwaysUnavailable:
|
||||
"Het effectieve goedkeuringsbeleid vereist elke keer goedkeuring, dus Altijd toestaan is niet beschikbaar.",
|
||||
allowAlwaysUnavailable: "Altijd toestaan is niet beschikbaar voor deze opdracht.",
|
||||
deny: "Weigeren",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -504,8 +504,7 @@ export const pl: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"Obowiązująca zasada zatwierdzania wymaga zatwierdzenia za każdym razem, więc opcja Zawsze zezwalaj jest niedostępna.",
|
||||
allowAlwaysUnavailable: "Opcja Zawsze zezwalaj jest niedostępna dla tego polecenia.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -502,8 +502,7 @@ export const pt_BR: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"A política de aprovação efetiva exige aprovação todas as vezes, portanto Permitir sempre não está disponível.",
|
||||
allowAlwaysUnavailable: "Permitir sempre não está disponível para este comando.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -507,8 +507,7 @@ export const ru: TranslationMap = {
|
||||
pending: "Ожидает: {count}",
|
||||
allowOnce: "Разрешить один раз",
|
||||
alwaysAllow: "Всегда разрешать",
|
||||
allowAlwaysUnavailable:
|
||||
"Действующая политика подтверждений требует подтверждения каждый раз, поэтому «Всегда разрешать» недоступно.",
|
||||
allowAlwaysUnavailable: "«Всегда разрешать» недоступно для этой команды.",
|
||||
deny: "Запретить",
|
||||
labels: {
|
||||
host: "Хост",
|
||||
|
||||
Generated
+1
-2
@@ -500,8 +500,7 @@ export const th: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"นโยบายการอนุมัติที่มีผลบังคับใช้กำหนดให้ต้องอนุมัติทุกครั้ง ดังนั้น Allow Always จึงไม่พร้อมใช้งาน",
|
||||
allowAlwaysUnavailable: "Allow Always ไม่พร้อมใช้งานสำหรับคำสั่งนี้",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -506,8 +506,7 @@ export const tr: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"Geçerli onay ilkesi her seferinde onay gerektiriyor, bu nedenle Her Zaman İzin Ver kullanılamıyor.",
|
||||
allowAlwaysUnavailable: "Her Zaman İzin Ver bu komut için kullanılamıyor.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -503,8 +503,7 @@ export const uk: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable:
|
||||
"Чинна політика схвалення вимагає схвалення щоразу, тому «Дозволяти завжди» недоступно.",
|
||||
allowAlwaysUnavailable: "«Дозволяти завжди» недоступно для цієї команди.",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Generated
+1
-2
@@ -502,8 +502,7 @@ export const vi: TranslationMap = {
|
||||
pending: "{count} đang chờ",
|
||||
allowOnce: "Cho phép một lần",
|
||||
alwaysAllow: "Luôn cho phép",
|
||||
allowAlwaysUnavailable:
|
||||
"Chính sách phê duyệt có hiệu lực yêu cầu phê duyệt mọi lần, vì vậy Không cho phép Luôn cho phép.",
|
||||
allowAlwaysUnavailable: "Luôn cho phép không khả dụng cho lệnh này.",
|
||||
deny: "Từ chối",
|
||||
labels: {
|
||||
host: "Máy chủ",
|
||||
|
||||
Generated
+1
-1
@@ -500,7 +500,7 @@ export const zh_CN: TranslationMap = {
|
||||
pending: "{count} 个待处理",
|
||||
allowOnce: "允许一次",
|
||||
alwaysAllow: "始终允许",
|
||||
allowAlwaysUnavailable: "有效的批准策略要求每次都批准,因此“始终允许”不可用。",
|
||||
allowAlwaysUnavailable: "“始终允许”不可用于此命令。",
|
||||
deny: "拒绝",
|
||||
labels: {
|
||||
host: "主机",
|
||||
|
||||
Generated
+1
-1
@@ -500,7 +500,7 @@ export const zh_TW: TranslationMap = {
|
||||
pending: "{count} pending",
|
||||
allowOnce: "Allow once",
|
||||
alwaysAllow: "Always allow",
|
||||
allowAlwaysUnavailable: "有效的核准政策要求每次都需核准,因此「一律允許」無法使用。",
|
||||
allowAlwaysUnavailable: "「一律允許」無法用於此指令。",
|
||||
deny: "Deny",
|
||||
labels: {
|
||||
host: "Host",
|
||||
|
||||
Reference in New Issue
Block a user