Skip to content

Commit d9d3eb7

Browse files
feat(app-shell): Connect an Agent marks claude.ai (web) and Doubao cloud tasks as not available on a non-public address (#30973)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} --> _Requested by **Tesla** · [project thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6Jao4R5vgzn4JR1Ewtt4rWD5cr)_ Fixes #30897 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:「连接 AI 助手」页显示的地址不是公网 HTTPS(http://、localhost、内网地址)时,claude.ai 网页版和豆包工作的云端任务会标出「此部署不可用」,一句话说明原因(写出该地址),并说明怎样才能用(把系统部署到公网 HTTPS 地址)。 - 为什么改:公司在内网试用时照着 claude.ai 步骤粘贴地址,连接失败却没有可执行的原因;页面本来就知道自己显示的地址,可以先说清楚。 - 风险与回滚:只在页面显示层判断地址,不改任何服务端行为;Claude Desktop、Claude Code、Codex、Cursor 等本地客户端的步骤不变;公网 HTTPS 地址下页面与之前完全一样。回滚即 revert 本 PR。 - 先看:`ui/packages/app-shell/src/console/connect/deploymentReach.ts`(地址判定)、`ConnectAgentWidget.tsx` 里的 `Unavailable` 与两处使用、测试文件末尾新增的 describe。 - 两分钟验证:本地部署打开 设置 → 连接 AI 助手:Claude 页签下 claude.ai 一栏出现虚线框「claude.ai(网页版):此部署不可用」,切到「豆包工作」出现「云端任务:此部署不可用」,切到 Codex 没有提示。 - 需要你做的:无,席位落地。 - **席位意见**:ui 席 2 对照 head `a70c0f26` 的 diff 复核:15 个文件、+293 / −9,无受治理路径。新增 `deploymentReach.ts` 的 `isPublicHttpsAddress` 判定公网 HTTPS(`http://`、`localhost`、单标签或 `.local`/`.internal` 主机、回环/私网/链路本地/CGNAT 的 IPv4 与 IPv6 字面量,含 IPv4 映射形式,均判为不可达);地址不可达时 claude.ai(网页版)与豆包工作的云端任务显示「此部署不可用」、原因(点名地址)与补救,其他客户端不变,公网 HTTPS 下与 main 相同。五条文案进所有语言包,繁体由简体生成。CI 全绿,Clause-② no,不欠契约复审。同意落地。 ## What changes - `deploymentReach.ts` (new): `isPublicHttpsAddress(address)` — false for a non-`https:` address, `localhost` / `*.localhost`, a single-label host, `.local` / `.internal`, and loopback, private (10/8, 172.16/12, 192.168/16), link-local, CGNAT and unspecified IPv4 literals, plus `::1`, `fc00::/7`, `fe80::/10` and IPv4-mapped private IPv6. A host name with a dot is taken as public (the page cannot see the reader's DNS). - `ConnectAgentWidget.tsx`: when the MCP address is not public HTTPS, the claude.ai / Claude Desktop column shows an `Unavailable` note (title, one-sentence reason naming the address's origin, remedy) in place of the static reachability small print, and the Doubao Work steps gain the same note for cloud tasks. Claude Desktop's steps, Claude Code, Codex, Cursor, WorkBuddy and QwenWork are unchanged. On a public HTTPS address nothing renders differently from `main`. - i18n: five new keys under `connectAgent.unreachable` in all ten console packs (PR #30902 is not on `main`: today's `zh.ts` / `pt.ts`). - Root changeset `.changeset/30897-connect-agent-unreachable-address.md` (`@object-ui/app-shell`, `@object-ui/i18n`: patch). ## Tests In `ConnectAgentWidget.keyName-13355.test.tsx` (the component's one harness file), a new top-level describe: the address classification table (16 non-public, 5 public); on `http://localhost:3000` the claude.ai note with the address and the Doubao cloud-task note render, Claude Desktop / Claude Code steps stay, Codex and Cursor carry no note; on `https://crm.example.com` no note renders and the original reachability line is back. The test `t` mock now echoes the `address` option beside `name`. ## Acceptance notes - The page judges only the address it shows (the discovery-relative MCP route resolved against the console's origin). A public-looking domain that resolves to a private IP on the reader's network is taken as public: the page cannot see DNS. - The Doubao hint keeps its last sentence about cloud tasks needing public HTTPS; on a non-public address the note now says so first, for this deployment. - The fallback hints that say "create a key below" are unchanged here; #30898 rewrites that copy and will name Advanced. - The Claude column keeps its heading "claude.ai / Claude Desktop"; only the web half (claude.ai) is marked unavailable, per the card's Expected. (Seat note at ACCEPT.) ## Verification Head `1851c124`: branch restarted on `main` `6ddf8272` (PR #30943's merge), this card's commit re-applied cleanly; full `pnpm build` on that base (118/118). <details><summary>Live check on a local deployment (showcase with the fresh flag, console Vite dev, admin)</summary> - before (`main`): on `http://localhost` the claude.ai column shows the address with a copy button and the static small print "claude.ai (web) connects from Anthropic's servers — the deployment must be reachable over public HTTPS"; the Doubao steps carry the same kind of static line. Nothing reacts to the address. - after: Claude tab — a note "claude.ai (web): not available for this deployment / claude.ai connects from Anthropic's servers, and they cannot reach http://localhost:5197: only a public HTTPS address is reachable from there. / Serve this system at a public HTTPS address (https:// on a domain the internet can reach) to make it available."; Doubao Work tab — "Cloud tasks: not available for this deployment" with the same reason shape and remedy; Codex tab — no note. </details> <details><summary>Local tests and gates</summary> - `pnpm --dir ui exec vitest run packages/app-shell/src/console/connect/ packages/i18n/ packages/app-shell/src/__tests__/product-neutral-renderer.ratchet.test.ts` → 99 files, 1565 passed, 13 skipped (widget file 12/12) - `pnpm --filter @object-ui/i18n run type-check && pnpm --filter @object-ui/app-shell run type-check` → exit 0 - eslint `packages/app-shell/src/console/connect/` → 0 errors (3 pre-existing `no-explicit-any` warnings); `pnpm check:new-line-citations` → 0 new - `dispatch-gates --commands` derived 36 commands on 1851c12; all 36 exit 0 (incl. `node scripts/check-sdui-manifest.mjs`, `pnpm --dir ui exec vitest run scripts/` 170 files passed); `--ran` reconciliation: 36 run, 0 NOT-MEASURED, 0 UNRUN. </details> <!-- signed: domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6bd00d2 commit d9d3eb7

15 files changed

Lines changed: 293 additions & 9 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
feat(app-shell): Connect an Agent marks claude.ai (web) and Doubao cloud tasks as not available on an address that is not public HTTPS
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
claude.ai on the web and Doubao Work's cloud tasks connect from their vendor's servers, which reach only a public HTTPS address. When the address Connect an Agent shows is an `http://` address, `localhost`, a single-label or `.local` host, or a private, loopback or link-local IP, those two ways in now carry a "not available for this deployment" note with the reason in one sentence (naming the address) and what makes them available (serving the system at a public HTTPS address). Claude Desktop, Claude Code, Codex, Cursor and the other clients stay as they are, and on a public HTTPS address nothing changes. The five new strings ship in every console language pack, Traditional Chinese generated from Simplified.

‎ui/packages/app-shell/src/console/connect/ConnectAgentWidget.keyName-13355.test.tsx‎

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
* The key form lives in the collapsed "Advanced: scripts and CI" section, so
2121
* those cases open it first. The last block holds the page's shape: the
2222
* endpoint and SKILL.md on top, a picker that shows one client's steps and
23-
* remembers the choice on this browser, and the key form collapsed.
23+
* remembers the choice on this browser, and the key form collapsed. The
24+
* reachability block holds that claude.ai (web) and Doubao Work's cloud tasks
25+
* are marked not available on an address that is not public HTTPS.
2426
*
25-
* `fetch` is stubbed by path; `t` echoes the KEY (with the `name` option
26-
* appended when one is passed), as the sibling suites do, so the assertions
27-
* read which string the widget asked for and with which name.
27+
* `fetch` is stubbed by path; `t` echoes the KEY (with the `name` or
28+
* `address` option appended when one is passed), as the sibling suites do,
29+
* so the assertions read which string the widget asked for and with which
30+
* value.
2831
*/
2932

3033
import '@testing-library/jest-dom/vitest';
@@ -34,17 +37,22 @@ import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/re
3437
vi.mock('@object-ui/i18n', async (importOriginal) => ({
3538
...(await importOriginal<Record<string, unknown>>()),
3639
useObjectTranslation: () => ({
37-
t: (key: string, opts?: { name?: string }) =>
38-
opts && typeof opts.name === 'string' ? `«${key}|${opts.name}»` : `«${key}»`,
40+
t: (key: string, opts?: { name?: string; address?: string }) => {
41+
const arg = opts?.name ?? opts?.address;
42+
return typeof arg === 'string' ? `«${key}|${arg}»` : `«${key}»`;
43+
},
3944
language: 'en',
4045
}),
4146
}));
4247

4348
import { ConnectAgent } from './ConnectAgentWidget';
49+
import { isPublicHttpsAddress } from './deploymentReach';
4450

4551
const MINTED_KEY = 'osk_test_0123456789';
4652

4753
let fetchMock: ReturnType<typeof vi.fn>;
54+
/** The `routes.mcp` discovery answers; a case may point it at another address. */
55+
let discoveredMcp = '/api/v1/mcp';
4856

4957
/** The bodies of every `POST /api/v1/keys` the widget sent. */
5058
function keyPosts(): unknown[] {
@@ -55,10 +63,11 @@ function keyPosts(): unknown[] {
5563

5664
beforeEach(() => {
5765
window.localStorage.clear();
66+
discoveredMcp = '/api/v1/mcp';
5867
fetchMock = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
5968
const url = String(input);
6069
if (url.includes('/api/v1/discovery')) {
61-
return new Response(JSON.stringify({ data: { routes: { mcp: '/api/v1/mcp' } } }), {
70+
return new Response(JSON.stringify({ data: { routes: { mcp: discoveredMcp } } }), {
6271
status: 200,
6372
headers: { 'content-type': 'application/json' },
6473
});
@@ -279,3 +288,73 @@ describe('Connect an Agent asks which client the person uses and shows only thos
279288
expect(screen.getByText(CLAUDE_CODE)).toBeInTheDocument();
280289
});
281290
});
291+
292+
describe('Connect an Agent marks the cloud-connected ways in as not available on an address that is not public HTTPS', () => {
293+
const notes = () => screen.queryAllByRole('note').map((n) => n.textContent ?? '');
294+
295+
it('§1 classifies the address: http, localhost, single-label and private hosts are not public HTTPS', () => {
296+
for (const address of [
297+
'http://crm.example.com/api/v1/mcp',
298+
'https://localhost:3000/api/v1/mcp',
299+
'https://app.localhost/api/v1/mcp',
300+
'https://crm/api/v1/mcp',
301+
'https://crm.local/api/v1/mcp',
302+
'https://10.1.2.3/api/v1/mcp',
303+
'https://172.20.0.5/api/v1/mcp',
304+
'https://192.168.1.10/api/v1/mcp',
305+
'https://127.0.0.1/api/v1/mcp',
306+
'https://169.254.1.1/api/v1/mcp',
307+
'https://100.64.0.1/api/v1/mcp',
308+
'https://[::1]/api/v1/mcp',
309+
'https://[fd12:3456::1]/api/v1/mcp',
310+
'https://[fe80::1]/api/v1/mcp',
311+
'https://[::ffff:10.0.0.1]/api/v1/mcp',
312+
'not a url',
313+
]) {
314+
expect(isPublicHttpsAddress(address), address).toBe(false);
315+
}
316+
for (const address of [
317+
'https://crm.example.com/api/v1/mcp',
318+
'https://crm.example.com:8443/api/v1/mcp',
319+
'https://8.8.8.8/api/v1/mcp',
320+
'https://172.32.0.1/api/v1/mcp',
321+
'https://[2001:db8::1]/api/v1/mcp',
322+
]) {
323+
expect(isPublicHttpsAddress(address), address).toBe(true);
324+
}
325+
});
326+
327+
it('§2 on an http://localhost address, claude.ai (web) and Doubao cloud tasks say why and what fixes it; local clients unchanged', async () => {
328+
discoveredMcp = 'http://localhost:3000/api/v1/mcp';
329+
await renderPage();
330+
expect(notes()).toEqual([
331+
'«connectAgent.unreachable.claudeWebTitle»«connectAgent.unreachable.claudeWebReason|http://localhost:3000»«connectAgent.unreachable.remedy»',
332+
]);
333+
expect(screen.queryByText('«connectAgent.claude.reachability»')).not.toBeInTheDocument();
334+
// Claude Desktop and Claude Code keep their steps.
335+
expect(screen.getByText('«connectAgent.claude.body»')).toBeInTheDocument();
336+
expect(screen.getByText(/^claude mcp add --transport http objectstack http:\/\/localhost:3000\/api\/v1\/mcp$/)).toBeInTheDocument();
337+
338+
pickClient('«connectAgent.doubao.title»');
339+
await screen.findByText('«connectAgent.doubao.body»');
340+
expect(notes()).toEqual([
341+
'«connectAgent.unreachable.doubaoCloudTitle»«connectAgent.unreachable.doubaoCloudReason|http://localhost:3000»«connectAgent.unreachable.remedy»',
342+
]);
343+
344+
for (const local of ['Codex', 'Cursor']) {
345+
pickClient(local);
346+
await waitFor(() => expect(screen.getByRole('tab', { name: local })).toHaveAttribute('aria-selected', 'true'));
347+
expect(notes()).toEqual([]);
348+
}
349+
});
350+
351+
it('§3 on a public HTTPS address nothing is marked', async () => {
352+
discoveredMcp = 'https://crm.example.com/api/v1/mcp';
353+
await renderPage();
354+
expect(notes()).toEqual([]);
355+
expect(screen.getByText('«connectAgent.claude.reachability»')).toBeInTheDocument();
356+
pickClient('«connectAgent.doubao.title»');
357+
await screen.findByText('«connectAgent.doubao.body»');
358+
expect(notes()).toEqual([]);
359+
});
360+
});

‎ui/packages/app-shell/src/console/connect/ConnectAgentWidget.tsx‎

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
* OAuth is the default story for every client (the deployment is its own
2121
* authorization server; you sign in as yourself); the Chinese clients'
2222
* steps name the API-key header as the fallback for a client version
23-
* without the OAuth flow,
23+
* without the OAuth flow. claude.ai (web) and Doubao Work's cloud tasks
24+
* connect from their vendor's servers, so on an address that is not
25+
* public HTTPS (`deploymentReach.ts`) both are marked not available,
26+
* with the reason and what makes them available; the local clients stay
27+
* as they are,
2428
* 4. API-key minting for headless callers (CI, machine accounts) via the
2529
* existing `POST /api/v1/keys`, in a collapsed "Advanced: scripts and CI"
2630
* section at the bottom — no client, so not a peer of the clients.
@@ -62,6 +66,7 @@ import {
6266
TabsTrigger,
6367
} from '@object-ui/components';
6468
import {
69+
Ban,
6570
Bot,
6671
Check,
6772
ChevronRight,
@@ -82,6 +87,7 @@ import {
8287
isConnectClientId,
8388
type ConnectClientId,
8489
} from './connectClientPreference.js';
90+
import { isPublicHttpsAddress } from './deploymentReach.js';
8591

8692
const SERVER_URL = (import.meta.env.VITE_SERVER_URL || '').replace(/\/$/, '');
8793

@@ -154,6 +160,32 @@ function FieldRows({ rows }: { rows: Array<{ label: string; value: string }> })
154160
);
155161
}
156162

163+
/** The scheme and host a reader recognises (`http://localhost:3000`), not the full MCP path. */
164+
function addressOf(url: string): string {
165+
try {
166+
return new URL(url).origin;
167+
} catch {
168+
return url;
169+
}
170+
}
171+
172+
/**
173+
* A way in this deployment's address cannot offer: what is not available,
174+
* why in one sentence, and what makes it available.
175+
*/
176+
function Unavailable({ title, reason, remedy }: { title: string; reason: string; remedy: string }) {
177+
return (
178+
<div role="note" className="flex gap-2 rounded-md border border-dashed px-3 py-2 text-xs">
179+
<Ban className="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
180+
<div className="space-y-0.5">
181+
<div className="font-medium">{title}</div>
182+
<p className="text-muted-foreground">{reason}</p>
183+
<p className="text-muted-foreground">{remedy}</p>
184+
</div>
185+
</div>
186+
);
187+
}
188+
157189
/** The `mcpServers` JSON shape most clients import, with the client's own transport spelling. */
158190
function mcpServersJson(type: string | null, url: string): string {
159191
const server = type ? { type, url } : { url };
@@ -198,6 +230,10 @@ export function ConnectAgent() {
198230
}, []);
199231

200232
const skillUrl = mcpUrl ? `${mcpUrl}/skill` : null;
233+
// claude.ai (web) and Doubao Work's cloud tasks connect from their vendor's
234+
// servers: they reach only a public HTTPS address.
235+
const cloudReachable = mcpUrl ? isPublicHttpsAddress(mcpUrl) : false;
236+
const shownAddress = mcpUrl ? addressOf(mcpUrl) : '';
201237

202238
const cursorDeeplink = useMemo(() => {
203239
if (!mcpUrl) return null;
@@ -324,7 +360,15 @@ export function ConnectAgent() {
324360
<h4 className="font-medium">claude.ai / Claude Desktop</h4>
325361
<p className="text-muted-foreground">{t('connectAgent.claude.body')}</p>
326362
<Snippet text={mcpUrl} />
327-
<p className="text-xs text-muted-foreground">{t('connectAgent.claude.reachability')}</p>
363+
{cloudReachable ? (
364+
<p className="text-xs text-muted-foreground">{t('connectAgent.claude.reachability')}</p>
365+
) : (
366+
<Unavailable
367+
title={t('connectAgent.unreachable.claudeWebTitle')}
368+
reason={t('connectAgent.unreachable.claudeWebReason', { address: shownAddress })}
369+
remedy={t('connectAgent.unreachable.remedy')}
370+
/>
371+
)}
328372
</div>
329373
<div className="min-w-0 space-y-2">
330374
<h4 className="font-medium">Claude Code</h4>
@@ -376,6 +420,13 @@ export function ConnectAgent() {
376420
]}
377421
/>
378422
<p className="text-xs text-muted-foreground">{t('connectAgent.doubao.hint')}</p>
423+
{!cloudReachable && (
424+
<Unavailable
425+
title={t('connectAgent.unreachable.doubaoCloudTitle')}
426+
reason={t('connectAgent.unreachable.doubaoCloudReason', { address: shownAddress })}
427+
remedy={t('connectAgent.unreachable.remedy')}
428+
/>
429+
)}
379430
</TabsContent>
380431

381432
<TabsContent value="qwenwork" className="space-y-2 text-sm">
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* Whether a client that connects from its vendor's cloud (claude.ai on the
5+
* web, Doubao Work's cloud tasks) can reach this deployment at the address
6+
* Connect an Agent shows. Only a public HTTPS address is reachable from
7+
* there: an `http://` address, `localhost`, a single-label or `.local` host
8+
* name, and a loopback, private, link-local or carrier-grade NAT IP literal
9+
* are not. A host name with a dot is taken as public: the page cannot see
10+
* how the reader's DNS resolves it.
11+
*/
12+
export function isPublicHttpsAddress(address: string): boolean {
13+
let url: URL;
14+
try {
15+
url = new URL(address);
16+
} catch {
17+
return false;
18+
}
19+
if (url.protocol !== 'https:') return false;
20+
const host = url.hostname.toLowerCase().replace(/^\[|\]$/g, '').replace(/\.$/, '');
21+
if (!host) return false;
22+
if (host.includes(':')) return !isNonPublicIpv6(host);
23+
const octets = ipv4Octets(host);
24+
if (octets) return !isNonPublicIpv4(octets);
25+
if (host === 'localhost' || host.endsWith('.localhost')) return false;
26+
if (!host.includes('.')) return false;
27+
if (host.endsWith('.local') || host.endsWith('.internal')) return false;
28+
return true;
29+
}
30+
31+
function ipv4Octets(host: string): number[] | null {
32+
const parts = host.split('.');
33+
if (parts.length !== 4 || !parts.every((p) => /^\d{1,3}$/.test(p))) return null;
34+
const octets = parts.map(Number);
35+
return octets.every((n) => n <= 255) ? octets : null;
36+
}
37+
38+
function isNonPublicIpv4([a, b]: number[]): boolean {
39+
return (
40+
a === 0 ||
41+
a === 10 ||
42+
a === 127 ||
43+
(a === 100 && b >= 64 && b <= 127) ||
44+
(a === 169 && b === 254) ||
45+
(a === 172 && b >= 16 && b <= 31) ||
46+
(a === 192 && b === 168)
47+
);
48+
}
49+
50+
function isNonPublicIpv6(host: string): boolean {
51+
if (host === '::' || host === '::1') return true;
52+
// IPv4-mapped (`::ffff:10.0.0.1`, or the hex form the URL parser writes).
53+
const mapped = /^::ffff:(.+)$/.exec(host);
54+
if (mapped) {
55+
const dotted = ipv4Octets(mapped[1]);
56+
if (dotted) return isNonPublicIpv4(dotted);
57+
const hex = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(mapped[1]);
58+
if (hex) {
59+
const hi = parseInt(hex[1], 16);
60+
return isNonPublicIpv4([hi >> 8, hi & 0xff]);
61+
}
62+
}
63+
const first = parseInt(host.split(':')[0] || '0', 16);
64+
// fc00::/7 unique local, fe80::/10 link-local.
65+
return (first & 0xfe00) === 0xfc00 || (first & 0xffc0) === 0xfe80;
66+
}

‎ui/packages/i18n/src/locales/ar.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4137,6 +4137,13 @@ const ar = {
41374137
advanced: {
41384138
title: 'متقدم: البرامج النصية وCI',
41394139
},
4140+
unreachable: {
4141+
claudeWebTitle: 'claude.ai (الويب): غير متاح لهذا النشر',
4142+
claudeWebReason: 'يتصل claude.ai من خوادم Anthropic، وهي لا تستطيع الوصول إلى {{address}}: لا يمكن الوصول من هناك إلا إلى عنوان HTTPS عام.',
4143+
doubaoCloudTitle: 'مهام السحابة: غير متاحة لهذا النشر',
4144+
doubaoCloudReason: 'يشغّل Doubao Work مهام السحابة من خوادمه الخاصة، وهي لا تستطيع الوصول إلى {{address}}: لا يمكن الوصول من هناك إلا إلى عنوان HTTPS عام.',
4145+
remedy: 'قدّم هذا النظام على عنوان HTTPS عام (https:// على نطاق يمكن الوصول إليه من الإنترنت) ليصبح متاحًا.',
4146+
},
41404147
apiKey: {
41414148
title: 'مفاتيح API',
41424149
badge: 'بدون واجهة',

‎ui/packages/i18n/src/locales/de.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3832,6 +3832,13 @@ const de = {
38323832
advanced: {
38333833
title: 'Erweitert: Skripte und CI',
38343834
},
3835+
unreachable: {
3836+
claudeWebTitle: 'claude.ai (Web): für diese Bereitstellung nicht verfügbar',
3837+
claudeWebReason: 'claude.ai verbindet sich von den Servern von Anthropic, und diese erreichen {{address}} nicht: Von dort ist nur eine öffentliche HTTPS-Adresse erreichbar.',
3838+
doubaoCloudTitle: 'Cloud-Aufgaben: für diese Bereitstellung nicht verfügbar',
3839+
doubaoCloudReason: 'Doubao Work führt Cloud-Aufgaben auf den eigenen Servern aus, und diese erreichen {{address}} nicht: Von dort ist nur eine öffentliche HTTPS-Adresse erreichbar.',
3840+
remedy: 'Stellen Sie dieses System unter einer öffentlichen HTTPS-Adresse bereit (https:// auf einer aus dem Internet erreichbaren Domain), um es verfügbar zu machen.',
3841+
},
38353842
apiKey: {
38363843
title: 'API-Schlüssel',
38373844
badge: 'headless',

‎ui/packages/i18n/src/locales/en.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4639,6 +4639,13 @@ const en = {
46394639
advanced: {
46404640
title: 'Advanced: scripts and CI',
46414641
},
4642+
unreachable: {
4643+
claudeWebTitle: 'claude.ai (web): not available for this deployment',
4644+
claudeWebReason: 'claude.ai connects from Anthropic\'s servers, and they cannot reach {{address}}: only a public HTTPS address is reachable from there.',
4645+
doubaoCloudTitle: 'Cloud tasks: not available for this deployment',
4646+
doubaoCloudReason: 'Doubao Work runs cloud tasks from its own servers, and they cannot reach {{address}}: only a public HTTPS address is reachable from there.',
4647+
remedy: 'Serve this system at a public HTTPS address (https:// on a domain the internet can reach) to make it available.',
4648+
},
46424649
apiKey: {
46434650
title: 'API keys',
46444651
badge: 'headless',

‎ui/packages/i18n/src/locales/es.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3909,6 +3909,13 @@ const es = {
39093909
advanced: {
39103910
title: 'Avanzado: scripts y CI',
39113911
},
3912+
unreachable: {
3913+
claudeWebTitle: 'claude.ai (web): no disponible para esta implementación',
3914+
claudeWebReason: 'claude.ai se conecta desde los servidores de Anthropic, y estos no pueden alcanzar {{address}}: desde allí solo se alcanza una dirección HTTPS pública.',
3915+
doubaoCloudTitle: 'Tareas en la nube: no disponibles para esta implementación',
3916+
doubaoCloudReason: 'Doubao Work ejecuta las tareas en la nube desde sus propios servidores, y estos no pueden alcanzar {{address}}: desde allí solo se alcanza una dirección HTTPS pública.',
3917+
remedy: 'Sirve este sistema en una dirección HTTPS pública (https:// en un dominio accesible desde Internet) para que esté disponible.',
3918+
},
39123919
apiKey: {
39133920
title: 'Claves API',
39143921
badge: 'headless',

‎ui/packages/i18n/src/locales/fr.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3905,6 +3905,13 @@ const fr = {
39053905
advanced: {
39063906
title: 'Avancé : scripts et CI',
39073907
},
3908+
unreachable: {
3909+
claudeWebTitle: 'claude.ai (web) : indisponible pour ce déploiement',
3910+
claudeWebReason: 'claude.ai se connecte depuis les serveurs d’Anthropic, qui ne peuvent pas atteindre {{address}} : seule une adresse HTTPS publique est joignable depuis là-bas.',
3911+
doubaoCloudTitle: 'Tâches cloud : indisponibles pour ce déploiement',
3912+
doubaoCloudReason: 'Doubao Work exécute les tâches cloud depuis ses propres serveurs, qui ne peuvent pas atteindre {{address}} : seule une adresse HTTPS publique est joignable depuis là-bas.',
3913+
remedy: 'Servez ce système à une adresse HTTPS publique (https:// sur un domaine joignable depuis Internet) pour le rendre disponible.',
3914+
},
39083915
apiKey: {
39093916
title: 'Clés API',
39103917
badge: 'headless',

‎ui/packages/i18n/src/locales/ja.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3834,6 +3834,13 @@ const ja = {
38343834
advanced: {
38353835
title: '詳細設定:スクリプトと CI',
38363836
},
3837+
unreachable: {
3838+
claudeWebTitle: 'claude.ai(Web 版):このデプロイでは利用できません',
3839+
claudeWebReason: 'claude.ai は Anthropic のサーバーから接続するため、{{address}} には到達できません。到達できるのは公開 HTTPS アドレスだけです。',
3840+
doubaoCloudTitle: 'クラウドタスク:このデプロイでは利用できません',
3841+
doubaoCloudReason: 'Doubao Work のクラウドタスクは自社サーバーから実行されるため、{{address}} には到達できません。到達できるのは公開 HTTPS アドレスだけです。',
3842+
remedy: 'このシステムを公開 HTTPS アドレス(インターネットから到達できるドメインの https://)で提供すると利用できます。',
3843+
},
38373844
apiKey: {
38383845
title: 'API キー',
38393846
badge: 'ヘッドレス',

0 commit comments

Comments
 (0)