mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
feat(ui): add standalone operator approval links (#103698)
* feat(gateway): standalone approval deep-link page Squash-rebased #103698 segment onto the typed-actions tip on current main. Adds the tokenless /approve/{id} standalone approval UI served by the gateway control-UI router, gateway-store ephemeral login fix (selectGateway only on changed URL), and approval-page i18n strings. Drift reconciliation: union-merged i18n translation-memory caches and regenerated locale metadata via control-ui-i18n sync (33 approvalPage keys remain English fallbacks in minor locales, as on the original branch). (cherry picked from commit c82f56011bfe9f0debb8ebe052f14590c187340d) (cherry picked from commit 80f5636a8b67a3d6a5f330620541a39d4ef3fe6f) (cherry picked from commit a3e300d337a92bf1b593a0bb52b7ec4549910a21) (cherry picked from commit 860ad01f9658bba54cb3d59644e5e1a032c0bb3f) (cherry picked from commit d8b697b28a847950a1797da07fc0ae4c24928492) (cherry picked from commit 8a654e3271fd5721358812f961a7a7bb386d6726) (cherry picked from commit 2f776d2e7bf910271fcbd9697597f6f5478b0f30) (cherry picked from commit 14e64e6e4d763be830830801eeec1a6f17441688) (cherry picked from commit 4df9ec828d0034fdc76540ff0fe341e599b0f281) (cherry picked from commit e52968f4ab7628692ca07af73eb8eb454fb1344d) (cherry picked from commit 7214fc25013966f99ff4b2d506aa2f5f789e2113) (cherry picked from commit c6259ff79787c759c136086e1a54c9ead8e89539) (cherry picked from commit a58d9f271d27481615f0c94a828704c563d5354f) (cherry picked from commit dcf1cb6d980598232cbfabd1d7ba33f538b43422) * fix(ui): preserve approval page gateway auth * fix(ui): keep approval disconnects fail closed * style(ui): format approval disconnect copy
This commit is contained in:
committed by
GitHub
parent
50400c92bc
commit
4eb1f5225c
@@ -166,6 +166,8 @@ Add kind-agnostic reviewer methods:
|
||||
| `approval.get { id }` | Returns a visible pending or retained terminal projection. |
|
||||
| `approval.resolve { id, kind, decision }` | Accepts the canonical ID or fixed-size transport reference, then runs authorization, kind and allowed-decision validation, deadline reconciliation, and terminal CAS. The response always carries the canonical ID. |
|
||||
|
||||
After a successful CAS, return the committed projection immediately. Legacy events, channel forwarders, and push terminalizers are best-effort follow-ups; a slow or failed surface must not delay or roll back the winning response.
|
||||
|
||||
Kind-specific request validation remains in `exec.approval.request` and `plugin.approval.request`. Existing `exec.approval.get/list/waitDecision/resolve` and `plugin.approval.list/waitDecision/resolve` become protocol-boundary adapters to the canonical service because they are shipped Gateway API. Internal callers migrate to the service in the same change.
|
||||
|
||||
A reviewer projection is a tagged union:
|
||||
@@ -229,6 +231,8 @@ The route is `${basePath}/approve/{approvalId}`. The ID is the only path paramet
|
||||
|
||||
Because the current router has exact static routes and rewrites unknown paths to Chat, detect this deep link in `ui/src/app/bootstrap.ts` before normal route normalization. Reuse normal Gateway/auth setup, but render a standalone approval page outside the sidebar shell and global modal.
|
||||
|
||||
The document is owned by the Gateway that served its URL. Its initial connection ignores the full app's persisted remote-Gateway selection without changing or copying that selection's settings; only auth stays session-scoped to the serving Gateway. Trusted native auth or a separately confirmed `gatewayUrl` override may retarget it. The core reserves the one-segment `/approve` namespace ahead of plugin HTTP routes and static-extension detection, including IDs that end in `.json` or `.js`; when Control UI serving is disabled, the reserved route fails closed with `404`. Keep the page in the main Control UI bundle so a failed lazy chunk cannot strand a security decision on a spinner.
|
||||
|
||||
Page states:
|
||||
|
||||
- loading
|
||||
@@ -371,6 +375,8 @@ Do not silently change them in the storage PR. The strict-semantics PR must upda
|
||||
### PR 3: Control UI deep link
|
||||
|
||||
- Standalone authenticated approval page and base-path-aware startup routing.
|
||||
- Serving-Gateway binding without mutating the operator's saved remote selection.
|
||||
- Core-owned approval HTTP namespace, including asset-like IDs.
|
||||
- Gateway-authored URL payload and pending-state polling until lifecycle events ship.
|
||||
- Mobile-width, reconnect, competing-answer, reload, and mounted-path proof.
|
||||
|
||||
|
||||
@@ -570,7 +570,14 @@ When gateway auth is configured, assistant local-media previews use a two-step r
|
||||
|
||||
This keeps media rendering compatible with browser-native media elements without putting reusable gateway credentials in visible media URLs.
|
||||
|
||||
## Building the UI
|
||||
## Approval links
|
||||
|
||||
Operator approval notifications can deep-link to a standalone approval document served under the reserved `${controlUiBasePath}/approve/{approvalId}` namespace (for example `/approve/<approvalId>`, or `/openclaw/approve/<approvalId>` with a configured base path). The URL is stable for the lifetime of the approval and safe to forward between your own devices: it identifies the approval, never authorizes it.
|
||||
|
||||
- The one-segment `/approve/<approvalId>` namespace is reserved by the Gateway ahead of plugin HTTP routes for **all** HTTP methods, so a plugin route can never shadow or intercept an approval document.
|
||||
- Opening an approval document requires the same gateway auth as the rest of the Control UI (token/password, Tailscale Serve identity, or trusted-proxy identity); credentials are never part of the approval URL.
|
||||
- When Control UI serving is disabled, requests to the namespace return `404` instead of falling through to plugin handlers.
|
||||
- Signing in on an approval document is ephemeral for that page: it does not overwrite the gateway selection or settings saved by the full Control UI in the same browser.
|
||||
|
||||
The Gateway serves static files from `dist/control-ui`:
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
* Control UI gateway routing tests.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { classifyControlUiRequest, isControlUiPluginManagerRequest } from "./control-ui-routing.js";
|
||||
import {
|
||||
classifyControlUiRequest,
|
||||
isControlUiApprovalDocumentPath,
|
||||
isControlUiPluginManagerRequest,
|
||||
} from "./control-ui-routing.js";
|
||||
|
||||
describe("isControlUiPluginManagerRequest", () => {
|
||||
it.each([
|
||||
@@ -21,6 +25,25 @@ describe("isControlUiPluginManagerRequest", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("isControlUiApprovalDocumentPath", () => {
|
||||
it.each([
|
||||
{ basePath: "", pathname: "/approve" },
|
||||
{ basePath: "", pathname: "/approve/" },
|
||||
{ basePath: "", pathname: "/approve/plugin%3Arequest.json" },
|
||||
{ basePath: "/openclaw", pathname: "/openclaw/approve/exec%3Aa%2Fb" },
|
||||
])("reserves $pathname", ({ basePath, pathname }) => {
|
||||
expect(isControlUiApprovalDocumentPath({ basePath, pathname })).toBe(true);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ basePath: "", pathname: "/approvals/id" },
|
||||
{ basePath: "", pathname: "/approve/id/extra" },
|
||||
{ basePath: "/openclaw", pathname: "/approve/id" },
|
||||
])("does not reserve $pathname", ({ basePath, pathname }) => {
|
||||
expect(isControlUiApprovalDocumentPath({ basePath, pathname })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("classifyControlUiRequest", () => {
|
||||
describe("root-mounted control ui", () => {
|
||||
it.each([
|
||||
|
||||
@@ -23,6 +23,23 @@ export function isControlUiPluginManagerRequest(params: {
|
||||
return params.pathname === path || params.pathname === `${path}/`;
|
||||
}
|
||||
|
||||
/** Core-owned standalone approval document namespace, before plugin routing. */
|
||||
export function isControlUiApprovalDocumentPath(params: {
|
||||
basePath: string;
|
||||
pathname: string;
|
||||
}): boolean {
|
||||
const root = `${params.basePath}/approve`;
|
||||
if (params.pathname === root || params.pathname === `${root}/`) {
|
||||
return true;
|
||||
}
|
||||
const prefix = `${root}/`;
|
||||
if (!params.pathname.startsWith(prefix)) {
|
||||
return false;
|
||||
}
|
||||
const encodedId = params.pathname.slice(prefix.length);
|
||||
return encodedId.length > 0 && !encodedId.includes("/");
|
||||
}
|
||||
|
||||
/** Classify an HTTP request as Control UI serving, redirect, 404, or non-Control-UI. */
|
||||
export function classifyControlUiRequest(params: {
|
||||
basePath: string;
|
||||
|
||||
@@ -1842,6 +1842,89 @@ describe("handleControlUiHttpRequest", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "root-mounted",
|
||||
basePath: undefined,
|
||||
url: "/approve/Approval%3AMobile%2F%E6%9D%B1%E4%BA%AC%20100%25%20%F0%9F%A6%9E",
|
||||
},
|
||||
{
|
||||
name: "configured-base-path",
|
||||
basePath: "/openclaw",
|
||||
url: "/openclaw/approve/Approval%3AMobile%2F%E6%9D%B1%E4%BA%AC%20100%25%20%F0%9F%A6%9E",
|
||||
},
|
||||
{
|
||||
name: "asset-like-id",
|
||||
basePath: undefined,
|
||||
url: "/approve/plugin%3Arequest.json",
|
||||
},
|
||||
{
|
||||
name: "configured-base-asset-like-id",
|
||||
basePath: "/openclaw",
|
||||
url: "/openclaw/approve/plugin%3Arequest.js",
|
||||
},
|
||||
])("serves $name approval deep links through the SPA fallback", async ({ basePath, url }) => {
|
||||
await withControlUiRoot({
|
||||
indexHtml: "<html><body>approval-spa</body></html>\n",
|
||||
fn: async (tmp) => {
|
||||
for (const method of ["GET", "HEAD"] as const) {
|
||||
const { res, end, handled } = await runControlUiRequest({
|
||||
url,
|
||||
method,
|
||||
rootPath: tmp,
|
||||
basePath,
|
||||
});
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(res.statusCode).toBe(200);
|
||||
if (method === "HEAD") {
|
||||
expect(firstEndCallLength(end)).toBe(0);
|
||||
} else {
|
||||
expect(responseBody(end)).toContain("approval-spa");
|
||||
if (basePath) {
|
||||
expect(responseBody(end)).toContain('data-openclaw-control-ui-base-path="/openclaw"');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "root-mounted",
|
||||
basePath: undefined,
|
||||
url: "/approve/Approval%3AMobile%2F%E6%9D%B1%E4%BA%AC%20100%25%20%F0%9F%A6%9E",
|
||||
},
|
||||
{
|
||||
name: "configured-base-path",
|
||||
basePath: "/openclaw",
|
||||
url: "/openclaw/approve/Approval%3AMobile%2F%E6%9D%B1%E4%BA%AC%20100%25%20%F0%9F%A6%9E",
|
||||
},
|
||||
{
|
||||
name: "asset-like-id",
|
||||
basePath: undefined,
|
||||
url: "/approve/plugin%3Arequest.json",
|
||||
},
|
||||
])("declines POST to $name approval deep links at the UI module", async ({ basePath, url }) => {
|
||||
await withControlUiRoot({
|
||||
fn: async (tmp) => {
|
||||
const { handled, end } = await runControlUiRequest({
|
||||
url,
|
||||
method: "POST",
|
||||
rootPath: tmp,
|
||||
basePath,
|
||||
});
|
||||
|
||||
// The UI module only serves reads; the gateway's approval-document
|
||||
// stage (server-http.ts) owns the terminal 404 for write methods, so
|
||||
// these requests never reach plugin HTTP handlers in production.
|
||||
expect(handled).toBe(false);
|
||||
expect(end).not.toHaveBeenCalled();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects symlinked SPA fallback index.html outside control-ui root", async () => {
|
||||
await withControlUiRoot({
|
||||
fn: async (tmp) => {
|
||||
|
||||
@@ -56,7 +56,7 @@ import {
|
||||
respondNotFound as respondControlUiNotFound,
|
||||
respondPlainText,
|
||||
} from "./control-ui-http-utils.js";
|
||||
import { classifyControlUiRequest } from "./control-ui-routing.js";
|
||||
import { classifyControlUiRequest, isControlUiApprovalDocumentPath } from "./control-ui-routing.js";
|
||||
import {
|
||||
buildControlUiAvatarUrl,
|
||||
CONTROL_UI_AVATAR_PREFIX,
|
||||
@@ -1087,6 +1087,7 @@ export async function handleControlUiHttpRequest(
|
||||
|
||||
const uiPath =
|
||||
basePath && pathname.startsWith(`${basePath}/`) ? pathname.slice(basePath.length) : pathname;
|
||||
const approvalDocument = isControlUiApprovalDocumentPath({ basePath, pathname });
|
||||
const rel = (() => {
|
||||
if (uiPath === ROOT_PREFIX) {
|
||||
return "";
|
||||
@@ -1103,7 +1104,11 @@ export async function handleControlUiHttpRequest(
|
||||
}
|
||||
return uiPath.slice(1);
|
||||
})();
|
||||
const requested = rel && !rel.endsWith("/") ? rel : `${rel}index.html`;
|
||||
const requested = approvalDocument
|
||||
? "index.html"
|
||||
: rel && !rel.endsWith("/")
|
||||
? rel
|
||||
: `${rel}index.html`;
|
||||
const fileRel = requested || "index.html";
|
||||
if (!isSafeRelativePath(fileRel)) {
|
||||
respondControlUiNotFound(res);
|
||||
|
||||
+44
-14
@@ -26,7 +26,10 @@ import {
|
||||
type GatewayAuthResult,
|
||||
type ResolvedGatewayAuth,
|
||||
} from "./auth.js";
|
||||
import { isControlUiPluginManagerRequest } from "./control-ui-routing.js";
|
||||
import {
|
||||
isControlUiApprovalDocumentPath,
|
||||
isControlUiPluginManagerRequest,
|
||||
} from "./control-ui-routing.js";
|
||||
import type { ControlUiRootState } from "./control-ui.js";
|
||||
import type { AuthorizedGatewayHttpRequest } from "./http-auth-utils.js";
|
||||
import { sendGatewayAuthFailure, setDefaultSecurityHeaders } from "./http-common.js";
|
||||
@@ -544,6 +547,19 @@ export function createGatewayHttpServer(opts: {
|
||||
? resolvePluginRoutePathContext(scopedRequestPath)
|
||||
: null;
|
||||
const resolvedAuthValue = getResolvedAuth();
|
||||
const handleControlUiRequest = async () =>
|
||||
(await getControlUiModule()).handleControlUiHttpRequest(req, res, {
|
||||
basePath: controlUiBasePath,
|
||||
config: configSnapshot,
|
||||
terminalEnabled:
|
||||
opts.isTerminalEnabled?.() ?? configSnapshot.gateway?.terminal?.enabled === true,
|
||||
agentId: resolveAssistantIdentity({ cfg: configSnapshot }).agentId,
|
||||
root: controlUiRoot,
|
||||
auth: resolvedAuthValue,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
});
|
||||
const requestStages: GatewayHttpRequestStage[] = [
|
||||
{
|
||||
name: "gateway-probes",
|
||||
@@ -674,6 +690,32 @@ export function createGatewayHttpServer(opts: {
|
||||
),
|
||||
});
|
||||
}
|
||||
if (
|
||||
isControlUiApprovalDocumentPath({
|
||||
basePath: controlUiBasePath,
|
||||
pathname: scopedRequestPath,
|
||||
})
|
||||
) {
|
||||
requestStages.push({
|
||||
name: "control-ui-approval-document",
|
||||
run: async () => {
|
||||
if (!controlUiEnabled) {
|
||||
res.statusCode = 404;
|
||||
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
res.end("Not Found");
|
||||
return true;
|
||||
}
|
||||
const handled = await handleControlUiRequest();
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
res.statusCode = 404;
|
||||
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
res.end("Not Found");
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
handlePluginRequest &&
|
||||
pluginPathContext &&
|
||||
@@ -800,19 +842,7 @@ export function createGatewayHttpServer(opts: {
|
||||
});
|
||||
requestStages.push({
|
||||
name: "control-ui-http",
|
||||
run: async () =>
|
||||
(await getControlUiModule()).handleControlUiHttpRequest(req, res, {
|
||||
basePath: controlUiBasePath,
|
||||
config: configSnapshot,
|
||||
terminalEnabled:
|
||||
opts.isTerminalEnabled?.() ?? configSnapshot.gateway?.terminal?.enabled === true,
|
||||
agentId: resolveAssistantIdentity({ cfg: configSnapshot }).agentId,
|
||||
root: controlUiRoot,
|
||||
auth: resolvedAuthValue,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
}),
|
||||
run: handleControlUiRequest,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -654,6 +654,78 @@ describe("gateway plugin HTTP auth boundary", () => {
|
||||
},
|
||||
);
|
||||
|
||||
test("reserves standalone approval documents ahead of plugin routes", async () => {
|
||||
const handlePluginRequest = vi.fn(async (_req: IncomingMessage, res: ServerResponse) => {
|
||||
res.statusCode = 200;
|
||||
res.end("plugin-shadowed-approval");
|
||||
return true;
|
||||
});
|
||||
|
||||
await withRootMountedControlUiServer({
|
||||
prefix: "openclaw-plugin-http-approval-reservation-test-",
|
||||
handlePluginRequest,
|
||||
run: async (server) => {
|
||||
const response = await sendRequest(server, { path: "/approve/plugin%3Arequest.json" });
|
||||
|
||||
expect(response.res.statusCode).toBe(503);
|
||||
expect(response.getBody()).toContain("Control UI assets not found");
|
||||
expect(handlePluginRequest).not.toHaveBeenCalled();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("terminates approval-document writes at the reservation stage", async () => {
|
||||
const handlePluginRequest = vi.fn(async (_req: IncomingMessage, res: ServerResponse) => {
|
||||
res.statusCode = 200;
|
||||
res.end("plugin-shadowed-approval-write");
|
||||
return true;
|
||||
});
|
||||
|
||||
await withRootMountedControlUiServer({
|
||||
prefix: "openclaw-plugin-http-approval-write-reservation-test-",
|
||||
handlePluginRequest,
|
||||
run: async (server) => {
|
||||
for (const method of ["POST", "PUT"] as const) {
|
||||
const response = await sendRequest(server, {
|
||||
path: "/approve/plugin%3Arequest.json",
|
||||
method,
|
||||
});
|
||||
|
||||
// The server approval-document stage owns the terminal 404 for all
|
||||
// methods; writes never fall through to plugin HTTP handlers.
|
||||
expect(response.res.statusCode, method).toBe(404);
|
||||
expect(response.getBody(), method).toBe("Not Found");
|
||||
}
|
||||
expect(handlePluginRequest).not.toHaveBeenCalled();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("keeps approval documents reserved when control ui serving is disabled", async () => {
|
||||
const handlePluginRequest = vi.fn(async (_req: IncomingMessage, res: ServerResponse) => {
|
||||
res.statusCode = 200;
|
||||
res.end("plugin-shadowed-disabled-approval");
|
||||
return true;
|
||||
});
|
||||
|
||||
await withPluginGatewayServer({
|
||||
prefix: "openclaw-plugin-http-disabled-approval-reservation-test-",
|
||||
resolvedAuth: AUTH_NONE,
|
||||
overrides: {
|
||||
controlUiEnabled: false,
|
||||
controlUiBasePath: "",
|
||||
handlePluginRequest,
|
||||
},
|
||||
run: async (server) => {
|
||||
const response = await sendRequest(server, { path: "/approve/exec%3Arequest" });
|
||||
|
||||
expect(response.res.statusCode).toBe(404);
|
||||
expect(response.getBody()).toBe("Not Found");
|
||||
expect(handlePluginRequest).not.toHaveBeenCalled();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("passes POST webhook routes through root-mounted control ui to plugins", async () => {
|
||||
const handlePluginRequest = vi.fn(async (req: IncomingMessage, res: ServerResponse) => {
|
||||
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
||||
|
||||
@@ -33,6 +33,7 @@ import { isWorkboardEnabledInConfigSnapshot } from "../lib/plugin-activation.ts"
|
||||
import { searchForSession } from "../lib/sessions/index.ts";
|
||||
import { OpenClawLightDomElement } from "../lit/openclaw-element.ts";
|
||||
import { SubscriptionsController } from "../lit/subscriptions-controller.ts";
|
||||
import "../pages/approval/approval-page.ts";
|
||||
import { renderDevicePairSetup } from "../pages/nodes/view-pairing.ts";
|
||||
import { pluginTabKey, pluginTabRefFromSearch } from "../pages/plugin/route.ts";
|
||||
import { bootstrapApplication, type ApplicationRuntime } from "./bootstrap.ts";
|
||||
@@ -111,6 +112,25 @@ function renderConnectingSplash(basePath: string) {
|
||||
`;
|
||||
}
|
||||
|
||||
function renderApprovalDocument(runtime: ApplicationRuntime) {
|
||||
const documentMode = runtime.documentMode;
|
||||
if (documentMode?.kind !== "approval") {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<openclaw-approval-page .approvalId=${documentMode.approvalId ?? ""}>
|
||||
<main class="approval-page approval-page--booting" role="status" aria-live="polite">
|
||||
<img
|
||||
class="connect-splash__logo"
|
||||
src=${controlUiPublicAssetPath("favicon.svg", runtime.context.basePath)}
|
||||
alt=""
|
||||
/>
|
||||
<span>${t("common.loading")}</span>
|
||||
</main>
|
||||
</openclaw-approval-page>
|
||||
`;
|
||||
}
|
||||
|
||||
function isTerminalAvailable(
|
||||
snapshot: ApplicationContext["gateway"]["snapshot"],
|
||||
terminalEnabled: boolean,
|
||||
@@ -384,6 +404,13 @@ class OpenClawApp extends OpenClawLightDomElement {
|
||||
</openclaw-tooltip-provider>
|
||||
`;
|
||||
}
|
||||
if (runtime.documentMode?.kind === "approval") {
|
||||
return html`
|
||||
<openclaw-tooltip-provider>
|
||||
${gatewayUrlConfirmation} ${renderApprovalDocument(runtime)}
|
||||
</openclaw-tooltip-provider>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<openclaw-tooltip-provider>
|
||||
<openclaw-github-link-hovercard-provider .client=${gatewaySnapshot.client}>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveApprovalDocumentMode } from "./approval-deep-link.ts";
|
||||
|
||||
describe("resolveApprovalDocumentMode", () => {
|
||||
it("resolves root and configured-base approval links", () => {
|
||||
expect(resolveApprovalDocumentMode("/approve/exec%3A123", "")).toEqual({
|
||||
kind: "approval",
|
||||
approvalId: "exec:123",
|
||||
});
|
||||
expect(resolveApprovalDocumentMode("/operator/approve/plugin%3A456", "/operator/")).toEqual({
|
||||
kind: "approval",
|
||||
approvalId: "plugin:456",
|
||||
});
|
||||
});
|
||||
|
||||
it("decodes one stable path segment without narrowing valid approval ids", () => {
|
||||
const approvalId = "plugin:a/b%🦞";
|
||||
expect(resolveApprovalDocumentMode(`/approve/${encodeURIComponent(approvalId)}`, "")).toEqual({
|
||||
kind: "approval",
|
||||
approvalId,
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
"/approve",
|
||||
"/approve/",
|
||||
"/approve/%",
|
||||
"/approve/%2e",
|
||||
"/approve/%2E%2E",
|
||||
"/approve/id/extra",
|
||||
"/approve/id/",
|
||||
])("keeps malformed approval-shaped paths shellless: %s", (pathname) => {
|
||||
expect(resolveApprovalDocumentMode(pathname, "")).toEqual({
|
||||
kind: "approval",
|
||||
approvalId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not claim ordinary or out-of-mount paths", () => {
|
||||
expect(resolveApprovalDocumentMode("/chat", "")).toBeNull();
|
||||
expect(resolveApprovalDocumentMode("/approve/id", "/operator")).toBeNull();
|
||||
expect(resolveApprovalDocumentMode("/operator/approvals/id", "/operator")).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { normalizeBasePath } from "../app-route-paths.ts";
|
||||
|
||||
export type ApprovalDocumentMode = {
|
||||
kind: "approval";
|
||||
approvalId: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recognizes the shellless approval document before the exact-path app router
|
||||
* can replace it with Chat. The Gateway validates the decoded id; this parser
|
||||
* only preserves the one-segment URL contract and rejects ambiguous paths.
|
||||
*/
|
||||
export function resolveApprovalDocumentMode(
|
||||
pathname: string,
|
||||
basePath: string,
|
||||
): ApprovalDocumentMode | null {
|
||||
const normalizedBasePath = normalizeBasePath(basePath);
|
||||
const approvalRoot = `${normalizedBasePath}/approve`;
|
||||
if (pathname === approvalRoot || pathname === `${approvalRoot}/`) {
|
||||
return { kind: "approval", approvalId: null };
|
||||
}
|
||||
const prefix = `${approvalRoot}/`;
|
||||
if (!pathname.startsWith(prefix)) {
|
||||
return null;
|
||||
}
|
||||
const encodedId = pathname.slice(prefix.length);
|
||||
if (!encodedId || encodedId.includes("/")) {
|
||||
return { kind: "approval", approvalId: null };
|
||||
}
|
||||
try {
|
||||
const approvalId = decodeURIComponent(encodedId);
|
||||
return approvalId && approvalId !== "." && approvalId !== ".."
|
||||
? { kind: "approval", approvalId }
|
||||
: { kind: "approval", approvalId: null };
|
||||
} catch {
|
||||
return { kind: "approval", approvalId: null };
|
||||
}
|
||||
}
|
||||
+28
-9
@@ -16,6 +16,7 @@ import { createRuntimeConfigCapability } from "../lib/config/index.ts";
|
||||
import { createSessionCapability } from "../lib/sessions/index.ts";
|
||||
import { createWorkboardCapability } from "../lib/workboard/capability.ts";
|
||||
import { createAgentSelectionCapability } from "./agent-selection.ts";
|
||||
import { resolveApprovalDocumentMode, type ApprovalDocumentMode } from "./approval-deep-link.ts";
|
||||
import { createBrowserHistory, resolveControlUiBasePath } from "./browser.ts";
|
||||
import { createApplicationConfigCapability } from "./config.ts";
|
||||
import type {
|
||||
@@ -34,7 +35,9 @@ import { createApplicationOverlays } from "./overlays.ts";
|
||||
import {
|
||||
loadSettings,
|
||||
patchSettings,
|
||||
persistSessionToken,
|
||||
resolveApplicationStartupSettings,
|
||||
resolvePageGatewaySettings,
|
||||
saveSettings,
|
||||
type UiSettings,
|
||||
} from "./settings.ts";
|
||||
@@ -220,6 +223,7 @@ function createSkillWorkshopRevisionHandoff(): ApplicationSkillWorkshopRevisionH
|
||||
export type ApplicationRuntime = {
|
||||
readonly context: ApplicationContext<RouteId>;
|
||||
readonly router: ApplicationRouter;
|
||||
readonly documentMode: ApprovalDocumentMode | null;
|
||||
readonly pendingGatewayConnection: {
|
||||
readonly gatewayUrl: string;
|
||||
readonly token: string;
|
||||
@@ -231,20 +235,30 @@ export type ApplicationRuntime = {
|
||||
};
|
||||
|
||||
export function bootstrapApplication(): ApplicationRuntime {
|
||||
const initialSettings = loadSettings();
|
||||
const history = createBrowserHistory();
|
||||
const startup = resolveApplicationStartupSettings(initialSettings, history.location());
|
||||
const startupLocation = history.location();
|
||||
const initialBasePath = resolveControlUiBasePath(
|
||||
startupLocation.pathname || globalThis.location?.pathname || "/",
|
||||
);
|
||||
const documentMode = resolveApprovalDocumentMode(startupLocation.pathname, initialBasePath);
|
||||
const persistedSettings = loadSettings();
|
||||
const initialSettings = documentMode
|
||||
? resolvePageGatewaySettings(persistedSettings)
|
||||
: persistedSettings;
|
||||
const startup = resolveApplicationStartupSettings(initialSettings, startupLocation);
|
||||
if (startup.changed) {
|
||||
saveSettings(startup.settings);
|
||||
if (documentMode) {
|
||||
persistSessionToken(startup.settings.gatewayUrl, startup.settings.token);
|
||||
} else {
|
||||
saveSettings(startup.settings);
|
||||
}
|
||||
}
|
||||
const basePath = resolveControlUiBasePath(
|
||||
startup.location.pathname || globalThis.location?.pathname || "/",
|
||||
);
|
||||
const initialLocation = normalizeInitialApplicationLocation(
|
||||
startup.location,
|
||||
basePath,
|
||||
startup.settings.sessionKey,
|
||||
);
|
||||
const initialLocation = documentMode
|
||||
? startup.location
|
||||
: normalizeInitialApplicationLocation(startup.location, basePath, startup.settings.sessionKey);
|
||||
const currentLocation = history.location();
|
||||
if (
|
||||
currentLocation.pathname !== initialLocation.pathname ||
|
||||
@@ -259,6 +273,8 @@ export function bootstrapApplication(): ApplicationRuntime {
|
||||
settings,
|
||||
startup.password ?? "",
|
||||
startup.pendingBootstrapToken ?? "",
|
||||
undefined,
|
||||
{ persistDefaultConnectionSettings: documentMode === null },
|
||||
);
|
||||
const agents = createAgentCapability(gateway);
|
||||
const agentIdentity = createAgentIdentityCapability(gateway);
|
||||
@@ -371,6 +387,7 @@ export function bootstrapApplication(): ApplicationRuntime {
|
||||
return {
|
||||
context,
|
||||
router,
|
||||
documentMode,
|
||||
get pendingGatewayConnection() {
|
||||
return pendingGatewayConnection;
|
||||
},
|
||||
@@ -378,7 +395,9 @@ export function bootstrapApplication(): ApplicationRuntime {
|
||||
cancelPendingGatewayConnection,
|
||||
start: async () => {
|
||||
void config.refresh({ skipWithoutAuthCandidate: true });
|
||||
const routerStart = startApplicationRouter(router, history, basePath, context);
|
||||
const routerStart = documentMode
|
||||
? Promise.resolve()
|
||||
: startApplicationRouter(router, history, basePath, context);
|
||||
gateway.start();
|
||||
await routerStart;
|
||||
},
|
||||
|
||||
@@ -34,13 +34,24 @@ class FakeGatewayClient {
|
||||
}
|
||||
}
|
||||
|
||||
function createStore() {
|
||||
function createStore(
|
||||
params: {
|
||||
settings?: ReturnType<typeof loadSettings>;
|
||||
persistDefaultConnectionSettings?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
const clients: FakeGatewayClient[] = [];
|
||||
const gateway = createApplicationGateway(loadSettings(), "", "", (opts) => {
|
||||
const client = new FakeGatewayClient(opts);
|
||||
clients.push(client);
|
||||
return client as unknown as GatewayBrowserClient;
|
||||
});
|
||||
const gateway = createApplicationGateway(
|
||||
params.settings ?? loadSettings(),
|
||||
"",
|
||||
"",
|
||||
(opts) => {
|
||||
const client = new FakeGatewayClient(opts);
|
||||
clients.push(client);
|
||||
return client as unknown as GatewayBrowserClient;
|
||||
},
|
||||
{ persistDefaultConnectionSettings: params.persistDefaultConnectionSettings },
|
||||
);
|
||||
const current = () => {
|
||||
const client = clients.at(-1);
|
||||
if (!client) {
|
||||
@@ -153,4 +164,73 @@ describe("createApplicationGateway reconnecting snapshot", () => {
|
||||
// The superseded client cannot demote the fresh attempt's snapshot.
|
||||
expect(gateway.snapshot.reconnecting).toBe(true);
|
||||
});
|
||||
|
||||
it("does not copy selected-remote settings into an ephemeral document Gateway", () => {
|
||||
const pageGateway = "ws://127.0.0.1:18789";
|
||||
const remoteGateway = "wss://saved-remote.example.test";
|
||||
const pageSettingsKey = `openclaw.control.settings.v1:${pageGateway}`;
|
||||
const selectionKey = `openclaw.control.currentGateway.v1:${pageGateway}`;
|
||||
const storedPageSettings = JSON.stringify({
|
||||
gatewayUrl: pageGateway,
|
||||
theme: "claw",
|
||||
sessionKey: "agent:page:saved",
|
||||
});
|
||||
const settings = {
|
||||
...loadSettings(),
|
||||
gatewayUrl: pageGateway,
|
||||
token: "page-token",
|
||||
theme: "dash" as const,
|
||||
sessionKey: "agent:page:document",
|
||||
lastActiveSessionKey: "agent:page:document",
|
||||
};
|
||||
localStorage.setItem(pageSettingsKey, storedPageSettings);
|
||||
localStorage.setItem(selectionKey, remoteGateway);
|
||||
const { gateway, current } = createStore({
|
||||
settings,
|
||||
persistDefaultConnectionSettings: false,
|
||||
});
|
||||
|
||||
gateway.start();
|
||||
expect(current().opts.token).toBe("page-token");
|
||||
current().opts.onHello?.(HELLO);
|
||||
gateway.connect({ token: "replacement-page-token" });
|
||||
|
||||
expect(current().opts.token).toBe("replacement-page-token");
|
||||
expect(localStorage.getItem(pageSettingsKey)).toBe(storedPageSettings);
|
||||
expect(localStorage.getItem(selectionKey)).toBe(remoteGateway);
|
||||
});
|
||||
|
||||
it("keeps ephemeral login on the serving gateway from persisting the selection", () => {
|
||||
const pageGateway = "ws://127.0.0.1:18789";
|
||||
const remoteGateway = "wss://saved-remote.example.test";
|
||||
const otherGateway = "wss://other-remote.example.test";
|
||||
const pageSettingsKey = `openclaw.control.settings.v1:${pageGateway}`;
|
||||
const selectionKey = `openclaw.control.currentGateway.v1:${pageGateway}`;
|
||||
const settings = {
|
||||
...loadSettings(),
|
||||
gatewayUrl: pageGateway,
|
||||
token: "",
|
||||
};
|
||||
localStorage.setItem(selectionKey, remoteGateway);
|
||||
const { gateway, current } = createStore({
|
||||
settings,
|
||||
persistDefaultConnectionSettings: false,
|
||||
});
|
||||
|
||||
gateway.start();
|
||||
// The login gate always resubmits its prefilled (serving) gateway URL;
|
||||
// an unchanged URL must not count as an explicit gateway selection.
|
||||
gateway.connect({ gatewayUrl: pageGateway, token: "approval-token", password: "pw" });
|
||||
|
||||
expect(current().opts.url).toBe(pageGateway);
|
||||
expect(current().opts.token).toBe("approval-token");
|
||||
expect(localStorage.getItem(pageSettingsKey)).toBeNull();
|
||||
expect(localStorage.getItem(selectionKey)).toBe(remoteGateway);
|
||||
|
||||
// A genuinely changed URL is an explicit selection and persists.
|
||||
gateway.connect({ gatewayUrl: otherGateway });
|
||||
|
||||
expect(current().opts.url).toBe(otherGateway);
|
||||
expect(localStorage.getItem(selectionKey)).toBe(otherGateway);
|
||||
});
|
||||
});
|
||||
|
||||
+40
-14
@@ -15,7 +15,7 @@ import type {
|
||||
ApplicationGatewayConnection,
|
||||
ApplicationGatewaySnapshot,
|
||||
} from "./context.ts";
|
||||
import { loadSettings, patchSettings } from "./settings.ts";
|
||||
import { loadSettings, patchSettings, persistSessionToken } from "./settings.ts";
|
||||
|
||||
type GatewayClientFactory = (opts: GatewayBrowserClientOptions) => GatewayBrowserClient;
|
||||
|
||||
@@ -26,8 +26,10 @@ export function createApplicationGateway(
|
||||
initialPassword = "",
|
||||
initialBootstrapToken = "",
|
||||
createClient: GatewayClientFactory = defaultClientFactory,
|
||||
options: { persistDefaultConnectionSettings?: boolean } = {},
|
||||
): ApplicationGateway {
|
||||
let settings = initialSettings;
|
||||
let persistConnectionSettings = options.persistDefaultConnectionSettings !== false;
|
||||
let connection: ApplicationGatewayConnection = {
|
||||
gatewayUrl: settings.gatewayUrl,
|
||||
token: settings.token,
|
||||
@@ -81,6 +83,18 @@ export function createApplicationGateway(
|
||||
listener(eventLog);
|
||||
}
|
||||
};
|
||||
const updateSettings = (patch: Partial<typeof settings>, selectGateway = false) => {
|
||||
const next = { ...settings, ...patch };
|
||||
if (!persistConnectionSettings && !selectGateway) {
|
||||
settings = next;
|
||||
if (patch.gatewayUrl !== undefined || patch.token !== undefined) {
|
||||
persistSessionToken(next.gatewayUrl, next.token);
|
||||
}
|
||||
return;
|
||||
}
|
||||
persistConnectionSettings = true;
|
||||
settings = patchSettings(patch, { selectGateway });
|
||||
};
|
||||
const recordGatewayEvent = (event: Parameters<GatewayEventListener>[0]) => {
|
||||
eventLog = [{ ts: Date.now(), event: event.event, payload: event.payload }, ...eventLog].slice(
|
||||
0,
|
||||
@@ -96,17 +110,27 @@ export function createApplicationGateway(
|
||||
const nextSessionKey = hasRequestedSessionKey
|
||||
? requestedSessionKey.trim()
|
||||
: snapshot.sessionKey;
|
||||
// Only a gateway URL that differs from the current connection counts as an
|
||||
// explicit selection. The login gate always resubmits its prefilled URL, so
|
||||
// treating any override as a selection would let an ephemeral approval
|
||||
// document persist the serving gateway and clobber a saved remote choice.
|
||||
const gatewayUrlChanged =
|
||||
connectionOverrides.gatewayUrl !== undefined &&
|
||||
connectionOverrides.gatewayUrl !== connection.gatewayUrl;
|
||||
connection = nextConnection;
|
||||
settings = patchSettings({
|
||||
gatewayUrl: nextConnection.gatewayUrl,
|
||||
token: nextConnection.token,
|
||||
...(hasRequestedSessionKey
|
||||
? {
|
||||
sessionKey: nextSessionKey,
|
||||
lastActiveSessionKey: nextSessionKey,
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
updateSettings(
|
||||
{
|
||||
gatewayUrl: nextConnection.gatewayUrl,
|
||||
token: nextConnection.token,
|
||||
...(hasRequestedSessionKey
|
||||
? {
|
||||
sessionKey: nextSessionKey,
|
||||
lastActiveSessionKey: nextSessionKey,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
persistConnectionSettings || gatewayUrlChanged,
|
||||
);
|
||||
client?.stop();
|
||||
stopClientEvents?.();
|
||||
stopClientEvents = undefined;
|
||||
@@ -127,7 +151,9 @@ export function createApplicationGateway(
|
||||
return;
|
||||
}
|
||||
connection = { ...connection, bootstrapToken: "" };
|
||||
settings = loadSettings();
|
||||
if (persistConnectionSettings) {
|
||||
settings = loadSettings();
|
||||
}
|
||||
const sessionDefaults = readSessionDefaults(hello);
|
||||
const sessionKey = resolveSessionKey(snapshot.sessionKey, hello);
|
||||
const lastActiveSessionKey = resolveSessionKey(settings.lastActiveSessionKey, hello);
|
||||
@@ -135,7 +161,7 @@ export function createApplicationGateway(
|
||||
sessionKey !== settings.sessionKey ||
|
||||
lastActiveSessionKey !== settings.lastActiveSessionKey
|
||||
) {
|
||||
settings = patchSettings({
|
||||
updateSettings({
|
||||
sessionKey,
|
||||
lastActiveSessionKey,
|
||||
});
|
||||
@@ -213,7 +239,7 @@ export function createApplicationGateway(
|
||||
if (!nextSessionKey || nextSessionKey === snapshot.sessionKey) {
|
||||
return;
|
||||
}
|
||||
settings = patchSettings({
|
||||
updateSettings({
|
||||
sessionKey: nextSessionKey,
|
||||
lastActiveSessionKey: nextSessionKey,
|
||||
});
|
||||
|
||||
@@ -5,6 +5,8 @@ import { createStorageMock } from "../test-helpers/storage.ts";
|
||||
import {
|
||||
loadLocalUserIdentity,
|
||||
loadSettings,
|
||||
persistSessionToken,
|
||||
resolvePageGatewaySettings,
|
||||
resolveApplicationStartupSettings,
|
||||
saveSettings,
|
||||
type UiSettings,
|
||||
@@ -129,6 +131,32 @@ describe("loadSettings default gateway URL derivation", () => {
|
||||
expect(loadSettings().gatewayUrl).toBe(expectedGatewayUrl("/openclaw"));
|
||||
});
|
||||
|
||||
it("binds standalone documents to the page Gateway without persisting a selection", () => {
|
||||
setTestLocation({
|
||||
protocol: "https:",
|
||||
host: "gateway.example:8443",
|
||||
pathname: "/openclaw/approve/exec%3A1",
|
||||
});
|
||||
setControlUiBasePath("/openclaw");
|
||||
const remote = makeSettings("wss://remote.example:8443", {
|
||||
sessionKey: "agent:remote:main",
|
||||
lastActiveSessionKey: "agent:remote:main",
|
||||
});
|
||||
const sessionCredential = ["page", "session", "credential"].join("-");
|
||||
persistSessionToken(expectedGatewayUrl("/openclaw"), sessionCredential);
|
||||
const before = [...Array(localStorage.length)].map((_, index) => localStorage.key(index));
|
||||
|
||||
expect(resolvePageGatewaySettings(remote)).toMatchObject({
|
||||
gatewayUrl: expectedGatewayUrl("/openclaw"),
|
||||
token: sessionCredential,
|
||||
sessionKey: "main",
|
||||
lastActiveSessionKey: "main",
|
||||
});
|
||||
expect([...Array(localStorage.length)].map((_, index) => localStorage.key(index))).toEqual(
|
||||
before,
|
||||
);
|
||||
});
|
||||
|
||||
it("defaults chat auto-scroll to near-bottom", () => {
|
||||
setTestLocation({
|
||||
protocol: "https:",
|
||||
|
||||
+30
-3
@@ -342,6 +342,28 @@ function deriveDefaultGatewayUrl(): { pageUrl: string; effectiveUrl: string } {
|
||||
return { pageUrl, effectiveUrl };
|
||||
}
|
||||
|
||||
/**
|
||||
* Standalone documents are owned by the Gateway that served their URL. Do not
|
||||
* let the full app's persisted remote selection retarget a security decision.
|
||||
* Native auth and explicit URL overrides are applied after this default.
|
||||
*/
|
||||
export function resolvePageGatewaySettings(settings: UiSettings): UiSettings {
|
||||
const { effectiveUrl } = deriveDefaultGatewayUrl();
|
||||
if (
|
||||
normalizeGatewayTokenScope(settings.gatewayUrl) === normalizeGatewayTokenScope(effectiveUrl)
|
||||
) {
|
||||
return settings;
|
||||
}
|
||||
const session = loadGatewaySessionSelection(effectiveUrl);
|
||||
return {
|
||||
...settings,
|
||||
gatewayUrl: effectiveUrl,
|
||||
token: resolveGatewayTokenForUrlEdit(settings.gatewayUrl, effectiveUrl, settings.token),
|
||||
sessionKey: session.sessionKey,
|
||||
lastActiveSessionKey: session.lastActiveSessionKey,
|
||||
};
|
||||
}
|
||||
|
||||
function getSessionStorage(): Storage | null {
|
||||
return getSafeSessionStorage();
|
||||
}
|
||||
@@ -459,7 +481,7 @@ export function resolveGatewayTokenForUrlEdit(
|
||||
return loadSessionToken(nextGatewayUrl);
|
||||
}
|
||||
|
||||
function persistSessionToken(gatewayUrl: string, token: string) {
|
||||
export function persistSessionToken(gatewayUrl: string, token: string) {
|
||||
try {
|
||||
const storage = getSessionStorage();
|
||||
if (!storage) {
|
||||
@@ -589,9 +611,14 @@ export function saveSettings(next: UiSettings) {
|
||||
persistSettings(next);
|
||||
}
|
||||
|
||||
export function patchSettings(patch: Partial<UiSettings>): UiSettings {
|
||||
export function patchSettings(
|
||||
patch: Partial<UiSettings>,
|
||||
options: { selectGateway?: boolean } = {},
|
||||
): UiSettings {
|
||||
const next = { ...loadSettings(), ...patch };
|
||||
persistSettings(next, { selectGateway: patch.gatewayUrl !== undefined });
|
||||
persistSettings(next, {
|
||||
selectGateway: options.selectGateway ?? patch.gatewayUrl !== undefined,
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
import { copyFile, mkdir, rm } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { chromium, type Browser, type BrowserContext, type Page, type Video } from "playwright";
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import type {
|
||||
AllowedApprovalSnapshot,
|
||||
PendingApprovalSnapshot,
|
||||
} from "../../../packages/gateway-protocol/src/index.js";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
installMockGateway,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
type ControlUiE2eServer,
|
||||
type MockGatewayControls,
|
||||
} from "../test-helpers/control-ui-e2e.ts";
|
||||
|
||||
const chromiumExecutablePath = resolvePlaywrightChromiumExecutablePath(chromium.executablePath());
|
||||
const chromiumAvailable = canRunPlaywrightChromium(chromiumExecutablePath);
|
||||
const allowMissingChromium = process.env.OPENCLAW_UI_E2E_ALLOW_MISSING_CHROMIUM === "1";
|
||||
const describeControlUiE2e = chromiumAvailable || !allowMissingChromium ? describe : describe.skip;
|
||||
|
||||
const APPROVAL_ID = "Approval:Mobile/東京 100% 🦞";
|
||||
const APPROVAL_NOW_MS = Date.UTC(2026, 6, 10, 18, 0, 0);
|
||||
const ARTIFACT_DIR = path.resolve(".artifacts/control-ui-e2e/approval-page");
|
||||
const MOBILE_RAW_VIDEO_DIR = path.join(ARTIFACT_DIR, "mobile-raw");
|
||||
const MOBILE_VIEWPORT = { height: 844, width: 390 } as const;
|
||||
const DESKTOP_VIEWPORT = { height: 800, width: 1200 } as const;
|
||||
|
||||
type ApprovalSurface = {
|
||||
context: BrowserContext;
|
||||
gateway: MockGatewayControls;
|
||||
page: Page;
|
||||
pageErrors: string[];
|
||||
rawVideoDir?: string;
|
||||
};
|
||||
|
||||
let browser: Browser | undefined;
|
||||
let server: ControlUiE2eServer | undefined;
|
||||
const openContexts = new Set<BrowserContext>();
|
||||
const rawVideoDirs = new Set<string>();
|
||||
|
||||
function approvalPath(basePath: string): string {
|
||||
return `${basePath}/approve/${encodeURIComponent(APPROVAL_ID)}`;
|
||||
}
|
||||
|
||||
function approvalUrl(basePath: string): string {
|
||||
return new URL(approvalPath(basePath), server?.baseUrl ?? "http://127.0.0.1/").href;
|
||||
}
|
||||
|
||||
function pendingApproval(basePath: string): PendingApprovalSnapshot {
|
||||
const commandLines = Array.from(
|
||||
{ length: 14 },
|
||||
(_value, index) =>
|
||||
`step-${String(index + 1).padStart(2, "0")}: curl --header "Authorization: <redacted>" https://example.invalid/review`,
|
||||
);
|
||||
return {
|
||||
id: APPROVAL_ID,
|
||||
status: "pending",
|
||||
urlPath: approvalPath(basePath),
|
||||
createdAtMs: APPROVAL_NOW_MS - 30_000,
|
||||
expiresAtMs: APPROVAL_NOW_MS + 5 * 60_000,
|
||||
presentation: {
|
||||
kind: "exec",
|
||||
commandText: commandLines.join("\n"),
|
||||
commandPreview: 'curl --header "Authorization: <redacted>" …',
|
||||
warningText: "This command requests external network access.",
|
||||
host: "gateway",
|
||||
nodeId: null,
|
||||
agentId: "main",
|
||||
allowedDecisions: ["allow-once", "deny"],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function allowedApproval(pending: PendingApprovalSnapshot): AllowedApprovalSnapshot {
|
||||
return {
|
||||
...pending,
|
||||
status: "allowed",
|
||||
decision: "allow-once",
|
||||
reason: "user",
|
||||
resolvedAtMs: APPROVAL_NOW_MS,
|
||||
};
|
||||
}
|
||||
|
||||
function requireBrowser(): Browser {
|
||||
if (!browser) {
|
||||
throw new Error("Control UI E2E browser is not running");
|
||||
}
|
||||
return browser;
|
||||
}
|
||||
|
||||
async function createSurface(params: {
|
||||
basePath: string;
|
||||
deferredMethods?: string[];
|
||||
pending: PendingApprovalSnapshot;
|
||||
recordVideo?: boolean;
|
||||
viewport: { height: number; width: number };
|
||||
}): Promise<ApprovalSurface> {
|
||||
const rawVideoDir = params.recordVideo ? MOBILE_RAW_VIDEO_DIR : undefined;
|
||||
if (rawVideoDir) {
|
||||
await mkdir(ARTIFACT_DIR, { recursive: true });
|
||||
await rm(rawVideoDir, { force: true, recursive: true });
|
||||
await mkdir(rawVideoDir, { recursive: true });
|
||||
rawVideoDirs.add(rawVideoDir);
|
||||
}
|
||||
const context = await requireBrowser().newContext({
|
||||
colorScheme: "dark",
|
||||
hasTouch: params.viewport.width <= MOBILE_VIEWPORT.width,
|
||||
isMobile: params.viewport.width <= MOBILE_VIEWPORT.width,
|
||||
locale: "en-US",
|
||||
reducedMotion: "reduce",
|
||||
serviceWorkers: "block",
|
||||
viewport: params.viewport,
|
||||
...(rawVideoDir ? { recordVideo: { dir: rawVideoDir, size: params.viewport } } : {}),
|
||||
});
|
||||
openContexts.add(context);
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
await page.clock.setFixedTime(new Date(APPROVAL_NOW_MS));
|
||||
const pageErrors: string[] = [];
|
||||
page.on("pageerror", (error) => pageErrors.push(String(error)));
|
||||
const gateway = await installMockGateway(page, {
|
||||
basePath: params.basePath,
|
||||
deferredMethods: params.deferredMethods,
|
||||
methodResponses: {
|
||||
"approval.get": { approval: params.pending },
|
||||
},
|
||||
});
|
||||
return { context, gateway, page, pageErrors, rawVideoDir };
|
||||
}
|
||||
|
||||
async function closeRecordedSurface(surface: ApprovalSurface, targetName: string): Promise<void> {
|
||||
const video: Video | null = surface.page.video();
|
||||
openContexts.delete(surface.context);
|
||||
await surface.context.close().catch(() => {});
|
||||
if (!video || !surface.rawVideoDir) {
|
||||
return;
|
||||
}
|
||||
const rawVideoPath = await video.path();
|
||||
await copyFile(rawVideoPath, path.join(ARTIFACT_DIR, targetName));
|
||||
rawVideoDirs.delete(surface.rawVideoDir);
|
||||
await rm(surface.rawVideoDir, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
async function waitForApprovalPage(page: Page): Promise<void> {
|
||||
await page.locator("openclaw-approval-page").waitFor();
|
||||
await page.getByText("Waiting for your decision", { exact: true }).waitFor();
|
||||
}
|
||||
|
||||
async function expectStandaloneApprovalPage(page: Page): Promise<void> {
|
||||
expect(await page.locator("openclaw-approval-page").count()).toBe(1);
|
||||
expect(await page.locator(".approval-page").count()).toBe(1);
|
||||
expect(await page.locator("openclaw-app-shell, .shell").count()).toBe(0);
|
||||
expect(await page.locator("openclaw-app-topbar, openclaw-app-sidebar").count()).toBe(0);
|
||||
expect(await page.locator("openclaw-exec-approval").count()).toBe(0);
|
||||
}
|
||||
|
||||
async function expectNoDecisionButtons(page: Page): Promise<void> {
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const allowCount = await page.getByRole("button", { name: "Allow once" }).count();
|
||||
const denyCount = await page.getByRole("button", { name: "Deny" }).count();
|
||||
return allowCount + denyCount;
|
||||
})
|
||||
.toBe(0);
|
||||
}
|
||||
|
||||
async function waitForStableApprovalPaint(page: Page): Promise<void> {
|
||||
await page.evaluate(async () => {
|
||||
await document.fonts.ready;
|
||||
await new Promise<void>((resolve) => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
||||
});
|
||||
});
|
||||
if (page.viewportSize()?.width !== MOBILE_VIEWPORT.width) {
|
||||
return;
|
||||
}
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const bounds = await page.locator(".approval-page__card").boundingBox();
|
||||
return Boolean(
|
||||
bounds && bounds.x >= 10 && bounds.width >= 350 && bounds.x + bounds.width <= 380,
|
||||
);
|
||||
})
|
||||
.toBe(true);
|
||||
}
|
||||
|
||||
async function expectMobilePendingLayout(page: Page): Promise<void> {
|
||||
const allowButton = page.getByRole("button", { name: "Allow once" });
|
||||
const denyButton = page.getByRole("button", { name: "Deny" });
|
||||
const [allowBounds, denyBounds] = await Promise.all([
|
||||
allowButton.boundingBox(),
|
||||
denyButton.boundingBox(),
|
||||
]);
|
||||
if (!allowBounds || !denyBounds) {
|
||||
throw new Error("Approval decision buttons are missing layout bounds");
|
||||
}
|
||||
expect(allowBounds.height).toBeGreaterThanOrEqual(44);
|
||||
expect(denyBounds.height).toBeGreaterThanOrEqual(44);
|
||||
|
||||
const metrics = await page.evaluate(() => {
|
||||
const root = document.querySelector<HTMLElement>(".approval-page");
|
||||
const card = document.querySelector<HTMLElement>(".approval-page__card");
|
||||
const preview = document.querySelector<HTMLElement>(".approval-page__preview");
|
||||
if (!root || !card || !preview) {
|
||||
throw new Error("Approval page layout elements are missing");
|
||||
}
|
||||
const rootBounds = root.getBoundingClientRect();
|
||||
const cardBounds = card.getBoundingClientRect();
|
||||
const previewBounds = preview.getBoundingClientRect();
|
||||
const backLink = document.querySelector<HTMLElement>(".approval-page__back-link");
|
||||
if (!backLink) {
|
||||
throw new Error("Approval page back link is missing");
|
||||
}
|
||||
const backLinkBounds = backLink.getBoundingClientRect();
|
||||
return {
|
||||
backLinkTop: backLinkBounds.top,
|
||||
cardBottom: cardBounds.bottom,
|
||||
cardLeft: cardBounds.left,
|
||||
cardRight: cardBounds.right,
|
||||
documentOverflow: document.documentElement.scrollWidth - window.innerWidth,
|
||||
previewClientHeight: preview.clientHeight,
|
||||
previewRight: previewBounds.right,
|
||||
previewScrollHeight: preview.scrollHeight,
|
||||
rootLeft: rootBounds.left,
|
||||
rootRight: rootBounds.right,
|
||||
viewportWidth: window.innerWidth,
|
||||
};
|
||||
});
|
||||
expect(metrics.documentOverflow).toBeLessThanOrEqual(0);
|
||||
expect(metrics.rootLeft).toBeGreaterThanOrEqual(0);
|
||||
expect(metrics.cardLeft).toBeGreaterThanOrEqual(0);
|
||||
expect(metrics.rootRight).toBeLessThanOrEqual(metrics.viewportWidth);
|
||||
expect(metrics.cardRight).toBeLessThanOrEqual(metrics.viewportWidth);
|
||||
expect(metrics.previewRight).toBeLessThanOrEqual(metrics.viewportWidth);
|
||||
expect(metrics.previewScrollHeight).toBeGreaterThanOrEqual(metrics.previewClientHeight);
|
||||
expect(metrics.backLinkTop).toBeGreaterThanOrEqual(metrics.cardBottom + 10);
|
||||
}
|
||||
|
||||
describeControlUiE2e("Control UI standalone approval page", () => {
|
||||
beforeAll(async () => {
|
||||
if (!chromiumAvailable) {
|
||||
throw new Error(`Playwright Chromium is unavailable at ${chromiumExecutablePath}`);
|
||||
}
|
||||
server = await startControlUiE2eServer();
|
||||
browser = await chromium.launch({ executablePath: chromiumExecutablePath });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all([...openContexts].map((context) => context.close().catch(() => {})));
|
||||
openContexts.clear();
|
||||
await Promise.all(
|
||||
[...rawVideoDirs].map((rawVideoDir) => rm(rawVideoDir, { force: true, recursive: true })),
|
||||
);
|
||||
rawVideoDirs.clear();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await browser?.close().catch(() => {});
|
||||
await server?.close();
|
||||
});
|
||||
|
||||
it("keeps one canonical winner across conflicting surfaces and terminal reload", async () => {
|
||||
const pending = pendingApproval("");
|
||||
const terminal = allowedApproval(pending);
|
||||
const mobile = await createSurface({
|
||||
basePath: "",
|
||||
deferredMethods: ["approval.resolve"],
|
||||
pending,
|
||||
recordVideo: true,
|
||||
viewport: MOBILE_VIEWPORT,
|
||||
});
|
||||
const desktop = await createSurface({
|
||||
basePath: "",
|
||||
deferredMethods: ["approval.resolve"],
|
||||
pending,
|
||||
viewport: DESKTOP_VIEWPORT,
|
||||
});
|
||||
|
||||
try {
|
||||
const [mobileResponse, desktopResponse] = await Promise.all([
|
||||
mobile.page.goto(approvalUrl("")),
|
||||
desktop.page.goto(approvalUrl("")),
|
||||
]);
|
||||
expect(mobileResponse?.status()).toBe(200);
|
||||
expect(desktopResponse?.status()).toBe(200);
|
||||
await Promise.all([waitForApprovalPage(mobile.page), waitForApprovalPage(desktop.page)]);
|
||||
|
||||
const [mobileGet, desktopGet] = await Promise.all([
|
||||
mobile.gateway.waitForRequest("approval.get"),
|
||||
desktop.gateway.waitForRequest("approval.get"),
|
||||
]);
|
||||
expect(mobileGet.params).toEqual({ id: APPROVAL_ID });
|
||||
expect(desktopGet.params).toEqual({ id: APPROVAL_ID });
|
||||
expect(new URL(mobile.page.url()).pathname).toBe(approvalPath(""));
|
||||
await Promise.all([
|
||||
expectStandaloneApprovalPage(mobile.page),
|
||||
expectStandaloneApprovalPage(desktop.page),
|
||||
]);
|
||||
await expectMobilePendingLayout(mobile.page);
|
||||
expect(await mobile.page.title()).toBe("Command approval — OpenClaw");
|
||||
await waitForStableApprovalPaint(mobile.page);
|
||||
await mobile.page.screenshot({
|
||||
path: path.join(ARTIFACT_DIR, "01-pending-mobile.png"),
|
||||
});
|
||||
await mobile.page.getByRole("button", { name: "Allow once" }).scrollIntoViewIfNeeded();
|
||||
await waitForStableApprovalPaint(mobile.page);
|
||||
await mobile.page.screenshot({
|
||||
path: path.join(ARTIFACT_DIR, "01b-pending-actions-mobile.png"),
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
mobile.page.getByRole("button", { name: "Allow once" }).click(),
|
||||
desktop.page.getByRole("button", { name: "Deny" }).click(),
|
||||
]);
|
||||
const [mobileResolve, desktopResolve] = await Promise.all([
|
||||
mobile.gateway.waitForRequest("approval.resolve"),
|
||||
desktop.gateway.waitForRequest("approval.resolve"),
|
||||
]);
|
||||
expect(mobileResolve.params).toEqual({
|
||||
id: APPROVAL_ID,
|
||||
kind: "exec",
|
||||
decision: "allow-once",
|
||||
});
|
||||
expect(desktopResolve.params).toEqual({
|
||||
id: APPROVAL_ID,
|
||||
kind: "exec",
|
||||
decision: "deny",
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
mobile.gateway.setMethodResponse("approval.get", { approval: terminal }),
|
||||
desktop.gateway.setMethodResponse("approval.get", { approval: terminal }),
|
||||
]);
|
||||
await Promise.all([
|
||||
mobile.gateway.resolveDeferred("approval.resolve", {
|
||||
applied: true,
|
||||
approval: terminal,
|
||||
}),
|
||||
desktop.gateway.resolveDeferred("approval.resolve", {
|
||||
applied: false,
|
||||
approval: terminal,
|
||||
}),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
mobile.page.getByRole("heading", { name: "Approved here", exact: true }).waitFor(),
|
||||
desktop.page.getByRole("heading", { name: "Resolved elsewhere", exact: true }).waitFor(),
|
||||
]);
|
||||
await Promise.all([
|
||||
expectNoDecisionButtons(mobile.page),
|
||||
expectNoDecisionButtons(desktop.page),
|
||||
]);
|
||||
const terminalFocus = await mobile.page.evaluate(() => {
|
||||
const active = document.activeElement as HTMLElement | null;
|
||||
const bounds = active?.getBoundingClientRect();
|
||||
return {
|
||||
bottom: bounds?.bottom ?? Number.POSITIVE_INFINITY,
|
||||
id: active?.id ?? null,
|
||||
top: bounds?.top ?? Number.NEGATIVE_INFINITY,
|
||||
viewportHeight: window.innerHeight,
|
||||
};
|
||||
});
|
||||
expect(terminalFocus.id).toBe("approval-page-title");
|
||||
expect(terminalFocus.top).toBeGreaterThanOrEqual(0);
|
||||
expect(terminalFocus.bottom).toBeLessThanOrEqual(terminalFocus.viewportHeight);
|
||||
expect(await mobile.page.title()).toBe("Approved here — OpenClaw");
|
||||
await waitForStableApprovalPaint(mobile.page);
|
||||
await mobile.page.screenshot({
|
||||
path: path.join(ARTIFACT_DIR, "02-competing-answer-terminal.png"),
|
||||
});
|
||||
await waitForStableApprovalPaint(desktop.page);
|
||||
await desktop.page.screenshot({
|
||||
path: path.join(ARTIFACT_DIR, "02b-competing-answer-loser-desktop.png"),
|
||||
});
|
||||
|
||||
const terminalReload = await mobile.page.reload();
|
||||
expect(terminalReload?.status()).toBe(200);
|
||||
await mobile.gateway.waitForRequest("approval.get");
|
||||
await mobile.page.getByRole("heading", { name: "Approved", exact: true }).waitFor();
|
||||
expect(await mobile.page.title()).toBe("Approved — OpenClaw");
|
||||
expect(new URL(mobile.page.url()).pathname).toBe(approvalPath(""));
|
||||
await expectStandaloneApprovalPage(mobile.page);
|
||||
await expectNoDecisionButtons(mobile.page);
|
||||
await waitForStableApprovalPaint(mobile.page);
|
||||
await mobile.page.screenshot({
|
||||
path: path.join(ARTIFACT_DIR, "03-terminal-reload-mobile.png"),
|
||||
});
|
||||
|
||||
expect(mobile.pageErrors).toEqual([]);
|
||||
expect(desktop.pageErrors).toEqual([]);
|
||||
} finally {
|
||||
await closeRecordedSurface(mobile, "approval-page-mobile.webm");
|
||||
}
|
||||
});
|
||||
|
||||
it("preserves a mounted deep link across the authentication gate", async () => {
|
||||
const basePath = "/openclaw";
|
||||
const pending = pendingApproval(basePath);
|
||||
const surface = await createSurface({
|
||||
basePath,
|
||||
deferredMethods: ["connect"],
|
||||
pending,
|
||||
viewport: MOBILE_VIEWPORT,
|
||||
});
|
||||
|
||||
const response = await surface.page.goto(approvalUrl(basePath));
|
||||
expect(response?.status()).toBe(200);
|
||||
await surface.gateway.waitForRequest("connect");
|
||||
await surface.page.locator("openclaw-login-gate").waitFor();
|
||||
expect(new URL(surface.page.url()).pathname).toBe(approvalPath(basePath));
|
||||
expect(await surface.gateway.getRequests("approval.get")).toHaveLength(0);
|
||||
|
||||
await surface.gateway.resolveDeferred("connect");
|
||||
await waitForApprovalPage(surface.page);
|
||||
const request = await surface.gateway.waitForRequest("approval.get");
|
||||
expect(request.params).toEqual({ id: APPROVAL_ID });
|
||||
expect(new URL(surface.page.url()).pathname).toBe(approvalPath(basePath));
|
||||
await expectStandaloneApprovalPage(surface.page);
|
||||
expect(surface.pageErrors).toEqual([]);
|
||||
});
|
||||
|
||||
it("uses the page Gateway without replacing a saved remote selection", async () => {
|
||||
const pending = pendingApproval("");
|
||||
const surface = await createSurface({
|
||||
basePath: "",
|
||||
pending,
|
||||
viewport: MOBILE_VIEWPORT,
|
||||
});
|
||||
const appUrl = new URL(server?.baseUrl ?? "http://127.0.0.1/");
|
||||
const pageGatewayScope = `ws://${appUrl.host}`;
|
||||
const selectionKey = `openclaw.control.currentGateway.v1:${pageGatewayScope}`;
|
||||
const pageGateway = `ws://${appUrl.hostname}:18789`;
|
||||
const pageSettingsKey = `openclaw.control.settings.v1:${pageGateway}`;
|
||||
const pageSettings = JSON.stringify({
|
||||
gatewayUrl: pageGateway,
|
||||
theme: "claw",
|
||||
sessionKey: "agent:page:saved",
|
||||
});
|
||||
const remoteGateway = "wss://saved-remote.example.test";
|
||||
const remoteSettingsKey = `openclaw.control.settings.v1:${remoteGateway}`;
|
||||
await surface.page.addInitScript(
|
||||
({
|
||||
nextPageSettings,
|
||||
nextPageSettingsKey,
|
||||
nextRemoteGateway,
|
||||
nextRemoteSettingsKey,
|
||||
nextSelectionKey,
|
||||
}) => {
|
||||
localStorage.setItem(nextPageSettingsKey, nextPageSettings);
|
||||
localStorage.setItem(
|
||||
nextRemoteSettingsKey,
|
||||
JSON.stringify({ gatewayUrl: nextRemoteGateway }),
|
||||
);
|
||||
localStorage.setItem(nextSelectionKey, nextRemoteGateway);
|
||||
},
|
||||
{
|
||||
nextPageSettings: pageSettings,
|
||||
nextPageSettingsKey: pageSettingsKey,
|
||||
nextRemoteGateway: remoteGateway,
|
||||
nextRemoteSettingsKey: remoteSettingsKey,
|
||||
nextSelectionKey: selectionKey,
|
||||
},
|
||||
);
|
||||
|
||||
await surface.page.goto(
|
||||
`${approvalUrl("")}#token=approval-document-token&session=agent%3Aapproval%3Atemporary`,
|
||||
);
|
||||
await waitForApprovalPage(surface.page);
|
||||
const startupHash = new URLSearchParams(new URL(surface.page.url()).hash.slice(1));
|
||||
expect(startupHash.has("token")).toBe(false);
|
||||
expect(startupHash.get("session")).toBe("agent:approval:temporary");
|
||||
const socketUrls = await surface.gateway.getSocketUrls();
|
||||
expect(socketUrls.length).toBeGreaterThan(0);
|
||||
expect(new URL(socketUrls.at(-1) ?? "ws://invalid").origin).toBe(pageGateway);
|
||||
expect(await surface.page.evaluate((key) => localStorage.getItem(key), selectionKey)).toBe(
|
||||
remoteGateway,
|
||||
);
|
||||
expect(await surface.page.evaluate((key) => localStorage.getItem(key), pageSettingsKey)).toBe(
|
||||
pageSettings,
|
||||
);
|
||||
expect(surface.pageErrors).toEqual([]);
|
||||
});
|
||||
|
||||
it("renders changed Gateway content after reload instead of a hard-coded fixture", async () => {
|
||||
const pending = pendingApproval("");
|
||||
if (pending.presentation.kind !== "exec") {
|
||||
throw new Error("Expected an exec approval fixture");
|
||||
}
|
||||
const surface = await createSurface({
|
||||
basePath: "",
|
||||
pending,
|
||||
viewport: MOBILE_VIEWPORT,
|
||||
});
|
||||
|
||||
await surface.page.goto(approvalUrl(""));
|
||||
await waitForApprovalPage(surface.page);
|
||||
const changed = {
|
||||
...pending,
|
||||
presentation: {
|
||||
...pending.presentation,
|
||||
commandText: "printf 'fixture changed at the Gateway'",
|
||||
warningText: "Changed warning from the live approval fixture.",
|
||||
},
|
||||
} satisfies PendingApprovalSnapshot;
|
||||
await surface.gateway.setMethodResponse("approval.get", { approval: changed });
|
||||
|
||||
await surface.page.reload();
|
||||
await surface.gateway.waitForRequest("approval.get");
|
||||
await surface.page.getByText("Changed warning from the live approval fixture.").waitFor();
|
||||
await surface.page
|
||||
.getByText("printf 'fixture changed at the Gateway'", { exact: true })
|
||||
.waitFor();
|
||||
expect(surface.pageErrors).toEqual([]);
|
||||
});
|
||||
|
||||
it("fails closed on malformed Gateway data", async () => {
|
||||
const surface = await createSurface({
|
||||
basePath: "",
|
||||
pending: pendingApproval(""),
|
||||
viewport: MOBILE_VIEWPORT,
|
||||
});
|
||||
await surface.page.goto(approvalUrl(""));
|
||||
await waitForApprovalPage(surface.page);
|
||||
await surface.gateway.setMethodResponse("approval.get", {
|
||||
approval: { id: APPROVAL_ID, status: "pending" },
|
||||
});
|
||||
|
||||
await surface.page.reload();
|
||||
await surface.page.getByRole("heading", { name: "Approval unavailable" }).waitFor();
|
||||
await expectStandaloneApprovalPage(surface.page);
|
||||
await expectNoDecisionButtons(surface.page);
|
||||
expect(surface.pageErrors).toEqual([]);
|
||||
});
|
||||
|
||||
it("retains context but disables decisions through a reconnect", async () => {
|
||||
const pending = pendingApproval("");
|
||||
const surface = await createSurface({
|
||||
basePath: "",
|
||||
pending,
|
||||
viewport: MOBILE_VIEWPORT,
|
||||
});
|
||||
await surface.page.goto(approvalUrl(""));
|
||||
await waitForApprovalPage(surface.page);
|
||||
const initialConnectCount = (await surface.gateway.getRequests("connect")).length;
|
||||
await surface.gateway.deferNext("connect");
|
||||
|
||||
await surface.gateway.closeLatest(1012, "test reconnect");
|
||||
await Promise.all([
|
||||
surface.page.getByText("Connection interrupted", { exact: true }).waitFor(),
|
||||
expect
|
||||
.poll(async () => (await surface.gateway.getRequests("connect")).length)
|
||||
.toBeGreaterThan(initialConnectCount),
|
||||
]);
|
||||
expect(await surface.page.locator(".approval-page__preview").textContent()).toContain(
|
||||
"step-01",
|
||||
);
|
||||
expect(await surface.page.getByRole("button", { name: "Allow once" }).isDisabled()).toBe(true);
|
||||
await surface.page
|
||||
.getByText(
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
{ exact: true },
|
||||
)
|
||||
.waitFor();
|
||||
|
||||
await surface.gateway.resolveDeferred("connect");
|
||||
await surface.gateway.waitForRequest("approval.get");
|
||||
await expect
|
||||
.poll(() => surface.page.getByRole("button", { name: "Allow once" }).isEnabled())
|
||||
.toBe(true);
|
||||
expect(surface.pageErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
Generated
+3
@@ -331,6 +331,7 @@
|
||||
{"cache_key":"a135b16081fe2550b01623e6f190e240d53d2fd945b22b16df7bb4aebb2b8860","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.stored","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Stored","text_hash":"91da9626894c82dd4d5ed7ab48ed4ed4b1fc57ff98858cde93945254e36c4198","tgt_lang":"ar","translated":"مخزّن","updated_at":"2026-07-09T10:01:43.759Z"}
|
||||
{"cache_key":"a1885dbab8aa55629dea7d25ca4906cf03a391c02d4a2b094bced8f6b4df111f","model":"gpt-5.5","provider":"openai","segment_id":"nativeLinkMenu.openInline","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Open in Sidebar","text_hash":"ee39dc2999ce3acefff3c4c5440266e6a044feb3fb0a405a754f3ee4f697b201","tgt_lang":"ar","translated":"فتح في الشريط الجانبي","updated_at":"2026-07-09T11:02:53.077Z"}
|
||||
{"cache_key":"a202b44cbc5314a4d17b6ac96719cbcb251115f13613bdd421e9177c55a41ed9","model":"gpt-5.5","provider":"openai","segment_id":"quickSettings.appearance.lobsterdex","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Lobsterdex","text_hash":"5e32f89430f682bf1a241c402ea32a317b1e869fc85cdcab7d897a813ab6e107","tgt_lang":"ar","translated":"Lobsterdex","updated_at":"2026-07-09T23:55:55.921Z"}
|
||||
{"cache_key":"a330504b9be95b959f7a796a08af9d4cc818df16776ceb5effbd0753f97c15d6","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"ar","translated":"الأمر","updated_at":"2026-06-16T14:15:44.085Z"}
|
||||
{"cache_key":"a3b7d431b505483b1b65978835fb7bf254357e8253b12a4295410599c354fdfc","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.truncatedFile","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Diff truncated.","text_hash":"2a4f4803ed395dae4c1d0573e8cff6e4123aaba9f2c6e6cbc4581d5d4d3e4571","tgt_lang":"ar","translated":"تم اقتطاع diff.","updated_at":"2026-07-11T04:53:10.428Z"}
|
||||
{"cache_key":"a41b3be69a33846f37e3e6f71f4412aebd67bd1e23872b7d05c9743167a9297a","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.footer.navigate","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"navigate","text_hash":"d0cda6559bb347db706f6fa92a5b2491658e0c1e5bda98bb14e3c8a711b8fa33","tgt_lang":"ar","translated":"تنقّل","updated_at":"2026-07-12T00:09:17.960Z"}
|
||||
{"cache_key":"a45d50099a270e5883cad841617d2f1ad135bb8b5abbf5f156bccee521e25c2b","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.groupBy","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Group by","text_hash":"956a51f6b098a41b7c3108015f0790bb24af7693717b07cee39d5df6a5da1826","tgt_lang":"ar","translated":"تجميع حسب","updated_at":"2026-07-05T14:39:56.977Z"}
|
||||
@@ -416,6 +417,7 @@
|
||||
{"cache_key":"c15d871f391d624fb995c412b179552d6527a469a4513537e2fbf79516bdebd0","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.actions","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Actions","text_hash":"ff8059dc6752afdd30d275932b1d5031a2ec854b387a8c57ecc6689915293a43","tgt_lang":"ar","translated":"الإجراءات","updated_at":"2026-07-05T21:01:06.223Z"}
|
||||
{"cache_key":"c186d6d65f70ec43ef67e7d84a4fed239fd70bf244f2e8f280e821a2debcba65","model":"gpt-5.6-sol","provider":"openai","segment_id":"attention.modelAuthExpired","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Model auth expired: {providers}","text_hash":"1af839b53686632bd3d0b5e0b89025a75052d0b7cfa84ce5e1654d4cd2469c61","tgt_lang":"ar","translated":"انتهت صلاحية مصادقة النموذج: {providers}","updated_at":"2026-07-12T00:09:15.712Z"}
|
||||
{"cache_key":"c19dc4c22c3fa18ea0719010644e229be1ac61e4a44be75d2376e2cfcc7cc647","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.healthRunning","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"running","text_hash":"c071cf5f5ed6f884cc70155b6f05f755fd46a302d05e4261b7e92ce878bbfed8","tgt_lang":"ar","translated":"قيد التشغيل","updated_at":"2026-06-17T14:15:04.326Z"}
|
||||
{"cache_key":"c21fa457fa672f8c3e9dac6398c901217aecdde1a889020ba69b0336c7486aa3","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"ar","translated":"عقدة","updated_at":"2026-07-09T10:01:43.759Z"}
|
||||
{"cache_key":"c233241cc23d7d2177c4d793589327b8469616ba77558d39e5dde23793e6e497","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailDiagnostics","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Diagnostics","text_hash":"268f14bbfe119c1e92150583af960a086d7db9619a097f8aa72ff6779842f610","tgt_lang":"ar","translated":"التشخيصات","updated_at":"2026-06-16T14:15:27.039Z"}
|
||||
{"cache_key":"c2a247cf9ed54d6a385632d930b723ecaec8d015f7a82705713211d0da5edaea","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.items.debugMode","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Debug Mode","text_hash":"5f75368293f2c806ad6db16cde4b2a5329bca96422bf47a76986619f61feb73f","tgt_lang":"ar","translated":"وضع تصحيح الأخطاء","updated_at":"2026-07-12T00:09:17.960Z"}
|
||||
{"cache_key":"c32edbbed739b7ea4c8f0a9e4fb93b19e8a451ae4d7e01a6d4995a2aac76d9f3","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotateClear","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Clear","text_hash":"83b12c2216efb4fdc924e1deb5182e905e4926ed0c1c324d467107f46d5a26a9","tgt_lang":"ar","translated":"مسح","updated_at":"2026-07-11T02:18:45.104Z"}
|
||||
@@ -549,6 +551,7 @@
|
||||
{"cache_key":"fbbebeaeb00675160d3e6b43b349ca1b0348f60d6ae9d6af656971a6a55a950e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailRun","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Run","text_hash":"00d60e31a4e6b8344d4201f25a6a7dee770713107f6d097abb01559d32b17f26","tgt_lang":"ar","translated":"تشغيل","updated_at":"2026-06-16T14:15:27.039Z"}
|
||||
{"cache_key":"fbdd7d1ac8cb9349b937e7eda1ef8df25034f759af78ada24b49a6e86ac647a6","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotate","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Annotate page","text_hash":"a195c16075cc573ed53b608e832e1656b59bd30481eea941f6f264dc10294c65","tgt_lang":"ar","translated":"إضافة تعليق توضيحي على الصفحة","updated_at":"2026-07-11T02:18:45.104Z"}
|
||||
{"cache_key":"fc0a388648bdb4a88bb5c58b3436bc6bb0b7634b7ce594be0d12df5d15b3e2f7","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.checksPending","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"CI checks running","text_hash":"451411025de9b78bc4a991c45efb7131807d53f84d5a2aeaf516c802d9705401","tgt_lang":"ar","translated":"فحوصات CI قيد التشغيل","updated_at":"2026-07-10T17:04:04.784Z"}
|
||||
{"cache_key":"fcfbc44549a25002847d404f7672c7c7900b02156b00171ff69e7df4f04faa3c","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"ar","translated":"منتهي الصلاحية","updated_at":"2026-07-01T10:32:31.521Z"}
|
||||
{"cache_key":"fd1d589229234f3a192995d618a41ecd8ac8c236a49908e38610414d752a1ea9","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.refresh","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Refresh background tasks","text_hash":"837e39f46163ffb4dbed66ba4910c35f2383c1708c9a5593d120a53d51cdebf1","tgt_lang":"ar","translated":"تحديث المهام في الخلفية","updated_at":"2026-07-11T00:45:17.687Z"}
|
||||
{"cache_key":"fd62fbf939e7fcff810d10222fa51cf501598d19c82bb8028a3923f3a2220557","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.ageHours","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"{count}h","text_hash":"5828ef1c1e95e0bae1c98548d1795a2482cc8e14a8b161b183960a06018ce10d","tgt_lang":"ar","translated":"{count} س","updated_at":"2026-06-17T14:15:04.326Z"}
|
||||
{"cache_key":"fdd163f0b3dcf99f6994fff54757cf008ca139329050fc0c11ba7746dfb37277","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.access.connectHint","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Click Connect to apply connection changes.","text_hash":"473e1a24ad5a8bff00b2db667b8ff16a9b537a5b127dd2af42842620ea830b6d","tgt_lang":"ar","translated":"انقر على «اتصال» لتطبيق تغييرات الاتصال.","updated_at":"2026-07-12T00:09:09.397Z"}
|
||||
|
||||
Generated
+3
@@ -166,6 +166,7 @@
|
||||
{"cache_key":"534e0905e9bd6ea745c2c638354dcbbe9ecdee7e59889bbbcae83761556a6842","model":"gpt-5","provider":"openai","segment_id":"codexSessions.eyebrow","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Codex fleet","text_hash":"64e0510e4f9e07ad1283b7c1d55e67b5b853081b6ca4013fc8d710aa658d5127","tgt_lang":"de","translated":"Codex-Flotte","updated_at":"2026-07-09T10:01:43.726Z"}
|
||||
{"cache_key":"537bb0ffdddf752b257a000a97ab9fae16848b3e3e2fd9919b320e4c9b29d3d9","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.loading","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Loading background tasks…","text_hash":"b8f8eaea7ccdee15740c7daa3d290a534fd3db2b4f0b2835243a6627d9ff7ff6","tgt_lang":"de","translated":"Hintergrundaufgaben werden geladen…","updated_at":"2026-07-11T00:44:58.681Z"}
|
||||
{"cache_key":"548a58e7c7ef396d40294cde34a13a0dfc98fb4b480ac957140a86731dfba889","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.disconnected","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Gateway is disconnected.","text_hash":"7fd9356b0539a2b43987e019ea9c2725c80301b34006c23556a439d85e646e57","tgt_lang":"de","translated":"Gateway ist getrennt.","updated_at":"2026-07-11T04:52:40.877Z"}
|
||||
{"cache_key":"54ec1d5c3612291941d72e49affe8b265a8842f5d6f750705594b51330af3e3e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"de","translated":"Abgelaufen","updated_at":"2026-07-01T10:30:56.717Z"}
|
||||
{"cache_key":"5541b5d85468a9d5589abb4201fc72c53c1448d965beb0429b3bb1f97f3f6944","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.untitled","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Untitled Claude session","text_hash":"d319ed271fdc80d4b7c1733f5e9466335db68fc760807b13e83f50c48e800636","tgt_lang":"de","translated":"Unbenannte Claude-Sitzung","updated_at":"2026-07-11T13:50:20.837Z"}
|
||||
{"cache_key":"555797a869800fe5bbd48323276e0559980a1b3bb69c1d68310c4a902051cc5c","model":"gpt-5","provider":"openai","segment_id":"codexSessions.status.systemError","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"System error","text_hash":"b9564eaf21a9356d06f7f3c67a5b9cb7e6538687c33bebbf1e1b64715018f310","tgt_lang":"de","translated":"Systemfehler","updated_at":"2026-07-09T10:01:43.726Z"}
|
||||
{"cache_key":"557aa579ebe429c27dc39a744d8ea95e062b2724d9c899e4845231b55314a13a","model":"gpt-5.5","provider":"openai","segment_id":"chat.sidebar.sortBy","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Sort by","text_hash":"c9129025bd3ff6522a7eeebc1abf1481f36e4ac9d74524a473ac1c3be1c6fc2f","tgt_lang":"de","translated":"Sortieren nach","updated_at":"2026-07-06T23:40:48.838Z"}
|
||||
@@ -194,6 +195,7 @@
|
||||
{"cache_key":"5f60d04e50be0e22c14d761f808667c2dfd5623e67247c367c1d280613bcffca","model":"gpt-5.5","provider":"openai","segment_id":"workboard.badgeWorkerLogs","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"{count} worker logs","text_hash":"2923e2a84e6ed0ca048d280206198b156da6148859e474498d335a44e323e0a8","tgt_lang":"de","translated":"{count} Worker-Protokolle","updated_at":"2026-05-30T15:38:11.508Z"}
|
||||
{"cache_key":"607f6579fe326db8118df72dd6e3998b53f573ecb54e243e59f7231f93a4b828","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.contextUsage","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"{percent}% of context used ({used} / {context} tokens)","text_hash":"f626ed78b8aca81f039ef64637bbdd4cffe0a289b402fd0c6039e977040aba72","tgt_lang":"de","translated":"{percent}% des Kontexts verwendet ({used} / {context} Token)","updated_at":"2026-07-09T07:06:14.874Z"}
|
||||
{"cache_key":"60915cb1505e77218989007efc94709d33b51656877199b1b6303406eea9b4a9","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotateClear","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Clear","text_hash":"83b12c2216efb4fdc924e1deb5182e905e4926ed0c1c324d467107f46d5a26a9","tgt_lang":"de","translated":"Löschen","updated_at":"2026-07-11T02:17:39.826Z"}
|
||||
{"cache_key":"611c11ba77c523041dee3e0ebf867a041053ea08086d8bc63a17561c2e170acf","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"de","translated":"Knoten","updated_at":"2026-07-09T10:01:43.726Z"}
|
||||
{"cache_key":"619a6d19fa8353908ccc6666ae1fb62f5fba13a7b58ab0e6416c0114477d067f","model":"gpt-5","provider":"openai","segment_id":"usage.costWindows.selectedRange","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Selected Range","text_hash":"95917ae71066a19c266cd4530068f4bf775ed2401951ebf37ab0c91daa1a67d3","tgt_lang":"de","translated":"Ausgewählter Zeitraum","updated_at":"2026-07-05T20:24:32.108Z"}
|
||||
{"cache_key":"619bed6cbc73e096e361270d4a10052a8db58b7ba3bd70a67555616b82945422","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.outro","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Please look at the marked area and tell me what you make of it.","text_hash":"fdf6ad77887cf4668105f142e42a6fc67d025d92f7852d80c352e2fbacebd9bf","tgt_lang":"de","translated":"Bitte sehen Sie sich den markierten Bereich an und sagen Sie mir, was Sie davon halten.","updated_at":"2026-07-11T02:17:45.131Z"}
|
||||
{"cache_key":"619edc09ebc180104bfa46c14205d0f1a8456aa1b7a0bf6870267c5f3dffece3","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.loadingMore","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Loading…","text_hash":"ba3bbbe10d8bef66441c88536ce7b8e724e2829b59a3da658654f4961cd61ae5","tgt_lang":"de","translated":"Wird geladen…","updated_at":"2026-07-09T10:01:43.726Z"}
|
||||
@@ -288,6 +290,7 @@
|
||||
{"cache_key":"8b1c1eda411ab2416305f6c9ba0cc166e3490f1063510c2d9e5fcd8562da1581","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailRun","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Run","text_hash":"00d60e31a4e6b8344d4201f25a6a7dee770713107f6d097abb01559d32b17f26","tgt_lang":"de","translated":"Ausführung","updated_at":"2026-06-16T14:12:53.111Z"}
|
||||
{"cache_key":"8b3954a3a2d1b02e639f90bce1b404b51a9b39010d6b018412be088d75c83b8b","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.statusRenamed","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Renamed","text_hash":"05487af3f074b4f31e4f9a1ec75044ab182f037a7978e1a8909c42103fb1297a","tgt_lang":"de","translated":"Umbenannt","updated_at":"2026-07-11T04:52:40.877Z"}
|
||||
{"cache_key":"8b76858925e546540267bbab2e8488c3b1649cbe73307bda69abca280b437bab","model":"claude-opus-4-8","provider":"anthropic","segment_id":"claudeSessions.host.sessionCount","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"{count} shown","text_hash":"e57b4adfe868fd74a183650103d820176d4960bd0bdb677d9985db09f9752867","tgt_lang":"de","translated":"{count} angezeigt","updated_at":"2026-06-16T14:13:06.672Z"}
|
||||
{"cache_key":"8bba0aebf5ed20f8e87b3949842d4b11896cb23780173380e17ea0db5335ec5e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"de","translated":"Befehl","updated_at":"2026-06-16T14:13:08.672Z"}
|
||||
{"cache_key":"8c7c377445ceaf3cf30e73a65bff29f19e253f41e82e0e258b56b8e9cbae560e","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.loading","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Loading changes…","text_hash":"99f48f20532c48dcd9f2bfcd0f4d4ba230fb0396b320e67bdfa2f3383901fd1a","tgt_lang":"de","translated":"Änderungen werden geladen…","updated_at":"2026-07-11T04:52:40.877Z"}
|
||||
{"cache_key":"8d069ee6de760a85e91ce1788f050aa0b23ac2f88e431b1d4d2eb3cb12c2ce70","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.refresh","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Refresh changes","text_hash":"c6479e2f497062a67fdcf74f201ded7592369db242c129301b5d740cf3576e61","tgt_lang":"de","translated":"Änderungen aktualisieren","updated_at":"2026-07-11T04:52:40.877Z"}
|
||||
{"cache_key":"8d8bee4267ec378ae0371bdd8deeb6a54c511cfe21e49e1135ea89d35dc44d41","model":"gpt-5.5","provider":"openai","segment_id":"workboard.badgeWorkerProtocol","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"worker {state}","text_hash":"f16b9e04d42182b421ce4f4e982b2ef75fab9bd581bdc8b87e62899ba28de11c","tgt_lang":"de","translated":"Worker {state}","updated_at":"2026-05-30T15:38:11.508Z"}
|
||||
|
||||
Generated
+3
@@ -119,6 +119,7 @@
|
||||
{"cache_key":"29acef0acb9f0e1df98abcc24b192628e93efea6600e96dc4b87b4fa02bd0a02","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.transcript.you","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"You","text_hash":"08b041935798fbf6fd6ff51099ffedb140a475889986d14f5559ff8e7fc571dd","tgt_lang":"es","translated":"Tú","updated_at":"2026-07-11T13:50:24.508Z"}
|
||||
{"cache_key":"29c5677c887e39bb42893790c0b34b27f1c21dac6a87d7847c82acb9cb0318d9","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.help.step2","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Get a tokenized dashboard URL:","text_hash":"c697a6e03fa9ac7f8036204eb6c2a95a143a4de97961318cb00b3e5c039b1794","tgt_lang":"es","translated":"Obtén una URL del panel con token:","updated_at":"2026-07-12T00:08:26.917Z"}
|
||||
{"cache_key":"29df215094fc34f10c62e91a760ce0257d4d83a7ab52fc0e2b36ab8d172efcea","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkSensitivityLow","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Low","text_hash":"f793de205ead5ac302c4a1627829dea41f176b1068b993a32373fc869918374b","tgt_lang":"es","translated":"Baja","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"29ee90221c646d43c97a34cf40679b29cced3c077d025d8bec9fa5441b65c229","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"es","translated":"Nodo","updated_at":"2026-07-09T10:01:43.721Z"}
|
||||
{"cache_key":"2a012c591d333084582c46cc398feeede030ea25732055969a1d483852973cb5","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.noInstalledTitle","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"No optional plugins installed","text_hash":"a81a3fa635d8fd42dda404f4f4dce9231230acfbb87684baab44217ad642a954","tgt_lang":"es","translated":"No hay plugins opcionales instalados","updated_at":"2026-07-10T02:23:45.986Z"}
|
||||
{"cache_key":"2a12488d59c8ed57ec0d57bacf354486376a131687975f7866c863a04cfcd6b5","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.commentaryToggle","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Keep commentary after the final answer","text_hash":"febdff0791d1ceeddb2b7596da8282f4dcfd5cff4cad11dea4c0a23944cd8ffe","tgt_lang":"es","translated":"Mantener los comentarios después de la respuesta final","updated_at":"2026-07-01T01:06:39.912Z"}
|
||||
{"cache_key":"2a4df890a2abe43c5128a6465921bfc92e485c97d5d4adf41c8dd0fb448d7b61","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.cancel","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Cancel","text_hash":"19766ed6ccb2f4a32778eed80d1928d2c87a18d7c275ccb163ec6709d3eb2e27","tgt_lang":"es","translated":"Cancelar","updated_at":"2026-07-10T02:23:54.836Z"}
|
||||
@@ -142,6 +143,7 @@
|
||||
{"cache_key":"334cfb54f716c266a23ce7d84b9a9426af714fff123ee6dfad987490f17240e9","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.fromClawHub","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"From ClawHub","text_hash":"7ab917666959f3e9cfd5cdf9d06636b7908a0ca5445889cb7812629f3b39d250","tgt_lang":"es","translated":"De ClawHub","updated_at":"2026-07-10T04:28:16.685Z"}
|
||||
{"cache_key":"3364743de01ca2958ad4eb8599707e07af63d3aa3054d342dcb6255d3f39641d","model":"gpt-5.5","provider":"openai","segment_id":"browser.untitledTab","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"New tab","text_hash":"1e08fda9c966d3bafb00c51e70935fad9f56990d4bfd0fdb70300ce15a60c7a6","tgt_lang":"es","translated":"Nueva pestaña","updated_at":"2026-07-11T02:17:49.455Z"}
|
||||
{"cache_key":"33b6096dadd7f3493b65fd3726daca058e80c5719dfb99d08ac04b9959d9af4d","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.quickCreate.createAndRun","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Create & run now","text_hash":"410ca8781cd841242df09224cb339e9e1327e934e5253a006aaa9272f0471954","tgt_lang":"es","translated":"Crear y ejecutar ahora","updated_at":"2026-07-11T22:45:06.362Z"}
|
||||
{"cache_key":"34333e8996a9d65c6f83c5ae35f931134c80badfe9fa961bafa4870d268267f4","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"es","translated":"Caducado","updated_at":"2026-07-01T10:31:44.118Z"}
|
||||
{"cache_key":"345358e0962f203fa5c2148974e39697ea65be312eb2bff156c93da1298914b7","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.loading","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Loading session workspace…","text_hash":"bc6b2400fad20ee1d95d8de4ec6eef9ff1818ab080f86513384029519eaf4f4e","tgt_lang":"es","translated":"Cargando espacio de trabajo de la sesión…","updated_at":"2026-06-16T14:14:17.778Z"}
|
||||
{"cache_key":"3458a965443880c3ec6ce5cec1587d67743132e671babad60d93ac4dc8d1f8af","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.dateToday","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Today","text_hash":"2b065c7c9ce466e5ebcad757987d5d660ee4c9ea708bc62c43444b53334738ba","tgt_lang":"es","translated":"Hoy","updated_at":"2026-07-05T14:39:41.363Z"}
|
||||
{"cache_key":"346177aa7ebe3befa956512911bc8f5927918750cf9bde84c4338947c512be71","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.placeholder","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Search chats and commands…","text_hash":"4f67ac6ab88a864f3a3648f5ac4b67c30f72d79db34acdbb4fd65adeadc2fa8e","tgt_lang":"es","translated":"Buscar chats y comandos…","updated_at":"2026-07-12T00:08:26.918Z"}
|
||||
@@ -387,6 +389,7 @@
|
||||
{"cache_key":"90025a95c709087d3c4be39b45a51659e9ad62b7f608ca304b7ef37cc8791619","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkAdvancedSettingsRequiresAdminTitle","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Advanced Talk settings require operator.admin access.","text_hash":"fa933a90d7dde5f8f1a324bd13a5daceb0ad9e04bd77f3aae07c8348edfe4dd7","tgt_lang":"es","translated":"La configuración avanzada de Talk requiere acceso operator.admin.","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"900e9daeafc87184e3dbed59eec12d0641de85e7af52f26b74576f8cfa21e572","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.items.skills","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Skills","text_hash":"66d0f523a379b2de6f8d5fba3a817ebc395f7bcaa54cc132ca9dfa665d1e9378","tgt_lang":"es","translated":"Skills","updated_at":"2026-07-12T00:08:30.876Z"}
|
||||
{"cache_key":"91d4cbc6a529c96c79c3cd88bf91b63b4f23a1899be34841ed782f3121a20122","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.snapshot.tickInterval","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Tick Interval","text_hash":"5e913b1331d1645eed8f87e79af3016b78b2ebe8b1286f2ce861c50671ae6886","tgt_lang":"es","translated":"Intervalo de actualización","updated_at":"2026-07-12T00:08:26.917Z"}
|
||||
{"cache_key":"91ec7f54081064ed7e1bc2b3d40e049ee24b4fc02cbca413e945d334a09a9107","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"es","translated":"Comando","updated_at":"2026-06-16T14:14:26.057Z"}
|
||||
{"cache_key":"92640da35588e5ec1aa0be4ba4471fe21801e87414456621324351e32eaa1c02","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.connectorGroupLife","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Everyday life","text_hash":"6ffcf9be10dcf4ad0f1cb6a4cc66ac839cad453ed842c7a3215f04cd5200cae5","tgt_lang":"es","translated":"Vida cotidiana","updated_at":"2026-07-10T05:22:04.319Z"}
|
||||
{"cache_key":"927a504b1d1e896aafd1e5f7c6c4fc90166397b741f6ca3ecc7aeb5e21b59ee5","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.mcpTargetLabel","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"URL or command","text_hash":"4e49fdb8abf994ea306ebecc12b9b95ea244bd6f81b363a1db8e0ec2c0cb57ce","tgt_lang":"es","translated":"URL o comando","updated_at":"2026-07-10T02:23:49.859Z"}
|
||||
{"cache_key":"9293474dd2f449b6e0db785e9668f9e8eafa861bf91ce051050a52c05eaaeb47","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.mcpNameTaken","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"An MCP server named “{name}” already exists.","text_hash":"32cef939d87970acbaf7a2dbc668f06f2e6f78f3e2f21252f66eb6a4148477cd","tgt_lang":"es","translated":"Ya existe un servidor MCP llamado “{name}”.","updated_at":"2026-07-10T02:23:49.859Z"}
|
||||
|
||||
Generated
+3
@@ -6,6 +6,7 @@
|
||||
{"cache_key":"0169d4249811ffb158470270f39eae6a53505ec93b5909328c40c4807d766905","model":"gpt-5.5","provider":"openai","segment_id":"nav.exitSettings","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Back to app","text_hash":"a6989680b3528cd399ebaea75e660da6ce8d155d24226532180f90ab37c05e9e","tgt_lang":"fa","translated":"بازگشت به برنامه","updated_at":"2026-07-09T08:08:16.435Z"}
|
||||
{"cache_key":"016a517f920477ec59e72297b9b109da12cf27b542d29e99a0bbcc836797cb60","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.elementDetail","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Marked element (page-reported): {descriptor} — {width}×{height}px at ({x}, {y}).","text_hash":"26f6a06bb620377485f379992db59e348653f7dd09db7ebbad9984c6da3c1d37","tgt_lang":"fa","translated":"عنصر نشانهگذاریشده (گزارششده از صفحه): {descriptor} — {width}×{height}px در ({x}, {y}).","updated_at":"2026-07-11T02:20:28.644Z"}
|
||||
{"cache_key":"01a580ba8d16feda69f05cc3763f19a73ffee12f1d3ab904d348a31e8e843f2a","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.help.step3","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Paste the WebSocket URL and token above, or open the tokenized URL directly.","text_hash":"9c978945315941b9182aa1d51e3465e2250e626234123299ff5fc59b7b01b0ab","tgt_lang":"fa","translated":"نشانی URL وبسوکت و توکن را در بالا جایگذاری کنید، یا نشانی URL توکندار را مستقیماً باز کنید.","updated_at":"2026-07-12T00:11:15.410Z"}
|
||||
{"cache_key":"02335432c12a7b1897346cf2c3f47d1c6901decaf514c43514888e4d14f0d42e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"fa","translated":"دستور","updated_at":"2026-06-16T14:18:51.277Z"}
|
||||
{"cache_key":"02649d9444dede2f7341c2b50e5bac7f1ee89f7f6d760c1a0c25798613c78a15","model":"gpt-5.5","provider":"openai","segment_id":"chat.splitView.sessionSelect","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Pane session","text_hash":"0deb0759c3643f2659c0838326276513c119e7923672a118c4ed13c012c4b628","tgt_lang":"fa","translated":"نشست پنل","updated_at":"2026-07-06T07:24:38.563Z"}
|
||||
{"cache_key":"02d9671244d20a7a9b1e5654272d64dc82d1f3ad471ebfbc731fdc1256d0272b","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.summary","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Session workspace summary","text_hash":"1ed422c34dc1802d4c7366164ae810c496e206fe82e8e6565cefc38230b56bb4","tgt_lang":"fa","translated":"خلاصه فضای کاری جلسه","updated_at":"2026-06-16T14:18:48.731Z"}
|
||||
{"cache_key":"051a48d85247d15c65dce97fc3914f02c2c60457cac553ed4640dbc2c2254d02","model":"gpt-5","provider":"openai","segment_id":"modelProviders.status.ok","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Connected","text_hash":"22965568d22a14ee17af055d2870b50afcfe9fd94a83eec3196e266932297bb2","tgt_lang":"fa","translated":"متصل","updated_at":"2026-07-09T10:01:43.762Z"}
|
||||
@@ -47,6 +48,7 @@
|
||||
{"cache_key":"133debfd7db44a5af720e7fb16b8c11e61001736a2e5287bee2e0b19a729dfd0","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.insightModel","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Most used model","text_hash":"a13c86cd4f835d2c2b5af940171ede2a27e0f805cef070d87628f1bd333bb706","tgt_lang":"fa","translated":"پرکاربردترین مدل","updated_at":"2026-07-09T11:29:16.474Z"}
|
||||
{"cache_key":"137bc81b44fac5bd013153ed2270e1dc1beeb16eec10ccd80f7922a55a8c4a61","model":"gpt-5.5","provider":"openai","segment_id":"quickSettings.appearance.lobsterVisitsOn","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Drops by occasionally","text_hash":"620c90596deb02d1164d4036d540b11c780b61cb04e4825230efed1cd8a45e6e","tgt_lang":"fa","translated":"گاهی سر میزند","updated_at":"2026-07-09T20:51:59.140Z"}
|
||||
{"cache_key":"13f663da7d5d1b243727bb0c9a05e00b7a4c4611b3b6535c6786ac4809fb81ea","model":"gpt-5","provider":"openai","segment_id":"codexSessions.threadId","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Thread","text_hash":"5373c7f8a5a69019e959540ef127be3302afdd5e2313244e6d08cbd5e975d06d","tgt_lang":"fa","translated":"رشته","updated_at":"2026-07-09T10:01:43.762Z"}
|
||||
{"cache_key":"1403d8d3cae7ae1ca7c105f594677b3310817a684143a2e2a18e50bc1c5d82f9","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"fa","translated":"منقضیشده","updated_at":"2026-07-01T10:34:16.869Z"}
|
||||
{"cache_key":"14160078de1ee3ae94b667d248d532efd92386a5b90d43494d5848e014c5223b","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.agentFilterUnassigned","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Unassigned (uses {agent})","text_hash":"2700af0c4ab5e86726f72a723ecdf50370b87690db35f00b83723d6457879c8e","tgt_lang":"fa","translated":"تخصیصنیافته (از {agent} استفاده میکند)","updated_at":"2026-06-17T14:17:45.318Z"}
|
||||
{"cache_key":"141af5cbd195c30628ce0abc754dcf0295c13afb9fa5d5d48ca055bfaa04da26","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.subtitle","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Isolated repository checkouts owned by OpenClaw.","text_hash":"6a3984ca864c9188fa8c05e732f6831b501b4caed6bd61b60e48e9b0cf74bd0c","tgt_lang":"fa","translated":"checkoutهای ایزولهٔ مخزن که متعلق به OpenClaw هستند.","updated_at":"2026-07-05T21:01:42.282Z"}
|
||||
{"cache_key":"1572ba82025e96e3bf0387d0ac68167d85bb9b109d6434340c79d736e5f4629f","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.nightWatch.prompt","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Check that my services and gateway are healthy: scan recent logs for new errors, restarts, or unusual load. Stay quiet if everything is fine; if something looks broken, message me what failed and where to start looking.","text_hash":"ff691fc0bcd98cc27aea75758d323fc926a74252f5007eb43b49073d1a5716b7","tgt_lang":"fa","translated":"بررسی کن که سرویسها و Gateway من سالم باشند: لاگهای اخیر را برای خطاهای جدید، راهاندازی مجدد یا بار غیرعادی اسکن کن. اگر همه چیز خوب است، ساکت بمان؛ اگر چیزی خراب به نظر میرسد، به من پیام بده چه چیزی خراب شده و از کجا شروع به بررسی کنم.","updated_at":"2026-07-11T22:49:36.745Z"}
|
||||
@@ -238,6 +240,7 @@
|
||||
{"cache_key":"6bdaa3139332c4d7ca7737e2787fc15b34f9c4a719572215b64cdb003aab7d68","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.access.hideToken","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Hide token","text_hash":"ae132305cb4bfbfe5508d7a36a29a914ce321156b8b2e26d5cbddd29d033c713","tgt_lang":"fa","translated":"پنهان کردن توکن","updated_at":"2026-07-12T00:11:09.186Z"}
|
||||
{"cache_key":"6c8ea91f6929828ca51c1229f0b89b9a3e8bfe2ba9947994bb149ac60c7a84ef","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.untitled","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Untitled Claude session","text_hash":"d319ed271fdc80d4b7c1733f5e9466335db68fc760807b13e83f50c48e800636","tgt_lang":"fa","translated":"جلسهٔ بدون عنوان Claude","updated_at":"2026-07-11T13:51:37.631Z"}
|
||||
{"cache_key":"6c91024a4cfefd1c3462f990d5ae31444f656d6c0aecab780581aba1238210e2","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.openPullRequest","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Open PR","text_hash":"04c24026b2f00d817b610318ab2e984393c65576e67b591fb8fb0467f5aef0cb","tgt_lang":"fa","translated":"باز کردن PR","updated_at":"2026-07-11T04:04:54.036Z"}
|
||||
{"cache_key":"6c9c75c148bcdba24fc75a4d8588d26c0e12f2d64728be7471ffa56ab3aa8d57","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"fa","translated":"گره","updated_at":"2026-07-09T10:01:43.762Z"}
|
||||
{"cache_key":"6cb4e2778c55baeda3aff2d90126dbd43cb8f967113ab9dd25fae121647ad280","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.region","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Marked region {index}: centered around {x}% across / {y}% down, spanning about {width}% × {height}% of the view.","text_hash":"e2e51195aefb95748b2c7f794b41b042d70dfeab5de6420e196824eb7780a2ba","tgt_lang":"fa","translated":"ناحیهٔ نشانهگذاریشده {index}: با مرکز در حدود {x}% از عرض / {y}% از بالا، و گستردگی حدود {width}% × {height}% از نما.","updated_at":"2026-07-11T02:20:28.644Z"}
|
||||
{"cache_key":"6cc20a81aa5f0f568c50d432a86fd0e96c8bd9ea1b35d1211ad064ede00e7b03","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.today","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Today","text_hash":"2b065c7c9ce466e5ebcad757987d5d660ee4c9ea708bc62c43444b53334738ba","tgt_lang":"fa","translated":"امروز","updated_at":"2026-07-05T14:40:24.519Z"}
|
||||
{"cache_key":"6e3f54b8e3bcbde213c3d56867a41e7beb31c8adc28684a83a1f32dc9bfe9de0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailTitle","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Card details","text_hash":"93985f84673405070ffdf7e6f64175caff0f2c489c10e40627718525e79af631","tgt_lang":"fa","translated":"جزئیات کارت","updated_at":"2026-06-16T14:18:33.052Z"}
|
||||
|
||||
Generated
+4
@@ -154,6 +154,7 @@
|
||||
{"cache_key":"4255a719f4f69f4be7edecc3dbdc5279ceb09478ea0e2d4f428d4b10b5dd6740","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.parentFolder","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Parent folder","text_hash":"158f5a01ef8cfb1e6d91f8c321dd3a63f5e457f9650eecd662857701762bd31d","tgt_lang":"fr","translated":"Dossier parent","updated_at":"2026-06-16T14:14:38.496Z"}
|
||||
{"cache_key":"42a9e3bcb3f332b85cdc3c53db87838f64d7ad09c440d1d8df6f21da187716be","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.connectorAdded","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Added","text_hash":"6b02e0d363a4af1c95eef50364bb0202c8b250aa05a48a69e68fd7787b4b0632","tgt_lang":"fr","translated":"Ajouté","updated_at":"2026-07-10T02:24:45.579Z"}
|
||||
{"cache_key":"4348d8b8b481e750f43855decc77578211c8b11edff0aab7474256f612664206","model":"gpt-5.5","provider":"openai","segment_id":"tasksPage.runtime.subagent","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Subagent","text_hash":"d6cb4188b8fa57aae3e4ca3a1210c9afe7ca995375c2fb36d90a1fa73529a44e","tgt_lang":"fr","translated":"Sous-agent","updated_at":"2026-07-06T08:42:32.187Z"}
|
||||
{"cache_key":"443270e382af6de712c8623de146d04b1eb60e095faffc1e30443ab21e5b2838","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.cancelled","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Cancelled","text_hash":"d353a99eb4556847ceeb3c306ac886cf6b4fa13043eb1864b9aeb0607fd5f2cc","tgt_lang":"fr","translated":"Annulé","updated_at":"2026-07-06T08:42:32.187Z"}
|
||||
{"cache_key":"445667ee63b3998cda03cc9f148048d488fa2a70a04e052be534e751f9b86cc3","model":"gpt-5.5","provider":"openai","segment_id":"nativeLinkMenu.openInline","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Open in Sidebar","text_hash":"ee39dc2999ce3acefff3c4c5440266e6a044feb3fb0a405a754f3ee4f697b201","tgt_lang":"fr","translated":"Ouvrir dans la barre latérale","updated_at":"2026-07-09T11:02:48.820Z"}
|
||||
{"cache_key":"44af3c13b3d3654d758b55ff2be9d8ad98ef796691eaab42a796a2434baa2c7d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.groupByDate","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Date","text_hash":"99c40ab405926cb5ad1def9cff4d7ce624f8f8abfff4e85f655347fcb949d08e","tgt_lang":"fr","translated":"Date","updated_at":"2026-07-05T14:39:49.624Z"}
|
||||
{"cache_key":"4540f080433dae98660b540962423c69f6204906d19437eabfc5319b063f3602","model":"gpt-5.5","provider":"openai","segment_id":"browser.dockBottom","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Dock to bottom","text_hash":"e2e55afd4848203700e890012a976e47e9976649e479d960662403575476ccd2","tgt_lang":"fr","translated":"Ancrer en bas","updated_at":"2026-07-11T02:18:15.605Z"}
|
||||
@@ -463,6 +464,7 @@
|
||||
{"cache_key":"b73c07687f92b896d93825be662c1db0b17e09bc9c2965300cb87b02ba906d8a","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.noMicrophones","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"No additional microphones found","text_hash":"a6e4a20dda44dead8daa06da30fca7e7d90fa5aa4c15cbada30af1f52874d347","tgt_lang":"fr","translated":"Aucun microphone supplémentaire trouvé","updated_at":"2026-07-06T17:33:45.160Z"}
|
||||
{"cache_key":"b75b6a2248bfccef2ce65ba40de07979a0533ac51f18c427ce8311ee2e14e9f2","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.empty.title","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"No Claude sessions found","text_hash":"a5d53a2e8c2fcb71ff6e4931e6c03a7dbf878bb44592e9d306c9057862cfe8cc","tgt_lang":"fr","translated":"Aucune session Claude trouvée","updated_at":"2026-07-11T13:50:39.277Z"}
|
||||
{"cache_key":"b7f85401d948d158128a68836d4736ee8a027a011c767be91776fdc0953e4669","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.codePlugin","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Code plugin","text_hash":"f1765020c657263e9429231379ba42b2baca07c69512c9c63268e9939d0f9db7","tgt_lang":"fr","translated":"Plugin de code","updated_at":"2026-07-10T02:24:53.076Z"}
|
||||
{"cache_key":"b868d7155b17dcc7054a25d7f0167d9bed38822763726021d1dc5debd187dfa0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"fr","translated":"Commande","updated_at":"2026-06-16T14:14:40.922Z"}
|
||||
{"cache_key":"b8c0e490fb05b434f693a1fa6697add28190eb0c6ab7feaf41e7862d4043e168","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.sidebar.title","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Claude sessions","text_hash":"45d8dde95eda96ef87a6371eefdef22b667880c6e55ef402313b25f589bd983b","tgt_lang":"fr","translated":"Sessions Claude","updated_at":"2026-07-11T13:50:39.277Z"}
|
||||
{"cache_key":"b8da071449693eb7d9e89345d91e1edd4a687129e21a4966ab121c5d7c1a2862","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.viewDetails","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"View details","text_hash":"d1bf045bb524dae5b02c471c230958bcd1bf232d7a49367b1cdf977855a06b41","tgt_lang":"fr","translated":"Voir les détails","updated_at":"2026-06-16T14:14:26.985Z"}
|
||||
{"cache_key":"b8e1888a56c84aadfd1cffd3a6e6b99edda596bd5b348571883ee7f9d659a846","model":"gpt-5.5","provider":"openai","segment_id":"subtitles.plugins","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Install and manage optional capabilities.","text_hash":"61975da9493fce9ed5b684bbf3a300bc7a50b5a5c1866008fa35462f35cada6b","tgt_lang":"fr","translated":"Installez et gérez des fonctionnalités optionnelles.","updated_at":"2026-07-10T02:24:41.383Z"}
|
||||
@@ -513,6 +515,7 @@
|
||||
{"cache_key":"cd6c90688637767c0b4c7382f4f3da4fd8a4dabc3165a9f3c1d7a36b2a2998a9","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.connectorsGroup","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Connect your world","text_hash":"5936f0296a1716ced3d9a1b8635599b1bbe23743beb51b3f8c0c6cce97456cba","tgt_lang":"fr","translated":"Connectez votre monde","updated_at":"2026-07-10T02:24:45.578Z"}
|
||||
{"cache_key":"cd77f12d0d2e9f4427a199e8f15448b58283cb78c2b9def9a0d985e0da1260c6","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkSensitivity","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Sensitivity","text_hash":"ebb57a260d58207c3cce2e12e8663ecdc0c74147d138655d6714bc577a0768f6","tgt_lang":"fr","translated":"Sensibilité","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"cdd06bf29eb5b03da7910c9c707fd4d7eda844d2c347d04dedd3b48397b78e9d","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.title","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Changes","text_hash":"bbd4b6a86bc65b6ac8e79e97afc61499158edb40f7bb404c70637b46d80a7ad2","tgt_lang":"fr","translated":"Modifications","updated_at":"2026-07-11T04:52:52.885Z"}
|
||||
{"cache_key":"cdf1f8df4da0bd91f2b7487d85ca705dd398951c0afc6409bf9271348353bb18","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"fr","translated":"Expiré","updated_at":"2026-07-01T10:32:03.163Z"}
|
||||
{"cache_key":"ce070814382c8b20cf3ea58f2a8eeb7a7a12aaf8bd7965a5eac631d34a56920d","model":"gpt-5","provider":"openai","segment_id":"codexSessions.host.unavailable","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Session catalog unavailable","text_hash":"7214837a3c6e83c01215e8128a4f7ac095be446b09dc0bd464178c9d1f03a039","tgt_lang":"fr","translated":"Catalogue de sessions indisponible","updated_at":"2026-07-09T10:01:43.739Z"}
|
||||
{"cache_key":"ce1a20201a6524749bc488b41a6e17f3ef6e54f399c3b802761ccc6332fe40a9","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.markUnreadCount","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Mark {count} as unread","text_hash":"19b370543f8c7b0e263a73d5bbd6d0ef8df6b3ed4da0941dc5de1feec926e270","tgt_lang":"fr","translated":"Marquer {count} comme non lus","updated_at":"2026-07-11T10:40:53.431Z"}
|
||||
{"cache_key":"cec91c4b83ff3734be036979677d830e23e3320b58460d22e5435f0315a06609","model":"gpt-5.5","provider":"openai","segment_id":"newSession.messagePlaceholder","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"What should this session work on?","text_hash":"5ee1ce48f2e07db6edcfc03ead8916c26911ae5935e0446a950f2559afc5b534","tgt_lang":"fr","translated":"Sur quoi cette session doit-elle travailler ?","updated_at":"2026-07-10T15:21:04.486Z"}
|
||||
@@ -645,6 +648,7 @@
|
||||
{"cache_key":"fa3c640fea38f452db0ad4f612ddfc6b73d5022b4e00ba7936f8bf73b35d2651","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.stored","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Stored","text_hash":"91da9626894c82dd4d5ed7ab48ed4ed4b1fc57ff98858cde93945254e36c4198","tgt_lang":"fr","translated":"Stockée","updated_at":"2026-07-09T10:01:43.739Z"}
|
||||
{"cache_key":"faa7f865d7b3bb036dd703281b2b8efb480fac88b07808dd4ca9a7e02563fd19","model":"gpt-5.5","provider":"openai","segment_id":"tasksPage.emptyActive","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"No queued or running tasks.","text_hash":"00db4a453c2e92f4d807847fc0d8d340708ed9ab547280ce376ba1d610bcb5a6","tgt_lang":"fr","translated":"Aucune tâche en file d’attente ou en cours d’exécution.","updated_at":"2026-07-06T08:42:28.842Z"}
|
||||
{"cache_key":"fb052060d6a0cc337edcd1ab42a3879e873232b9cfb6280dec911247bca7e789","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.openChecks","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Open checks on GitHub","text_hash":"420244dba5fbf609d59521d9039f0a36ec19a7a0e8413cfb1d7de17f7d39d813","tgt_lang":"fr","translated":"Ouvrir les vérifications sur GitHub","updated_at":"2026-07-10T16:20:01.450Z"}
|
||||
{"cache_key":"fb577ac830e5a83fe6d0c0f5bf19445d82087eeab80907e4c01bca8fbc13a543","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"fr","translated":"Nœud","updated_at":"2026-07-09T10:01:43.739Z"}
|
||||
{"cache_key":"fb6686fd89bfeddf30898c0d757d0d1ddb8f99f0e963caa158bd53ad334abde1","model":"gpt-5","provider":"openai","segment_id":"usage.costWindows.selectedRange","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Selected Range","text_hash":"95917ae71066a19c266cd4530068f4bf775ed2401951ebf37ab0c91daa1a67d3","tgt_lang":"fr","translated":"Période sélectionnée","updated_at":"2026-07-05T20:24:32.108Z"}
|
||||
{"cache_key":"fc609f266b51d6f0dd8c26007ba694f96d323b98a4ac2c83282a46b2d82c7b94","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.contextUsage.limitDaily","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Daily limit","text_hash":"1e4ce9cd955f07b1b79cddb1bec9df28d4033d4238c0e54b0b766239133afc8c","tgt_lang":"fr","translated":"Limite quotidienne","updated_at":"2026-07-09T11:49:23.923Z"}
|
||||
{"cache_key":"fdb8014561e4ea45e0bce1cf3a449e3294ac0e277c7c328fabac9bd3cab62506","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.hackerNewsScout.name","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Hacker News scout","text_hash":"6a00a3389ce54f09fe80af84deb8f1543f16ae6c3fd5917764ed30334367eb3e","tgt_lang":"fr","translated":"Éclaireur Hacker News","updated_at":"2026-07-11T22:45:53.930Z"}
|
||||
|
||||
Generated
+6
@@ -497,6 +497,7 @@
|
||||
{"cache_key":"3c83036aacb6b737b38423f59254862c5fe24e9e0bf7935fff1ddaa462b0538d","model":"gpt-5.5","provider":"openai","segment_id":"cron.jobDetail.system","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"System","text_hash":"6725e7bbcd28f3a8a586fa34bf191fd72dde8b61756932cd3237c17a6f196f1a","tgt_lang":"hi","translated":"सिस्टम","updated_at":"2026-06-26T21:38:12.145Z"}
|
||||
{"cache_key":"3c8f3e0a5020e92e9b479953ee510edf812c902f4d4c053e0daeb9532a170d27","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.statusTimeout","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Timed out","text_hash":"9718cc761cfd5810041ef007ae258fa1308b8487d0f30c5f36a442f8fe5f76c5","tgt_lang":"hi","translated":"समय समाप्त","updated_at":"2026-06-26T21:30:33.640Z"}
|
||||
{"cache_key":"3c9a45f95bf7740d5b2f0f41994055f8f861d8b883ff8ca56f6399326b8b3941","model":"gpt-5.5","provider":"openai","segment_id":"workboard.detailAutomationSkills","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Skills: {skills}","text_hash":"4788d5f9db66e1421a762bbd942c64450c73d2145a6ef929ce32a919a0f2e3a1","tgt_lang":"hi","translated":"कौशल: {skills}","updated_at":"2026-06-26T21:32:11.358Z"}
|
||||
{"cache_key":"3cb99a78592baad169c5e93a7f1a217a2afb8f0d92ee86d3676c46b34755262c","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"hi","translated":"समाप्त","updated_at":"2026-07-02T14:30:19.917Z"}
|
||||
{"cache_key":"3cc55898ff4bf7f99b2408671ceff2b875983bde7a817ac4cd7b360bf5539138","model":"gpt-5.5","provider":"openai","segment_id":"cron.errors.systemEventTextRequired","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"System event text required.","text_hash":"b6a571210cc1c529ced733fc25d04ce3fa25c68673d841b33dca8aebcffe130d","tgt_lang":"hi","translated":"System event text आवश्यक।","updated_at":"2026-06-26T21:38:17.792Z"}
|
||||
{"cache_key":"3cc5efd60068c5a44592ad6d7c3b6a906a1a2169a3d56b70075a0de31666cbb2","model":"gpt-5.5","provider":"openai","segment_id":"dreaming.phrases.whisperingVectorStore","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"whispering to the vector store…","text_hash":"44f8f2666f20599ad12e2e33ea95c6f37c8a2b422bf438d4bdb59e778ae6a527","tgt_lang":"hi","translated":"vector store से फुसफुसाते हुए बात की जा रही है…","updated_at":"2026-06-26T21:34:31.303Z"}
|
||||
{"cache_key":"3cc70693f91cd8a6d2247e00b0ccbb02e27cbad725ad1c10436cc1cbd07948e1","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.schedule","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Schedule","text_hash":"f4830a1dae2980447c716bd4b5779b7013575ef09f70ef4731457218792487b3","tgt_lang":"hi","translated":"शेड्यूल","updated_at":"2026-06-26T21:37:31.894Z"}
|
||||
@@ -512,6 +513,7 @@
|
||||
{"cache_key":"3e0828d7249ea99d4ab0a66bc08ad662b013d42f14d006fdbe8100af95760c92","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.watchdog.prompt","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Check that my services and gateway are healthy: scan recent logs for new errors, restarts, or unusual load. Reply with a single short all-clear line when everything is fine; if something looks broken, report what failed and where to start looking.","text_hash":"81c27753a3ba9ba3f5687e7b00bf943abdf2bf187ac0f2aed10136f5dc043aec","tgt_lang":"hi","translated":"मेरी सेवाओं और Gateway की जांच करें: हाल के लॉग में नई त्रुटियाँ, पुनरारंभ, या असामान्य लोड खोजें। सब ठीक हो तो एक छोटी सी क्लियर लाइन दें; कुछ गड़बड़ लगे तो बताएं क्या विफल हुआ और कहाँ से जांच शुरू करें।","updated_at":"2026-07-11T22:59:27.404Z"}
|
||||
{"cache_key":"3e0e28f501e36fec513dd65b9b30af566d507557225523bd916fceb7b4a5bd69","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.statPeakDay","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Peak day","text_hash":"c3a0833ac4b7cd06e29368f323fef10520637658605aa35de342df7bac6357f1","tgt_lang":"hi","translated":"सर्वोच्च दिन","updated_at":"2026-07-09T11:27:28.426Z"}
|
||||
{"cache_key":"3e35b43c8619567580cc4ecc4e71b8cdd9d1a8499f5d4751f7d1d464479909b9","model":"gpt-5.5","provider":"openai","segment_id":"languages.zhCN","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"简体中文 (Simplified Chinese)","text_hash":"e34fcc9872e46b54fd22bd89aae921332644df9ff58d7778cba9c4007dbeafb2","tgt_lang":"hi","translated":"简体中文 (सरलीकृत चीनी)","updated_at":"2026-06-26T21:36:47.054Z"}
|
||||
{"cache_key":"3e415acdae3dd5d341d17dd3ae7c2faa6e42f7bc5230d6f23ff9aa009969a2c8","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"hi","translated":"नोड","updated_at":"2026-06-26T21:30:08.627Z"}
|
||||
{"cache_key":"3ebc0d2198c79062faf040c9b74cb2f374e862b38902066f2eaf5fd86ab9b749","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.tooLarge","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Diff too large to display.","text_hash":"7d4eba6d7db613ab97b942cf267e384a562be26f8fd2712c0995e0f9b54ef327","tgt_lang":"hi","translated":"Diff प्रदर्शित करने के लिए बहुत बड़ा है।","updated_at":"2026-07-11T04:53:05.719Z"}
|
||||
{"cache_key":"3edf48ba7dc23fae423f7bcfd877b8178145f41ef940f3df74f5c10346b131f0","model":"gpt-5.5","provider":"openai","segment_id":"codexSessions.host.connected","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Connected","text_hash":"22965568d22a14ee17af055d2870b50afcfe9fd94a83eec3196e266932297bb2","tgt_lang":"hi","translated":"कनेक्टेड","updated_at":"2026-06-26T21:29:19.678Z"}
|
||||
{"cache_key":"3ee30074cb227d8aad5719db18f8d3a87c8d2df48d541ddee3f4672cef548280","model":"gpt-5.5","provider":"openai","segment_id":"agents.setDefaultTitle","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Set as the default agent","text_hash":"f588662bdbbb9073d53dee24c3f99bfcbdd13bd639ed73092d2ae59272c19542","tgt_lang":"hi","translated":"डिफ़ॉल्ट एजेंट के रूप में सेट करें","updated_at":"2026-06-26T21:30:41.032Z"}
|
||||
@@ -749,6 +751,7 @@
|
||||
{"cache_key":"6031e737922d2e5da86bcf46f33ce9ddfb18f8892a0ecfe39ce15daaa15adc12","model":"gpt-5.5","provider":"openai","segment_id":"connection.help.step2","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Get a tokenized dashboard URL:","text_hash":"c697a6e03fa9ac7f8036204eb6c2a95a143a4de97961318cb00b3e5c039b1794","tgt_lang":"hi","translated":"टोकनयुक्त डैशबोर्ड URL प्राप्त करें:","updated_at":"2026-06-26T21:33:34.535Z"}
|
||||
{"cache_key":"605b4821f4def973f57839bc5a6695888050355bf42e10be040ccdd8bf8612b9","model":"gpt-5.5","provider":"openai","segment_id":"cron.jobs.recentlyUpdated","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Recently updated","text_hash":"474b2a869ac1477d2c174d764815230c13edb7a9d194d5aa8ea349c6d0c9dee2","tgt_lang":"hi","translated":"हाल ही में अपडेट किया गया","updated_at":"2026-06-26T21:37:15.387Z"}
|
||||
{"cache_key":"607810205e547ea3c72f57ad11ff864a68ea6384899867174a554bb38bbf3b7e","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.main","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Main","text_hash":"eb814be3ca3b78c0734c560518be2a03e8d8f6e7e26447224cc7c7b105e1193e","tgt_lang":"hi","translated":"मुख्य","updated_at":"2026-06-26T21:37:38.564Z"}
|
||||
{"cache_key":"607f3b550aaafafedb2fb31ac1f54ca0e94f810611058e18883e8b21195a6eeb","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.toolLabel","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Tool","text_hash":"2e53bdcd0740867b597599e733c04a994f55fb17c89a61595183a001742e5705","tgt_lang":"hi","translated":"टूल","updated_at":"2026-06-26T21:31:44.582Z"}
|
||||
{"cache_key":"608206a46705d0ef52e2c78d11b5db3d777a30537ae45a79ae0654b5a9f8fbe1","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.region","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Marked region {index}: centered around {x}% across / {y}% down, spanning about {width}% × {height}% of the view.","text_hash":"e2e51195aefb95748b2c7f794b41b042d70dfeab5de6420e196824eb7780a2ba","tgt_lang":"hi","translated":"चिह्नित क्षेत्र {index}: {x}% दाएँ / {y}% नीचे के आसपास केंद्रित, व्यू के लगभग {width}% × {height}% तक फैला हुआ।","updated_at":"2026-07-11T02:18:39.926Z"}
|
||||
{"cache_key":"6093ba70bdc64bcd53600077c113852353bf909635a1c986fc1920270821e16c","model":"gpt-5.5","provider":"openai","segment_id":"login.failure.rateLimited.summary","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"The Gateway is temporarily limiting authentication attempts for this client.","text_hash":"d8fa743e54d8cb80e08e44fdfe20a74b3c99505a82ca5b7a2a65d7dd53ac9f6c","tgt_lang":"hi","translated":"Gateway इस क्लाइंट के लिए authentication प्रयासों को अस्थायी रूप से सीमित कर रहा है।","updated_at":"2026-06-26T21:35:56.265Z"}
|
||||
{"cache_key":"615175731c109cbf38df0fb6f6374e911fba9d98dbea8b7842d07e3725c89fde","model":"gpt-5.5","provider":"openai","segment_id":"overview.cards.modelAuthAttentionExpiringTitle","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Model auth expiring soon","text_hash":"330e48cb1ac5728e8207087132398a091310c7ec1497ee8a553b5681e1b3eccb","tgt_lang":"hi","translated":"मॉडल प्रमाणीकरण जल्द समाप्त होगा","updated_at":"2026-06-26T21:33:40.484Z"}
|
||||
@@ -820,6 +823,7 @@
|
||||
{"cache_key":"6b15c01c8519286cf33b10d54694be598b04c0fc7e46e1073cdddd1a470c93c4","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.talkSensitivityMedium","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Medium","text_hash":"8e588cd187741f1cd76f5fab77b7208782a8c21d764ce7d7a4cf3ac4e0968873","tgt_lang":"hi","translated":"मध्यम","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"6b18e8012e689dfbcee8de46f88b57d46417dd0856cc0d4ca26fca1f1509def7","model":"gpt-5.6-sol","provider":"openai","segment_id":"attention.modelAuthExpiring","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Model auth expiring: {providers}","text_hash":"6e81ee6c190d3fde402e7d82f1c86ac14a8ac8ec8d555b527be7842fbd72992a","tgt_lang":"hi","translated":"मॉडल प्रमाणीकरण की समय-सीमा जल्द समाप्त होगी: {providers}","updated_at":"2026-07-12T00:09:04.271Z"}
|
||||
{"cache_key":"6b39fe20d19096faee5a1984457152332fdd875b9681d307be8f3bec05db31e1","model":"gpt-5.5","provider":"openai","segment_id":"channels.nostr.nip05Help","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Verifiable identifier (e.g., you@domain.com)","text_hash":"621809d0907c8a18fa79d4d21f7d41bed3ddccb2a2dd5cd134957ef4e7b3f0f3","tgt_lang":"hi","translated":"सत्यापनीय पहचानकर्ता (उदा., you@domain.com)","updated_at":"2026-06-26T21:29:59.416Z"}
|
||||
{"cache_key":"6b3a1d474659304be63d65db1bb085a7bdf18d9b21f5bb69ac1346e624160b6d","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.resolvedLabel","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Resolved","text_hash":"5be3c2c8354e1eb924b03a3dcc7fa4172e9aa0f4917b46b44fcc7daf8835d7a7","tgt_lang":"hi","translated":"समाधानित","updated_at":"2026-06-26T21:31:18.653Z"}
|
||||
{"cache_key":"6b76be73df9e19caa2514e56bf282d311d9dffedd784583b3dd10c1e4dfaf29b","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.optionalPlaceholder","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"(optional)","text_hash":"0059798b7f7023e4d9e5c4595f7b9ba7ee64f69993ee524824d57e5a48b1228c","tgt_lang":"hi","translated":"(वैकल्पिक)","updated_at":"2026-06-26T21:30:15.460Z"}
|
||||
{"cache_key":"6b7c6b123d43cabfd3f6f3ce3cbb00a9300f4a50fbdd6d7251a4118e0bfbfcf3","model":"gpt-5.5","provider":"openai","segment_id":"common.running","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Running","text_hash":"f4ccae29e1bb0c20a124570a1b43f4347ea94bba9f84ffdfddd9c7445b126128","tgt_lang":"hi","translated":"चल रहा है","updated_at":"2026-06-26T21:29:24.057Z"}
|
||||
{"cache_key":"6b984e0a7962a4daed917c76f192c5ba67975e42b2c2f84697066f1665d06131","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.dragSessionHint","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Drag to move between groups","text_hash":"3e8692b1cd1c1f9a606a779f1037aa390c885fde224ddb841df9259e8aab03ae","tgt_lang":"hi","translated":"समूहों के बीच ले जाने के लिए खींचें","updated_at":"2026-07-05T14:39:53.244Z"}
|
||||
@@ -910,6 +914,7 @@
|
||||
{"cache_key":"782b365f73e8c29e6497a36304a6a5e116e5fea4c4db0f06264155ea22ad554c","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.on","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"on","text_hash":"b8d31e852725afb1e26d53bab6095b2bff1749c9275be13ed1c05a56ed31ec09","tgt_lang":"hi","translated":"चालू","updated_at":"2026-06-26T21:30:21.093Z"}
|
||||
{"cache_key":"7845adb212b60bc7d44f925e99f11841814356f2b624f7d8f1e7e24ee4d4971d","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.advanced","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Advanced","text_hash":"9f088dbebd6c3c70a5ddbc2c943b11e4ca9acea5757b0b4f2b32479f0dbb747e","tgt_lang":"hi","translated":"उन्नत","updated_at":"2026-06-26T21:37:57.526Z"}
|
||||
{"cache_key":"78589be683272327775f6b631b75610d33849f774f8ee81c05ef8e8f36725d45","model":"gpt-5.5","provider":"openai","segment_id":"overview.access.wsUrl","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"WebSocket URL","text_hash":"e09731b4efa96f0a1f1d5a2d054151ab0297af95bd92b137008cc61534b09e95","tgt_lang":"hi","translated":"WebSocket URL","updated_at":"2026-06-26T21:33:07.229Z"}
|
||||
{"cache_key":"785ae57327d6cdcf6f99897f15f0d32ab6a65f91a3e2a862c27c7d358128f4fc","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"hi","translated":"Command","updated_at":"2026-06-26T21:37:46.380Z"}
|
||||
{"cache_key":"78637e64101b53f0f3bf8710c30ee20c1eeb4aef2f588c82a2fcccc1039a0608","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.ownerWorkboard","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Workboard","text_hash":"48d4659e64e383e94d3bc3badcf8e6e8c162ada4e5254958994531748fd7ab3b","tgt_lang":"hi","translated":"वर्कबोर्ड","updated_at":"2026-06-26T21:31:23.820Z"}
|
||||
{"cache_key":"788568476f4b025d0ab808655f26909c4faaa29ff5242fb2858d3b2bc95c329c","model":"gpt-5.5","provider":"openai","segment_id":"usage.metrics.session","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"session","text_hash":"3f3af1ecebbd1410ab417ec0d27bbfcb5d340e177ae159b59fc8626c2dfd9175","tgt_lang":"hi","translated":"सेशन","updated_at":"2026-06-26T21:34:31.303Z"}
|
||||
{"cache_key":"789b99942f38056aaf60fefd5c8f2acadf2063c27a0cc62d9a67246a3ff5538f","model":"gpt-5.5","provider":"openai","segment_id":"dreaming.phrases.forgettingNoise","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"forgetting what doesn't matter…","text_hash":"b1682b9653c2540fd575cc52cbf7c2e68d8fc54b3987c593f2b94fe4a6a8fc5a","tgt_lang":"hi","translated":"जो मायने नहीं रखता, उसे भुलाया जा रहा है…","updated_at":"2026-06-26T21:34:24.815Z"}
|
||||
@@ -1493,6 +1498,7 @@
|
||||
{"cache_key":"c88bfe613ae98e3e2b6ab4baa4ebe47a0899a1b8a12f4a081d6eb3c9cdaec355","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.contextUsage.limitHours","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"{hours}-hour limit","text_hash":"c9091350c3c5c4e3c54dae43eec58cd35555724276a0acc388b98239a573f9df","tgt_lang":"hi","translated":"{hours}-घंटे की सीमा","updated_at":"2026-07-09T11:49:28.360Z"}
|
||||
{"cache_key":"c8911f329b9b2052aebaea320995deb23b4a04856414b33d9fa5a9ee3ed52ead","model":"gpt-5.5","provider":"openai","segment_id":"usage.metrics.sessions","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"sessions","text_hash":"1225ae6c1ae69dcb4ee4781b703e12206f3b549cd3ca151070a8d8d8f371dd71","tgt_lang":"hi","translated":"सेशन","updated_at":"2026-06-26T21:34:31.303Z"}
|
||||
{"cache_key":"c8922f33bbe32c460504d2fa947bf4907501957e6a095f1d6c4e2c7dd0cebb3c","model":"gpt-5.5","provider":"openai","segment_id":"usage.breakdown.costByType","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Cost by Type","text_hash":"191407927e3b9ed0accd8cc9d2b8952704dfd9a8cc6edfe8c04a722e146fe612","tgt_lang":"hi","translated":"प्रकार के अनुसार लागत","updated_at":"2026-06-26T21:34:59.501Z"}
|
||||
{"cache_key":"c8b95f648a17e59f1c5b5f9b71fdec35057453fa93056f999a273358f2e569a8","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.retry","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Retry","text_hash":"942087cc2d41e01304b7195558d093d10c72af8e838c7556d6a02d471ee71852","tgt_lang":"hi","translated":"पुनः प्रयास करें","updated_at":"2026-06-26T21:36:30.561Z"}
|
||||
{"cache_key":"c8cd9cea4fda8eaf0555798465f8e59ab6fcb3216b2c4297cb3845ab090ba5fa","model":"gpt-5.5","provider":"openai","segment_id":"palette.items.agents","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Agents","text_hash":"279b44d2ab4b40c0fc132f8f3051293544cca91de9c8aa14f2cd29adb132b0ee","tgt_lang":"hi","translated":"एजेंट","updated_at":"2026-06-26T21:31:23.820Z"}
|
||||
{"cache_key":"c8cf6e21e48d287c4e0fe369249b3df9e454b4b02fb0c1e20b5f7f4794b87890","model":"gpt-5","provider":"openai","segment_id":"usage.costWindows.lastDays","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Last {count} days","text_hash":"4aa456a0fa9b73dcc14766740b19fc52c452950ccb7bc892499c3c29a4122162","tgt_lang":"hi","translated":"पिछले {count} दिन","updated_at":"2026-07-05T20:24:32.108Z"}
|
||||
{"cache_key":"c90c26faa0162a19a48463403317e5524c2ecc3b5722e4bf5cb1a02ae5c2e634","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.defaultOption","source_path":"ui/src/i18n/locales/hi.ts","src_lang":"en","text":"Default ({value})","text_hash":"a9d6571117890ef77ecc72f77ba43e9d8b05ed82c1c64ff27a352c02dff3c2bd","tgt_lang":"hi","translated":"डिफ़ॉल्ट ({value})","updated_at":"2026-06-26T21:30:21.093Z"}
|
||||
|
||||
Generated
+3
@@ -200,6 +200,7 @@
|
||||
{"cache_key":"52d071945fb95e4e6464a11611df447d7d03859140aa72a4a4da1c124f1557cd","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.draft","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Draft","text_hash":"ebf12ef47cf575b3ba9a3cc019c5310146fdac88f6d1be6618d6e91158c2f174","tgt_lang":"id","translated":"Draf","updated_at":"2026-07-10T17:04:17.152Z"}
|
||||
{"cache_key":"53569f49c6e28f91008e3f8c403207c97c8288cf7a13cdfe16f81db760bf66d3","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.statLongestSession","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Longest session","text_hash":"7f727c1b85939ac165087fe5c3081e15ca00c6e6a0c0b6f8c908ff21eda7a4f2","tgt_lang":"id","translated":"Sesi terpanjang","updated_at":"2026-07-09T11:28:19.904Z"}
|
||||
{"cache_key":"5373e60a62ac2a52cc5a7523708720010dc3db94326a73d4ce760802229597e7","model":"gpt-5.5","provider":"openai","segment_id":"chat.sidebar.chats","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Chats","text_hash":"ef5b4049bb367b05531fa2c2982dbc5b710c3dde724d9a2683747c1da9b61eac","tgt_lang":"id","translated":"Chat","updated_at":"2026-07-10T15:21:37.072Z"}
|
||||
{"cache_key":"541470b355be148a6b7b6585adb2a458b10dc090711f5707c1f093b0a3117b9a","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"id","translated":"Perintah","updated_at":"2026-06-16T14:16:59.378Z"}
|
||||
{"cache_key":"54772267c364941a63a2130f8e64bb284025e7af724031a488704fd230b72849","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.title","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Managed Worktrees","text_hash":"dde32010185098a47e873fb25dd99446b0cb1a75614068587f7cd0bffb5aed18","tgt_lang":"id","translated":"Worktree Terkelola","updated_at":"2026-07-05T21:01:23.086Z"}
|
||||
{"cache_key":"559ab5cf0c7b3e1668f9ab6eaa3b3b44d24de403972c50dd1cd4ab7ceff53a74","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.statLongestStreak","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Longest streak","text_hash":"49095cff1349a49e9b8672a0ef850d5bec7be2af58e803a0f17c41faf6753f39","tgt_lang":"id","translated":"Rentetan terpanjang","updated_at":"2026-07-09T11:28:19.904Z"}
|
||||
{"cache_key":"55bc5c9d9e963edca9cd27039b499d3a994d32dc7b005b3850b5abdbe82055f5","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.workspace","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Session","text_hash":"6959b4159575d8dd76d9f3bbe2c6437904f861e7860c35abd18deffb1c3425a0","tgt_lang":"id","translated":"Sesi","updated_at":"2026-06-16T14:16:50.406Z"}
|
||||
@@ -459,6 +460,7 @@
|
||||
{"cache_key":"c4a986489505b9522919b48440c09774080213beb208fed0621e78cef3e42a2b","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.snapshot.uptime","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Uptime","text_hash":"d63ab4711473b0398feb4b56622605d5d2ec7ecd3b1bb5070a7dd56de96aaf88","tgt_lang":"id","translated":"Waktu aktif","updated_at":"2026-07-12T00:09:54.975Z"}
|
||||
{"cache_key":"c555d35c23340c4c8ce7a451c92f251d655b3e777cef38ffa5dd3b6631e6a31a","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.microphoneNoneFound","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"No microphone inputs were found.","text_hash":"3aa0952aa2a5987227a12656a28131c7e153b5efe3fca4043c742fb289eeb37c","tgt_lang":"id","translated":"Tidak ditemukan input mikrofon.","updated_at":"2026-07-06T17:57:03.488Z"}
|
||||
{"cache_key":"c602df6d7a66b36cbf051f81c1d9774c915e4c7f87dc18510d6a16c8146176f6","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.toolsTitle","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Most used tools","text_hash":"8bc3f9b213a6e4c632b3c09d45d7c373a07c75389ab5d6c17cc053352ea16847","tgt_lang":"id","translated":"Tool yang paling sering digunakan","updated_at":"2026-07-09T11:28:23.299Z"}
|
||||
{"cache_key":"c63aa05e76a327abb2f1f52476759883958f3ae8d1a5c1f53b5e713bd0c50d12","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"id","translated":"Node","updated_at":"2026-07-09T10:01:43.737Z"}
|
||||
{"cache_key":"c7327dcdbefe9c102dc92626d1dad26644bb416f62543550124ec25a49e2152f","model":"gpt-5","provider":"openai","segment_id":"codexSessions.empty.title","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"No Codex hosts found","text_hash":"aaad17f2d1d59a936c7882613d1eb75ad6e82d0e82ec79837a587a43352ce24e","tgt_lang":"id","translated":"Tidak ditemukan host Codex","updated_at":"2026-07-09T10:01:43.737Z"}
|
||||
{"cache_key":"c816a4783b1bd963494f2c11d0f458568f24d49391ecb92152c2772d9ad8e90f","model":"gpt-5.5","provider":"openai","segment_id":"browser.closeTab","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Close tab","text_hash":"50a3f9523122bd0776d8a43c5356c47eaa9c626eb2aa849c88a3ebc2e12c4c99","tgt_lang":"id","translated":"Tutup tab","updated_at":"2026-07-11T02:19:24.198Z"}
|
||||
{"cache_key":"c816c85ea1a1deb9e0fa2eaa93dbc216082419194388f6013efad84e2758d097","model":"gpt-5.5","provider":"openai","segment_id":"chat.welcome.recentSessions","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Recent chats","text_hash":"2ccfecbca1011bad772fce00fa6479c9af2d398ce3b3951b7713b2655b6999eb","tgt_lang":"id","translated":"Chat terbaru","updated_at":"2026-07-11T08:43:19.151Z"}
|
||||
@@ -542,6 +544,7 @@
|
||||
{"cache_key":"e47516a37e023e5469c9b6709da447f721bed85a93f2dc39fa38659aa56a53a9","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.truncatedFile","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Diff truncated.","text_hash":"2a4f4803ed395dae4c1d0573e8cff6e4123aaba9f2c6e6cbc4581d5d4d3e4571","tgt_lang":"id","translated":"Diff dipotong.","updated_at":"2026-07-11T04:53:24.485Z"}
|
||||
{"cache_key":"e4e8ba9c944177cf1fb7f7c95fd09f6b8433f4448833b2b7db68b73f8edfbb90","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.dependencyRadar.prompt","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Check my main project for outdated or vulnerable dependencies. List the notable updates with a one-line risk note each, and draft the upgrade command.","text_hash":"37e748522c37a70784490e38e52cad91fec0022910bb86f70a18badbebb3c4b4","tgt_lang":"id","translated":"Periksa proyek utama saya untuk dependensi yang usang atau rentan. Daftarkan pembaruan penting dengan catatan risiko satu baris masing-masing, dan buat perintah peningkatannya.","updated_at":"2026-07-11T22:47:43.038Z"}
|
||||
{"cache_key":"e50911899ee7eeaa5d59087b7ea0ce0458907a72ab256f654e6cd18ca56799e0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"claudeSessions.host.sessionCount","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"{count} shown","text_hash":"e57b4adfe868fd74a183650103d820176d4960bd0bdb677d9985db09f9752867","tgt_lang":"id","translated":"{count} ditampilkan","updated_at":"2026-06-16T14:16:57.267Z"}
|
||||
{"cache_key":"e50bccc01ca20d142658c4407e04de5ed30abc0d8dfb944d960b54e56e71564a","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"id","translated":"Kedaluwarsa","updated_at":"2026-07-01T10:33:20.040Z"}
|
||||
{"cache_key":"e523524bb221cdd7479f54d061c011bb5c8900235d23fd5f41602d2f20c10a93","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.pinSession","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Pin session","text_hash":"813273b54d2df112a0fa1903110e9386779f8848ae288142d3f91d7a5891c8ff","tgt_lang":"id","translated":"Sematkan sesi","updated_at":"2026-07-02T14:30:35.554Z"}
|
||||
{"cache_key":"e5ca3610e62811f451e93aaef650cbca7eff29c9259d28163bb022c39ae779a6","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.archivedOnlyTooltip","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Show only archived sessions.","text_hash":"de4c6803e169c7f2d3116da6fa5b95417d952edf88f69b0b279d5d17e9e34e87","tgt_lang":"id","translated":"Tampilkan hanya sesi yang diarsipkan.","updated_at":"2026-07-02T14:30:35.554Z"}
|
||||
{"cache_key":"e5f59311d94707ed8928d876a621d4b32381fd65775c2f8da0f201b120a73ed5","model":"gpt-5.5","provider":"openai","segment_id":"common.close","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Close","text_hash":"7d9eb7acb13e24625c404401d8e88b2350e32162455885f18276cf802f7701ed","tgt_lang":"id","translated":"Tutup","updated_at":"2026-07-10T15:21:37.072Z"}
|
||||
|
||||
Generated
+3
@@ -221,6 +221,7 @@
|
||||
{"cache_key":"538a0ced1101af2e1eb9a4b4b126cc8313eea778cf7267e794427cfd22bb3829","model":"gpt-5.5","provider":"openai","segment_id":"chat.workspaceFiles.dragToDock","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Drag to dock right or bottom","text_hash":"3fae26368a3c23df2e4e25691983c2a56efdbf92d5b970101e0aa432db9c48f6","tgt_lang":"it","translated":"Trascina per agganciare a destra o in basso","updated_at":"2026-07-10T06:08:23.266Z"}
|
||||
{"cache_key":"53b5e5ca884235befe9e5415ce97835d686aea7b826d61070f41020b2c6dec36","model":"gpt-5.6-sol","provider":"openai","segment_id":"attention.modelAuthExpired","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Model auth expired: {providers}","text_hash":"1af839b53686632bd3d0b5e0b89025a75052d0b7cfa84ce5e1654d4cd2469c61","tgt_lang":"it","translated":"Autenticazione del modello scaduta: {providers}","updated_at":"2026-07-12T00:09:25.070Z"}
|
||||
{"cache_key":"54c6837f7eb486aae64084dc4a1e60d76d596509c9f7718183261478bd1b365d","model":"gpt-5.5","provider":"openai","segment_id":"browser.loading","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Loading page…","text_hash":"ba7d61388ac8c05b7eca9e4eb40049222eb87f904783a718c148392b7538b29f","tgt_lang":"it","translated":"Caricamento pagina…","updated_at":"2026-07-11T02:19:01.933Z"}
|
||||
{"cache_key":"55255bcad526460e8765750ccbc3061469b38954394b018542859845ad89c9af","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"it","translated":"Nodo","updated_at":"2026-07-09T10:01:43.724Z"}
|
||||
{"cache_key":"55c230324417512546a0c1a88a92bab9dff250c39fd98e26eb874309ff811655","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.noResults","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"No results","text_hash":"a43619f321175f57a27f2a38da381fd367f6806093031b1f82960bcbf542729d","tgt_lang":"it","translated":"Nessun risultato","updated_at":"2026-07-12T00:09:25.070Z"}
|
||||
{"cache_key":"56ed50e4eecc5cdf964e7b65d43a1beacf9e76ec5013ca47ae255b8657fac60d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.openPullRequest","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Open PR","text_hash":"04c24026b2f00d817b610318ab2e984393c65576e67b591fb8fb0467f5aef0cb","tgt_lang":"it","translated":"Apri PR","updated_at":"2026-07-11T04:04:42.484Z"}
|
||||
{"cache_key":"572c7a98a9f57b4ff64396ca773ca90a152197053ca0202fbeaa39afa9e7c4ab","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.region","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Marked region {index}: centered around {x}% across / {y}% down, spanning about {width}% × {height}% of the view.","text_hash":"e2e51195aefb95748b2c7f794b41b042d70dfeab5de6420e196824eb7780a2ba","tgt_lang":"it","translated":"Regione contrassegnata {index}: centrata circa a {x}% in orizzontale / {y}% in verticale, copre circa {width}% × {height}% della vista.","updated_at":"2026-07-11T02:19:01.933Z"}
|
||||
@@ -281,6 +282,7 @@
|
||||
{"cache_key":"6dac58af7fefd8865074b90290355756daa7c2423bb06721cd81e8e0a79514b8","model":"gpt-5.5","provider":"openai","segment_id":"newSession.worktreeNameInvalid","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Worktree names use lowercase letters, digits, and dashes.","text_hash":"6a34593b030e5dc2e8e8c55a2be4a5e9a6b415676d4d91e9f521b8586ea3c28f","tgt_lang":"it","translated":"I nomi dei worktree usano lettere minuscole, cifre e trattini.","updated_at":"2026-07-10T17:59:26.805Z"}
|
||||
{"cache_key":"6dd3de4d4fcd4634b47292090a2247542d29b86abacadec290dcf69514db1f04","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.requests","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"{count} requests","text_hash":"1e23ff6956124091cd470f5091cee8108c3766314b69871b3ff792eaf506455f","tgt_lang":"it","translated":"{count} richieste","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"6dd4c72b312c462a2b7acd131394474d136dde89d8ca61e8d13536a76bc58350","model":"gpt-5.5","provider":"openai","segment_id":"workboard.badgeWorkerLogs","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"{count} worker logs","text_hash":"2923e2a84e6ed0ca048d280206198b156da6148859e474498d335a44e323e0a8","tgt_lang":"it","translated":"{count} log del worker","updated_at":"2026-05-30T15:38:31.723Z"}
|
||||
{"cache_key":"6e34d85f4b15c45bce542ac26a030c8614a42079e7732dd22d707303d15b3023","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"it","translated":"Comando","updated_at":"2026-06-16T14:15:54.477Z"}
|
||||
{"cache_key":"6e7b8ac51a3b2a3ea99c1f5a17015408766fc26a61e420cc6179779cccc5ebce","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.summary.onlineHosts","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"online","text_hash":"f6fc84c9f21c24907d6bee6eec38cabab5fa9a7be8c4a7827fe9e56f245bd2d5","tgt_lang":"it","translated":"online","updated_at":"2026-07-09T10:01:43.724Z"}
|
||||
{"cache_key":"6ecf5ddecf19046f830e83bbbb345984d7b559dfa1de28b5fce1844154f8b7db","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotationSent","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Annotation added to the chat composer.","text_hash":"d68fff7737c5145c3ac6dc95a99ff8f6cb205c0220dcdd8f7e602d14aef37f23","tgt_lang":"it","translated":"Annotazione aggiunta al compositore della chat.","updated_at":"2026-07-11T02:19:01.933Z"}
|
||||
{"cache_key":"6f1dde23edd101e9558dfce32ef37e8580482e8ed2924c471e9e7f01016f8273","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailWorkerLogs","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Worker logs","text_hash":"67766b9f222a7ccdae6beb7d6e7877d1a13abb8a346a8c5c803a4380bdf851b1","tgt_lang":"it","translated":"Log del worker","updated_at":"2026-06-16T14:15:39.914Z"}
|
||||
@@ -352,6 +354,7 @@
|
||||
{"cache_key":"8b936ef9cb90a3295136fc78a25d90b3da45b9efccc7b8e8259779e9916f16f1","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.streakDays","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"{count} days","text_hash":"e9f0a85930cc6fa61b7ac01763893020adc4c712d1b8e8897bdd13971637d529","tgt_lang":"it","translated":"{count} giorni","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"8bc992c95973ae45bbe50bba495103ec642179b547f3643035e12b23f4e19702","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.commentaryLabel","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Commentary","text_hash":"4a7a75ab79cde05b0b1baa8f7a704c991586ea44d7e7793e57178ef56f778ff8","tgt_lang":"it","translated":"Commento","updated_at":"2026-07-01T01:07:32.292Z"}
|
||||
{"cache_key":"8bce0d5ded0a183c1ff95b42676f179db60e49fff0c546ca55cccb6d1eec62ac","model":"gpt-5.5","provider":"openai","segment_id":"chat.sidebar.chats","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Chats","text_hash":"ef5b4049bb367b05531fa2c2982dbc5b710c3dde724d9a2683747c1da9b61eac","tgt_lang":"it","translated":"Chat","updated_at":"2026-07-10T17:59:29.738Z"}
|
||||
{"cache_key":"8c502f17555e407d68b0ec7b210d3c390969f029f915889412a218500c3bf06c","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"it","translated":"Scaduto","updated_at":"2026-07-01T10:32:45.702Z"}
|
||||
{"cache_key":"8c526e9039eca3bd2a4bdd8abb49fa356b5cfe1f43878ab30d238d3b8dd54df2","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.footer.close","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"close","text_hash":"310ff200149b44a32f124023d7caba19a1a890763a980606813d3a3d4a085d36","tgt_lang":"it","translated":"chiudi","updated_at":"2026-07-12T00:09:26.639Z"}
|
||||
{"cache_key":"8c691617ac081d19578c53fd91739b51f3b967c52756283b7e6853727ab4603e","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.use","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Use idea →","text_hash":"caa3014323f67cf4fc56fe94e334baf2be9b5cf852c5c7b00fd97286f8c3b5e7","tgt_lang":"it","translated":"Usa l'idea →","updated_at":"2026-07-11T22:46:48.930Z"}
|
||||
{"cache_key":"8cbbc60912164272f1d266e313bccdb817433ee2efdd4e6e71e20e5074e2fec1","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.summary.sessions","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"sessions","text_hash":"1225ae6c1ae69dcb4ee4781b703e12206f3b549cd3ca151070a8d8d8f371dd71","tgt_lang":"it","translated":"sessioni","updated_at":"2026-07-09T10:01:43.724Z"}
|
||||
|
||||
Generated
+3
@@ -79,6 +79,7 @@
|
||||
{"cache_key":"25b2307bca1322bdb3d84ae78b257478ee82ce573241120edea60b044e1411e7","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.sidebar.truncated","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"More sessions are available in the full catalog.","text_hash":"ae786cbbf6505d291f86749ea8ecd0feac7a7fcfadf82c3acd5b7c4221e8143b","tgt_lang":"ja-JP","translated":"完全なカタログには、さらに多くのセッションがあります。","updated_at":"2026-07-11T13:50:30.155Z"}
|
||||
{"cache_key":"272bce7c19a6ecbaa01dd2450b1c1723dd2037acb5a58e57d7a4a96cf339cdd2","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.show","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Show session changes","text_hash":"1abcb040185e89fcbfcd026a1fe5416279e4368cf18834b64c1f3bba2105ee7b","tgt_lang":"ja-JP","translated":"セッションの変更を表示","updated_at":"2026-07-11T04:52:47.140Z"}
|
||||
{"cache_key":"27ad1eb7b08340fd6cefce719be659056165a444ebf3fe95acef0e31f2ad008d","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.microphonePermissionBlocked","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Microphone access is blocked. Allow it in browser site settings to list inputs.","text_hash":"707f9594b092cf816d6d7a74381665a74acfecbe32d859d0a4adac9e9c9ff77b","tgt_lang":"ja-JP","translated":"マイクへのアクセスがブロックされています。入力を一覧表示するには、ブラウザのサイト設定で許可してください。","updated_at":"2026-07-06T17:56:23.525Z"}
|
||||
{"cache_key":"27f6879537af173b3c35a5a9e64f07e5d4a9b57cec118eba1b41c312d93f56f9","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"ja-JP","translated":"コマンド","updated_at":"2026-06-16T14:14:21.377Z"}
|
||||
{"cache_key":"294c8673a1ef63863a9bf8ec8ce01fd2014a0cfde6bbe593b32fb6ba56ae9d52","model":"claude-opus-4-8","provider":"anthropic","segment_id":"cron.jobDetail.cwd","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"CWD","text_hash":"0217f1cb7725737f15a6710df3bcfa3bc10a239f0f7801ec3d7168e675f5ebd6","tgt_lang":"ja-JP","translated":"CWD","updated_at":"2026-06-16T14:14:21.377Z"}
|
||||
{"cache_key":"29f36d39cb763f5d51353a9918ea244af6f949f68f0b59ac4382f4bd12f9db76","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.dateOlder","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Older","text_hash":"03281c889c2869e091390f9ad5dd13f0f0e46b42c9c4698f857902451deb3450","tgt_lang":"ja-JP","translated":"以前","updated_at":"2026-07-05T14:39:44.116Z"}
|
||||
{"cache_key":"2ae652f50a840f2ccdb93804e388794e872e3b1e3a80886a6a527e50c72721c5","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.preview","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Preview","text_hash":"324b134f57c70c729ae3dc4d298bb451656717d70523e942c1ce667b8024ea07","tgt_lang":"ja-JP","translated":"プレビュー","updated_at":"2026-06-16T14:14:21.377Z"}
|
||||
@@ -351,6 +352,7 @@
|
||||
{"cache_key":"b48cdfa2b31c7ba33aa225a2ec2267aadd978996af05094c34813360367a3988","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkModel","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Model","text_hash":"5e2c614c23f02239bc03c6c04fcb681950f9e72bf8fdff6be79c79841cbb10c0","tgt_lang":"ja-JP","translated":"モデル","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"b5da5df9f05841310e48272ac3b3a7010f1fbc69cb9f6eec02824640751960f7","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.contextUsage.limitWeekly","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Weekly · all models","text_hash":"144f0e5ca031e40c0cba8a53a9dcb4d9534c74edd976587231da2cd14b4944df","tgt_lang":"ja-JP","translated":"週次 · すべてのモデル","updated_at":"2026-07-09T11:49:17.247Z"}
|
||||
{"cache_key":"b5da6546178ab3f19c2c262a7935d841b4823835bd11468f524ae11c50c20a21","model":"gpt-5","provider":"openai","segment_id":"codexSessions.summaryLabel","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Codex session summary","text_hash":"667dedf7bd0ebc80d4e312cc52f824e6a5307c1c6210f2e72e5b93da824da502","tgt_lang":"ja-JP","translated":"Codex セッションの概要","updated_at":"2026-07-09T10:01:43.715Z"}
|
||||
{"cache_key":"b5fab2ffb5c3b2f440e9cd0e29d1fddab6011eceaa51ca31f3e615b8cca9027e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"ja-JP","translated":"期限切れ","updated_at":"2026-07-01T10:31:53.015Z"}
|
||||
{"cache_key":"b61346116969aed93153099a59d43c734e7f6b25a7ab861a57390a98773ab2d5","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.refresh","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Refresh","text_hash":"0e91610117029a62a478b7fa7df0b8598bebe3ab1e192d4b1882e310719c9671","tgt_lang":"ja-JP","translated":"更新","updated_at":"2026-07-09T10:01:43.715Z"}
|
||||
{"cache_key":"b7e4ae3b1c85267494d3e8b49e8ea435ec40930fd524df61666240492d1c3f28","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"agents.tabs.memory","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Memory","text_hash":"c3963aedaac6c83c04cf8fb997b479c61e66b3caeecfadd2f2d4bd5b0aef1778","tgt_lang":"ja-JP","translated":"メモリ","updated_at":"2026-07-11T21:07:24.892Z"}
|
||||
{"cache_key":"b87bc6805d1174940ff2f06ebc4e5561e91020c0c1917103cd5884cd7425cadd","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailWorkerLogs","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Worker logs","text_hash":"67766b9f222a7ccdae6beb7d6e7877d1a13abb8a346a8c5c803a4380bdf851b1","tgt_lang":"ja-JP","translated":"ワーカーログ","updated_at":"2026-06-16T14:14:04.101Z"}
|
||||
@@ -394,6 +396,7 @@
|
||||
{"cache_key":"ccea54fe13bd4c7bef2c59e4cdf45cc5cabc9f68e0c96309a6068b6c4fcf15ca","model":"gpt-5.5","provider":"openai","segment_id":"subtitles.worktrees","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Isolated agent task checkouts and recovery snapshots.","text_hash":"bc794dc846493e3c5f88964268af19b7dd818eae942c596002ef4067ba5a3d0c","tgt_lang":"ja-JP","translated":"分離されたエージェントタスクのチェックアウトと復旧スナップショット。","updated_at":"2026-07-05T21:00:44.514Z"}
|
||||
{"cache_key":"cd0d813d43d7b61d13e0ccf95ad3a2ae3b80f3f80964596324d5e5b86fac360e","model":"gpt-5.5","provider":"openai","segment_id":"workboard.badgeAttachments","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"{count} attachments","text_hash":"7bb1847693bc91e6e4624d996a96840396a71052786ab143ccb47fbdaa77cf41","tgt_lang":"ja-JP","translated":"{count} 件の添付ファイル","updated_at":"2026-05-30T15:38:16.645Z"}
|
||||
{"cache_key":"cd6caa1e1b37847f1a6d0faa44f6f60821d2a451b66077f335c4bf6e7601481b","model":"gpt-5.5","provider":"openai","segment_id":"nativeLinkMenu.label","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Link actions","text_hash":"bffef58c5284b351b41a353b723845cca19cf29bf817f7b74c2e77e74d282a20","tgt_lang":"ja-JP","translated":"リンクのアクション","updated_at":"2026-07-09T11:02:45.719Z"}
|
||||
{"cache_key":"cf2fe30505e82e0fee714d681dd343fe54ccc04a17371f5f8db5a46c3cdacc4c","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"ja-JP","translated":"ノード","updated_at":"2026-07-09T10:01:43.715Z"}
|
||||
{"cache_key":"cfb14088a576eb4ec87049025524b43dc89100c33cb1407187bf7ad2be07b89b","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.viewTranscript","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"View transcript","text_hash":"f5190d98549b91feb2368776ba76d6b5bc6aebdac5f4b4bf9b0e9d523a2db4c4","tgt_lang":"ja-JP","translated":"トランスクリプトを表示","updated_at":"2026-07-11T00:45:03.355Z"}
|
||||
{"cache_key":"d0b56050176fa6d32b3e216097f41856a87dd23aedce798f0ece4013f3dfb26e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.search","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Search files","text_hash":"179fed85ec50a433bb23932745d18f1ade2f84a6ebe145b0025ed3ce5f89fd5a","tgt_lang":"ja-JP","translated":"ファイルを検索","updated_at":"2026-06-16T14:14:19.257Z"}
|
||||
{"cache_key":"d0ca0e3a2f66b83fd3a48485bf4f6ad66e20930a2adcee4917bdb4e03ef2d3fd","model":"gpt-5.6-sol","provider":"openai","segment_id":"chat.backgroundTasks.toolUseMany","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"{count} tool uses","text_hash":"e07aff3c0765d81f1df023b13c1e9b18446cb6c33163e91090ac07684bdf56a0","tgt_lang":"ja-JP","translated":"ツール使用 {count} 回","updated_at":"2026-07-11T23:27:10.722Z"}
|
||||
|
||||
Generated
+3
@@ -10,6 +10,7 @@
|
||||
{"cache_key":"0491bb8fff6c0c4ec5eac44ed606ce714682e29e678a0639cc7c2d1f8d108243","model":"gpt-5.5","provider":"openai","segment_id":"chat.workspaceFiles.showFiles","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Show session files","text_hash":"88e60963b00018033f164b496f29e784fddfdb400cd19baf3311e04645bab27a","tgt_lang":"ko","translated":"세션 파일 표시","updated_at":"2026-07-10T06:08:07.604Z"}
|
||||
{"cache_key":"04a70a6c2acfe18b4598d5b9d5b1309bc46063bec44a16bdd61601e48f86f41e","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.groupByDate","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Date","text_hash":"99c40ab405926cb5ad1def9cff4d7ce624f8f8abfff4e85f655347fcb949d08e","tgt_lang":"ko","translated":"날짜","updated_at":"2026-07-05T14:39:46.951Z"}
|
||||
{"cache_key":"059f8d220822244193450a02baf0ade7de8f2f8afcabc51dc010780e7578bbb1","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkModelAuto","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Auto","text_hash":"0286249762f7c94349cdc0ba3bb2255baf9a80036e2193ead1d77696f888582f","tgt_lang":"ko","translated":"자동","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"05a6b2bc430ed5e78cea37f355d165ff94d6a74d207cbc6501b4b1910dd5e58f","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"ko","translated":"만료됨","updated_at":"2026-07-01T10:32:01.566Z"}
|
||||
{"cache_key":"05c8a6d94b76839551c9b8943c0eb1ed0ff778148f867f1468c1c8aa59b6768e","model":"gpt-5.5","provider":"openai","segment_id":"nav.settingsGroupConnections","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Connections","text_hash":"dc273117482b4429ada500ecd2e0c75532454194892cb901ca64cc7df369fdf6","tgt_lang":"ko","translated":"연결","updated_at":"2026-07-09T08:07:54.348Z"}
|
||||
{"cache_key":"0770a04dcf3bb445f9a096a5e83216fc030f69328702dd58e88a7d75755cb797","model":"gpt-5.5","provider":"openai","segment_id":"chat.sidebar.sortBy","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Sort by","text_hash":"c9129025bd3ff6522a7eeebc1abf1481f36e4ac9d74524a473ac1c3be1c6fc2f","tgt_lang":"ko","translated":"정렬 기준","updated_at":"2026-07-06T23:40:54.646Z"}
|
||||
{"cache_key":"07953a597f6300b1920472c01f242c65562c0067e7791c7be9cf11cd1cea4863","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.autoRefresh5s","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"5s","text_hash":"93e3d8c5b10657d2884f177488b689aadf82a83f962237cb602b3314386ab3b7","tgt_lang":"ko","translated":"5초","updated_at":"2026-06-17T14:14:20.553Z"}
|
||||
@@ -367,6 +368,7 @@
|
||||
{"cache_key":"a5556e51beb0c5dbf3269acf77bc3c0dce20dccf07f96794927f1962e98f6421","model":"gpt-5.5","provider":"openai","segment_id":"browser.dockRight","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Dock to right","text_hash":"df50a8c47b03e86a5edfdfaf2cd7289a22f9ce8dc0f91a80d71438bc887c964e","tgt_lang":"ko","translated":"오른쪽에 고정","updated_at":"2026-07-11T02:18:07.814Z"}
|
||||
{"cache_key":"a57575670b7f05b979027ef33d1ffde20445da365c2133f3c09c197c169a0156","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.loading","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Loading Claude sessions…","text_hash":"82030ec6f1c8034f675775716487e73a468b89b47724afb5b7d665622600624b","tgt_lang":"ko","translated":"Claude 세션을 불러오는 중…","updated_at":"2026-07-11T13:50:35.257Z"}
|
||||
{"cache_key":"a5f1ea8004c1818dd7c0ce0b970f49a275f0579437bc0470a1c52a5591a7f602","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.nightWatch.prompt","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Check that my services and gateway are healthy: scan recent logs for new errors, restarts, or unusual load. Stay quiet if everything is fine; if something looks broken, message me what failed and where to start looking.","text_hash":"ff691fc0bcd98cc27aea75758d323fc926a74252f5007eb43b49073d1a5716b7","tgt_lang":"ko","translated":"내 서비스와 Gateway가 정상인지 확인해 주세요: 최근 로그에서 새로운 오류, 재시작, 또는 비정상적인 부하를 스캔하세요. 모든 것이 정상이면 조용히 있어도 됩니다; 문제가 보이면 무엇이 실패했고 어디서부터 확인해야 할지 알려주세요.","updated_at":"2026-07-11T22:45:43.800Z"}
|
||||
{"cache_key":"a63f8e6abe07b9dc720665586dcd28dab5183f43c90dbc074bd44c6bc5533519","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"ko","translated":"노드","updated_at":"2026-07-09T10:01:43.732Z"}
|
||||
{"cache_key":"a6e7fd3b538fb02ae6321a007f609b92af1c099f422306ad5d7274ac70c76bc6","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.statusDeleted","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Deleted","text_hash":"b48ff39c2e0f5451b9b29b09c2a74d2760db230749ffd48a6e901cc91fef9a8d","tgt_lang":"ko","translated":"삭제됨","updated_at":"2026-07-11T04:52:50.079Z"}
|
||||
{"cache_key":"a6ec4eb3485f93ebb7a3a1fe8e52ddb6a00236662c02e0a4815131ccc5cc8c61","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.renameGroupMenu","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Rename group…","text_hash":"fe4e8d175e15f0a28c7c39b8bf3ea98b704e793c7efbc5231eb4a7448d0e675b","tgt_lang":"ko","translated":"그룹 이름 변경…","updated_at":"2026-07-06T23:40:54.646Z"}
|
||||
{"cache_key":"a73c1882b52cae52cdf0283246c8c53012073dec5af586caf93ef84e38f97fad","model":"gpt-5.6-sol","provider":"openai","segment_id":"attention.cronFailed","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"{count} cron job(s) failed","text_hash":"0a75fdcee152b66aa5e544a8dcea294f37c8a2d696fba50a86d0f0535376648d","tgt_lang":"ko","translated":"cron 작업 {count}개 실패","updated_at":"2026-07-12T00:08:48.860Z"}
|
||||
@@ -451,6 +453,7 @@
|
||||
{"cache_key":"cc30fd972b544ec9828287302d0aea3aa28673417bd561169181a9363e419a2e","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.repo","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Repository","text_hash":"13d6ff07b8a5d792ec87d5ec83bff2730ee77fa8f4fcd89ca5f1d688f64b4c73","tgt_lang":"ko","translated":"저장소","updated_at":"2026-07-05T21:00:52.598Z"}
|
||||
{"cache_key":"cd0480cc4f2f762f7685991753d38b978727ef9349b15b5bd6bba92486f33f01","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailAutomationWorkspace","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Workspace: {workspace}","text_hash":"17f5e696e557a646a9003fc8448f6f6761f5fe6bdf7478f750f471496e87c17b","tgt_lang":"ko","translated":"워크스페이스: {workspace}","updated_at":"2026-06-16T14:14:21.259Z"}
|
||||
{"cache_key":"cd7a1ade73d2c2d70ba4349fec823e5d4662ef4ee810116728030f6dce21b497","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.browser","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Project files","text_hash":"2a3d9a240c9206964ee7237a1d99fda05ed501a485262e18f33c446c9f735d1c","tgt_lang":"ko","translated":"프로젝트 파일","updated_at":"2026-06-16T14:14:34.760Z"}
|
||||
{"cache_key":"cdd66c4009a245983a81e476ff59a7231ed34b00406db95c7bf662829b9d66b8","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"ko","translated":"명령","updated_at":"2026-06-16T14:14:37.028Z"}
|
||||
{"cache_key":"ceb57d76cdf38aa06b2ec69cbb5538dff13e70b7a8ef18285f58aa37c5f6395d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.archiveSession","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Archive session","text_hash":"740ded37480365eae8bf833ccaaa58350fc9434a77b7bb65b5516eba476fbec3","tgt_lang":"ko","translated":"세션 보관","updated_at":"2026-07-02T14:30:10.945Z"}
|
||||
{"cache_key":"cecaf5c745ee1fe54273ce1a29f2226b164bcaff5e9eebe7f0413aee5b794cac","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.introUntitled","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"I annotated the page at {url} — the attached screenshot shows my markup.","text_hash":"c54bf197cc35241ef3dcb469ef22a8c2467b6ddd47d02fbae7f4b5a4641d1429","tgt_lang":"ko","translated":"{url}의 페이지에 주석을 달았습니다 — 첨부된 스크린샷에 제 마크업이 표시되어 있습니다.","updated_at":"2026-07-11T02:18:12.376Z"}
|
||||
{"cache_key":"cf42bbae5db4a9112f92bcad2e0947dd3e876413b8a0ca3cb37b5917ab1ef01c","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.standupGhostwriter.prompt","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Draft my standup update from yesterday's commits, merged pull requests, and open review threads. Three bullets max: done, doing, blocked.","text_hash":"f579d93618226238ca346e3f109c798d24bf913c43f2ace07315fc0dfbb507cb","tgt_lang":"ko","translated":"어제의 커밋, 병합된 풀 리퀘스트, 열린 리뷰 스레드를 바탕으로 스탠드업 업데이트를 작성해 주세요. 최대 세 줄: 완료, 진행 중, 블로킹.","updated_at":"2026-07-11T22:45:38.762Z"}
|
||||
|
||||
Generated
+3
@@ -148,6 +148,7 @@
|
||||
{"cache_key":"38a68daa8bf8d789ae46ce8ada766e4c043992bf73434b0306b958a749247a92","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.lastDays","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"{count} days","text_hash":"e9f0a85930cc6fa61b7ac01763893020adc4c712d1b8e8897bdd13971637d529","tgt_lang":"nl","translated":"{count} dagen","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"3973453f74ecdf399ca3550b05c66d8601ce1d9c1d8b1e058f3dfdbb3f78aa73","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.outputTokens","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"{count} output","text_hash":"e433f6601aaa1a1cce63c5ca6b15fddd247bf53697d09171d25592f70f2e949a","tgt_lang":"nl","translated":"{count} uitvoertokens","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"3a8f90934c613ad55413822bdb50730ee26508bd08db306bced987dbf47191d0","model":"gpt-5.5","provider":"openai","segment_id":"workboard.eventProtocolViolation","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Protocol violation","text_hash":"367bb2052963f7d75beb672d3ca0430d7d49ac48a2759d578c7df933178fe564","tgt_lang":"nl","translated":"Protocolschending","updated_at":"2026-05-30T15:38:50.257Z"}
|
||||
{"cache_key":"3aaa6e5e7fedbef384e65ec90f31dbe426740942ef8c77c89b0bb9bb09afefcd","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"nl","translated":"Verlopen","updated_at":"2026-07-01T10:34:14.146Z"}
|
||||
{"cache_key":"3ad1531c790237f28cb8cb25461c618af964dfb68ad8cd08b79e44a5638a599c","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.statusRenamed","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Renamed","text_hash":"05487af3f074b4f31e4f9a1ec75044ab182f037a7978e1a8909c42103fb1297a","tgt_lang":"nl","translated":"Hernoemd","updated_at":"2026-07-11T04:53:40.304Z"}
|
||||
{"cache_key":"3adaa6c091fbbe313ceeadcf1c95848a4b53a6d44754c143516678c5c6863ccb","model":"gpt-5.5","provider":"openai","segment_id":"newSession.start","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Start session","text_hash":"b1c52ee3677debeb3b2e7dc8b41d1da1b08c02241ec1cc1f35d28637afcecf5c","tgt_lang":"nl","translated":"Sessie starten","updated_at":"2026-07-10T15:21:56.238Z"}
|
||||
{"cache_key":"3b742bceb583fe4990be276d4796fba557994fc1795cf6f891aca83f1858529d","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.layoutComfortable","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Comfortable card density","text_hash":"bfaaf4553fd254bf24431ebabf62faebfd862685e9e7a52f5e799b11488dc7fe","tgt_lang":"nl","translated":"Comfortabele kaartdichtheid","updated_at":"2026-06-17T14:17:30.702Z"}
|
||||
@@ -203,6 +204,7 @@
|
||||
{"cache_key":"52066e6d005012f830aedf3e368422d3ac5a9b25c9f9d0d39ecbe29c81cb4b10","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.statMcpServers","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"MCP servers","text_hash":"22a7559f09bf8f82c510280f934bf50db4c45cc611fd4dd47d7cbf7c7d4f5b82","tgt_lang":"nl","translated":"MCP-servers","updated_at":"2026-07-10T02:28:58.148Z"}
|
||||
{"cache_key":"52a73400c21be56486cd522df1930b79f449f626eec248d621af51f2a2670841","model":"gpt-5","provider":"openai","segment_id":"codexSessions.partial","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Unavailable hosts: {count}. Other hosts remain available.","text_hash":"00ca17db32e78382e78e5877fd167f21e6baf40783b4cf581f34be5ffd1bd05b","tgt_lang":"nl","translated":"Onbeschikbare hosts: {count}. Andere hosts blijven beschikbaar.","updated_at":"2026-07-09T10:01:43.729Z"}
|
||||
{"cache_key":"530bc96a3f3d267032d76e62e196e5a38afde994ee8ef7069e5f577299538b76","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.included","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Included","text_hash":"ba829a98b799408899294035fa50f73daa14b204e672049da9697d5b3e8d5757","tgt_lang":"nl","translated":"Inbegrepen","updated_at":"2026-07-10T02:29:02.639Z"}
|
||||
{"cache_key":"5334ffbd83801c20d6b9988b82b8e06593867620f3d85dfbaf8cd653af14ff39","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"nl","translated":"Opdracht","updated_at":"2026-06-16T14:18:26.226Z"}
|
||||
{"cache_key":"53410f9646e260f167a21b211d2916b326d955a5963aac95871da0298dfed711","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.noMicrophones","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"No additional microphones found","text_hash":"a6e4a20dda44dead8daa06da30fca7e7d90fa5aa4c15cbada30af1f52874d347","tgt_lang":"nl","translated":"Geen extra microfoons gevonden","updated_at":"2026-07-06T17:34:05.382Z"}
|
||||
{"cache_key":"537b0b2776345305d7b083d67eb7ddd29439f76dff90fbc9aab55b0e7341f87b","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.group","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Group","text_hash":"34ca0e76608842ff3e7d924a455a396a82f471052c15e3f2ed7f090ac702e5c1","tgt_lang":"nl","translated":"Groep","updated_at":"2026-07-05T14:40:20.847Z"}
|
||||
{"cache_key":"540da702152182083b21b5eded461054b7c561b2dc960579467298b45b90d0ed","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.title","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Managed Worktrees","text_hash":"dde32010185098a47e873fb25dd99446b0cb1a75614068587f7cd0bffb5aed18","tgt_lang":"nl","translated":"Beheerde worktrees","updated_at":"2026-07-05T21:01:37.071Z"}
|
||||
@@ -490,6 +492,7 @@
|
||||
{"cache_key":"b7bb61f518897e0143d2df20dd421e874b31559928070099e5180c1d8f134b0f","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.use","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Use idea →","text_hash":"caa3014323f67cf4fc56fe94e334baf2be9b5cf852c5c7b00fd97286f8c3b5e7","tgt_lang":"nl","translated":"Idee gebruiken →","updated_at":"2026-07-11T22:49:02.172Z"}
|
||||
{"cache_key":"b854160ba9d693405027bcf8a0fdafd399eb3a96489c07559f61f90fc6932048","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.empty","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"No background tasks for this agent yet.","text_hash":"823cdd790c108c21546c09bdfcfa549742c92f81e3bf5ea14e072fc34ac434cf","tgt_lang":"nl","translated":"Nog geen achtergrondtaken voor deze agent.","updated_at":"2026-07-11T00:45:39.382Z"}
|
||||
{"cache_key":"b88a8b291919e908fa48356e27a4791373abb7ba481336faf1bc8d4d0a0e4353","model":"gpt-5.5","provider":"openai","segment_id":"pluginsPage.working","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Working…","text_hash":"5474eef8d0f179c707cf418e2bbb468c77cc24edc5e9f5f4e137e85e06a8eea0","tgt_lang":"nl","translated":"Bezig…","updated_at":"2026-07-10T04:28:53.665Z"}
|
||||
{"cache_key":"b89326ebec9133407fb8e05bdebd1561df4ed3b4baa603a0a3a2ab3b8aa91e59","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"nl","translated":"Node","updated_at":"2026-07-09T10:01:43.729Z"}
|
||||
{"cache_key":"b8d588e4b3ffb799a3668b45b9a1e8c5de2991f96f4d67e17e38ebcde0399935","model":"gpt-5.5","provider":"openai","segment_id":"languages.hi","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"हिन्दी (Hindi)","text_hash":"fab2abfce45382f3031c59477017700a8cb5dfaf8d15379dc24304809b97c7d5","tgt_lang":"nl","translated":"हिन्दी (Hindi)","updated_at":"2026-06-26T21:43:45.251Z"}
|
||||
{"cache_key":"b919100a05176b823138371115ee0296014ab0e56c680777b6e407f66b739e25","model":"claude-opus-4-8","provider":"anthropic","segment_id":"codexSessions.host.sessionCount","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"{count} shown","text_hash":"e57b4adfe868fd74a183650103d820176d4960bd0bdb677d9985db09f9752867","tgt_lang":"nl","translated":"{count} getoond","updated_at":"2026-06-16T14:18:24.009Z"}
|
||||
{"cache_key":"b97564a3936698085de72c348b34765f46b9dd48d42585c67d6b20d8eff6e5d1","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.nightWatch.prompt","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Check that my services and gateway are healthy: scan recent logs for new errors, restarts, or unusual load. Stay quiet if everything is fine; if something looks broken, message me what failed and where to start looking.","text_hash":"ff691fc0bcd98cc27aea75758d323fc926a74252f5007eb43b49073d1a5716b7","tgt_lang":"nl","translated":"Controleer of mijn services en gateway gezond zijn: scan recente logs op nieuwe fouten, herstarts of ongewone belasting. Blijf stil als alles in orde is; als er iets stuk lijkt, stuur me een bericht over wat er is misgelopen en waar ik moet beginnen zoeken.","updated_at":"2026-07-11T22:49:06.392Z"}
|
||||
|
||||
Generated
+3
@@ -219,6 +219,7 @@
|
||||
{"cache_key":"5602a32e32eecce5ac39f7b1ef36f97ce7b1bd50d67a92a2528fbc5d1b4ca133","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.restorable","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Restorable","text_hash":"bc97d2ddd2dba3ab2391f21314316556111065c4b870bc05679fadd60a754c01","tgt_lang":"pl","translated":"Możliwe do przywrócenia","updated_at":"2026-07-05T21:01:26.445Z"}
|
||||
{"cache_key":"565f281ffda11fb4195b4d27d4bd8422020cd7d7489a98020eb04525c657346a","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.refresh","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Refresh","text_hash":"0e91610117029a62a478b7fa7df0b8598bebe3ab1e192d4b1882e310719c9671","tgt_lang":"pl","translated":"Odśwież","updated_at":"2026-07-09T10:01:43.766Z"}
|
||||
{"cache_key":"56763526931f57089c700380c0a2cfd52b46cd41607727d622ed6fa8d845273f","model":"gpt-5.5","provider":"openai","segment_id":"subtitles.worktrees","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Isolated agent task checkouts and recovery snapshots.","text_hash":"bc794dc846493e3c5f88964268af19b7dd818eae942c596002ef4067ba5a3d0c","tgt_lang":"pl","translated":"Izolowane kopie robocze zadań agentów i migawki do odzyskiwania.","updated_at":"2026-07-05T21:01:26.445Z"}
|
||||
{"cache_key":"57df5f1e43b7e0b057b9119ff60f437c60204ac5aff62544dd2b2dc1a62457b0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"pl","translated":"Polecenie","updated_at":"2026-06-16T14:17:24.224Z"}
|
||||
{"cache_key":"58a0eaa4e0c270ec0052a47a1403f286ca9cb4a3436debb14aeb056797297ab7","model":"gpt-5.5","provider":"openai","segment_id":"browser.hide","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Hide browser panel","text_hash":"9addb46dd1c2c965fc79703cb42b245c24a1745ff662cf67c255ad840e576b72","tgt_lang":"pl","translated":"Ukryj panel przeglądarki","updated_at":"2026-07-11T02:19:32.402Z"}
|
||||
{"cache_key":"58cf39eb6de64d02d3269042880a293eb70f862bbe80f177fadc8ceacccc4873","model":"gpt-5.5","provider":"openai","segment_id":"browser.toggle","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Toggle browser panel","text_hash":"cfd0e6c787d9b0fd9341c1bc377dca3a0987588b1fdb68ef23b5d0ce3bced9bc","tgt_lang":"pl","translated":"Przełącz panel przeglądarki","updated_at":"2026-07-11T02:19:32.402Z"}
|
||||
{"cache_key":"592b063f2ea57efa3a286c829740827d9ee6c76bb63b255831923680b95bb0e3","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.today","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Today","text_hash":"2b065c7c9ce466e5ebcad757987d5d660ee4c9ea708bc62c43444b53334738ba","tgt_lang":"pl","translated":"Dzisiaj","updated_at":"2026-07-05T14:40:11.071Z"}
|
||||
@@ -477,6 +478,7 @@
|
||||
{"cache_key":"c989cb43963eff0b0a75e2ca1abe177a3da2b64ceddd17c286919c93395e1e80","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.dependenciesReady","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"{count} ready","text_hash":"f5f5fd424d7c18f19a51ee147857efddc320a0ec6e1eeb4354be129425632f05","tgt_lang":"pl","translated":"{count} gotowych","updated_at":"2026-06-16T14:17:14.640Z"}
|
||||
{"cache_key":"c98abc4d911ff51a463925dc3e6e501fe9d6baf3ab2a9a619dca57a0b4e7b139","model":"gpt-5.5","provider":"openai","segment_id":"newSession.createFailed","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Couldn't create the session.","text_hash":"5ba041f31fe891ed7958e64cb191ecf176c3c3d6088f383c125a04286acb7f99","tgt_lang":"pl","translated":"Nie udało się utworzyć sesji.","updated_at":"2026-07-10T15:21:41.615Z"}
|
||||
{"cache_key":"c99cc0f8cf1519602cdb276cf81cb5d43d6d41174c70fc594c76031ea37e45cf","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.expand","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Expand session workspace","text_hash":"ac1d210db40c5026879774849ad74a9e1247523192a795ac33965b3ee72691c2","tgt_lang":"pl","translated":"Rozwiń obszar roboczy sesji","updated_at":"2026-06-16T14:17:14.640Z"}
|
||||
{"cache_key":"ca6ee2bbeae954282386a7bb9eb6bcf8be36f30d6cb29114359ed289a6cfcd9f","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"pl","translated":"Węzeł","updated_at":"2026-07-09T10:01:43.766Z"}
|
||||
{"cache_key":"cab99c49eadbb51dd0e105b26f3e8173a6d7996f11a4eb5184a250dece978bae","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.moveToGroup","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Move session to a group","text_hash":"7db4b663aebb86158b454c49ad05115941c0411cb8ed6182bdc8fd5840f32dff","tgt_lang":"pl","translated":"Przenieś sesję do grupy","updated_at":"2026-07-05T14:40:11.071Z"}
|
||||
{"cache_key":"cb4b8f959fc968909c5e822c8ce57b5bb5cf06e8a36dc6c6116e3666ecf46b2a","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.statLongestSession","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Longest session","text_hash":"7f727c1b85939ac165087fe5c3081e15ca00c6e6a0c0b6f8c908ff21eda7a4f2","tgt_lang":"pl","translated":"Najdłuższa sesja","updated_at":"2026-07-09T11:28:29.733Z"}
|
||||
{"cache_key":"cc1867ae4af932710b7e7366c488622e52a83ea25ac3ec38e66e7c013e0d7420","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.last7Days","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"7 days","text_hash":"7f920bb639c9307589b65e5f639391d65dcb86b0611ac47f58f7c769215326ee","tgt_lang":"pl","translated":"7 dni","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
@@ -555,6 +557,7 @@
|
||||
{"cache_key":"ec8a25609f58db275de801d929003f44ce9a2e2bfda2a283f128315db8740c1b","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailRun","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Run","text_hash":"00d60e31a4e6b8344d4201f25a6a7dee770713107f6d097abb01559d32b17f26","tgt_lang":"pl","translated":"Uruchomienie","updated_at":"2026-06-16T14:17:07.423Z"}
|
||||
{"cache_key":"ec99dcc8e5227031b10b641a31fabe05c1d0ab514c9865f355ce88798730dc7b","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkVoice","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Voice","text_hash":"87bf2bc08589f0bd4a078db145c34ad5e14b8fda53c3ae65b78601294913df95","tgt_lang":"pl","translated":"Głos","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"ecabcf3aa68752624c19259d2a38a18d1503d66d63a232646f46f3e71203b30c","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.inputTokens","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"{count} input","text_hash":"f24231cff78fed82d155712973ede6f9369e96b015acc30d5de2b740677edce9","tgt_lang":"pl","translated":"{count} tokenów wejściowych","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"ecca190abac85135a90cfe8760a9c78f12ffdce6630a6059d39f65ad4d2df914","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"pl","translated":"Wygasł","updated_at":"2026-07-01T10:33:32.568Z"}
|
||||
{"cache_key":"eceac1fda68d6b3c662758286aafcab57f64bc7170e1d9e9b5578858a41373a3","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.standupGhostwriter.tagline","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Your standup update, drafted from yesterday's work.","text_hash":"23ce2b22c8aff730b9b9c43dd92f4b16e39b4bab36bb09452a45a8238475ccf3","tgt_lang":"pl","translated":"Twoja aktualizacja na standup, opracowana na podstawie wczorajszej pracy.","updated_at":"2026-07-11T22:47:58.550Z"}
|
||||
{"cache_key":"ed264f10c1fd819c124704ad3b3d8a33917871a47d948ea5c3fa9c7548f748b5","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.open","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Open","text_hash":"ed077f3d8125d60dca1979c7133601bd187d47c73ed9975028f677e49e709942","tgt_lang":"pl","translated":"Otwarte","updated_at":"2026-07-10T17:04:20.062Z"}
|
||||
{"cache_key":"ed4c73ef1e8f31755a129a9d6ed365f3d03e17a5dcef7e744507f6f9498b024b","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.restoreSession","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Restore session","text_hash":"35e4dc9befd3b3a29b50938839af0efb41b08051988dde53e1c1e73d1c2a039f","tgt_lang":"pl","translated":"Przywróć sesję","updated_at":"2026-07-02T14:30:38.319Z"}
|
||||
|
||||
Generated
+3
@@ -64,6 +64,7 @@
|
||||
{"cache_key":"18cb1aace6d0a4144c9f693c628fd5efba791bdc5d6e876d0829a67d2effa575","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.ownerManual","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Manual","text_hash":"b0b9fe24ffa9629125bdc59b122f80d605ab604eb1b74485c2f2ecfde26576ae","tgt_lang":"pt-BR","translated":"Manual","updated_at":"2026-07-10T17:58:42.698Z"}
|
||||
{"cache_key":"193cf41e702e12d201f1a223890c21c6b8ad9a5178310ed836c91629548710e2","model":"gpt-5.5","provider":"openai","segment_id":"tabs.worktrees","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Worktrees","text_hash":"aec2f93d67b7c4c5fd9b94042f33299f7a0e55cdcb7e8e35feb9d0f6da697f3d","tgt_lang":"pt-BR","translated":"Worktrees","updated_at":"2026-07-05T21:00:34.411Z"}
|
||||
{"cache_key":"1976ff9509914040e67305c22c7f7c4c0e899633fda98eec11db66b5452a8d09","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.refresh","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Refresh background tasks","text_hash":"837e39f46163ffb4dbed66ba4910c35f2383c1708c9a5593d120a53d51cdebf1","tgt_lang":"pt-BR","translated":"Atualizar tarefas em segundo plano","updated_at":"2026-07-11T00:44:56.540Z"}
|
||||
{"cache_key":"1a52f7217b702be8e79ac30def797c8223709add8ca3e562f1ed16d4338d0f87","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"pt-BR","translated":"Nó","updated_at":"2026-07-09T10:01:43.718Z"}
|
||||
{"cache_key":"1a9710b3c9e635f7a54a4f0851b5e3a8def1828a980ee3400f7abaa118fce7ec","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailUpdatedValue","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Updated: {time}","text_hash":"5e72d5445f018c9d08aa34ae0178fb9aa49eea6a0afd0c8d379f20b7af3e8aa0","tgt_lang":"pt-BR","translated":"Atualizado: {time}","updated_at":"2026-06-16T14:13:11.260Z"}
|
||||
{"cache_key":"1cbe3f73c1fc750e057b51bfa5d194e57be2fb176705a2816f75f561daa71e06","model":"gpt-5.5","provider":"openai","segment_id":"quickSettings.appearance.lobsterdexSeen","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"{seen}/{total} visited","text_hash":"e256f4f2c8acf9532195feecb6268817520de975b7e7e6d02c346126c660f556","tgt_lang":"pt-BR","translated":"{seen}/{total} visitados","updated_at":"2026-07-09T23:55:45.637Z"}
|
||||
{"cache_key":"1d2dc6c34af7a5508f4f3fe675b7610ce01d3bd112fde2334908216c0e566455","model":"gpt-5.5","provider":"openai","segment_id":"browser.empty","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"No open tabs. Enter a URL above to browse.","text_hash":"a9e25255aa326aac375865aac61e932f80d6030997ad0d8d2fe04b6d30772edd","tgt_lang":"pt-BR","translated":"Nenhuma aba aberta. Insira uma URL acima para navegar.","updated_at":"2026-07-11T02:17:35.876Z"}
|
||||
@@ -369,6 +370,7 @@
|
||||
{"cache_key":"9f867a9118148e8f65246055ab31c37e681b250a61f9670fd8d826c05bca7ebd","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.items.scheduled","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Scheduled","text_hash":"4724f344c1c0e4a1c5e4085610cc31bf67d0959dfda9793d4605b7b329399775","tgt_lang":"pt-BR","translated":"Agendados","updated_at":"2026-07-12T00:08:10.895Z"}
|
||||
{"cache_key":"a1c2ee627f96f0d4ccd3ae21e51895f218dbf079d82269c6f92f2b79ecea9eb9","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.show","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Show background tasks","text_hash":"7cce70ac350d780017a5a7f109b28cbe69f5a1c7bfc92d1c1d9479f402ab8bdf","tgt_lang":"pt-BR","translated":"Mostrar tarefas em segundo plano","updated_at":"2026-07-11T00:44:56.540Z"}
|
||||
{"cache_key":"a1cb01b3761d31fd13681276eca4d60dc8faae6502644c7ac2944e231234af6f","model":"claude-opus-4-8","provider":"anthropic","segment_id":"cron.jobDetail.cwd","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"CWD","text_hash":"0217f1cb7725737f15a6710df3bcfa3bc10a239f0f7801ec3d7168e675f5ebd6","tgt_lang":"pt-BR","translated":"CWD","updated_at":"2026-06-16T14:13:27.459Z"}
|
||||
{"cache_key":"a2b3f6d2d7d3df4cd96fce9a97c142ed26776bb5da8f14644658cdd4ac1a976e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"pt-BR","translated":"Comando","updated_at":"2026-06-16T14:13:27.459Z"}
|
||||
{"cache_key":"a2ffca77312fac49eebd9fcbdeda9b6c190513dcc3b22835f7b905eaccd83d6d","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.repoPulse.tagline","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Overnight issues, PRs, and CI failures, ranked by urgency.","text_hash":"aa33e4b9ff871c66f7aaf6968a47a615afe77eea9baf6f3e7d4e7e5eb1145e75","tgt_lang":"pt-BR","translated":"Issues, PRs e falhas de CI da noite, ordenados por urgência.","updated_at":"2026-07-11T22:44:39.671Z"}
|
||||
{"cache_key":"a3ed8aac7b293199f786dec9533b299d5197f9282dd722fda4a63279c2309462","model":"gpt-5.5","provider":"openai","segment_id":"workboard.eventOrchestration","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Orchestration","text_hash":"ed4fdd1721677737cffb2862fe34d5b63901c7cc76b8c67c51e92a467b31a5e7","tgt_lang":"pt-BR","translated":"Orquestração","updated_at":"2026-05-30T15:38:08.357Z"}
|
||||
{"cache_key":"a42348a92c7f2b355caffb2211845c06851100e590b3b519aa6329e19fcbf6f5","model":"gpt-5.5","provider":"openai","segment_id":"workboard.badgeWorkerProtocol","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"worker {state}","text_hash":"f16b9e04d42182b421ce4f4e982b2ef75fab9bd581bdc8b87e62899ba28de11c","tgt_lang":"pt-BR","translated":"worker {state}","updated_at":"2026-05-30T15:38:08.357Z"}
|
||||
@@ -404,6 +406,7 @@
|
||||
{"cache_key":"b1a2fbb65c9edfa287e5e1b19b63070d3ba2ee32d988051eb2540b3b65819d00","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.empty","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"No background tasks for this agent yet.","text_hash":"823cdd790c108c21546c09bdfcfa549742c92f81e3bf5ea14e072fc34ac434cf","tgt_lang":"pt-BR","translated":"Ainda não há tarefas em segundo plano para este agente.","updated_at":"2026-07-11T00:44:56.540Z"}
|
||||
{"cache_key":"b22b43928f55ba25a66fac72938fe831c01118aecfeaa7d29c3766e62205bb15","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.transcript.toolResult","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Tool result","text_hash":"9bb620efa692f707a302a5f42464015a54c20843e2f76f18a1542626b886bb91","tgt_lang":"pt-BR","translated":"Resultado da ferramenta","updated_at":"2026-07-11T13:50:16.727Z"}
|
||||
{"cache_key":"b22fc41688d7e04263fa0198036c837d00b2a3c584b4b5e77427d5f082b5fafc","model":"gpt-5.5","provider":"openai","segment_id":"codexSessions.transcript.item","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Codex item","text_hash":"df3ec75afd74487c4d8078774fdab6cbc9cccb56681c6508e86c009503d86616","tgt_lang":"pt-BR","translated":"Item do Codex","updated_at":"2026-07-11T10:24:43.509Z"}
|
||||
{"cache_key":"b27d339ee04d37b62e1aa4d07059d9770b9a4564692bad39fb78b4b6bd14813e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"pt-BR","translated":"Expirado","updated_at":"2026-07-01T10:31:00.782Z"}
|
||||
{"cache_key":"b2ae112020df5a30d136a4a5377a6882282b5e793a03e6f6946ab30ad44dccef","model":"gpt-5.5","provider":"openai","segment_id":"browser.notRunning","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"The gateway browser is not running.","text_hash":"a062240dbfdbaf47389f06257b05e9d0a4a42db667f7261c65403c7246a43ba4","tgt_lang":"pt-BR","translated":"O navegador do Gateway não está em execução.","updated_at":"2026-07-11T02:17:35.876Z"}
|
||||
{"cache_key":"b42f47158cd5593f085bf82670134b024167a2ab5bc9c49a62f4cea6e83c034c","model":"gpt-5","provider":"openai","segment_id":"codexSessions.loading","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Loading Codex sessions…","text_hash":"18a71c76786db89f928536e164096422e68e86db86fa3684bc3644f36df70300","tgt_lang":"pt-BR","translated":"Carregando sessões do Codex…","updated_at":"2026-07-09T10:01:43.718Z"}
|
||||
{"cache_key":"b4fecfbcc0f636a846f75cf7dc84cf779b41ddefd07a25d845428646f72a7503","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.deleteGroupConfirm","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Delete group \"{group}\"? Its sessions move to Ungrouped.","text_hash":"8efc8cb301bca2d82627c05eb36558e603c1b1ad0d58a2bd6584aa1c3a01c710","tgt_lang":"pt-BR","translated":"Excluir grupo \"{group}\"? Suas sessões serão movidas para Sem grupo.","updated_at":"2026-07-06T23:40:46.278Z"}
|
||||
|
||||
Generated
+6
@@ -21,6 +21,7 @@
|
||||
{"cache_key":"0284fb8fda805db046652f2df1f213ef31077da383747369b2d8291a09fc413a","model":"gpt-5.5","provider":"openai","segment_id":"cron.errors.cronExprRequired","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Cron expression is required.","text_hash":"8fbe41c6aff5762238faf1f7bd7d9f99c0c82e7a932c3e9feeaf8d42c77f275d","tgt_lang":"ru","translated":"Требуется cron-выражение.","updated_at":"2026-06-26T21:42:51.343Z"}
|
||||
{"cache_key":"0295f60fdc2bc1f75458ed9091f756b3fe7be306330fb788eb90cd06e2dd4ed8","model":"gpt-5.5","provider":"openai","segment_id":"channels.gatewayUrlConfirmation.subtitle","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"This will reconnect to a different gateway server","text_hash":"20c2df24b9c9bc9124ef6f0805dcf42b59951522b40868addc0508ffb7c0c645","tgt_lang":"ru","translated":"Это переподключит вас к другому серверу шлюза","updated_at":"2026-06-26T21:38:40.558Z"}
|
||||
{"cache_key":"02af1302437b65ae568fa54a133421a2efe2437c5f5a84148abe537c7a429375","model":"gpt-5.5","provider":"openai","segment_id":"dreaming.advanced.stagedDescription","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Replay candidates pulled from older daily log entries.","text_hash":"66e7a8b3e05e33e61428644192797de53a97e2f142f9b1b475847fa601e4fdfd","tgt_lang":"ru","translated":"Повторное воспроизведение кандидатов, извлеченных из более старых записей ежедневного журнала.","updated_at":"2026-06-26T21:40:44.743Z"}
|
||||
{"cache_key":"02b0009ca4bbda7b1739df8fbe8693a2698b52ba2939b8bc648ec5124cd6719f","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.retry","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Retry","text_hash":"942087cc2d41e01304b7195558d093d10c72af8e838c7556d6a02d471ee71852","tgt_lang":"ru","translated":"Повторить","updated_at":"2026-06-26T21:38:44.774Z"}
|
||||
{"cache_key":"02b2524c55869bddfcdae44178fb094ecc1c7d9f33a8caf040b1d36e9e5c9ef6","model":"gpt-5.5","provider":"openai","segment_id":"common.theme","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Theme","text_hash":"efb52e7172b77731d996ff4f51cd7b3dcfd55fc6f07392994619418d58d170dd","tgt_lang":"ru","translated":"Тема","updated_at":"2026-06-26T21:38:30.975Z"}
|
||||
{"cache_key":"02b326087ea6935417cda820110d43dd71dff174b9eac2ba40b18b046360d63d","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.dailyCost","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Daily provider cost","text_hash":"0d03078a4d1fba12122e32e9abbc929ea64b948445810cf1e0d29cbdfd5cb18d","tgt_lang":"ru","translated":"Ежедневные расходы провайдера","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"02bdff9a4e46589d766d08ffdb15fbf89f6dd50340bf733994ad3129011f96e7","model":"gpt-5.5","provider":"openai","segment_id":"logsView.searchPlaceholder","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Search logs","text_hash":"82e10d7fa547e62eca0b3fb7b0d719febe032b86cfedb7b60729a3937a694405","tgt_lang":"ru","translated":"Поиск в логах","updated_at":"2026-06-26T21:39:38.402Z"}
|
||||
@@ -270,6 +271,7 @@
|
||||
{"cache_key":"2231929fb678ddcd84aa7ccfbd9d061ebbe7800def80aa50b5d6c1b203291919","model":"gpt-5.5","provider":"openai","segment_id":"agents.cronPanel.agentJobsTitle","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Agent Cron Jobs","text_hash":"69a868abf16029a87237a20520c80bb929ad2586aa4eff49eea9812b2e6ab0cb","tgt_lang":"ru","translated":"Cron-задания агента","updated_at":"2026-06-26T21:39:07.415Z"}
|
||||
{"cache_key":"223788b4007184b7f5783d902294e63ca63c418824c6ebfa2fac407da885fe2c","model":"gpt-5.5","provider":"openai","segment_id":"workboard.lifecycleDoneDetail","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Moved to review","text_hash":"2fa7fea7da3d6234a5ac340eb30585102f9b13f81efc73f9e87a51718283bbff","tgt_lang":"ru","translated":"Перемещено на проверку","updated_at":"2026-06-26T21:40:07.529Z"}
|
||||
{"cache_key":"225633a9fff7a6dff72ce709ee77d51b525144b2337f4bd92a0c9350a64f7245","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.noMicrophones","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"No additional microphones found","text_hash":"a6e4a20dda44dead8daa06da30fca7e7d90fa5aa4c15cbada30af1f52874d347","tgt_lang":"ru","translated":"Дополнительные микрофоны не найдены","updated_at":"2026-07-06T17:34:09.324Z"}
|
||||
{"cache_key":"22799e7adc1013534a1aaf527df61ddda89f24147571911aee392d3a9d6dbf99","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"ru","translated":"Истек","updated_at":"2026-07-02T14:31:15.337Z"}
|
||||
{"cache_key":"22ef6ddf151772c49c44f36d591e8187b2afabacebfa0b7216b6ca4d6694a92b","model":"gpt-5.5","provider":"openai","segment_id":"channels.gatewayUrlConfirmation.warning","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Only confirm if you trust this URL. Malicious URLs can compromise your system.","text_hash":"c67ff862ac6adf5342af661a4383b9f75fd21ef37baaf80bcb6c799982a1a7e2","tgt_lang":"ru","translated":"Подтверждайте только если вы доверяете этому URL. Вредоносные URL могут скомпрометировать вашу систему.","updated_at":"2026-06-26T21:38:40.558Z"}
|
||||
{"cache_key":"22fd5acd7a808fcede18f4207cda24efb299703bbea7a96157692722733b3854","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.transcript.loadMore","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Load older transcript items","text_hash":"2dd9c742f15de60d977597a17faf62db2cd79cd58caf87f349dac75899b3788e","tgt_lang":"ru","translated":"Загрузить более старые элементы расшифровки","updated_at":"2026-07-11T10:25:33.998Z"}
|
||||
{"cache_key":"230858aba6375a24ded2b639dae3a2dde79333c47f87dbd97a5b4483d6ceff16","model":"gpt-5.5","provider":"openai","segment_id":"chat.welcome.suggestions.checkSystemHealth","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Check system health","text_hash":"67c43fadcdb90a5a90db660c805dcc67f97330ef4c3d87387bee88977898c7d7","tgt_lang":"ru","translated":"Проверить состояние системы","updated_at":"2026-06-26T21:41:54.248Z"}
|
||||
@@ -338,6 +340,7 @@
|
||||
{"cache_key":"2b2f00119c4adf8d137049d22b88ff4c91f1dc80da4d37968a129dc0737d858a","model":"gpt-5.5","provider":"openai","segment_id":"workboard.autoRefresh5s","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"5s","text_hash":"93e3d8c5b10657d2884f177488b689aadf82a83f962237cb602b3314386ab3b7","tgt_lang":"ru","translated":"5 с","updated_at":"2026-06-26T21:39:57.757Z"}
|
||||
{"cache_key":"2b354cf48d6ac71d2ea00828bc884536c352e0228622669ace5c27b46191b262","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.executionSub","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Choose when to wake, and what this job should do.","text_hash":"9869059549e542582d729fa6b7b84eb6f4d0eccee80f734646a44d443b945267","tgt_lang":"ru","translated":"Выберите, когда активироваться и что должно делать это задание.","updated_at":"2026-06-26T21:42:31.568Z"}
|
||||
{"cache_key":"2b7a26b68d3cb6505ad766504a1f82fc80f8201fe55cebc458b8749d2020e1e0","model":"gpt-5.5","provider":"openai","segment_id":"cron.quickCreate.whatHeading","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"What should it do?","text_hash":"1970bec54875f6bdd238a7b9e2889e98fb652edab85498a790d73c937e6cdb76","tgt_lang":"ru","translated":"Что должно быть сделано?","updated_at":"2026-06-26T21:42:14.996Z"}
|
||||
{"cache_key":"2bd5379bd86a4c99a4414768158a9cbc8d474247ccc4277f50416009d840fecd","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.resolvedLabel","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Resolved","text_hash":"5be3c2c8354e1eb924b03a3dcc7fa4172e9aa0f4917b46b44fcc7daf8835d7a7","tgt_lang":"ru","translated":"Разрешено","updated_at":"2026-06-26T21:39:20.621Z"}
|
||||
{"cache_key":"2c294f76a43e9f1ca8c0c6c9098d8c764e1168b819a9500fc5c086758b584d8f","model":"gpt-5.5","provider":"openai","segment_id":"workboard.detailAutomationSummary","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Summary: {summary}","text_hash":"3a2270b3cd47b523936c13efec489f36112e0a64fe763dbe972d21fef029e814","tgt_lang":"ru","translated":"Сводка: {summary}","updated_at":"2026-06-26T21:39:47.132Z"}
|
||||
{"cache_key":"2c40ee7f14515e9e2f6dbc48d34bd52931712a55820620578a49101ac00a6c71","model":"gpt-5.5","provider":"openai","segment_id":"agents.channels.noAccounts","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"no accounts","text_hash":"11397ad5e7303cdd127ac98987b3c52e35c06a11428c6e7503a128dd96749dbd","tgt_lang":"ru","translated":"нет аккаунтов","updated_at":"2026-06-26T21:39:07.415Z"}
|
||||
{"cache_key":"2c4bd2527e00b369a9dda1f9ab16913bd7732bacad1cad94bb2f9fd7d9823086","model":"gpt-5.5","provider":"openai","segment_id":"agents.files.editFile","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Edit file","text_hash":"9608dd142d9b10d7799422fe96eab7262a5db3de6edbb1fde660d74ddaa2617b","tgt_lang":"ru","translated":"Редактировать файл","updated_at":"2026-06-26T21:39:11.166Z"}
|
||||
@@ -645,6 +648,7 @@
|
||||
{"cache_key":"53106109e0507f4ec6bfae14388a8b8a4a5ad87e026577454c5852239a74c9eb","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.transcript.back","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"All Claude sessions","text_hash":"aa40fc035a7a4bc4b6ca03a1411bcca398a1ee0db9f297eb058d0417b24f06de","tgt_lang":"ru","translated":"Все сеансы Claude","updated_at":"2026-07-11T13:51:42.664Z"}
|
||||
{"cache_key":"534ff78d76695822cbb4e7c8bade3aaa987a845ad32cbd40c9c11bd69ae47ed7","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.to","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"To","text_hash":"f4b06ef6d3c81436f60a318c81c42f8f7e2d774d45a22f3b9b5f3b6980d28146","tgt_lang":"ru","translated":"Кому","updated_at":"2026-06-26T21:42:41.136Z"}
|
||||
{"cache_key":"5368e8787800bf8b40dda32e757da0e57eedd63dc9853743ce08295ccf85ac9d","model":"gpt-5.5","provider":"openai","segment_id":"cron.runs.subtitleAll","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Latest runs across all jobs.","text_hash":"518357fee0ecb18cbbd2f1d29ea0fdda418f839ce47a3a0c0613aa9f92eedd89","tgt_lang":"ru","translated":"Последние запуски по всем заданиям.","updated_at":"2026-06-26T21:42:21.706Z"}
|
||||
{"cache_key":"5374f355b8468834938f2b3be82be9bf6b5df1e1a9eaea5c2e0f0e9cc213fbb1","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.toolLabel","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Tool","text_hash":"2e53bdcd0740867b597599e733c04a994f55fb17c89a61595183a001742e5705","tgt_lang":"ru","translated":"Инструмент","updated_at":"2026-06-26T21:41:28.060Z"}
|
||||
{"cache_key":"53793eb6ac7c8cf02e6e5dd01486534730fe4ac662d507341c1bb2831e1a69bc","model":"gpt-5.5","provider":"openai","segment_id":"common.waitForScan","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Wait for scan","text_hash":"bd99a64030bbae315da9bba62c2ea6493386708c738d3b9ab0cb815e9be6c748","tgt_lang":"ru","translated":"Ожидание сканирования","updated_at":"2026-06-26T21:38:34.337Z"}
|
||||
{"cache_key":"53e4f278bdf62e10c4cc27c70c71cca903bb24f9712ef315d998939e3fd1bccc","model":"gpt-5.5","provider":"openai","segment_id":"dreaming.advanced.shortTermDescription","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Current short-term candidates waiting to graduate into real memory.","text_hash":"0895c842efb140d4ebcd01bd1e976ecfa7e8d7318bd70d4ff1874976ba4729b8","tgt_lang":"ru","translated":"Текущие краткосрочные кандидаты, ожидающие перехода в настоящую память.","updated_at":"2026-06-26T21:40:44.743Z"}
|
||||
{"cache_key":"53fbdcad07141c08fe5a86a155fd73fad8d759c61a6c3d0b4c19c898073541cb","model":"gpt-5.5","provider":"openai","segment_id":"cron.quickCreate.delivery.notify.description","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Deliver results to chat","text_hash":"2c52a24163167b77889acbbf34defbdaf4ca334db34c25c133c139e5152ad86d","tgt_lang":"ru","translated":"Отправлять результаты в чат","updated_at":"2026-06-26T21:42:14.995Z"}
|
||||
@@ -653,6 +657,7 @@
|
||||
{"cache_key":"54eae05eb09e0641e6ff6b04219440b532e92226318638ec4f18f67b0051b238","model":"gpt-5.5","provider":"openai","segment_id":"agents.selectTitle","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Select an agent","text_hash":"7d4cf06874635248d725bcf641438f58529d029c16d9c2a88cdb5aee88142b1d","tgt_lang":"ru","translated":"Выберите агента","updated_at":"2026-06-26T21:39:04.015Z"}
|
||||
{"cache_key":"556a5b80215b37d58fa34bb08fb6a1c6fdcecad927addb2445b74a5eb6b36625","model":"gpt-5.5","provider":"openai","segment_id":"common.none","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"none","text_hash":"140bedbf9c3f6d56a9846d2ba7088798683f4da0c248231336e6a05679e4fdfe","tgt_lang":"ru","translated":"нет","updated_at":"2026-06-26T21:38:28.190Z"}
|
||||
{"cache_key":"557577292a7e7ddbf05855cbd79f9efb06d3b222ce5aebfeaf6cc2bc5758defe","model":"gpt-5.5","provider":"openai","segment_id":"subtitles.worktrees","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Isolated agent task checkouts and recovery snapshots.","text_hash":"bc794dc846493e3c5f88964268af19b7dd818eae942c596002ef4067ba5a3d0c","tgt_lang":"ru","translated":"Изолированные копии для задач агентов и снимки восстановления.","updated_at":"2026-07-05T21:01:47.002Z"}
|
||||
{"cache_key":"55a61331f61fc87360901070f1553f2857493836460e01c1b0dfcefe602ed680","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"ru","translated":"Узел","updated_at":"2026-06-26T21:38:48.084Z"}
|
||||
{"cache_key":"55cbb8380a7cd712cb188bf5851fda57133ee8baf50b3672549eeec39c768fac","model":"gpt-5.5","provider":"openai","segment_id":"cron.errors.cronExprRequiredShort","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Cron expression required.","text_hash":"dcd8b9471afc9f89d49a6279aba723d2f38dcd28f4df55045be674608930bea0","tgt_lang":"ru","translated":"Требуется cron-выражение.","updated_at":"2026-06-26T21:42:51.343Z"}
|
||||
{"cache_key":"561580bbdfc6993527981b181bf81fd6e73b59be15764f4baf9ca0ac812bfea8","model":"gpt-5.5","provider":"openai","segment_id":"overview.snapshot.subtitle","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Latest gateway handshake information.","text_hash":"02c4ea80485c6beaf97787975883e58d65e0d1d4dd30e0c4c101e862fb45634a","tgt_lang":"ru","translated":"Последняя информация о рукопожатии шлюза.","updated_at":"2026-06-26T21:40:18.156Z"}
|
||||
{"cache_key":"5623ba711e9baae5e04b96f44267acc5c7ff0a802c0267c7bb813fd9f91f4b66","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.staggerUnit","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Stagger unit","text_hash":"91f427bfe9e5d6bb461f1cdcd124fbf3ee25ceec6e5763c69092ffe9120007ed","tgt_lang":"ru","translated":"Единица разброса","updated_at":"2026-06-26T21:42:41.136Z"}
|
||||
@@ -947,6 +952,7 @@
|
||||
{"cache_key":"7a516f2ebcb9bfe8e0c7048f1974554b3bf850ac0801cad8d93bae80b491eccf","model":"gpt-5.5","provider":"openai","segment_id":"cron.quickCreate.schedules.once.description","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"One-time, delete after run","text_hash":"19694753e141db752658d22dfb4c494a4f5452640d87b6cbcbb64bd665a13cd2","tgt_lang":"ru","translated":"Однократно, удалить после запуска","updated_at":"2026-06-26T21:42:14.995Z"}
|
||||
{"cache_key":"7a83709e50c8a383665ff92ca806900721ef80f426abd2f194d6bf2ad420c216","model":"gpt-5.5","provider":"openai","segment_id":"cron.form.modelHelp","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Start typing to pick a known model, or enter a custom one.","text_hash":"6ebac6c51e0da79d2ad76fe3d1395dff0c7a51ec7aa0d6b39ac38b0ba9fd8724","tgt_lang":"ru","translated":"Начните вводить, чтобы выбрать известную модель, или введите свою.","updated_at":"2026-06-26T21:42:44.768Z"}
|
||||
{"cache_key":"7ae58210608f3174df61be76dafefd9f55ba35b099b59ba7fbb15a58569a1aa2","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.insightAgents","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Agents in the reef","text_hash":"050a0a3d70a5c89d65789f7983024ee9eb2539cee6c2e0b31677ac78b0cd3534","tgt_lang":"ru","translated":"Агенты в рифе","updated_at":"2026-07-09T11:29:24.216Z"}
|
||||
{"cache_key":"7b057fe46c0f1058439bee2a325ecb9c4e0f55964e9788d289cb886ea43831af","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"ru","translated":"Команда","updated_at":"2026-06-26T21:42:36.583Z"}
|
||||
{"cache_key":"7b27334b28a606205b99589eb76738540c65ee6ec704380406fb0824ba74dda9","model":"gpt-5.5","provider":"openai","segment_id":"codexSessions.sidebar.unavailable","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Codex sessions unavailable","text_hash":"9d3177daebe3a0d81438f5a085018560a547616392838a73aa9ddc6c3e8d6a40","tgt_lang":"ru","translated":"Сеансы Codex недоступны","updated_at":"2026-07-11T10:25:33.998Z"}
|
||||
{"cache_key":"7b3d383edb2ea66000143b1866b44ab80451eb1072fa342b207c01c61b0059fc","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.checksPassed","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Passed","text_hash":"436fe71bb9561f0596161c4d50c7b23327b4189acaf63dc89f4f9205b67a7528","tgt_lang":"ru","translated":"Пройдено","updated_at":"2026-07-10T23:12:58.797Z"}
|
||||
{"cache_key":"7b5c412bbe32f0c1296be723357b9bb4be8eaaed2dd399b0ad834c8cf65ce7f7","model":"gpt-5.5","provider":"openai","segment_id":"nodes.binding.loadConfigHint","source_path":"ui/src/i18n/locales/ru.ts","src_lang":"en","text":"Load config to edit bindings.","text_hash":"075f4d7948e28bf0f85baefbdfe31e6a11a86d94ac38cbc3c100fdf8981c8839","tgt_lang":"ru","translated":"Загрузите конфигурацию, чтобы редактировать привязки.","updated_at":"2026-06-26T21:38:44.774Z"}
|
||||
|
||||
Generated
+3
@@ -372,6 +372,7 @@
|
||||
{"cache_key":"a4fe522a6e635775e7b93707d6e66242e24f03953f7135b321c746a2053bd578","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkMoreInSettings","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"More in Settings","text_hash":"87f1e602d68bdc42ae3fddc0c1541d323adc718b7b9b3f889b2ca71823e319b9","tgt_lang":"th","translated":"เพิ่มเติมในการตั้งค่า","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"a56778a37c2861829bdcde5b72602d882721cb3f27eafd2839fa71f2fe8e3994","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.items.plugins","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Plugins","text_hash":"9514b7ff4860ead73491768e45cce0ce20e6e3473a7b272e496c43c875d80ac5","tgt_lang":"th","translated":"ปลั๊กอิน","updated_at":"2026-07-12T00:10:41.112Z"}
|
||||
{"cache_key":"a6b027de110cc1e77b2de8584272196e0cf919e1c4852b28694bcfdd916325a4","model":"gpt-5.6-sol","provider":"openai","segment_id":"attention.cronFailed","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"{count} cron job(s) failed","text_hash":"0a75fdcee152b66aa5e544a8dcea294f37c8a2d696fba50a86d0f0535376648d","tgt_lang":"th","translated":"งาน cron ล้มเหลว {count} งาน","updated_at":"2026-07-12T00:10:22.896Z"}
|
||||
{"cache_key":"a6b18eb8c4e38ab25bc174f0015419e187d7f3f045238ff4c41ea21a2cd301fb","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"th","translated":"คำสั่ง","updated_at":"2026-06-16T14:17:40.285Z"}
|
||||
{"cache_key":"a6f1dc20603629daf073eccc63bb00a2ee94514f216f0f73dbf1b532b633d7a7","model":"claude-opus-4-8","provider":"anthropic","segment_id":"skillWorkshop.header.useCurrentChatTooltip","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Send revision requests to the current chat session instead of the proposal's workshop session.","text_hash":"9db782d40e88750d4faed33c8a73c24552070f101483881c60af8cf446c674a6","tgt_lang":"th","translated":"ส่งคำขอแก้ไขไปยังเซสชันแชทปัจจุบันแทนเซสชัน workshop ของข้อเสนอ","updated_at":"2026-06-16T14:17:16.747Z"}
|
||||
{"cache_key":"a80dd5b77f4050f9b309a95afa9f221d39aab95f5d7391f213242b2f1af5fd18","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.dismissTalkError","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Dismiss Talk error","text_hash":"72f032a5a37e7197cc94ea95f5da0829abb2262396cdcc35229bd8ce9a52de1e","tgt_lang":"th","translated":"ปิดข้อผิดพลาด Talk","updated_at":"2026-06-16T14:17:26.503Z"}
|
||||
{"cache_key":"aa253f2329e790a87c215528d0f2968072a2d87ae3721fd039e07fdf21db1517","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.statusRenamed","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Renamed","text_hash":"05487af3f074b4f31e4f9a1ec75044ab182f037a7978e1a8909c42103fb1297a","tgt_lang":"th","translated":"เปลี่ยนชื่อแล้ว","updated_at":"2026-07-11T04:53:32.869Z"}
|
||||
@@ -423,6 +424,7 @@
|
||||
{"cache_key":"c30471a9b30c61e1407f429594ab57b7c256d40bd66fdeb13d3eca7e192f221f","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.running","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Running ({count})","text_hash":"f59b64ba4fbd9531b500ab543433c50f6edba4b1f5bf17435988dbc9fb2d42a5","tgt_lang":"th","translated":"กำลังทำงาน ({count})","updated_at":"2026-07-11T00:45:34.273Z"}
|
||||
{"cache_key":"c360aaacce0da9b7539998282d59d78ef0f21c8a5e694936201515c0d20124e4","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.checksPassed","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Passed","text_hash":"436fe71bb9561f0596161c4d50c7b23327b4189acaf63dc89f4f9205b67a7528","tgt_lang":"th","translated":"ผ่านแล้ว","updated_at":"2026-07-10T23:12:49.455Z"}
|
||||
{"cache_key":"c364692054e957d7a498551c42968cb499a05943e042ff4bcec268d3af1ccce0","model":"gpt-5.5","provider":"openai","segment_id":"browser.toggle","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Toggle browser panel","text_hash":"cfd0e6c787d9b0fd9341c1bc377dca3a0987588b1fdb68ef23b5d0ce3bced9bc","tgt_lang":"th","translated":"สลับแผงเบราว์เซอร์","updated_at":"2026-07-11T02:19:42.169Z"}
|
||||
{"cache_key":"c397bac8e4b0c9cf15ce95b8bd5e21c145e00601c844dc652be7ed01d85640cb","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"th","translated":"โหนด","updated_at":"2026-07-09T10:01:43.768Z"}
|
||||
{"cache_key":"c3cfcb94e542aabbb0056e14f4de6974ba01e71dc0039b0ce5ff5efb6c0af3d0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"cron.jobDetail.cwd","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"CWD","text_hash":"0217f1cb7725737f15a6710df3bcfa3bc10a239f0f7801ec3d7168e675f5ebd6","tgt_lang":"th","translated":"CWD","updated_at":"2026-06-16T14:17:40.285Z"}
|
||||
{"cache_key":"c438f3366192bad65517fedde27265d08cd301058d0b6589a86b2e0510370321","model":"gpt-5.5","provider":"openai","segment_id":"nav.exitSettings","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Back to app","text_hash":"a6989680b3528cd399ebaea75e660da6ce8d155d24226532180f90ab37c05e9e","tgt_lang":"th","translated":"กลับไปที่แอป","updated_at":"2026-07-09T08:08:10.509Z"}
|
||||
{"cache_key":"c45cab3b2e62dd5f5c1030f66329f36d8c4d8e6c102a5e027112e49c802d2789","model":"gpt-5","provider":"openai","segment_id":"codexSessions.eyebrow","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Codex fleet","text_hash":"64e0510e4f9e07ad1283b7c1d55e67b5b853081b6ca4013fc8d710aa658d5127","tgt_lang":"th","translated":"กลุ่มเครื่อง Codex","updated_at":"2026-07-09T10:01:43.768Z"}
|
||||
@@ -542,6 +544,7 @@
|
||||
{"cache_key":"f79ab0563e452bc78cbd3dff5eea1e1b173afd46811de43d51232b9c1ef7351d","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.checksSkipped","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Skipped","text_hash":"12698ce1ea5cd4ab13ff4b7e6b1239908c41a4b2dfa0c2661cfb53fc2aa71bd0","tgt_lang":"th","translated":"ข้ามแล้ว","updated_at":"2026-07-10T23:12:49.455Z"}
|
||||
{"cache_key":"f79deab2a0132c2018218f43cc3e7dc9bf23d47c137806f93d8cbb3dda690f58","model":"gpt-5.5","provider":"openai","segment_id":"nodes.pairing.qrAlt","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"OpenClaw mobile pairing QR code","text_hash":"6c402a1c5d7208ea5d5ebf5dd95c5826c9bb81f74a880c0cebe4c2eb1347a7bf","tgt_lang":"th","translated":"คิวอาร์โค้ดสำหรับจับคู่ OpenClaw mobile","updated_at":"2026-07-04T16:48:49.478Z"}
|
||||
{"cache_key":"f7d58b91ce88fe59b2fbabe7aa2ee92134e6320b4df14fbc31a703d50204b6ec","model":"gpt-5.5","provider":"openai","segment_id":"subtitles.skillWorkshop","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Review, refine, and apply proposals before they become live skills.","text_hash":"f907c72e9f18a205027257cd6fecdd52b03732227a17dcec0db038e11de3f8cc","tgt_lang":"th","translated":"ตรวจสอบ ปรับแต่ง และนำข้อเสนอไปใช้ก่อนที่จะกลายเป็น Skills ที่ใช้งานจริง","updated_at":"2026-05-31T21:48:38.842Z"}
|
||||
{"cache_key":"f82f0ba597cabe4fdb4fb23a452c3caeb4e69dc3adad02477c0a99263ff9e915","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"th","translated":"หมดอายุ","updated_at":"2026-07-01T10:33:34.756Z"}
|
||||
{"cache_key":"f83cccdee97981e85f09bdbe9b67c01ff9dd8480f8628fd8ee8f2ca4dbeff053","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.lastActive","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Last active","text_hash":"bcdf701c4dfbaee3a2162f9b9affd87a23a13426c391f95e964d983851b58a05","tgt_lang":"th","translated":"ใช้งานล่าสุด","updated_at":"2026-07-05T21:01:30.011Z"}
|
||||
{"cache_key":"f8858923a8d3a2986391108644f83c16a727bbfd2f1a1fdbedd37ed621171697","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.groupByNone","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"None","text_hash":"dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91","tgt_lang":"th","translated":"ไม่มี","updated_at":"2026-07-05T14:40:13.915Z"}
|
||||
{"cache_key":"f89a9de135a72cdddcbc342c5bf46726d7c4e7a68de740805ffa8cb08a1c7bb6","model":"gpt-5.5","provider":"openai","segment_id":"browser.back","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Back","text_hash":"76900f1bfd16c8d4dd3d25e6f46638d7165aee23883ccea6bfe071c514421769","tgt_lang":"th","translated":"ย้อนกลับ","updated_at":"2026-07-11T02:19:42.169Z"}
|
||||
|
||||
Generated
+3
@@ -6,6 +6,7 @@
|
||||
{"cache_key":"033526609d4a6265b6fe4e2c4647fa2bfe4a5cc57e205cb80a849108310c7e6f","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.dependenciesBlocked","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"{count} blocked","text_hash":"fb39869b0fb3b8933126014e5c3739d7d67a620b8369781ca27e7395c595bde8","tgt_lang":"tr","translated":"{count} engellendi","updated_at":"2026-06-16T14:15:44.904Z"}
|
||||
{"cache_key":"03ff9fe6b24d649a6d85b6a0811306921ff677ecddcff658d3f82dd2645b8018","model":"gpt-5.6-sol","provider":"openai","segment_id":"palette.footer.navigate","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"navigate","text_hash":"d0cda6559bb347db706f6fa92a5b2491658e0c1e5bda98bb14e3c8a711b8fa33","tgt_lang":"tr","translated":"gezin","updated_at":"2026-07-12T00:09:36.357Z"}
|
||||
{"cache_key":"040135aa57e274603d56f34d01fddffd6e809f5fd173abc712de6efd635ed267","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkVoice","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Voice","text_hash":"87bf2bc08589f0bd4a078db145c34ad5e14b8fda53c3ae65b78601294913df95","tgt_lang":"tr","translated":"Ses","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"040aae3e0cb81b5f39a481574de72c22528c01af616b3ed92280254a7fdd4e0a","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"tr","translated":"Komut","updated_at":"2026-06-16T14:15:58.007Z"}
|
||||
{"cache_key":"04d72a26ac7a5155272413cda0949de9a91c5be887a33716789eeb62224b5e03","model":"gpt-5","provider":"openai","segment_id":"codexSessions.partial","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Unavailable hosts: {count}. Other hosts remain available.","text_hash":"00ca17db32e78382e78e5877fd167f21e6baf40783b4cf581f34be5ffd1bd05b","tgt_lang":"tr","translated":"Kullanılamayan ana makine sayısı: {count}. Diğer ana makineler kullanılabilir durumda.","updated_at":"2026-07-09T10:01:43.764Z"}
|
||||
{"cache_key":"054283601bc23780afb866b1c7af3331cf9b2b5d8d3ac5d11bc9601254928f69","model":"gpt-5","provider":"openai","segment_id":"claudeSessions.stored","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Stored","text_hash":"91da9626894c82dd4d5ed7ab48ed4ed4b1fc57ff98858cde93945254e36c4198","tgt_lang":"tr","translated":"Depolanmış","updated_at":"2026-07-09T10:01:43.764Z"}
|
||||
{"cache_key":"0640b555c6cc82eb5dbec3c2d235f4eb7702e6bc6ceca03332f36aa0e708cd14","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.agentFilterConfiguredDefault","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"{agent} (default)","text_hash":"7e996234f0fa55605720f9dc954a58411795bd882e948c87c739d43bd02137c3","tgt_lang":"tr","translated":"{agent} (varsayılan)","updated_at":"2026-06-17T14:15:34.754Z"}
|
||||
@@ -41,6 +42,7 @@
|
||||
{"cache_key":"147edaa3acf0216b69e5f43b326cbbec7877f05755df5abca9984623feb892b9","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.quickCreate.createAndRun","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Create & run now","text_hash":"410ca8781cd841242df09224cb339e9e1327e934e5253a006aaa9272f0471954","tgt_lang":"tr","translated":"Oluştur ve şimdi çalıştır","updated_at":"2026-07-11T22:47:07.116Z"}
|
||||
{"cache_key":"14818221915c27f3a647dc7bee02bfb709dd3669dc987d47f4092400ee746626","model":"gpt-5.5","provider":"openai","segment_id":"newSession.gateway","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Gateway · local","text_hash":"b82bf739d73b54a7ac3596fdf9bb9255573ce18675dda095cae645493b62df8f","tgt_lang":"tr","translated":"Gateway · yerel","updated_at":"2026-07-10T17:59:33.427Z"}
|
||||
{"cache_key":"158d692e079368de776f21e391d3722894a29060c9bb09f55b65e6ac2551219c","model":"gpt-5","provider":"openai","segment_id":"codexSessions.disconnected","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Reconnect to the gateway to refresh Codex sessions.","text_hash":"e5f80a33fab5ee6ffa4d7e3c58e7deb8e078e04b7a12cb9a007913904cbdb0c5","tgt_lang":"tr","translated":"Codex oturumlarını yenilemek için Gateway'e yeniden bağlanın.","updated_at":"2026-07-09T10:01:43.764Z"}
|
||||
{"cache_key":"15bf5aed8c3396edcda4610246053e89c462118cd25612f3e73708275619327e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"tr","translated":"Süresi doldu","updated_at":"2026-07-01T10:32:46.731Z"}
|
||||
{"cache_key":"15db176f83390bf298f9cfb15ac2e8f561bb1dc4840da437bc7c4b8f2787821f","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.label","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Session workspace","text_hash":"c0e8ea0cf983d14e8ba3f8fc28976954d637fd50f807c69e9695715fd2384b78","tgt_lang":"tr","translated":"Oturum çalışma alanı","updated_at":"2026-06-16T14:15:44.904Z"}
|
||||
{"cache_key":"167c01d51b430673379b1ec606e9db132fc6c7634ff0ba054fe250dcb6e56441","model":"gpt-5.5","provider":"openai","segment_id":"chat.welcome.recentSessions","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Recent chats","text_hash":"2ccfecbca1011bad772fce00fa6479c9af2d398ce3b3951b7713b2655b6999eb","tgt_lang":"tr","translated":"Son sohbetler","updated_at":"2026-07-11T08:43:17.120Z"}
|
||||
{"cache_key":"171c7e77ee6ee1a3c1e975a2e955ec2e6f9b606794586d343eced46b156ee2bf","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.access.title","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Gateway Access","text_hash":"a22d5425b3cb2d89a7e8d96398b1d9b8141b49afcdc4d9e0c6a591e64e82de5d","tgt_lang":"tr","translated":"Gateway Erişimi","updated_at":"2026-07-12T00:09:30.696Z"}
|
||||
@@ -527,6 +529,7 @@
|
||||
{"cache_key":"eee5ca6ff00eed93183d35386d902227d25e60e2e46c5b041e46631ac44ddb6b","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.empty","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"No changes in this session's checkout.","text_hash":"0345aa3b1a02eec8e7dbb6f8cf7fbb4c8b335ff6164c87b4ff250f753180d840","tgt_lang":"tr","translated":"Bu oturumun checkout'ında değişiklik yok.","updated_at":"2026-07-11T04:53:17.706Z"}
|
||||
{"cache_key":"ef076ed851ac04302da699a1cb853733152b535c91f035429a64dcbf6a7f0d9e","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.root","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Root","text_hash":"44cb005ee2e65d9cc817b0a083579369fb6c24a4be728cb43fd9d4c3ca7f4c2e","tgt_lang":"tr","translated":"Kök","updated_at":"2026-06-16T14:15:55.679Z"}
|
||||
{"cache_key":"efa08e578bca0a9d95b888d1e705a3f9a52217aa93bf23b853eae16fdc18868e","model":"gpt-5.5","provider":"openai","segment_id":"usage.providerUsage.inputTokens","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"{count} input","text_hash":"f24231cff78fed82d155712973ede6f9369e96b015acc30d5de2b740677edce9","tgt_lang":"tr","translated":"{count} giriş belirteci","updated_at":"2026-07-06T06:40:15.357Z"}
|
||||
{"cache_key":"f06b6d1ae27c3f273e2485b4fae2634eca1ca2b3ca5c45ef5ff602187d6dd557","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"tr","translated":"Düğüm","updated_at":"2026-07-09T10:01:43.764Z"}
|
||||
{"cache_key":"f0a7a04b0f7ae959edd0746e81aa24fc5c01a3bc67e8d9b588037284b04d01c3","model":"gpt-5.5","provider":"openai","segment_id":"chat.splitView.dropOpenHere","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Open here","text_hash":"b08e2fd2e872adcb575b305187b9db8482369325806953ce80190fc2dc1ab9fb","tgt_lang":"tr","translated":"Burada aç","updated_at":"2026-07-06T22:56:29.564Z"}
|
||||
{"cache_key":"f0aa575b9c8b229574dd918c574821d2cf1b52f60f014b88c2a556ddd3538639","model":"gpt-5.5","provider":"openai","segment_id":"tabs.mcp","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"MCP","text_hash":"53f13ae99ed53bd346eb8e1c8cefb7ef8260683b50401caf101360967ea052aa","tgt_lang":"tr","translated":"MCP","updated_at":"2026-05-31T05:36:46.292Z"}
|
||||
{"cache_key":"f269e0584fa4c79357ebddf2841dd009af4e1512ff0ec8fafb7ef4f75c33a560","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.microphoneFallback","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Microphone {number}","text_hash":"357eae20db9739dfdbb59ec21db70200f6ca9ee257c28ed637712f147af419ec","tgt_lang":"tr","translated":"Mikrofon {number}","updated_at":"2026-07-06T17:56:54.065Z"}
|
||||
|
||||
Generated
+3
@@ -116,6 +116,7 @@
|
||||
{"cache_key":"2aea6c70e72d89b6ec00c0b658b6bb01ee0e45afa60c0c866084203bf325bf08","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.moreRegions","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"…plus {count} more marked region(s), all visible in the screenshot.","text_hash":"d11184c08b1bb4c0899c97fdd9a27bb719de7b7f5540a9b2cdafe66c975ca65d","tgt_lang":"uk","translated":"…плюс ще {count} позначених областей, усі видно на знімку екрана.","updated_at":"2026-07-11T02:19:21.035Z"}
|
||||
{"cache_key":"2b7027b56f652adbdc50dee1418263cfd650f57d263749255993446f13cf6424","model":"gpt-5.6-sol","provider":"openai","segment_id":"subtitles.connection","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Gateway endpoint, credentials, and handshake status.","text_hash":"5d6324ca52f899e2db988c9a0b14314fe2240f17cb129b8ff2bf16bf87bef2e7","tgt_lang":"uk","translated":"Кінцева точка Gateway, облікові дані та стан рукостискання.","updated_at":"2026-07-12T00:09:41.150Z"}
|
||||
{"cache_key":"2c54c1c38c9442e9d738cc2a1b8ccd54ab02cf103ec3ef64f69edcd2a7f5bb1a","model":"gpt-5.5","provider":"openai","segment_id":"codexSessions.transcript.loading","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Loading transcript…","text_hash":"0606d0e8977e7005f2142a85ce689aec42a867a50eefaf25fc5f1691f960eae7","tgt_lang":"uk","translated":"Завантаження транскрипту…","updated_at":"2026-07-11T10:25:12.933Z"}
|
||||
{"cache_key":"2c7ac03f130980449f9076d4ee5fabc7029e7b6f11e0cd807e4ce1a9f07667f7","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"uk","translated":"Команда","updated_at":"2026-06-16T14:16:03.477Z"}
|
||||
{"cache_key":"2cf325892ff9f34d968822428fb780a5e656956b0fa5f5083b2576bd762bdd85","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.ciMonitoring","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"CI monitoring","text_hash":"b729ae0c12be4bfdccc13ca31d0ee718cfc6a324b564daa239a5bf2e147b3398","tgt_lang":"uk","translated":"Моніторинг CI","updated_at":"2026-07-10T23:12:41.714Z"}
|
||||
{"cache_key":"2d3e2199f7d61bd472b4e492a183d91e6318d33d0cf57ba16854237db4058669","model":"gpt-5","provider":"openai","segment_id":"codexSessions.status.active","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Active","text_hash":"92340695899bd2d86223e4a007620e0d6502fc0e08809773634c7e0743764a9c","tgt_lang":"uk","translated":"Активний","updated_at":"2026-07-09T10:01:43.750Z"}
|
||||
{"cache_key":"2d7406c2df89c36b38884f459eec6fa58c4ffca86a0b98344a592e4d39991791","model":"claude-opus-4-8","provider":"anthropic","segment_id":"skillWorkshop.header.useCurrentChatTooltip","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Send revision requests to the current chat session instead of the proposal's workshop session.","text_hash":"9db782d40e88750d4faed33c8a73c24552070f101483881c60af8cf446c674a6","tgt_lang":"uk","translated":"Надсилати запити на перегляд до поточної сесії чату замість сесії воркшопу пропозиції.","updated_at":"2026-06-16T14:15:40.204Z"}
|
||||
@@ -245,6 +246,7 @@
|
||||
{"cache_key":"5f6583887cb8a81a1305429506a9df6f09280a71268970b714fb1b6f20577570","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.snapshot.lastChannelsRefresh","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Last Channels Refresh","text_hash":"97a20d4f5b29914b8a08748cfc55d704a4d52ed948180cc90b7c1e06267c692f","tgt_lang":"uk","translated":"Останнє оновлення каналів","updated_at":"2026-07-12T00:09:44.762Z"}
|
||||
{"cache_key":"61e595c7160108a2b33aa271c862d64a8515761d31a88fefb625811d44b53748","model":"gpt-5.5","provider":"openai","segment_id":"browser.inspectName","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Name","text_hash":"dcd1d5223f73b3a965c07e3ff5dbee3eedcfedb806686a05b9b3868a2c3d6d50","tgt_lang":"uk","translated":"Назва","updated_at":"2026-07-05T21:01:19.646Z"}
|
||||
{"cache_key":"61f20a4d42aeab7cf650eaa2054942b8a90cef345436454dee7cd5a9b9519c5b","model":"claude-opus-4-6","provider":"anthropic","segment_id":"chat.composer.realtimeTalkRequiresMicrophone","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Realtime voice input requires browser microphone access.","text_hash":"a70d86265802e30aac70647cde33c62c5386741941d2ea9f54636a0242109dcd","tgt_lang":"uk","translated":"Голосовий ввід у реальному часі потребує доступу до мікрофона браузера.","updated_at":"2026-07-06T22:42:20.080Z"}
|
||||
{"cache_key":"62568a4518dcfcd91cc65101a6563060748e940a50c23043b42459d500530657","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"uk","translated":"Застарів","updated_at":"2026-07-01T10:32:49.580Z"}
|
||||
{"cache_key":"62f234669bbe6ccb59ee316fbb10772c2b7696fc3c7d6e3ebd8436c24c03648a","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailRun","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Run","text_hash":"00d60e31a4e6b8344d4201f25a6a7dee770713107f6d097abb01559d32b17f26","tgt_lang":"uk","translated":"Запуск","updated_at":"2026-06-16T14:15:40.204Z"}
|
||||
{"cache_key":"6309fed2305ec96850c4d67e24950add0663cc9a39a4f36c6c81051c1e64b0ab","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.renameGroupPrompt","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Rename group","text_hash":"98d254a311d0e820bb8739eb28d4e1eb5fc1cfc34f755167759864cd15504b4c","tgt_lang":"uk","translated":"Перейменувати групу","updated_at":"2026-07-06T23:41:10.447Z"}
|
||||
{"cache_key":"6358b220fd78f7c79d5833a322c467c4cee63eb35d91717f84d8e91a01a4c6ec","model":"gpt-5.5","provider":"openai","segment_id":"codexSessions.transcript.back","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"All Codex sessions","text_hash":"5632682031230868ee06c5cf99c4bc86fedf7824384653ab6caec90aaa40f9af","tgt_lang":"uk","translated":"Усі сеанси Codex","updated_at":"2026-07-11T10:25:12.933Z"}
|
||||
@@ -379,6 +381,7 @@
|
||||
{"cache_key":"a46184a1a331aa7153879b471c441959411149465b02416d3b23da9efa690588","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.finished","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Finished ({count})","text_hash":"075b0ee69a685d3a0fbf0b009794675b56ea66104ee5c931cd909140194f6be9","tgt_lang":"uk","translated":"Завершено ({count})","updated_at":"2026-07-11T00:45:26.267Z"}
|
||||
{"cache_key":"a4bd9b98e64254c411c083ac52654b0c5a466de108351420e2ba205a16996e64","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.archiveSession","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Archive session","text_hash":"740ded37480365eae8bf833ccaaa58350fc9434a77b7bb65b5516eba476fbec3","tgt_lang":"uk","translated":"Архівувати сеанс","updated_at":"2026-07-02T14:30:30.852Z"}
|
||||
{"cache_key":"a58009b310a2ac3e75b1d517a5f0a4442f3c6c55d963d0efed38ef0218522a53","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.help.step3","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Paste the WebSocket URL and token above, or open the tokenized URL directly.","text_hash":"9c978945315941b9182aa1d51e3465e2250e626234123299ff5fc59b7b01b0ab","tgt_lang":"uk","translated":"Вставте URL WebSocket і токен вище або безпосередньо відкрийте URL із токеном.","updated_at":"2026-07-12T00:09:44.762Z"}
|
||||
{"cache_key":"a628eda9a9c26bb0831af9212c12a1952d2814eb56f9c0a10409ebe31d74ab42","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"uk","translated":"Вузол","updated_at":"2026-07-09T10:01:43.750Z"}
|
||||
{"cache_key":"a6e27bc6275e087dfb962f35db43b5dffbe498c0c16ed21d3d511cd0724767d3","model":"gpt-5.5","provider":"openai","segment_id":"profilePage.statLongestSession","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Longest session","text_hash":"7f727c1b85939ac165087fe5c3081e15ca00c6e6a0c0b6f8c908ff21eda7a4f2","tgt_lang":"uk","translated":"Найдовший сеанс","updated_at":"2026-07-09T11:28:11.730Z"}
|
||||
{"cache_key":"a7141fa22e8e2bf9535a0d21f6487ddec3a9c01d0b5325bdb3177f958f5a4fd0","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.collapse","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Collapse background tasks","text_hash":"e793371743248cb45412e03ad89929c99a0018f1c517a1d71f11bdc9c854f357","tgt_lang":"uk","translated":"Згорнути фонові завдання","updated_at":"2026-07-11T00:45:26.267Z"}
|
||||
{"cache_key":"a741e3396b6b98579643aa4992b3994881476f863f194fa574f5a872112a6aa9","model":"gpt-5.6-sol","provider":"openai","segment_id":"connection.help.docsLink","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Read the docs →","text_hash":"412b59669150e05afaf4671cae2d9708750732c55d290efffeec7dcf7fef80e7","tgt_lang":"uk","translated":"Читати документацію →","updated_at":"2026-07-12T00:09:44.762Z"}
|
||||
|
||||
Generated
+3
@@ -438,6 +438,8 @@
|
||||
{"cache_key":"bd0a58cc11eb68f3726c86537ad9778bc1d8514d5a62d7fbd52105d569fcf9f4","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailUpdatedValue","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Updated: {time}","text_hash":"5e72d5445f018c9d08aa34ae0178fb9aa49eea6a0afd0c8d379f20b7af3e8aa0","tgt_lang":"vi","translated":"Đã cập nhật: {time}","updated_at":"2026-06-16T14:17:10.180Z"}
|
||||
{"cache_key":"be42b03403a5f0e24ff86f59e94e8a917b40ee674f81bd7d6177fbf2cd66c59d","model":"gpt-5.5","provider":"openai","segment_id":"chat.runControls.newSessionWorktree","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"New chat in worktree","text_hash":"4ce7f69c42b6b0fc700718d8e69101c9f04953b7be65044dc6d40f3975cd3cee","tgt_lang":"vi","translated":"Cuộc trò chuyện mới trong worktree","updated_at":"2026-07-06T04:56:43.746Z"}
|
||||
{"cache_key":"bea05cff43c64dca165880fc9a992ee73d2f47049fe03678b4f4ff3146ed45b0","model":"gpt-5","provider":"openai","segment_id":"codexSessions.disconnected","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Reconnect to the gateway to refresh Codex sessions.","text_hash":"e5f80a33fab5ee6ffa4d7e3c58e7deb8e078e04b7a12cb9a007913904cbdb0c5","tgt_lang":"vi","translated":"Kết nối lại với Gateway để làm mới các phiên Codex.","updated_at":"2026-07-09T10:01:43.734Z"}
|
||||
{"cache_key":"bed2d85a9c8808f98ae92a1081d8d6c01ae34faf2da87b2acd1d150f01fa8bad","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"vi","translated":"Nút","updated_at":"2026-07-09T10:01:43.734Z"}
|
||||
{"cache_key":"bef398de76d12578644d53792839af6ab70688389d26dc7182d7542fd4c0841b","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"vi","translated":"Lệnh","updated_at":"2026-06-16T14:17:27.580Z"}
|
||||
{"cache_key":"bf198b53e9eb164f70d29da416394d985750087deeb2fb59e27ca881b3e700c8","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.refresh","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Refresh background tasks","text_hash":"837e39f46163ffb4dbed66ba4910c35f2383c1708c9a5593d120a53d51cdebf1","tgt_lang":"vi","translated":"Làm mới tác vụ nền","updated_at":"2026-07-11T00:45:36.411Z"}
|
||||
{"cache_key":"bfedf0d0680045c5d36954b6530dfe1eea08724dbe4cbdf2e69cc61a9476e4b0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.viewAll","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"All cards","text_hash":"2306120917506b5998ec702f3661068b102dac538ba4c9e4634d65fe33eea98a","tgt_lang":"vi","translated":"Tất cả thẻ","updated_at":"2026-06-17T14:17:26.553Z"}
|
||||
{"cache_key":"bffac1dae6688c98dcaf3099fc3b8e3cd587e5dfd847d5b01a19fd683410cc1c","model":"gpt-5.5","provider":"openai","segment_id":"chat.sidebar.sortCreated","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Created","text_hash":"d70b9e24bca26b409b9458ceca6c9e5c2b5c3171c37ff050c6f6a0d7a4420d2a","tgt_lang":"vi","translated":"Đã tạo","updated_at":"2026-07-06T15:07:02.499Z"}
|
||||
@@ -545,6 +547,7 @@
|
||||
{"cache_key":"f0567dc0494fed24c47bb39433d72a0e0cf56000bddb5af41dc58f0192aa0539","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.checksFailed","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Failed","text_hash":"031a8f0f659df890dfd53c92e45295b0f14c997185bae46e168831e403b273f7","tgt_lang":"vi","translated":"Không đạt","updated_at":"2026-07-10T23:12:51.409Z"}
|
||||
{"cache_key":"f0785f703c03bed46e9c527ed4bb3fc10e6a52d97b50e7798a3b7b0f004c40f0","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.contextUsage.summary","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Session context usage: {used} of {limit} ({pct}%)","text_hash":"a62b97af0e5d02b8722725e2be0a936dd3d317a1f506ea15c766e87413b66a0d","tgt_lang":"vi","translated":"Mức sử dụng ngữ cảnh phiên: {used} trên {limit} ({pct}%)","updated_at":"2026-07-05T10:16:30.856Z"}
|
||||
{"cache_key":"f09884057acf2d5b752e060c3b375b8c9a704f7e20afa6b848889bec8be4fdf2","model":"gpt-5.5","provider":"openai","segment_id":"quickSettings.appearance.lobsterVisits","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Lobster visits","text_hash":"2183e8775ad3fccd8444a132501f24b35dd091741e1c168f24e29bbc57d7b77f","tgt_lang":"vi","translated":"Lượt ghé thăm của tôm hùm","updated_at":"2026-07-09T20:51:54.489Z"}
|
||||
{"cache_key":"f1cb31dfc11a41215c72f477a3ec2b14d519538e6d1da53b28a7b9b1b518dadf","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"vi","translated":"Đã hết hạn","updated_at":"2026-07-01T10:33:49.015Z"}
|
||||
{"cache_key":"f1df5c00c16ef8ec3d78ecad6fb241793dd55659051ca599750271bb31f0bf9c","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotatePrompt.elementDetail","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Marked element (page-reported): {descriptor} — {width}×{height}px at ({x}, {y}).","text_hash":"26f6a06bb620377485f379992db59e348653f7dd09db7ebbad9984c6da3c1d37","tgt_lang":"vi","translated":"Phần tử được đánh dấu (do trang báo cáo): {descriptor} — {width}×{height}px tại ({x}, {y}).","updated_at":"2026-07-11T02:20:00.545Z"}
|
||||
{"cache_key":"f29195f82027c10ec1df708d4f4b17b8dde21c22aa29c56824ab600c40a660ea","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotateClear","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Clear","text_hash":"83b12c2216efb4fdc924e1deb5182e905e4926ed0c1c324d467107f46d5a26a9","tgt_lang":"vi","translated":"Xóa","updated_at":"2026-07-11T02:19:55.107Z"}
|
||||
{"cache_key":"f36baee0510040170d069424eab336323790dca6c6559d8b75da263ba1fd3788","model":"gpt-5.5","provider":"openai","segment_id":"newSession.gateway","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Gateway · local","text_hash":"b82bf739d73b54a7ac3596fdf9bb9255573ce18675dda095cae645493b62df8f","tgt_lang":"vi","translated":"Gateway · cục bộ","updated_at":"2026-07-10T15:21:50.803Z"}
|
||||
|
||||
Generated
+3
@@ -77,6 +77,7 @@
|
||||
{"cache_key":"1fffa62e28ef665352adaf10cf53c278f17a5ba16a67f724b060e56128f45a5a","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.ownerWorkboard","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Workboard","text_hash":"48d4659e64e383e94d3bc3badcf8e6e8c162ada4e5254958994531748fd7ab3b","tgt_lang":"zh-CN","translated":"Workboard","updated_at":"2026-07-10T17:58:34.409Z"}
|
||||
{"cache_key":"208319c5fc26d80f7af2d918c6d4059b61b9cee09602fcae24bfba9a71d0b133","model":"claude-opus-4-8","provider":"anthropic","segment_id":"claudeSessions.sessionId","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Session","text_hash":"6959b4159575d8dd76d9f3bbe2c6437904f861e7860c35abd18deffb1c3425a0","tgt_lang":"zh-CN","translated":"会话","updated_at":"2026-06-16T14:13:07.632Z"}
|
||||
{"cache_key":"212414f51f44d0f39bac5f98dfe26faaf7aa176007948a1831495eb9dbb97511","model":"gpt-5.5","provider":"openai","segment_id":"chat.sidebar.sortUpdated","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Last updated","text_hash":"382ac5f308f76c24b2c981e2041943bc2be2229cbd285ad362b9af1cfc386ef8","tgt_lang":"zh-CN","translated":"最近更新","updated_at":"2026-07-06T15:07:02.499Z"}
|
||||
{"cache_key":"21851d39af4ed0bc939f12152163a018e39b55192685692fe29274f0b7fcb0ce","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"zh-CN","translated":"命令","updated_at":"2026-06-16T14:13:09.659Z"}
|
||||
{"cache_key":"220cbb7d49cf01237c86668802c4727bde6d299091eac6ee6aba1a67e5daaded","model":"claude-opus-4-8","provider":"anthropic","segment_id":"newSession.browserUp","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Parent folder","text_hash":"158f5a01ef8cfb1e6d91f8c321dd3a63f5e457f9650eecd662857701762bd31d","tgt_lang":"zh-CN","translated":"上级文件夹","updated_at":"2026-06-16T14:13:07.632Z"}
|
||||
{"cache_key":"227028963ad8f220a4fdb38eaaf4f68ef7a0b48512784da6b9aacc253268422a","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.unpinSession","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Unpin session","text_hash":"f4c582ee4d7a87bf069d05a49bb0211759d3db8366daab4ba7024425961af5dc","tgt_lang":"zh-CN","translated":"取消置顶会话","updated_at":"2026-07-02T14:29:55.120Z"}
|
||||
{"cache_key":"2373bff203ca1ad410a396ce9c05d29c24a25dd24f151cd0fd7e87e920846a91","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.ageHours","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"{count}h","text_hash":"5828ef1c1e95e0bae1c98548d1795a2482cc8e14a8b161b183960a06018ce10d","tgt_lang":"zh-CN","translated":"{count}小时","updated_at":"2026-06-17T14:13:17.789Z"}
|
||||
@@ -110,6 +111,7 @@
|
||||
{"cache_key":"33cbcaf5ef5aa72175cb0353f92e1d6bf748f859c75dc7a955e37dd42fd2c9d4","model":"gpt-5.5","provider":"openai","segment_id":"browser.toggle","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Toggle browser panel","text_hash":"cfd0e6c787d9b0fd9341c1bc377dca3a0987588b1fdb68ef23b5d0ce3bced9bc","tgt_lang":"zh-CN","translated":"切换浏览器面板","updated_at":"2026-07-11T02:17:12.867Z"}
|
||||
{"cache_key":"359fb4a263cb3e67b4a9144cf2753f391e6a747b5ac4cfd633ebf5846f6830da","model":"gpt-5","provider":"openai","segment_id":"codexSessions.empty.search","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"No sessions on this host match your search.","text_hash":"53e8e235da1a4490f8514580987af37d3693f5232882f414ce75de09cd4203f9","tgt_lang":"zh-CN","translated":"此主机上没有符合搜索条件的会话。","updated_at":"2026-07-09T10:01:43.701Z"}
|
||||
{"cache_key":"360b0866ae1b9ecad382bd2137c6c4ad2a99223f5aec4e35a366d588fcc7763f","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkAdvancedSettingsRequiresAdminTitle","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Advanced Talk settings require operator.admin access.","text_hash":"fa933a90d7dde5f8f1a324bd13a5daceb0ad9e04bd77f3aae07c8348edfe4dd7","tgt_lang":"zh-CN","translated":"高级 Talk 设置需要 operator.admin 权限。","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"36162987d5a8d860c4033ad6f039b456b4ac675586956a1cd61bf9eac22a502d","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"zh-CN","translated":"已过期","updated_at":"2026-07-01T10:31:03.966Z"}
|
||||
{"cache_key":"3677bed853588daf85c0d78524252651752cdbf295c46b6c963b9e1ce88e5a99","model":"gpt-5.5","provider":"openai","segment_id":"browser.openExternal","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Open in your browser","text_hash":"75b8439f0d30a51b884ea0cc7921161b73c3e8ceedb0968e21ceb0ccdd6f2fe1","tgt_lang":"zh-CN","translated":"在浏览器中打开","updated_at":"2026-07-11T02:17:12.867Z"}
|
||||
{"cache_key":"3699fb5fd71dbeaad1a9246eb96f66f3b19dea75d82e40c5aef32ca031f89673","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.title","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Managed Worktrees","text_hash":"dde32010185098a47e873fb25dd99446b0cb1a75614068587f7cd0bffb5aed18","tgt_lang":"zh-CN","translated":"托管的 Worktrees","updated_at":"2026-07-05T21:00:21.876Z"}
|
||||
{"cache_key":"36b9bcffa47d27701243a67910643209b76a5a53024d0d5ff1966e65878f6980","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.label","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Background tasks","text_hash":"c6907e94a3b7ea1b0e9cb7bb3c674bbaddb0216cab132a2bfa63507afebbc888","tgt_lang":"zh-CN","translated":"后台任务","updated_at":"2026-07-11T00:44:51.874Z"}
|
||||
@@ -464,6 +466,7 @@
|
||||
{"cache_key":"eac61937cea7a2fe57800d170b6ab7197de171e9e8ee3d6183cdf0e46a9b3b32","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.read","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Read","text_hash":"9b9a8d05a7ec353bda84f9c1bb3178c299de3001b5e970508ddc889c487f92ca","tgt_lang":"zh-CN","translated":"已读取","updated_at":"2026-06-16T14:13:07.632Z"}
|
||||
{"cache_key":"eb155d95bed3eb834fb5dee4e36b763fc1586f8909b56c9ceb8f1d0e2e100852","model":"gpt-5.5","provider":"openai","segment_id":"claudeSessions.transcript.back","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"All Claude sessions","text_hash":"aa40fc035a7a4bc4b6ca03a1411bcca398a1ee0db9f297eb058d0417b24f06de","tgt_lang":"zh-CN","translated":"所有 Claude 会话","updated_at":"2026-07-11T13:50:09.084Z"}
|
||||
{"cache_key":"eb32ae7ce4880969ff25232ca2acf2e30071a28b4f6c9cc1d4f1c7662d349cf0","model":"gpt-5.5","provider":"openai","segment_id":"browser.inspectRole","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Role","text_hash":"14736a2eb9f4159f4b6b86f192c3c222243fd9659aadf2ecc0139e3d72bed85c","tgt_lang":"zh-CN","translated":"角色","updated_at":"2026-07-11T02:17:17.686Z"}
|
||||
{"cache_key":"eb722f5115ed59b404ca64aff1c819e80674ac0e885e7fd0f7547eab8185e2bd","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"zh-CN","translated":"节点","updated_at":"2026-07-09T10:01:43.701Z"}
|
||||
{"cache_key":"ebaf9090107b70d4a8b61f74ce099cfbab2fcd92d3ce26ca5725fb0c1d4dfa84","model":"gpt-5.5","provider":"openai","segment_id":"chat.backgroundTasks.show","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Show background tasks","text_hash":"7cce70ac350d780017a5a7f109b28cbe69f5a1c7bfc92d1c1d9479f402ab8bdf","tgt_lang":"zh-CN","translated":"显示后台任务","updated_at":"2026-07-11T00:44:51.874Z"}
|
||||
{"cache_key":"ebc14d806ffb940059a46d54f2887abc2241d2dc895bb984514efd3518057dfd","model":"gpt-5.5","provider":"openai","segment_id":"codexSessions.sidebar.unavailable","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Codex sessions unavailable","text_hash":"9d3177daebe3a0d81438f5a085018560a547616392838a73aa9ddc6c3e8d6a40","tgt_lang":"zh-CN","translated":"Codex 会话不可用","updated_at":"2026-07-11T10:24:38.322Z"}
|
||||
{"cache_key":"ec6682e3ecd3bcc1f085ec0d07ee40f2d5bb89e2c9170a284f1944b16a62ddac","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.standupGhostwriter.tagline","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Your standup update, drafted from yesterday's work.","text_hash":"23ce2b22c8aff730b9b9c43dd92f4b16e39b4bab36bb09452a45a8238475ccf3","tgt_lang":"zh-CN","translated":"根据昨天的工作自动起草站会更新。","updated_at":"2026-07-11T22:44:10.578Z"}
|
||||
|
||||
Generated
+4
@@ -73,6 +73,7 @@
|
||||
{"cache_key":"22a508372058bca1f104bb6f765599709737e3c6812b941c52e9d22a7dbc4902","model":"gpt-5","provider":"openai","segment_id":"codexSessions.eyebrow","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Codex fleet","text_hash":"64e0510e4f9e07ad1283b7c1d55e67b5b853081b6ca4013fc8d710aa658d5127","tgt_lang":"zh-TW","translated":"Codex 裝置群","updated_at":"2026-07-09T10:01:43.713Z"}
|
||||
{"cache_key":"22cf25f084a4fd49a8297e023cf52a839327c3812d4870c9119745b13cd9a90d","model":"gpt-5.5","provider":"openai","segment_id":"palette.categories.search","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Search","text_hash":"49c266baaaa70981ea188fa714d5c40cf13830d786a861c9943ae0d26a7f3fe9","tgt_lang":"zh-TW","translated":"搜尋","updated_at":"2026-07-10T06:07:42.888Z"}
|
||||
{"cache_key":"239830e854cd40a1a174c34d37efde05b8b2c8a469068a0771ea117cf4642af6","model":"gpt-5.5","provider":"openai","segment_id":"workboard.eventAttachmentAdded","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Attachment added","text_hash":"f39a309fb0054d8e6c512733d6f3a4791c6b63157a388d72f635574d98b49b3e","tgt_lang":"zh-TW","translated":"已新增附件","updated_at":"2026-05-30T15:38:05.607Z"}
|
||||
{"cache_key":"24578c23dc9b784ebf7cb4a721aa8a4cec82aa61428fe48b98afa869eac5e7da","model":"gpt-5.5","provider":"openai","segment_id":"approvalPage.cancelled","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Cancelled","text_hash":"d353a99eb4556847ceeb3c306ac886cf6b4fa13043eb1864b9aeb0607fd5f2cc","tgt_lang":"zh-TW","translated":"已取消","updated_at":"2026-07-06T08:41:48.829Z"}
|
||||
{"cache_key":"245cfff3be1aeb0f46e10b44e468ed0fa52223c0e8148946aeb86dfa04c787f7","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkMoreInSettings","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"More in Settings","text_hash":"87f1e602d68bdc42ae3fddc0c1541d323adc718b7b9b3f889b2ca71823e319b9","tgt_lang":"zh-TW","translated":"設定中的更多選項","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"246bfe07ee9295208d03e36bf4aba3e40a6d21d2ac69af28ccfcdb3420b4a6b3","model":"gpt-5.5","provider":"openai","segment_id":"tasksPage.agent","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Agent: {agent}","text_hash":"b0a224d2a72b2aa43d4e0a1ffa0523c8c5da621a16408810fcb0385da86054a4","tgt_lang":"zh-TW","translated":"代理:{agent}","updated_at":"2026-07-06T08:41:46.878Z"}
|
||||
{"cache_key":"24df645d4c79511608a0f351c94278c46b7279c8a688cf8d35ffd2da80293d34","model":"gpt-5.5","provider":"openai","segment_id":"quickSettings.appearance.lobsterSoundsOn","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Tiny blubs when touched","text_hash":"35af4a22855e8564a6e31d589281759ff7f7d8b01e84b8d732d5466575b808db","tgt_lang":"zh-TW","translated":"觸碰時發出小小的咕嚕聲","updated_at":"2026-07-10T04:49:49.836Z"}
|
||||
@@ -274,6 +275,7 @@
|
||||
{"cache_key":"7bb6dcd8a9e8181be6623fdcebb87b38c6832df7f956e43f3fc3257767fb399c","model":"claude-sonnet-4-6","provider":"anthropic","segment_id":"cron.suggestions.ideas.hackerNewsScout.tagline","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Three links worth your coffee, with hot takes.","text_hash":"922d22c3e5d733801932294931d820adb4dae9b35ddf8651388152ea85b62d6f","tgt_lang":"zh-TW","translated":"三個值得配咖啡閱讀的連結,附上犀利短評。","updated_at":"2026-07-11T22:44:25.724Z"}
|
||||
{"cache_key":"7bf02dd8146f15240036f48e0562270bfbdc827fe428c82094945a740043fb80","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.workspaceFiles.noBrowserFiles","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"No files in this folder.","text_hash":"3847020c79b1c74e28aa550f0ae53838b764e87f1daf1480dd6aae45ae0529d6","tgt_lang":"zh-TW","translated":"此資料夾沒有檔案。","updated_at":"2026-06-16T14:13:16.738Z"}
|
||||
{"cache_key":"7c3a1ccdce05c71f2e7debb6cf500e221a601706bcfe4030e128e5b23d5f0b0f","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailUpdated","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Updated","text_hash":"3a5ecca188c0579c00ee24cf3cab21bd02c15a06f7a70cc8e0a8ff2381dcbbfd","tgt_lang":"zh-TW","translated":"已更新","updated_at":"2026-06-16T14:12:59.400Z"}
|
||||
{"cache_key":"7c83dc096fb5edeed6a73eed9932345353908a52ab8fbcfd647d58c531fded52","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.commandLabel","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Command","text_hash":"713166971d730f81fcf8b757f2ea239d1a0360d9f74e8f5afe60fba97105879c","tgt_lang":"zh-TW","translated":"指令","updated_at":"2026-06-16T14:13:18.599Z"}
|
||||
{"cache_key":"7d04aba9a0d017c59e00efe0c3b798bb4b9bad33fdc6c863c812ea4b75100460","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.archivedOnly","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Archived only","text_hash":"da7ebd8c482f38dc2a5b693a0ec25aaa04ea7b5fa3713cce9fa41a28f2201a6b","tgt_lang":"zh-TW","translated":"僅已封存","updated_at":"2026-07-02T14:29:59.019Z"}
|
||||
{"cache_key":"7d5637373e8298215396144198e43b0804ec1a8b7bda2483bd25c08f95f37ac6","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.title","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Managed Worktrees","text_hash":"dde32010185098a47e873fb25dd99446b0cb1a75614068587f7cd0bffb5aed18","tgt_lang":"zh-TW","translated":"受管理的 Worktrees","updated_at":"2026-07-05T21:00:31.397Z"}
|
||||
{"cache_key":"7d6da732fa7844908764c04ab695d2d41886031fea93b23089692ce356c625ba","model":"gpt-5","provider":"openai","segment_id":"codexSessions.empty.title","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"No Codex hosts found","text_hash":"aaad17f2d1d59a936c7882613d1eb75ad6e82d0e82ec79837a587a43352ce24e","tgt_lang":"zh-TW","translated":"找不到 Codex 主機","updated_at":"2026-07-09T10:01:43.713Z"}
|
||||
@@ -336,6 +338,7 @@
|
||||
{"cache_key":"96ad0f185af324a32149f91259382d31650fd814bc371788227dfd0f0ad80a38","model":"gpt-5.5","provider":"openai","segment_id":"nativeLinkMenu.openInline","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Open in Sidebar","text_hash":"ee39dc2999ce3acefff3c4c5440266e6a044feb3fb0a405a754f3ee4f697b201","tgt_lang":"zh-TW","translated":"在側邊欄開啟","updated_at":"2026-07-09T11:02:38.494Z"}
|
||||
{"cache_key":"96c905bd13add9b967968ffb872acaa82316a2ebe6d958a6c606ba67f7c87d83","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.archivedOnlyTooltip","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Show only archived sessions.","text_hash":"de4c6803e169c7f2d3116da6fa5b95417d952edf88f69b0b279d5d17e9e34e87","tgt_lang":"zh-TW","translated":"僅顯示已封存的工作階段。","updated_at":"2026-07-02T14:29:59.019Z"}
|
||||
{"cache_key":"971f9cdf8108eb62348e40417fd50f4b6e10b9a0d2090ca408506693b0f6a66e","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.renameSession","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Rename session","text_hash":"2cad0766accc2d3f70f007068524cea983e0d53f54543e9e82a4e73b2a07987f","tgt_lang":"zh-TW","translated":"重新命名工作階段","updated_at":"2026-07-02T14:29:59.020Z"}
|
||||
{"cache_key":"97273603db75534ee5080c7e10986ff97bb4e70730623d8f065a60de63c7681f","model":"gpt-5","provider":"openai","segment_id":"approvalPage.nodeLabel","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Node","text_hash":"e93372533f323b2f12783aa3a586135cf421486439c2cdcde47411b78f9839ec","tgt_lang":"zh-TW","translated":"節點","updated_at":"2026-07-09T10:01:43.713Z"}
|
||||
{"cache_key":"9784e5110dbefeea71d94133c7adb392cbe58d39fcb6ef4208822bc83333724d","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.merged","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Merged","text_hash":"bd0a06202c440a9ee86f50165aa66886259d89c3d219e2ef47a759cde6a38c00","tgt_lang":"zh-TW","translated":"已合併","updated_at":"2026-07-10T17:03:35.847Z"}
|
||||
{"cache_key":"97d8d4ba305f4779d5497b6f599003a9b8d6b4fe38f3330f146043bcefc5e8fb","model":"claude-opus-4-8","provider":"anthropic","segment_id":"chat.composer.talkSensitivityHigh","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"High","text_hash":"c4ebc6d4a5832cd9415f906ad03661110c705a72381c8b8b145761d02e2dd23a","tgt_lang":"zh-TW","translated":"高","updated_at":"2026-07-06T20:20:02.809Z"}
|
||||
{"cache_key":"987e79a166a2b686b309f13f4b5205438859562a799dd44a3e599d269a1fa0d0","model":"claude-opus-4-8","provider":"anthropic","segment_id":"workboard.detailAutomationWorkspace","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Workspace: {workspace}","text_hash":"17f5e696e557a646a9003fc8448f6f6761f5fe6bdf7478f750f471496e87c17b","tgt_lang":"zh-TW","translated":"工作區:{workspace}","updated_at":"2026-06-16T14:12:59.400Z"}
|
||||
@@ -464,6 +467,7 @@
|
||||
{"cache_key":"c99336cf7f69441afe34b9c22bf75dac517f09c6c350669dd215e710ab2de75f","model":"gpt-5.5","provider":"openai","segment_id":"browser.annotateHint","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Draw on the page, then send the markup to your chat.","text_hash":"6b604a858370bb1157c88694d2211aa61c1305d24a01ace6b551fcf465b0ee0d","tgt_lang":"zh-TW","translated":"在頁面上繪製,然後將標記傳送到你的聊天。","updated_at":"2026-07-11T02:17:28.017Z"}
|
||||
{"cache_key":"ca246986b2093ebd4aa148f4d721cde75add683fd993dcb1292662f3f566ed69","model":"gpt-5.5","provider":"openai","segment_id":"chat.pullRequests.open","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Open","text_hash":"ed077f3d8125d60dca1979c7133601bd187d47c73ed9975028f677e49e709942","tgt_lang":"zh-TW","translated":"開啟","updated_at":"2026-07-10T17:03:35.847Z"}
|
||||
{"cache_key":"ca7ad66b2d95356baadb06d6ea27654e57cfbb7e5629fbdb229e07b50515f1fc","model":"gpt-5.5","provider":"openai","segment_id":"chat.composer.microphoneBusy","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Microphone inputs are busy or unavailable to the browser.","text_hash":"9f33c30cb2370916f2edd079ad5cabab6a94dd185a89f4f7db357b4f31d1f3dd","tgt_lang":"zh-TW","translated":"麥克風輸入正忙碌或無法供瀏覽器使用。","updated_at":"2026-07-06T17:56:07.837Z"}
|
||||
{"cache_key":"ca96a059e33c4c17b0291668c7c82a8f8b1aad2dc8f354a0b95dd3755ee96d39","model":"claude-opus-4-8","provider":"anthropic","segment_id":"approvalPage.expired","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Expired","text_hash":"424a2551d356754c882d04ac16c63e6b50b80b159549d23231001f629455756e","tgt_lang":"zh-TW","translated":"已過期","updated_at":"2026-07-01T10:30:56.042Z"}
|
||||
{"cache_key":"ca9adde6fc13d0029370766c3bc831523fc1acb907bb574167caba7ffdb0135f","model":"gpt-5.5","provider":"openai","segment_id":"worktrees.restorable","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Restorable","text_hash":"bc97d2ddd2dba3ab2391f21314316556111065c4b870bc05679fadd60a754c01","tgt_lang":"zh-TW","translated":"可還原","updated_at":"2026-07-05T21:00:31.397Z"}
|
||||
{"cache_key":"cadbd6c0f3ed17cb5e3ac5fcdf6350932ca86aabc82315c087a480b6448c4619","model":"gpt-5.5","provider":"openai","segment_id":"chat.welcome.recentSessions","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Recent chats","text_hash":"2ccfecbca1011bad772fce00fa6479c9af2d398ce3b3951b7713b2655b6999eb","tgt_lang":"zh-TW","translated":"最近的聊天","updated_at":"2026-07-11T08:43:03.135Z"}
|
||||
{"cache_key":"cb2b0bc90ea5076a8a866950cf6078247cf81320d052de94542f196b115c0dc5","model":"gpt-5.5","provider":"openai","segment_id":"chat.sessionDiff.truncatedResult","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Some changes were omitted because the diff is very large.","text_hash":"1c0564ef3281e6e1c551539688c40190bb2124fa83bd3ff896c6fed8d4537d8d","tgt_lang":"zh-TW","translated":"由於 diff 非常大,部分變更已省略。","updated_at":"2026-07-11T04:52:33.969Z"}
|
||||
|
||||
Generated
+41
@@ -513,6 +513,47 @@ export const ar: TranslationMap = {
|
||||
plugin: "المكوّن الإضافي",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "منتهي الصلاحية",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "الأمر",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "عقدة",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "متصل: {id}",
|
||||
connected: "متصل",
|
||||
|
||||
Generated
+41
@@ -518,6 +518,47 @@ export const de: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Abgelaufen",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Befehl",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Knoten",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Verbunden: {id}",
|
||||
connected: "Verbunden",
|
||||
|
||||
@@ -512,6 +512,47 @@ export const en: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Expired",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Command",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Node",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Connected: {id}",
|
||||
connected: "Connected",
|
||||
|
||||
Generated
+41
@@ -515,6 +515,47 @@ export const es: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Caducado",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Comando",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Nodo",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Conectado: {id}",
|
||||
connected: "Conectado",
|
||||
|
||||
Generated
+41
@@ -515,6 +515,47 @@ export const fa: TranslationMap = {
|
||||
plugin: "افزونه",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "منقضیشده",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "دستور",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "گره",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "متصل: {id}",
|
||||
connected: "متصل",
|
||||
|
||||
Generated
+41
@@ -521,6 +521,47 @@ export const fr: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Expiré",
|
||||
cancelled: "Annulé",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Commande",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Nœud",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Connecté : {id}",
|
||||
connected: "Connecté",
|
||||
|
||||
Generated
+41
@@ -514,6 +514,47 @@ export const hi: TranslationMap = {
|
||||
plugin: "प्लगइन",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "पुनः प्रयास करें",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "समाप्त",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Command",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "नोड",
|
||||
toolLabel: "टूल",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "समाधानित",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "कनेक्टेड: {id}",
|
||||
connected: "कनेक्टेड",
|
||||
|
||||
Generated
+41
@@ -515,6 +515,47 @@ export const id: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Kedaluwarsa",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Perintah",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Node",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Terhubung: {id}",
|
||||
connected: "Terhubung",
|
||||
|
||||
Generated
+41
@@ -520,6 +520,47 @@ export const it: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Scaduto",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Comando",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Nodo",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Connesso: {id}",
|
||||
connected: "Connesso",
|
||||
|
||||
Generated
+41
@@ -520,6 +520,47 @@ export const ja_JP: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "期限切れ",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "コマンド",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "ノード",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "接続済み: {id}",
|
||||
connected: "接続済み",
|
||||
|
||||
Generated
+41
@@ -513,6 +513,47 @@ export const ko: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "만료됨",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "명령",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "노드",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "연결됨: {id}",
|
||||
connected: "연결됨",
|
||||
|
||||
Generated
+41
@@ -518,6 +518,47 @@ export const nl: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Verlopen",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Opdracht",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Node",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Verbonden: {id}",
|
||||
connected: "Verbonden",
|
||||
|
||||
Generated
+41
@@ -516,6 +516,47 @@ export const pl: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Wygasł",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Polecenie",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Węzeł",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Połączono: {id}",
|
||||
connected: "Połączono",
|
||||
|
||||
Generated
+41
@@ -514,6 +514,47 @@ export const pt_BR: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Expirado",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Comando",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Nó",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Conectado: {id}",
|
||||
connected: "Conectado",
|
||||
|
||||
Generated
+41
@@ -519,6 +519,47 @@ export const ru: TranslationMap = {
|
||||
plugin: "Плагин",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Повторить",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Истек",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Команда",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Узел",
|
||||
toolLabel: "Инструмент",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Разрешено",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Подключено: {id}",
|
||||
connected: "Подключено",
|
||||
|
||||
Generated
+41
@@ -512,6 +512,47 @@ export const th: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "หมดอายุ",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "คำสั่ง",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "โหนด",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "เชื่อมต่อแล้ว: {id}",
|
||||
connected: "เชื่อมต่อแล้ว",
|
||||
|
||||
Generated
+41
@@ -518,6 +518,47 @@ export const tr: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Süresi doldu",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Komut",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Düğüm",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Bağlı: {id}",
|
||||
connected: "Bağlandı",
|
||||
|
||||
Generated
+41
@@ -515,6 +515,47 @@ export const uk: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Застарів",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Команда",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Вузол",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Підключено: {id}",
|
||||
connected: "Підключено",
|
||||
|
||||
Generated
+41
@@ -514,6 +514,47 @@ export const vi: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "Đã hết hạn",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "Lệnh",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "Nút",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "Đã kết nối: {id}",
|
||||
connected: "Đã kết nối",
|
||||
|
||||
Generated
+41
@@ -512,6 +512,47 @@ export const zh_CN: TranslationMap = {
|
||||
plugin: "插件",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "已过期",
|
||||
cancelled: "Cancelled",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "命令",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "节点",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "已连接:{id}",
|
||||
connected: "已连接",
|
||||
|
||||
Generated
+41
@@ -512,6 +512,47 @@ export const zh_TW: TranslationMap = {
|
||||
plugin: "Plugin",
|
||||
},
|
||||
},
|
||||
approvalPage: {
|
||||
brandName: "OpenClaw",
|
||||
eyebrow: "Operator approval",
|
||||
loadingTitle: "Loading approval",
|
||||
loadingDescription: "Checking the current approval state with the Gateway.",
|
||||
unavailableTitle: "Approval unavailable",
|
||||
unavailableDescription:
|
||||
"This approval could not be found or this device is not authorized to review it.",
|
||||
connectionErrorTitle: "Connection interrupted",
|
||||
connectionErrorDescription:
|
||||
"OpenClaw cannot confirm or record a decision while disconnected. Reconnect to check the current status.",
|
||||
retry: "Retry",
|
||||
execTitle: "Command approval",
|
||||
pending: "Waiting for your decision",
|
||||
pendingDescription: "Review the request carefully. The first answer from any surface wins.",
|
||||
approvedHere: "Approved here",
|
||||
deniedHere: "Denied here",
|
||||
resolvedElsewhere: "Resolved elsewhere",
|
||||
resolvedElsewhereDescription:
|
||||
"Another surface or an earlier attempt recorded the decision first.",
|
||||
approved: "Approved",
|
||||
denied: "Denied",
|
||||
expired: "已過期",
|
||||
cancelled: "已取消",
|
||||
allowedOnceDescription: "The operation was approved for this request only.",
|
||||
allowedAlwaysDescription: "The operation was approved with the always-allow decision.",
|
||||
deniedDescription: "The operation was denied and will not continue.",
|
||||
expiredDescription: "No decision arrived before the deadline, so the operation was denied.",
|
||||
cancelledDescription: "The requesting run ended before a decision could be used.",
|
||||
summaryLabel: "Summary",
|
||||
commandLabel: "指令",
|
||||
requestLabel: "Request details",
|
||||
nodeLabel: "節點",
|
||||
toolLabel: "Tool",
|
||||
expiresLabel: "Expires",
|
||||
resolvedLabel: "Resolved",
|
||||
actionsLabel: "Approval decisions",
|
||||
resolvingDecision: "Recording {decision}…",
|
||||
safeToClose: "The decision is recorded. You can close this page.",
|
||||
openControlUi: "Open Control UI",
|
||||
},
|
||||
agentTools: {
|
||||
connectedSource: "已連線:{id}",
|
||||
connected: "已連線",
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { ContextProvider } from "@lit/context";
|
||||
import { LitElement } from "lit";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type {
|
||||
AllowedApprovalSnapshot,
|
||||
ApprovalGetResult,
|
||||
ApprovalResolveResult,
|
||||
ExpiredApprovalSnapshot,
|
||||
PendingApprovalSnapshot,
|
||||
} from "../../../../packages/gateway-protocol/src/index.js";
|
||||
import type { GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
import type { ApplicationContext, ApplicationGatewaySnapshot } from "../../app/context.ts";
|
||||
import { applicationContext } from "../../app/context.ts";
|
||||
import { i18n } from "../../i18n/index.ts";
|
||||
import "./approval-page.ts";
|
||||
|
||||
const PROVIDER_ELEMENT_NAME = "test-approval-page-context-provider";
|
||||
|
||||
class ApprovalPageContextProvider extends LitElement {
|
||||
private readonly contextProvider = new ContextProvider(this, {
|
||||
context: applicationContext,
|
||||
});
|
||||
|
||||
setContext(context: ApplicationContext) {
|
||||
this.contextProvider.setValue(context);
|
||||
}
|
||||
}
|
||||
|
||||
if (!customElements.get(PROVIDER_ELEMENT_NAME)) {
|
||||
customElements.define(PROVIDER_ELEMENT_NAME, ApprovalPageContextProvider);
|
||||
}
|
||||
|
||||
type TestApprovalPage = HTMLElement & {
|
||||
approvalId: string;
|
||||
updateComplete: Promise<boolean>;
|
||||
};
|
||||
|
||||
function pendingApproval(
|
||||
overrides: Partial<PendingApprovalSnapshot> = {},
|
||||
): PendingApprovalSnapshot {
|
||||
return {
|
||||
id: "exec:approval-1",
|
||||
urlPath: "/approve/exec%3Aapproval-1",
|
||||
status: "pending",
|
||||
createdAtMs: 1_000,
|
||||
expiresAtMs: Date.now() + 60_000,
|
||||
presentation: {
|
||||
kind: "exec",
|
||||
commandText: "printf safe",
|
||||
commandPreview: "printf …",
|
||||
warningText: null,
|
||||
host: "gateway",
|
||||
nodeId: null,
|
||||
agentId: "main",
|
||||
allowedDecisions: ["allow-once", "deny"],
|
||||
},
|
||||
...overrides,
|
||||
} as PendingApprovalSnapshot;
|
||||
}
|
||||
|
||||
function allowedApproval(
|
||||
overrides: Partial<AllowedApprovalSnapshot> = {},
|
||||
): AllowedApprovalSnapshot {
|
||||
return {
|
||||
...pendingApproval(),
|
||||
status: "allowed",
|
||||
decision: "allow-once",
|
||||
reason: "user",
|
||||
resolvedAtMs: 2_000,
|
||||
...overrides,
|
||||
} as AllowedApprovalSnapshot;
|
||||
}
|
||||
|
||||
function expiredApproval(): ExpiredApprovalSnapshot {
|
||||
return {
|
||||
...pendingApproval(),
|
||||
status: "expired",
|
||||
reason: "timeout",
|
||||
resolvedAtMs: 2_000,
|
||||
} as ExpiredApprovalSnapshot;
|
||||
}
|
||||
|
||||
function createGateway(client: GatewayBrowserClient, connected = true) {
|
||||
let snapshot: ApplicationGatewaySnapshot = {
|
||||
client,
|
||||
connected,
|
||||
reconnecting: false,
|
||||
hello: null,
|
||||
assistantAgentId: "main",
|
||||
sessionKey: "main",
|
||||
lastError: null,
|
||||
lastErrorCode: null,
|
||||
};
|
||||
const listeners = new Set<(next: ApplicationGatewaySnapshot) => void>();
|
||||
const gateway = {
|
||||
get snapshot() {
|
||||
return snapshot;
|
||||
},
|
||||
subscribe(listener: (next: ApplicationGatewaySnapshot) => void) {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
},
|
||||
} as unknown as ApplicationContext["gateway"];
|
||||
return {
|
||||
gateway,
|
||||
update(patch: Partial<ApplicationGatewaySnapshot>) {
|
||||
snapshot = { ...snapshot, ...patch };
|
||||
for (const listener of listeners) {
|
||||
listener(snapshot);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createPage(params: {
|
||||
client: GatewayBrowserClient;
|
||||
connected?: boolean;
|
||||
id?: string;
|
||||
withBootFallback?: boolean;
|
||||
}) {
|
||||
const source = createGateway(params.client, params.connected);
|
||||
const provider = document.createElement(PROVIDER_ELEMENT_NAME) as ApprovalPageContextProvider;
|
||||
const page = document.createElement("openclaw-approval-page") as TestApprovalPage;
|
||||
provider.setContext({
|
||||
basePath: "",
|
||||
gateway: source.gateway,
|
||||
} as unknown as ApplicationContext);
|
||||
page.approvalId = params.id ?? "exec:approval-1";
|
||||
if (params.withBootFallback) {
|
||||
const fallback = document.createElement("main");
|
||||
fallback.className = "approval-page approval-page--booting";
|
||||
page.append(fallback);
|
||||
}
|
||||
provider.append(page);
|
||||
document.body.append(provider);
|
||||
return { page, source };
|
||||
}
|
||||
|
||||
async function settle(page: TestApprovalPage) {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
await page.updateComplete;
|
||||
}
|
||||
|
||||
let visibilityState: DocumentVisibilityState;
|
||||
|
||||
beforeEach(async () => {
|
||||
await i18n.setLocale("en");
|
||||
visibilityState = "visible";
|
||||
vi.spyOn(document, "visibilityState", "get").mockImplementation(() => visibilityState);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
document.body.replaceChildren();
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
await i18n.setLocale("en");
|
||||
});
|
||||
|
||||
describe("ApprovalPage", () => {
|
||||
it("replaces the host boot fallback instead of duplicating the page", async () => {
|
||||
const request = vi.fn(async () => ({ approval: pendingApproval() }));
|
||||
const { page } = createPage({
|
||||
client: { request } as unknown as GatewayBrowserClient,
|
||||
withBootFallback: true,
|
||||
});
|
||||
|
||||
await settle(page);
|
||||
|
||||
expect(page.querySelectorAll(".approval-page")).toHaveLength(1);
|
||||
expect(page.querySelector(".approval-page--booting")).toBeNull();
|
||||
});
|
||||
|
||||
it("loads a durable approval and sends a kind-bound resolution", async () => {
|
||||
const pending = pendingApproval();
|
||||
const terminal = allowedApproval();
|
||||
const request = vi.fn(async (method: string): Promise<unknown> => {
|
||||
if (method === "approval.get") {
|
||||
return { approval: pending } satisfies ApprovalGetResult;
|
||||
}
|
||||
return { applied: true, approval: terminal } satisfies ApprovalResolveResult;
|
||||
});
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
|
||||
await settle(page);
|
||||
|
||||
expect(request).toHaveBeenCalledWith("approval.get", { id: pending.id });
|
||||
expect(page.querySelector(".approval-page__status")?.textContent).toContain(
|
||||
"Waiting for your decision",
|
||||
);
|
||||
expect(page.querySelector(".approval-page__preview")?.textContent).toBe("printf safe");
|
||||
|
||||
(page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement).click();
|
||||
await settle(page);
|
||||
|
||||
expect(request).toHaveBeenCalledWith("approval.resolve", {
|
||||
id: pending.id,
|
||||
kind: "exec",
|
||||
decision: "allow-once",
|
||||
});
|
||||
expect(page.querySelector("h1")?.textContent).toBe("Approved here");
|
||||
expect(document.activeElement).toBe(page.querySelector("h1"));
|
||||
});
|
||||
|
||||
it("keeps the selected decision named while a resolution is in flight", async () => {
|
||||
let resolveRequest!: (result: ApprovalResolveResult) => void;
|
||||
const pending = pendingApproval();
|
||||
const request = vi.fn((method: string): Promise<unknown> => {
|
||||
if (method === "approval.get") {
|
||||
return Promise.resolve({ approval: pending } satisfies ApprovalGetResult);
|
||||
}
|
||||
return new Promise<ApprovalResolveResult>((resolve) => {
|
||||
resolveRequest = resolve;
|
||||
});
|
||||
});
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
await settle(page);
|
||||
|
||||
(page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement).click();
|
||||
await page.updateComplete;
|
||||
|
||||
const allowButton = page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement;
|
||||
const denyButton = page.querySelector('[data-decision="deny"]') as HTMLButtonElement;
|
||||
expect(allowButton.textContent?.trim()).toBe("Recording Allow once…");
|
||||
expect(denyButton.textContent?.trim()).toBe("Deny");
|
||||
expect(allowButton.disabled).toBe(true);
|
||||
expect(denyButton.disabled).toBe(true);
|
||||
|
||||
resolveRequest({ applied: true, approval: allowedApproval() });
|
||||
await settle(page);
|
||||
});
|
||||
|
||||
it("formats approval times with the selected Control UI locale", async () => {
|
||||
await i18n.setLocale("de");
|
||||
const approval = pendingApproval();
|
||||
const request = vi.fn(async () => ({ approval }) satisfies ApprovalGetResult);
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
|
||||
await settle(page);
|
||||
|
||||
const expected = new Intl.DateTimeFormat("de", {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
}).format(new Date(approval.expiresAtMs));
|
||||
expect(page.querySelector("time")?.textContent?.trim()).toBe(expected);
|
||||
});
|
||||
|
||||
it("shows the canonical winner when another surface resolves first", async () => {
|
||||
const pending = pendingApproval();
|
||||
const terminal = allowedApproval();
|
||||
const request = vi.fn(
|
||||
async (method: string): Promise<unknown> =>
|
||||
method === "approval.get"
|
||||
? ({ approval: pending } satisfies ApprovalGetResult)
|
||||
: ({ applied: false, approval: terminal } satisfies ApprovalResolveResult),
|
||||
);
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
await settle(page);
|
||||
|
||||
(page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement).click();
|
||||
await settle(page);
|
||||
|
||||
expect(page.querySelector("h1")?.textContent).toBe("Resolved elsewhere");
|
||||
expect(page.textContent).toContain("Another surface or an earlier attempt");
|
||||
});
|
||||
|
||||
it("renders a fail-closed timeout distinctly from another surface's decision", async () => {
|
||||
const pending = pendingApproval();
|
||||
const expired = expiredApproval();
|
||||
const request = vi.fn(
|
||||
async (method: string): Promise<unknown> =>
|
||||
method === "approval.get"
|
||||
? ({ approval: pending } satisfies ApprovalGetResult)
|
||||
: ({ applied: false, approval: expired } satisfies ApprovalResolveResult),
|
||||
);
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
await settle(page);
|
||||
|
||||
(page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement).click();
|
||||
await settle(page);
|
||||
|
||||
expect(page.querySelector("h1")?.textContent).toBe("Expired");
|
||||
expect(page.textContent).toContain("No decision arrived before the deadline");
|
||||
});
|
||||
|
||||
it("fails closed when the Gateway returns a malformed projection", async () => {
|
||||
const request = vi.fn(async () => ({ approval: { status: "pending" } }));
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
|
||||
await settle(page);
|
||||
|
||||
expect(page.querySelector("h1")?.textContent).toBe("Approval unavailable");
|
||||
expect(page.querySelectorAll("[data-decision]")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("reconciles canonical state when an applied result does not match the submitted decision", async () => {
|
||||
const pending = pendingApproval();
|
||||
const mismatched = allowedApproval();
|
||||
const canonical = expiredApproval();
|
||||
const request = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ approval: pending } satisfies ApprovalGetResult)
|
||||
.mockResolvedValueOnce({
|
||||
applied: true,
|
||||
approval: mismatched,
|
||||
} satisfies ApprovalResolveResult)
|
||||
.mockResolvedValueOnce({ approval: canonical } satisfies ApprovalGetResult);
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
await settle(page);
|
||||
|
||||
(page.querySelector('[data-decision="deny"]') as HTMLButtonElement).click();
|
||||
await settle(page);
|
||||
|
||||
expect(request).toHaveBeenCalledTimes(3);
|
||||
expect(page.querySelector("h1")?.textContent).toBe("Expired");
|
||||
expect(page.querySelectorAll("[data-decision]")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("ignores an older lookup after a same-client reconnect", async () => {
|
||||
let resolveFirst!: (value: ApprovalGetResult) => void;
|
||||
const first = new Promise<ApprovalGetResult>((resolve) => {
|
||||
resolveFirst = resolve;
|
||||
});
|
||||
const terminal = allowedApproval();
|
||||
const request = vi
|
||||
.fn()
|
||||
.mockImplementationOnce(() => first)
|
||||
.mockResolvedValue({ approval: terminal } satisfies ApprovalGetResult);
|
||||
const client = { request } as unknown as GatewayBrowserClient;
|
||||
const { page, source } = createPage({ client });
|
||||
await settle(page);
|
||||
|
||||
source.update({ connected: false, reconnecting: true });
|
||||
source.update({ connected: true, reconnecting: false });
|
||||
await settle(page);
|
||||
resolveFirst({ approval: pendingApproval() });
|
||||
await settle(page);
|
||||
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
expect(page.querySelector("h1")?.textContent).toBe("Approved");
|
||||
expect(page.querySelectorAll("[data-decision]")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("polls only while the pending document is visible", async () => {
|
||||
vi.useFakeTimers();
|
||||
const pending = pendingApproval({ expiresAtMs: Date.now() + 60_000 });
|
||||
const request = vi.fn(async () => ({ approval: pending }) satisfies ApprovalGetResult);
|
||||
const { page } = createPage({ client: { request } as unknown as GatewayBrowserClient });
|
||||
await settle(page);
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(2_000);
|
||||
await settle(page);
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
|
||||
visibilityState = "hidden";
|
||||
document.dispatchEvent(new Event("visibilitychange"));
|
||||
await vi.advanceTimersByTimeAsync(4_000);
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
|
||||
visibilityState = "visible";
|
||||
document.dispatchEvent(new Event("visibilitychange"));
|
||||
await settle(page);
|
||||
expect(request).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("keeps one connection alert and disabled decisions across failed background polls", async () => {
|
||||
vi.useFakeTimers();
|
||||
const pending = pendingApproval({ expiresAtMs: Date.now() + 60_000 });
|
||||
const request = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ approval: pending } satisfies ApprovalGetResult)
|
||||
.mockRejectedValue(new Error("temporary Gateway failure"));
|
||||
const { page } = createPage({
|
||||
client: { request } as unknown as GatewayBrowserClient,
|
||||
});
|
||||
await settle(page);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(2_000);
|
||||
await settle(page);
|
||||
const alert = page.querySelector(".approval-page__callout");
|
||||
expect(alert).not.toBeNull();
|
||||
expect((page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement).disabled).toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(2_000);
|
||||
await settle(page);
|
||||
expect(request).toHaveBeenCalledTimes(3);
|
||||
expect(page.querySelector(".approval-page__callout")).toBe(alert);
|
||||
});
|
||||
|
||||
it("keeps pending context but disables decisions during reconnect", async () => {
|
||||
const pending = pendingApproval();
|
||||
const request = vi.fn(async () => ({ approval: pending }) satisfies ApprovalGetResult);
|
||||
const client = { request } as unknown as GatewayBrowserClient;
|
||||
const { page, source } = createPage({ client });
|
||||
await settle(page);
|
||||
|
||||
source.update({ connected: false, reconnecting: true });
|
||||
await page.updateComplete;
|
||||
|
||||
expect(page.querySelector(".approval-page__preview")?.textContent).toBe("printf safe");
|
||||
expect((page.querySelector('[data-decision="allow-once"]') as HTMLButtonElement).disabled).toBe(
|
||||
true,
|
||||
);
|
||||
expect(page.textContent).toContain("Connection interrupted");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,670 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { html, nothing, type PropertyValues } from "lit";
|
||||
import { property, state } from "lit/decorators.js";
|
||||
import {
|
||||
validateApprovalGetResult,
|
||||
validateApprovalResolveResult,
|
||||
type ApprovalDecision,
|
||||
type ApprovalGetResult,
|
||||
type ApprovalPresentation,
|
||||
type ApprovalResolveResult,
|
||||
type ApprovalSnapshot,
|
||||
} from "../../../../packages/gateway-protocol/src/index.js";
|
||||
import { GatewayRequestError, type GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
import type { RouteId } from "../../app-route-paths.ts";
|
||||
import {
|
||||
applicationContext,
|
||||
type ApplicationContext,
|
||||
type ApplicationGatewaySnapshot,
|
||||
} from "../../app/context.ts";
|
||||
import { controlUiPublicAssetPath } from "../../app/public-assets.ts";
|
||||
import { i18n, t } from "../../i18n/index.ts";
|
||||
import { OpenClawLightDomElement } from "../../lit/openclaw-element.ts";
|
||||
|
||||
const APPROVAL_POLL_INTERVAL_MS = 2_000;
|
||||
const APPROVAL_MIN_POLL_DELAY_MS = 250;
|
||||
|
||||
type ApprovalRequestError = "connection" | "unavailable" | null;
|
||||
type ResolutionOrigin = "here" | "elsewhere" | "observed";
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function isUnavailableApprovalError(error: unknown): boolean {
|
||||
if (!(error instanceof GatewayRequestError)) {
|
||||
return false;
|
||||
}
|
||||
const reason = isRecord(error.details) ? error.details.reason : undefined;
|
||||
return (
|
||||
reason === "APPROVAL_NOT_FOUND" ||
|
||||
error.gatewayCode === "APPROVAL_NOT_FOUND" ||
|
||||
error.gatewayCode === "INVALID_REQUEST"
|
||||
);
|
||||
}
|
||||
|
||||
function formatApprovalTime(timestampMs: number): string {
|
||||
return new Intl.DateTimeFormat(i18n.getLocale(), {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
}).format(new Date(timestampMs));
|
||||
}
|
||||
|
||||
function decisionLabel(decision: ApprovalDecision): string {
|
||||
switch (decision) {
|
||||
case "allow-once":
|
||||
return t("execApproval.allowOnce");
|
||||
case "allow-always":
|
||||
return t("execApproval.alwaysAllow");
|
||||
case "deny":
|
||||
return t("execApproval.deny");
|
||||
}
|
||||
const unreachable: never = decision;
|
||||
return unreachable;
|
||||
}
|
||||
|
||||
function appliedDecisionMatches(
|
||||
result: ApprovalResolveResult,
|
||||
decision: ApprovalDecision,
|
||||
): boolean {
|
||||
if (!result.applied) {
|
||||
return true;
|
||||
}
|
||||
return decision === "deny"
|
||||
? result.approval.status === "denied"
|
||||
: result.approval.status === "allowed" && result.approval.decision === decision;
|
||||
}
|
||||
|
||||
function renderMetaRow(label: string, value?: string | null) {
|
||||
return value
|
||||
? html`<div class="approval-page__meta-row">
|
||||
<dt>${label}</dt>
|
||||
<dd title=${value}><bdi dir="ltr">${value}</bdi></dd>
|
||||
</div>`
|
||||
: nothing;
|
||||
}
|
||||
|
||||
function renderPresentation(presentation: ApprovalPresentation) {
|
||||
if (presentation.kind === "exec") {
|
||||
return html`
|
||||
${presentation.warningText
|
||||
? html`<div class="approval-page__warning" role="note">${presentation.warningText}</div>`
|
||||
: nothing}
|
||||
${presentation.commandPreview
|
||||
? html`
|
||||
<div class="approval-page__preview-label">${t("approvalPage.summaryLabel")}</div>
|
||||
<div class="approval-page__summary mono" dir="ltr">${presentation.commandPreview}</div>
|
||||
`
|
||||
: nothing}
|
||||
<div class="approval-page__preview-label">${t("approvalPage.commandLabel")}</div>
|
||||
<pre class="approval-page__preview mono" dir="ltr">${presentation.commandText}</pre>
|
||||
<dl class="approval-page__meta">
|
||||
${renderMetaRow(t("execApproval.labels.host"), presentation.host)}
|
||||
${renderMetaRow(t("approvalPage.nodeLabel"), presentation.nodeId)}
|
||||
${renderMetaRow(t("execApproval.labels.agent"), presentation.agentId)}
|
||||
</dl>
|
||||
`;
|
||||
}
|
||||
const previewClass = "approval-page__preview approval-page__preview--prose";
|
||||
return html`
|
||||
<div class="approval-page__preview-label">${t("approvalPage.requestLabel")}</div>
|
||||
<div class=${previewClass}>${presentation.description}</div>
|
||||
<dl class="approval-page__meta">
|
||||
${renderMetaRow(t("execApproval.labels.severity"), presentation.severity)}
|
||||
${renderMetaRow(t("execApproval.labels.plugin"), presentation.pluginId)}
|
||||
${renderMetaRow(t("approvalPage.toolLabel"), presentation.toolName)}
|
||||
${renderMetaRow(t("execApproval.labels.agent"), presentation.agentId)}
|
||||
</dl>
|
||||
`;
|
||||
}
|
||||
|
||||
function terminalTitle(approval: ApprovalSnapshot, origin: ResolutionOrigin): string {
|
||||
if (origin === "elsewhere" && (approval.status === "allowed" || approval.status === "denied")) {
|
||||
return t("approvalPage.resolvedElsewhere");
|
||||
}
|
||||
if (origin === "here" && approval.status === "allowed") {
|
||||
return t("approvalPage.approvedHere");
|
||||
}
|
||||
if (origin === "here" && approval.status === "denied") {
|
||||
return t("approvalPage.deniedHere");
|
||||
}
|
||||
const status = approval.status;
|
||||
switch (status) {
|
||||
case "allowed":
|
||||
return t("approvalPage.approved");
|
||||
case "denied":
|
||||
return t("approvalPage.denied");
|
||||
case "expired":
|
||||
return t("approvalPage.expired");
|
||||
case "cancelled":
|
||||
return t("approvalPage.cancelled");
|
||||
case "pending":
|
||||
return t("approvalPage.pending");
|
||||
}
|
||||
const unreachable: never = status;
|
||||
return unreachable;
|
||||
}
|
||||
|
||||
function terminalDescription(approval: ApprovalSnapshot, origin: ResolutionOrigin): string {
|
||||
if (origin === "elsewhere" && (approval.status === "allowed" || approval.status === "denied")) {
|
||||
return t("approvalPage.resolvedElsewhereDescription");
|
||||
}
|
||||
const status = approval.status;
|
||||
switch (status) {
|
||||
case "allowed":
|
||||
return approval.decision === "allow-always"
|
||||
? t("approvalPage.allowedAlwaysDescription")
|
||||
: t("approvalPage.allowedOnceDescription");
|
||||
case "denied":
|
||||
return t("approvalPage.deniedDescription");
|
||||
case "expired":
|
||||
return t("approvalPage.expiredDescription");
|
||||
case "cancelled":
|
||||
return t("approvalPage.cancelledDescription");
|
||||
case "pending":
|
||||
return t("approvalPage.pendingDescription");
|
||||
}
|
||||
const unreachable: never = status;
|
||||
return unreachable;
|
||||
}
|
||||
|
||||
export class ApprovalPage extends OpenClawLightDomElement {
|
||||
@consume({ context: applicationContext, subscribe: false })
|
||||
context!: ApplicationContext<RouteId>;
|
||||
|
||||
@property({ attribute: "approval-id" }) approvalId = "";
|
||||
|
||||
@state() private approval: ApprovalSnapshot | null = null;
|
||||
@state() private connected = false;
|
||||
@state() private loading = true;
|
||||
@state() private resolving = false;
|
||||
@state() private resolvingDecision: ApprovalDecision | null = null;
|
||||
@state() private requestError: ApprovalRequestError = null;
|
||||
@state() private resolutionOrigin: ResolutionOrigin = "observed";
|
||||
|
||||
private client: GatewayBrowserClient | null = null;
|
||||
private operationGeneration = 0;
|
||||
private pollTimer: ReturnType<typeof globalThis.setTimeout> | undefined;
|
||||
private stopGateway: (() => void) | undefined;
|
||||
private boundApprovalId: string | undefined;
|
||||
private previousDocumentTitle: string | undefined;
|
||||
private activeDocumentTitle: string | undefined;
|
||||
|
||||
override connectedCallback() {
|
||||
// The host supplies a shellless loading fallback. Remove that unowned
|
||||
// light-DOM markup before Lit claims the root.
|
||||
this.replaceChildren();
|
||||
super.connectedCallback();
|
||||
document.addEventListener("visibilitychange", this.handleVisibilityChange);
|
||||
this.previousDocumentTitle = document.title;
|
||||
this.bindApprovalId(true);
|
||||
this.stopGateway = this.context.gateway.subscribe((snapshot) =>
|
||||
this.applyGatewaySnapshot(snapshot),
|
||||
);
|
||||
this.applyGatewaySnapshot(this.context.gateway.snapshot);
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
document.removeEventListener("visibilitychange", this.handleVisibilityChange);
|
||||
this.stopGateway?.();
|
||||
this.stopGateway = undefined;
|
||||
this.invalidateOperations();
|
||||
this.clearPollTimer();
|
||||
this.client = null;
|
||||
this.connected = false;
|
||||
if (
|
||||
this.previousDocumentTitle !== undefined &&
|
||||
(!this.activeDocumentTitle || document.title === this.activeDocumentTitle)
|
||||
) {
|
||||
document.title = this.previousDocumentTitle;
|
||||
}
|
||||
this.previousDocumentTitle = undefined;
|
||||
this.activeDocumentTitle = undefined;
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
protected override updated(changed: PropertyValues<this>) {
|
||||
if (changed.has("approvalId")) {
|
||||
this.bindApprovalId();
|
||||
}
|
||||
this.updateDocumentTitle();
|
||||
}
|
||||
|
||||
private bindApprovalId(force = false) {
|
||||
if (!force && this.boundApprovalId === this.approvalId) {
|
||||
return;
|
||||
}
|
||||
this.boundApprovalId = this.approvalId;
|
||||
this.invalidateOperations();
|
||||
this.clearPollTimer();
|
||||
this.approval = null;
|
||||
this.loading = Boolean(this.approvalId);
|
||||
this.resolving = false;
|
||||
this.resolvingDecision = null;
|
||||
this.requestError = this.approvalId ? null : "unavailable";
|
||||
this.resolutionOrigin = "observed";
|
||||
if (this.approvalId && this.connected && this.client) {
|
||||
void this.loadApproval();
|
||||
}
|
||||
}
|
||||
|
||||
private applyGatewaySnapshot(snapshot: ApplicationGatewaySnapshot) {
|
||||
const clientChanged = snapshot.client !== this.client;
|
||||
const connectionChanged = snapshot.connected !== this.connected;
|
||||
const becameConnected = snapshot.connected && !this.connected;
|
||||
this.client = snapshot.client;
|
||||
this.connected = snapshot.connected;
|
||||
if (clientChanged || connectionChanged) {
|
||||
this.invalidateOperations();
|
||||
this.clearPollTimer();
|
||||
this.resolving = false;
|
||||
this.resolvingDecision = null;
|
||||
}
|
||||
if (!snapshot.connected || !snapshot.client) {
|
||||
if (this.approvalId) {
|
||||
this.loading = false;
|
||||
this.requestError =
|
||||
!this.approval || this.approval.status === "pending" ? "connection" : null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this.approvalId) {
|
||||
this.loading = false;
|
||||
this.requestError = "unavailable";
|
||||
return;
|
||||
}
|
||||
if (clientChanged || becameConnected || !this.approval) {
|
||||
void this.loadApproval();
|
||||
return;
|
||||
}
|
||||
this.schedulePoll();
|
||||
}
|
||||
|
||||
private invalidateOperations() {
|
||||
this.operationGeneration += 1;
|
||||
}
|
||||
|
||||
private isCurrentOperation(params: {
|
||||
client: GatewayBrowserClient;
|
||||
generation: number;
|
||||
id: string;
|
||||
}): boolean {
|
||||
return (
|
||||
this.hasGatewayConnection &&
|
||||
this.client === params.client &&
|
||||
this.approvalId === params.id &&
|
||||
this.operationGeneration === params.generation
|
||||
);
|
||||
}
|
||||
|
||||
private get hasGatewayConnection(): boolean {
|
||||
return this.connected && Boolean(this.client);
|
||||
}
|
||||
|
||||
private async loadApproval(options: { background?: boolean } = {}) {
|
||||
const client = this.client;
|
||||
const id = this.approvalId;
|
||||
if (!client || !this.connected || !id) {
|
||||
return;
|
||||
}
|
||||
const generation = ++this.operationGeneration;
|
||||
const previousStatus = this.approval?.status;
|
||||
let shouldFocusTerminal = false;
|
||||
this.clearPollTimer();
|
||||
if (!options.background) {
|
||||
this.loading = true;
|
||||
}
|
||||
try {
|
||||
const result = await client.request<ApprovalGetResult>("approval.get", { id });
|
||||
if (!this.isCurrentOperation({ client, generation, id })) {
|
||||
return;
|
||||
}
|
||||
if (!validateApprovalGetResult(result) || result.approval.id !== id) {
|
||||
this.approval = null;
|
||||
this.requestError = "unavailable";
|
||||
return;
|
||||
}
|
||||
this.requestError = null;
|
||||
this.approval = result.approval;
|
||||
if (result.approval.status === "pending") {
|
||||
this.resolutionOrigin = "observed";
|
||||
} else if (previousStatus === "pending" && this.resolutionOrigin === "observed") {
|
||||
this.resolutionOrigin = "elsewhere";
|
||||
shouldFocusTerminal = true;
|
||||
}
|
||||
} catch (error) {
|
||||
if (!this.isCurrentOperation({ client, generation, id })) {
|
||||
return;
|
||||
}
|
||||
if (isUnavailableApprovalError(error)) {
|
||||
this.approval = null;
|
||||
this.requestError = "unavailable";
|
||||
} else {
|
||||
this.requestError = "connection";
|
||||
}
|
||||
} finally {
|
||||
if (this.isCurrentOperation({ client, generation, id })) {
|
||||
this.loading = false;
|
||||
this.schedulePoll();
|
||||
}
|
||||
}
|
||||
if (shouldFocusTerminal && this.isCurrentOperation({ client, generation, id })) {
|
||||
await this.focusTerminalState();
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveApproval(decision: ApprovalDecision) {
|
||||
const approval = this.approval;
|
||||
const client = this.client;
|
||||
const id = this.approvalId;
|
||||
if (
|
||||
!client ||
|
||||
!this.connected ||
|
||||
!id ||
|
||||
approval?.status !== "pending" ||
|
||||
!approval.presentation.allowedDecisions.includes(decision) ||
|
||||
this.resolving
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const kind = approval.presentation.kind;
|
||||
const generation = ++this.operationGeneration;
|
||||
let shouldFocusTerminal = false;
|
||||
let shouldRecoverCanonicalState = false;
|
||||
this.clearPollTimer();
|
||||
this.resolving = true;
|
||||
this.resolvingDecision = decision;
|
||||
this.requestError = null;
|
||||
try {
|
||||
const result = await client.request<ApprovalResolveResult>("approval.resolve", {
|
||||
id,
|
||||
kind,
|
||||
decision,
|
||||
});
|
||||
if (!this.isCurrentOperation({ client, generation, id })) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!validateApprovalResolveResult(result) ||
|
||||
result.approval.id !== id ||
|
||||
result.approval.presentation.kind !== kind ||
|
||||
!appliedDecisionMatches(result, decision)
|
||||
) {
|
||||
// The write outcome is unknown. Keep every decision disabled until a
|
||||
// fresh, strictly validated read establishes canonical Gateway truth.
|
||||
this.requestError = "connection";
|
||||
shouldRecoverCanonicalState = true;
|
||||
} else {
|
||||
this.approval = result.approval;
|
||||
this.resolutionOrigin = result.applied ? "here" : "elsewhere";
|
||||
shouldFocusTerminal = true;
|
||||
}
|
||||
} catch (error) {
|
||||
if (!this.isCurrentOperation({ client, generation, id })) {
|
||||
return;
|
||||
}
|
||||
this.requestError = isUnavailableApprovalError(error) ? "unavailable" : "connection";
|
||||
} finally {
|
||||
if (this.isCurrentOperation({ client, generation, id })) {
|
||||
this.resolving = false;
|
||||
this.resolvingDecision = null;
|
||||
this.schedulePoll();
|
||||
}
|
||||
}
|
||||
if (shouldRecoverCanonicalState && this.isCurrentOperation({ client, generation, id })) {
|
||||
await this.loadApproval({ background: true });
|
||||
return;
|
||||
}
|
||||
if (shouldFocusTerminal && this.isCurrentOperation({ client, generation, id })) {
|
||||
await this.focusTerminalState();
|
||||
}
|
||||
}
|
||||
|
||||
private async focusTerminalState() {
|
||||
await this.updateComplete;
|
||||
if (this.approval?.status === "pending") {
|
||||
return;
|
||||
}
|
||||
const heading = this.querySelector<HTMLElement>("#approval-page-title");
|
||||
heading?.focus({ preventScroll: true });
|
||||
if (typeof heading?.scrollIntoView === "function") {
|
||||
heading.scrollIntoView({ behavior: "auto", block: "center", inline: "nearest" });
|
||||
}
|
||||
}
|
||||
|
||||
private clearPollTimer() {
|
||||
if (this.pollTimer !== undefined) {
|
||||
globalThis.clearTimeout(this.pollTimer);
|
||||
this.pollTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private schedulePoll() {
|
||||
this.clearPollTimer();
|
||||
const approval = this.approval;
|
||||
if (
|
||||
!this.hasGatewayConnection ||
|
||||
this.resolving ||
|
||||
this.requestError === "unavailable" ||
|
||||
approval?.status !== "pending" ||
|
||||
document.visibilityState !== "visible"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const untilDeadline = approval.expiresAtMs - Date.now();
|
||||
const delay = Math.max(
|
||||
APPROVAL_MIN_POLL_DELAY_MS,
|
||||
Math.min(APPROVAL_POLL_INTERVAL_MS, untilDeadline + APPROVAL_MIN_POLL_DELAY_MS),
|
||||
);
|
||||
this.pollTimer = globalThis.setTimeout(() => {
|
||||
this.pollTimer = undefined;
|
||||
void this.loadApproval({ background: true });
|
||||
}, delay);
|
||||
}
|
||||
|
||||
private readonly handleVisibilityChange = () => {
|
||||
if (document.visibilityState !== "visible") {
|
||||
this.clearPollTimer();
|
||||
return;
|
||||
}
|
||||
if (this.approval?.status === "pending" && this.hasGatewayConnection && !this.resolving) {
|
||||
void this.loadApproval({ background: true });
|
||||
}
|
||||
};
|
||||
|
||||
private renderHeader() {
|
||||
return html`
|
||||
<header class="approval-page__brand">
|
||||
<img
|
||||
class="approval-page__logo"
|
||||
src=${controlUiPublicAssetPath("apple-touch-icon.png", this.context.basePath)}
|
||||
alt=""
|
||||
/>
|
||||
<div>
|
||||
<div class="approval-page__eyebrow">${t("approvalPage.eyebrow")}</div>
|
||||
<div class="approval-page__brand-name">${t("approvalPage.brandName")}</div>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderLoading() {
|
||||
return html`
|
||||
<div class="approval-page__state approval-page__state--loading" role="status">
|
||||
<div class="approval-page__spinner" aria-hidden="true"></div>
|
||||
<h1 id="approval-page-title">${t("approvalPage.loadingTitle")}</h1>
|
||||
<p>${t("approvalPage.loadingDescription")}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderUnavailable() {
|
||||
return html`
|
||||
<div class="approval-page__state approval-page__state--unavailable" role="alert">
|
||||
<div class="approval-page__state-mark" aria-hidden="true">!</div>
|
||||
<h1 id="approval-page-title">${t("approvalPage.unavailableTitle")}</h1>
|
||||
<p>${t("approvalPage.unavailableDescription")}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderConnectionState() {
|
||||
return html`
|
||||
<div class="approval-page__state approval-page__state--connection" role="alert">
|
||||
<div class="approval-page__state-mark" aria-hidden="true">!</div>
|
||||
<h1 id="approval-page-title">${t("approvalPage.connectionErrorTitle")}</h1>
|
||||
<p>${t("approvalPage.connectionErrorDescription")}</p>
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
?disabled=${!this.hasGatewayConnection || this.loading}
|
||||
@click=${() => void this.loadApproval()}
|
||||
>
|
||||
${t("approvalPage.retry")}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderConnectionError() {
|
||||
return html`
|
||||
<div class="approval-page__callout" role="alert">
|
||||
<div>
|
||||
<strong>${t("approvalPage.connectionErrorTitle")}</strong>
|
||||
<span>${t("approvalPage.connectionErrorDescription")}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn--sm"
|
||||
?disabled=${!this.hasGatewayConnection || this.loading}
|
||||
@click=${() => void this.loadApproval()}
|
||||
>
|
||||
${t("approvalPage.retry")}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderApproval(approval: ApprovalSnapshot) {
|
||||
const pending = approval.status === "pending";
|
||||
const presentation = approval.presentation;
|
||||
const title = pending
|
||||
? presentation.kind === "plugin"
|
||||
? presentation.title
|
||||
: t("approvalPage.execTitle")
|
||||
: terminalTitle(approval, this.resolutionOrigin);
|
||||
const statusDescription = pending
|
||||
? t("approvalPage.pendingDescription")
|
||||
: terminalDescription(approval, this.resolutionOrigin);
|
||||
return html`
|
||||
<div class="approval-page__status" aria-live="polite" aria-atomic="true">
|
||||
<span
|
||||
class="approval-page__status-dot approval-page__status-dot--${approval.status}"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
${pending ? t("approvalPage.pending") : terminalTitle(approval, this.resolutionOrigin)}
|
||||
</div>
|
||||
<div class="approval-page__heading">
|
||||
<h1 id="approval-page-title" tabindex=${pending ? nothing : -1}>${title}</h1>
|
||||
<p>${statusDescription}</p>
|
||||
</div>
|
||||
${renderPresentation(presentation)}
|
||||
<div class="approval-page__timing">
|
||||
<span>${pending ? t("approvalPage.expiresLabel") : t("approvalPage.resolvedLabel")}</span>
|
||||
<time
|
||||
datetime=${new Date(pending ? approval.expiresAtMs : approval.resolvedAtMs).toISOString()}
|
||||
>
|
||||
${formatApprovalTime(pending ? approval.expiresAtMs : approval.resolvedAtMs)}
|
||||
</time>
|
||||
</div>
|
||||
${this.requestError === "connection" ? this.renderConnectionError() : nothing}
|
||||
${pending
|
||||
? html`
|
||||
<div
|
||||
class="approval-page__actions"
|
||||
role="group"
|
||||
aria-label=${t("approvalPage.actionsLabel")}
|
||||
>
|
||||
${presentation.allowedDecisions.map(
|
||||
(decision) => html`
|
||||
<button
|
||||
type="button"
|
||||
class="btn approval-page__action approval-page__action--${decision}"
|
||||
data-decision=${decision}
|
||||
?disabled=${this.resolving ||
|
||||
!this.hasGatewayConnection ||
|
||||
this.requestError !== null}
|
||||
@click=${() => void this.resolveApproval(decision)}
|
||||
>
|
||||
${this.resolvingDecision === decision
|
||||
? t("approvalPage.resolvingDecision", { decision: decisionLabel(decision) })
|
||||
: decisionLabel(decision)}
|
||||
</button>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="approval-page__terminal" role="status">
|
||||
${t("approvalPage.safeToClose")}
|
||||
</div>
|
||||
`}
|
||||
`;
|
||||
}
|
||||
|
||||
override render() {
|
||||
const unavailable = this.requestError === "unavailable";
|
||||
const disconnected = this.requestError === "connection" && !this.approval;
|
||||
const documentState = unavailable
|
||||
? "unavailable"
|
||||
: disconnected
|
||||
? "connection-error"
|
||||
: (this.approval?.status ?? "loading");
|
||||
return html`
|
||||
<main class="approval-page" data-state=${documentState}>
|
||||
<div class="approval-page__backdrop" aria-hidden="true"></div>
|
||||
<section
|
||||
class="approval-page__card"
|
||||
aria-labelledby="approval-page-title"
|
||||
aria-busy=${this.loading || this.resolving ? "true" : "false"}
|
||||
>
|
||||
${this.renderHeader()}
|
||||
<div class="approval-page__content">
|
||||
${this.loading && !this.approval
|
||||
? this.renderLoading()
|
||||
: disconnected
|
||||
? this.renderConnectionState()
|
||||
: unavailable || !this.approval
|
||||
? this.renderUnavailable()
|
||||
: this.renderApproval(this.approval)}
|
||||
</div>
|
||||
</section>
|
||||
<a class="approval-page__back-link" href=${`${this.context.basePath}/chat`}>
|
||||
${t("approvalPage.openControlUi")}
|
||||
</a>
|
||||
</main>
|
||||
`;
|
||||
}
|
||||
|
||||
private updateDocumentTitle() {
|
||||
const pageTitle =
|
||||
this.requestError === "unavailable"
|
||||
? t("approvalPage.unavailableTitle")
|
||||
: this.requestError === "connection" && !this.approval
|
||||
? t("approvalPage.connectionErrorTitle")
|
||||
: this.approval
|
||||
? this.approval.status === "pending"
|
||||
? this.approval.presentation.kind === "plugin"
|
||||
? this.approval.presentation.title
|
||||
: t("approvalPage.execTitle")
|
||||
: terminalTitle(this.approval, this.resolutionOrigin)
|
||||
: t("approvalPage.loadingTitle");
|
||||
const title = `${pageTitle} — ${t("approvalPage.brandName")}`;
|
||||
document.title = title;
|
||||
this.activeDocumentTitle = title;
|
||||
}
|
||||
}
|
||||
|
||||
if (!customElements.get("openclaw-approval-page")) {
|
||||
customElements.define("openclaw-approval-page", ApprovalPage);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
@import "./styles/layout.css";
|
||||
@import "./styles/layout.mobile.css";
|
||||
@import "./styles/components.css";
|
||||
@import "./styles/approval.css";
|
||||
@import "./styles/activity.css";
|
||||
@import "./styles/about.css";
|
||||
@import "./styles/chat.css";
|
||||
|
||||
@@ -0,0 +1,490 @@
|
||||
openclaw-approval-page {
|
||||
display: block;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
min-height: 100vh;
|
||||
min-height: 100svh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.approval-page {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 720px);
|
||||
grid-template-rows: max-content max-content;
|
||||
grid-auto-rows: max-content;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
min-height: 100svh;
|
||||
align-content: start;
|
||||
align-content: safe center;
|
||||
justify-content: center;
|
||||
place-items: center;
|
||||
gap: 18px;
|
||||
overflow: hidden auto;
|
||||
padding: max(32px, var(--safe-area-top)) max(22px, var(--safe-area-right))
|
||||
max(24px, var(--safe-area-bottom)) max(22px, var(--safe-area-left));
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
@media (display-mode: standalone) {
|
||||
openclaw-approval-page {
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.approval-page {
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.approval-page--booting {
|
||||
align-content: center;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.approval-page__backdrop {
|
||||
position: fixed;
|
||||
z-index: 0;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background:
|
||||
linear-gradient(
|
||||
90deg,
|
||||
transparent 0 49.8%,
|
||||
color-mix(in srgb, var(--accent) 14%, transparent) 50%,
|
||||
transparent 50.2%
|
||||
),
|
||||
radial-gradient(
|
||||
circle at 50% 16%,
|
||||
color-mix(in srgb, var(--accent) 12%, transparent),
|
||||
transparent 34%
|
||||
),
|
||||
repeating-linear-gradient(
|
||||
90deg,
|
||||
transparent 0,
|
||||
transparent 79px,
|
||||
color-mix(in srgb, var(--text) 4%, transparent) 80px
|
||||
);
|
||||
mask-image: linear-gradient(to bottom, black, transparent 92%);
|
||||
}
|
||||
|
||||
.approval-page__card {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border-strong);
|
||||
border-left: 3px solid var(--accent);
|
||||
border-radius: 4px 18px 18px 4px;
|
||||
background: color-mix(in srgb, var(--card) 96%, transparent);
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
.approval-page__card::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-top: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
border-right: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
border-radius: 0 17px 0 0;
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.approval-page__brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-height: 76px;
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: color-mix(in srgb, var(--bg-elevated) 66%, transparent);
|
||||
}
|
||||
|
||||
.approval-page__logo {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.approval-page__eyebrow {
|
||||
color: var(--accent);
|
||||
font-family: var(--mono);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.11em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.approval-page__brand-name {
|
||||
margin-top: 2px;
|
||||
color: var(--text-strong);
|
||||
font-size: var(--control-ui-text-sm);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.approval-page__content {
|
||||
padding: 28px 30px 30px;
|
||||
}
|
||||
|
||||
.approval-page__status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border: 1px solid var(--border-strong);
|
||||
border-radius: var(--radius-full);
|
||||
color: var(--muted-strong);
|
||||
font-family: var(--mono);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.approval-page__status-dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: var(--muted);
|
||||
}
|
||||
|
||||
.approval-page__status-dot--pending {
|
||||
background: var(--warn);
|
||||
box-shadow: 0 0 0 4px var(--warn-subtle);
|
||||
}
|
||||
|
||||
.approval-page__status-dot--allowed {
|
||||
background: var(--ok);
|
||||
box-shadow: 0 0 0 4px var(--ok-subtle);
|
||||
}
|
||||
|
||||
.approval-page__status-dot--denied,
|
||||
.approval-page__status-dot--expired,
|
||||
.approval-page__status-dot--cancelled {
|
||||
background: var(--danger);
|
||||
box-shadow: 0 0 0 4px var(--danger-subtle);
|
||||
}
|
||||
|
||||
.approval-page__heading {
|
||||
margin: 22px 0 24px;
|
||||
}
|
||||
|
||||
.approval-page__heading h1,
|
||||
.approval-page__state h1 {
|
||||
margin: 0;
|
||||
color: var(--text-strong);
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(24px, 5vw, 34px);
|
||||
font-weight: 720;
|
||||
letter-spacing: -0.025em;
|
||||
line-height: 1.12;
|
||||
}
|
||||
|
||||
.approval-page__heading p,
|
||||
.approval-page__state p {
|
||||
max-width: 58ch;
|
||||
margin: 10px 0 0;
|
||||
color: var(--muted-strong);
|
||||
font-size: var(--control-ui-text-md);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.approval-page__preview-label {
|
||||
margin: 20px 0 8px;
|
||||
color: var(--muted);
|
||||
font-family: var(--mono);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.approval-page__summary,
|
||||
.approval-page__preview {
|
||||
overflow-wrap: anywhere;
|
||||
unicode-bidi: plaintext;
|
||||
border: 1px solid var(--border-strong);
|
||||
background: var(--bg);
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
.approval-page__summary {
|
||||
padding: 11px 13px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--control-ui-text-sm);
|
||||
}
|
||||
|
||||
.approval-page__preview {
|
||||
max-height: min(38vh, 330px);
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
padding: 17px 18px;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--control-ui-text-md);
|
||||
line-height: 1.55;
|
||||
tab-size: 2;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.approval-page__preview--prose {
|
||||
font-family: var(--font-body);
|
||||
}
|
||||
|
||||
.approval-page__warning {
|
||||
padding: 12px 14px;
|
||||
border: 1px solid color-mix(in srgb, var(--warn) 36%, var(--border));
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--warn-subtle);
|
||||
color: var(--text);
|
||||
font-size: var(--control-ui-text-sm);
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.approval-page__meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1px;
|
||||
overflow: hidden;
|
||||
margin: 14px 0 0;
|
||||
padding: 1px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
.approval-page__meta:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.approval-page__meta-row {
|
||||
min-width: 0;
|
||||
padding: 10px 12px;
|
||||
background: var(--card);
|
||||
}
|
||||
|
||||
.approval-page__meta-row dt {
|
||||
margin-bottom: 3px;
|
||||
color: var(--muted);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
}
|
||||
|
||||
.approval-page__meta-row dd {
|
||||
overflow-wrap: anywhere;
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-family: var(--mono);
|
||||
font-size: var(--control-ui-text-sm);
|
||||
unicode-bidi: plaintext;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.approval-page__timing {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-top: 18px;
|
||||
color: var(--muted);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
}
|
||||
|
||||
.approval-page__timing time {
|
||||
color: var(--text);
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
.approval-page__actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin-top: 26px;
|
||||
}
|
||||
|
||||
.approval-page__action {
|
||||
min-height: 48px;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.approval-page__action--allow-once {
|
||||
border-color: var(--accent);
|
||||
background: var(--accent);
|
||||
color: var(--accent-foreground);
|
||||
}
|
||||
|
||||
.approval-page__action--allow-once:hover:not(:disabled) {
|
||||
border-color: var(--accent-hover);
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
|
||||
.approval-page__action--deny {
|
||||
border-color: color-mix(in srgb, var(--danger) 52%, var(--border));
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.approval-page__actions .approval-page__action:only-child,
|
||||
.approval-page__action--deny:last-child:nth-child(odd) {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.approval-page__callout {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-top: 18px;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid color-mix(in srgb, var(--danger) 36%, var(--border));
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--danger-subtle);
|
||||
}
|
||||
|
||||
.approval-page__callout strong,
|
||||
.approval-page__callout span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.approval-page__callout span {
|
||||
margin-top: 3px;
|
||||
color: var(--muted-strong);
|
||||
font-size: var(--control-ui-text-xs);
|
||||
}
|
||||
|
||||
.approval-page__terminal {
|
||||
margin-top: 24px;
|
||||
padding-top: 18px;
|
||||
border-top: 1px solid var(--border);
|
||||
color: var(--muted-strong);
|
||||
font-size: var(--control-ui-text-sm);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.approval-page__state {
|
||||
display: grid;
|
||||
min-height: 330px;
|
||||
place-items: center;
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.approval-page__state p {
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.approval-page__state .btn {
|
||||
min-width: 120px;
|
||||
min-height: 44px;
|
||||
justify-content: center;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.approval-page__spinner {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
margin-bottom: 20px;
|
||||
border: 2px solid var(--border-strong);
|
||||
border-top-color: var(--accent);
|
||||
border-radius: 50%;
|
||||
animation: approval-page-spin 800ms linear infinite;
|
||||
}
|
||||
|
||||
.approval-page__state-mark {
|
||||
display: grid;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
place-items: center;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid color-mix(in srgb, var(--danger) 50%, var(--border));
|
||||
border-radius: 50%;
|
||||
color: var(--danger);
|
||||
font-family: var(--mono);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.approval-page__back-link {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-height: 44px;
|
||||
padding: 12px 16px;
|
||||
color: var(--muted-strong);
|
||||
font-size: var(--control-ui-text-sm);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.approval-page__back-link:hover {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
@keyframes approval-page-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.approval-page {
|
||||
align-content: start;
|
||||
place-items: start center;
|
||||
padding: max(14px, var(--safe-area-top)) max(12px, var(--safe-area-right))
|
||||
max(18px, var(--safe-area-bottom)) max(12px, var(--safe-area-left));
|
||||
}
|
||||
|
||||
.approval-page__card {
|
||||
border-radius: 3px 14px 14px 3px;
|
||||
}
|
||||
|
||||
.approval-page__brand {
|
||||
min-height: 68px;
|
||||
padding: 13px 17px;
|
||||
}
|
||||
|
||||
.approval-page__content {
|
||||
padding: 23px 17px 20px;
|
||||
}
|
||||
|
||||
.approval-page__heading {
|
||||
margin-block: 18px 21px;
|
||||
}
|
||||
|
||||
.approval-page__preview {
|
||||
max-height: 34vh;
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.approval-page__meta {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.approval-page__actions {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.approval-page__action--deny:last-child:nth-child(odd) {
|
||||
grid-column: auto;
|
||||
}
|
||||
|
||||
.approval-page__timing,
|
||||
.approval-page__callout {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.approval-page__timing {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.approval-page__callout .btn {
|
||||
min-height: 44px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.approval-page__spinner {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ export type MockGatewayRequest = {
|
||||
export type ControlUiMockGatewayScenario = {
|
||||
assistantAgentId?: string;
|
||||
assistantName?: string;
|
||||
basePath?: string;
|
||||
controlUiTabs?: Array<{
|
||||
group?: string;
|
||||
icon?: string;
|
||||
@@ -224,9 +225,20 @@ function normalizeScenario(
|
||||
): NormalizedControlUiMockGatewayScenario {
|
||||
const defaultAgentId = scenario.defaultAgentId?.trim() || "main";
|
||||
const sessionKey = scenario.sessionKey?.trim() || "main";
|
||||
const basePathValue = scenario.basePath?.trim() ?? "";
|
||||
const basePathWithSlash = basePathValue
|
||||
? basePathValue.startsWith("/")
|
||||
? basePathValue
|
||||
: `/${basePathValue}`
|
||||
: "";
|
||||
const basePath =
|
||||
basePathWithSlash.length > 1 && basePathWithSlash.endsWith("/")
|
||||
? basePathWithSlash.slice(0, -1)
|
||||
: basePathWithSlash;
|
||||
return {
|
||||
assistantAgentId: scenario.assistantAgentId?.trim() || defaultAgentId,
|
||||
assistantName: scenario.assistantName?.trim() || "OpenClaw",
|
||||
basePath,
|
||||
controlUiTabs: scenario.controlUiTabs ?? [],
|
||||
defaultAgentId,
|
||||
deferredMethods: scenario.deferredMethods ?? [],
|
||||
@@ -250,7 +262,7 @@ export function createControlUiMockBootstrapConfig(scenario: ControlUiMockGatewa
|
||||
assistantAgentId: normalizedScenario.assistantAgentId,
|
||||
assistantAvatar: "",
|
||||
assistantName: normalizedScenario.assistantName,
|
||||
basePath: "/",
|
||||
basePath: normalizedScenario.basePath,
|
||||
devGitBranch: normalizedScenario.devGitBranch || undefined,
|
||||
embedSandbox: "scripts",
|
||||
localMediaPreviewRoots: [],
|
||||
@@ -313,11 +325,25 @@ function installControlUiMockGateway(input: {
|
||||
socketUrls: () => string[];
|
||||
};
|
||||
type WindowWithGateway = Window & {
|
||||
__OPENCLAW_CONTROL_UI_BASE_PATH__?: string;
|
||||
openclawControlUiE2eGateway?: ExposedGateway;
|
||||
};
|
||||
|
||||
const scenario: BrowserScenario = input.scenario;
|
||||
(window as unknown as WindowWithGateway)["__OPENCLAW_CONTROL_UI_BASE_PATH__"] = scenario.basePath;
|
||||
const protocolVersion = input.protocolVersion;
|
||||
const methodResponseOverridesStorageKey = "openclaw.control-ui-e2e.method-responses.v1";
|
||||
const methodResponseOverrides: Record<string, unknown> = {};
|
||||
try {
|
||||
const storedOverrides = window.sessionStorage.getItem(methodResponseOverridesStorageKey);
|
||||
const parsedOverrides = storedOverrides ? (JSON.parse(storedOverrides) as unknown) : null;
|
||||
if (isRecord(parsedOverrides)) {
|
||||
Object.assign(methodResponseOverrides, parsedOverrides);
|
||||
Object.assign(scenario.methodResponses, parsedOverrides);
|
||||
}
|
||||
} catch {
|
||||
// Opaque initial documents may not expose storage; the target page will.
|
||||
}
|
||||
const deferredMethods: string[] = [...scenario.deferredMethods];
|
||||
const deferredResponses: DeferredResponse[] = [];
|
||||
const requests: BrowserRequest[] = [];
|
||||
@@ -898,6 +924,18 @@ function installControlUiMockGateway(input: {
|
||||
}
|
||||
MockWebSocket.latest?.openConnection();
|
||||
},
|
||||
setMethodResponse(method, payload) {
|
||||
scenario.methodResponses[method] = payload;
|
||||
methodResponseOverrides[method] = payload;
|
||||
try {
|
||||
window.sessionStorage.setItem(
|
||||
methodResponseOverridesStorageKey,
|
||||
JSON.stringify(methodResponseOverrides),
|
||||
);
|
||||
} catch {
|
||||
// Current-document responses still work if browser storage is unavailable.
|
||||
}
|
||||
},
|
||||
setHistoryMessages(messages) {
|
||||
scenario.historyMessages = Array.isArray(messages) ? messages : [];
|
||||
const configuredHistory = scenario.methodResponses["chat.history"];
|
||||
@@ -905,9 +943,6 @@ function installControlUiMockGateway(input: {
|
||||
configuredHistory.messages = scenario.historyMessages;
|
||||
}
|
||||
},
|
||||
setMethodResponse(method, payload) {
|
||||
scenario.methodResponses[method] = payload;
|
||||
},
|
||||
socketCount() {
|
||||
return sockets.length;
|
||||
},
|
||||
@@ -916,7 +951,7 @@ function installControlUiMockGateway(input: {
|
||||
},
|
||||
};
|
||||
|
||||
(window as WindowWithGateway).openclawControlUiE2eGateway = exposed;
|
||||
(window as unknown as WindowWithGateway).openclawControlUiE2eGateway = exposed;
|
||||
window.WebSocket = MockWebSocket as unknown as typeof WebSocket;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user