cozyclay 3.1.2 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/bin/agent/agent-runner.mjs +160 -151
- package/bin/agent/agent-stream.mjs +86 -0
- package/bin/agent/anthropic-subscription-events.mjs +120 -0
- package/bin/agent/anthropic-subscription-prompt.mjs +116 -0
- package/bin/agent/anthropic-subscription-stream.mjs +251 -0
- package/bin/agent/anthropic-subscription.mjs +73 -0
- package/bin/agent/claude-code-executable.mjs +93 -0
- package/bin/agent/cliproxy-provider.mjs +25 -11
- package/bin/agent/model-roles.mjs +112 -0
- package/bin/agent/openai-compatible-provider.mjs +95 -0
- package/bin/agent/pi-tools.mjs +19 -10
- package/bin/agent/provider-login.mjs +3 -1
- package/bin/agent/provider-routes.mjs +2 -0
- package/bin/agent/providers.mjs +35 -130
- package/dist/app/index.html +5 -5
- package/dist/assets/TaskBoard-U1Yl-4F1.js +1 -0
- package/dist/assets/app-BdRlMf4J.css +1 -0
- package/dist/assets/app-DwETmoQZ.js +5144 -0
- package/dist/assets/{motion3-compile-dgGhrvPK.js → motion3-compile-DDG3wklD.js} +1 -1
- package/dist/assets/scene-asset-sync-Bz59Ghdz.js +13 -0
- package/dist/assets/task-board-DFfNa0xg.js +15 -0
- package/dist/assets/{workflow-C87p6E1E.js → workflow-BMJGd_gZ.js} +1 -1
- package/dist/cozyclay-package.json +1 -1
- package/dist/workflow/index.html +3 -3
- package/package.json +6 -4
- package/src/App.jsx +28 -28
- package/src/agent-image-client.js +2 -2
- package/src/asset-pane.jsx +14 -14
- package/src/character-kind.js +13 -12
- package/src/commands/project.js +2 -1
- package/src/commands/shot.js +1 -1
- package/src/commands/view.js +2 -2
- package/src/domains/cast.js +15 -15
- package/src/domains/motion/motion-range-pin-rules.js +1 -1
- package/src/domains/motion.js +11 -11
- package/src/domains/objects.js +20 -30
- package/src/domains/scenes.js +14 -21
- package/src/domains/shots.js +3 -3
- package/src/first-success-guide.jsx +19 -3
- package/src/hierarchy-panel.jsx +6 -7
- package/src/locale-zh/app.js +124 -0
- package/src/locale-zh/domains.js +36 -0
- package/src/locale-zh/labels.js +148 -0
- package/src/locale-zh/panels.js +225 -0
- package/src/locale-zh/shell.js +230 -0
- package/src/locale-zh/timeline.js +145 -0
- package/src/locale-zh/workflow.js +104 -0
- package/src/locale-zh/workspace.js +190 -0
- package/src/locale-zh.js +21 -0
- package/src/locale.js +16 -6
- package/src/main.jsx +1 -1
- package/src/motion/beat-board-model.js +4 -4
- package/src/motion/beat-board.jsx +1 -1
- package/src/motion/ik-pick.js +24 -0
- package/src/motion/take-segments.jsx +5 -5
- package/src/motion/timeline.jsx +30 -40
- package/src/motion/waypoints.js +6 -6
- package/src/object-catalog.jsx +4 -5
- package/src/panels/CameraPanel.jsx +3 -3
- package/src/panels/HdrEnvironmentControls.jsx +2 -1
- package/src/panels/ObjectTransformPanel.jsx +19 -29
- package/src/panels/PoseImagePanel.jsx +8 -8
- package/src/panels/PosePanel.jsx +2 -2
- package/src/panels/ReferenceImageField.jsx +2 -2
- package/src/panels/RigControlPanel.jsx +2 -2
- package/src/panels/SculptPanel.jsx +9 -9
- package/src/panels/SubjectBox.jsx +3 -3
- package/src/panels/SubjectsPanel.jsx +1 -1
- package/src/posestudio.jsx +10 -8
- package/src/project-browser.css +7 -6
- package/src/project-browser.jsx +7 -6
- package/src/project-open-file.js +19 -0
- package/src/qa-label.js +1 -1
- package/src/range-pin-panel.jsx +14 -14
- package/src/resource-status.jsx +3 -3
- package/src/result-modal.jsx +10 -10
- package/src/settings-menu.jsx +4 -1
- package/src/shell/BoardSlot.jsx +5 -5
- package/src/shell/CompositionGuideButton.jsx +1 -1
- package/src/shell/GhostsMenuGroup.jsx +1 -1
- package/src/shell/StatusBar.jsx +4 -4
- package/src/shell/ViewportToolbar.jsx +3 -3
- package/src/shell/add-camera-shot.js +2 -2
- package/src/shell/details-selection.js +1 -1
- package/src/shell/preference-controls.jsx +2 -1
- package/src/shot-guides.js +5 -5
- package/src/stage-hdr.js +3 -3
- package/src/stage-labels-ko.js +2 -2
- package/src/stage-startup-defaults.js +3 -3
- package/src/studio-actions.js +2 -2
- package/src/styles/tokens.css +1 -1
- package/src/styles.css +1 -1
- package/src/use-case-question.jsx +18 -18
- package/src/workflow/AgentPanel.jsx +4 -4
- package/src/workflow/AgentPlanCard.jsx +1 -1
- package/src/workflow/AgentProgressCard.jsx +4 -4
- package/src/workflow/AgentTurnSteps.jsx +1 -1
- package/src/workflow/LoginPanel.jsx +1 -1
- package/src/workflow/TaskBoard.jsx +1 -1
- package/src/workflow/TaskInline.jsx +1 -1
- package/src/workflow/agent-client.js +1 -1
- package/src/workflow/agent-turn.js +5 -5
- package/src/workflow/task-board.js +4 -4
- package/tools/loc-baseline.json +1 -1
- package/tools/run-tests.mjs +4 -4
- package/dist/assets/TaskBoard-GR8xZm5c.js +0 -1
- package/dist/assets/app-Bhe0TpGz.css +0 -1
- package/dist/assets/app-C4QTcDcb.js +0 -5144
- package/dist/assets/scene-asset-sync-qoxcdrhj.js +0 -13
- package/dist/assets/task-board-BqReHzOi.js +0 -15
|
@@ -6,6 +6,6 @@ export function addCameraShot({ appContext, runStudioAction, setToast }) {
|
|
|
6
6
|
const made = shots.read().find((row) => row.id === receipt?.affectedIds.find((id) => !before.some((old) => old.id === id)));
|
|
7
7
|
if (!made) return;
|
|
8
8
|
setToast(made.kind === "still"
|
|
9
|
-
? ko(`${made.name} added — a storyboard panel at frame ${made.startFrame}`, `${made.name} 추가됨 — ${made.startFrame}프레임의 스토리보드
|
|
10
|
-
: ko(`${made.name} added — a camera cut at frame ${made.startFrame}`, `${made.name} 추가됨 — ${made.startFrame}프레임에서 카메라
|
|
9
|
+
? ko(`${made.name} added — a storyboard panel at frame ${made.startFrame}`, `${made.name} 추가됨 — ${made.startFrame}프레임의 스토리보드 패널`, `${made.name} 已添加 — 第 ${made.startFrame} 帧的故事板面板`)
|
|
10
|
+
: ko(`${made.name} added — a camera cut at frame ${made.startFrame}`, `${made.name} 추가됨 — ${made.startFrame}프레임에서 카메라 컷`, `${made.name} 已添加 — 第 ${made.startFrame} 帧的摄影机剪辑`));
|
|
11
11
|
}
|
|
@@ -9,7 +9,7 @@ import { LIGHT_KIND } from "../object-look.js";
|
|
|
9
9
|
const characterIndexForRow = (rowId, characters) => rowId === "characterA" ? 0
|
|
10
10
|
: rowId === "characterB" ? 1
|
|
11
11
|
: characters.findIndex((entry) => `character:${entry.id}` === rowId);
|
|
12
|
-
const characterTitle = (index) => ko(`Character ${index + 1}`, `인물 ${index + 1}`);
|
|
12
|
+
const characterTitle = (index) => ko(`Character ${index + 1}`, `인물 ${index + 1}`, `角色 ${index + 1}`);
|
|
13
13
|
|
|
14
14
|
/** The 2a selection header: the selected item's name and a "Kind · detail"
|
|
15
15
|
* type line. Null when nothing that owns settings is selected. */
|
|
@@ -56,7 +56,7 @@ export function ThemeControls() {
|
|
|
56
56
|
const [theme, setTheme] = useState(readTheme);
|
|
57
57
|
const options = [
|
|
58
58
|
{ id: "dark", label: ko("Dark", "다크") },
|
|
59
|
-
{ id: "light", label: ko("Light", "라이트") },
|
|
59
|
+
{ id: "light", label: ko("Light", "라이트", "浅色") },
|
|
60
60
|
];
|
|
61
61
|
return (
|
|
62
62
|
<div className="v2-preferences__language-controls" role="group" aria-label={ko("Theme", "테마")}>
|
|
@@ -80,6 +80,7 @@ export function LanguageControls() {
|
|
|
80
80
|
const options = [
|
|
81
81
|
{ id: "en", label: "English", action: "Switch to English" },
|
|
82
82
|
{ id: "ko", label: "한국어", action: "한국어로 전환" },
|
|
83
|
+
{ id: "zh", label: "简体中文", action: "切换到中文" },
|
|
83
84
|
];
|
|
84
85
|
return (
|
|
85
86
|
<div className="v2-preferences__language-controls">
|
package/src/shot-guides.js
CHANGED
|
@@ -9,11 +9,11 @@ export const GUIDE_STORAGE_KEY = "cozyclay.shot-guides.v1";
|
|
|
9
9
|
export const GUIDE_MODES = Object.freeze(["off", "thirds", "golden", "center", "safe"]);
|
|
10
10
|
|
|
11
11
|
export const GUIDE_LABELS = Object.freeze({
|
|
12
|
-
off: Object.freeze({ en: "Guides off", ko: "가이드 끔" }),
|
|
13
|
-
thirds: Object.freeze({ en: "Thirds", ko: "삼분할" }),
|
|
14
|
-
golden: Object.freeze({ en: "Golden ratio", ko: "골든 레이쇼" }),
|
|
15
|
-
center: Object.freeze({ en: "Center + diagonals", ko: "센터·대각선" }),
|
|
16
|
-
safe: Object.freeze({ en: "Safe areas", ko: "세이프 에어리어" }),
|
|
12
|
+
off: Object.freeze({ en: "Guides off", ko: "가이드 끔", zh: "参考线关闭" }),
|
|
13
|
+
thirds: Object.freeze({ en: "Thirds", ko: "삼분할", zh: "三分法" }),
|
|
14
|
+
golden: Object.freeze({ en: "Golden ratio", ko: "골든 레이쇼", zh: "黄金比例" }),
|
|
15
|
+
center: Object.freeze({ en: "Center + diagonals", ko: "센터·대각선", zh: "中心 + 对角线" }),
|
|
16
|
+
safe: Object.freeze({ en: "Safe areas", ko: "세이프 에어리어", zh: "安全框" }),
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
export function nextGuideMode(mode) {
|
package/src/stage-hdr.js
CHANGED
|
@@ -23,11 +23,11 @@ const HDR_TYPES = Object.freeze(["image/vnd.radiance", "image/x-exr", "image/png
|
|
|
23
23
|
* default camera); hdrRotation turns it about +y.
|
|
24
24
|
*/
|
|
25
25
|
export const HDR_BUILTINS = Object.freeze([
|
|
26
|
-
{ id: "builtin:night-street", name: "Night street", ko: "밤거리", brightest: [0.72, 0.2, 0.66],
|
|
26
|
+
{ id: "builtin:night-street", name: "Night street", ko: "밤거리", zh: "夜晚街道", brightest: [0.72, 0.2, 0.66],
|
|
27
27
|
note: "dark blue night sky, a building skyline with lit windows, two warm sodium street lamps (front right and back left) pooling light on wet asphalt, a dim moon" },
|
|
28
|
-
{ id: "builtin:overcast-field", name: "Overcast field", ko: "흐린 들판", brightest: [-0.35, 0.66, -0.67],
|
|
28
|
+
{ id: "builtin:overcast-field", name: "Overcast field", ko: "흐린 들판", zh: "阴天田野", brightest: [-0.35, 0.66, -0.67],
|
|
29
29
|
note: "bright soft grey overcast sky (brighter overhead), a faint sun glow behind the clouds back left, a distant tree line and a green field" },
|
|
30
|
-
{ id: "builtin:studio-softbox", name: "Studio softbox", ko: "스튜디오 소프트박스", brightest: [-0.6, 0.4, 0.7],
|
|
30
|
+
{ id: "builtin:studio-softbox", name: "Studio softbox", ko: "스튜디오 소프트박스", zh: "影棚柔光箱", brightest: [-0.6, 0.4, 0.7],
|
|
31
31
|
note: "dark grey photo studio: a large white softbox front left, a tall strip light right, a soft overhead panel and a rim panel behind" },
|
|
32
32
|
].map((entry) => Object.freeze({ ...entry, brightest: Object.freeze(entry.brightest) })));
|
|
33
33
|
const BUILTIN_IDS = new Set(HDR_BUILTINS.map((entry) => entry.id));
|
package/src/stage-labels-ko.js
CHANGED
|
@@ -76,7 +76,7 @@ export const CAMERA_MOVE_LABELS_KO = new Map([
|
|
|
76
76
|
["Dolly-zoom (vertigo)", ko("Dolly-zoom (vertigo)", "돌리 줌(버티고)")],
|
|
77
77
|
["Whip pan", ko("Whip pan", "휩 팬")],
|
|
78
78
|
["Aerial / drone", ko("Aerial / drone", "공중 / 드론")],
|
|
79
|
-
[CUSTOM_MOVE, ko(CUSTOM_MOVE, "직접 입력…")],
|
|
79
|
+
[CUSTOM_MOVE, ko(CUSTOM_MOVE, "직접 입력…", "自定义…")],
|
|
80
80
|
]);
|
|
81
81
|
|
|
82
82
|
export const POSE_LABELS_KO = new Map([
|
|
@@ -120,7 +120,7 @@ export const SCENE_RENDERER_LABELS_KO = new Map([
|
|
|
120
120
|
["cone", ko("cone", "원뿔")],
|
|
121
121
|
["plane", ko("plane", "평면")],
|
|
122
122
|
[CUTOUT_KIND, ko("cutout", "컷아웃")],
|
|
123
|
-
[MESH_KIND, ko("Mesh", "모델")],
|
|
123
|
+
[MESH_KIND, ko("Mesh", "모델", "模型")],
|
|
124
124
|
["sculpt", ko("Sculpt", "조형")],
|
|
125
125
|
]);
|
|
126
126
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
|
-
import { ko
|
|
2
|
+
import { ko } from "./locale.js";
|
|
3
3
|
import { SHOT_ASPECT_RATIOS } from "./shot.js";
|
|
4
4
|
import {
|
|
5
5
|
SCENES_QUARANTINE_KEY,
|
|
@@ -159,9 +159,9 @@ export function loadSceneStartup() {
|
|
|
159
159
|
// funnel's "scene created" step never fires for a brand-new room.
|
|
160
160
|
startupCreatedScene: result.status === "absent" || result.status === "corrupt",
|
|
161
161
|
toast: result.status === "corrupt"
|
|
162
|
-
? ko(`Saved scenes were unreadable — starting fresh; the old data is kept under ${SCENES_QUARANTINE_KEY}`, `저장된 장면을 읽을 수 없어 새로 시작합니다. 기존 데이터는 ${SCENES_QUARANTINE_KEY}에
|
|
162
|
+
? ko(`Saved scenes were unreadable — starting fresh; the old data is kept under ${SCENES_QUARANTINE_KEY}`, `저장된 장면을 읽을 수 없어 새로 시작합니다. 기존 데이터는 ${SCENES_QUARANTINE_KEY}에 보관했어요.`, `无法读取已保存的场景 — 将重新开始;旧数据保留在 ${SCENES_QUARANTINE_KEY} 下。`)
|
|
163
163
|
: result.dropped > 0
|
|
164
|
-
? (
|
|
164
|
+
? ko(`${result.dropped} saved scene(s) could not be restored`, `저장된 장면 ${result.dropped}개를 복원하지 못했어요`, `${result.dropped} 个已保存的场景无法恢复`)
|
|
165
165
|
: null,
|
|
166
166
|
};
|
|
167
167
|
} catch {
|
package/src/studio-actions.js
CHANGED
|
@@ -168,8 +168,8 @@ export function studioActionRefusal(code, message, uiMessage) {
|
|
|
168
168
|
}
|
|
169
169
|
// A localized toast producer is evaluated twice, without showing it twice:
|
|
170
170
|
// once for the existing UI and once in English for command evidence.
|
|
171
|
-
export function resolveStudioToast(value, isKo, ko) {
|
|
172
|
-
return typeof value === "function" ? { uiMessage: value(isKo, ko), message: value(false, en => en) } : { uiMessage: value, message: value };
|
|
171
|
+
export function resolveStudioToast(value, isKo, ko, isZh = false) {
|
|
172
|
+
return typeof value === "function" ? { uiMessage: value(isKo, ko, isZh), message: value(false, en => en, false) } : { uiMessage: value, message: value };
|
|
173
173
|
}
|
|
174
174
|
const unknown = (id, known) => fail("INVALID_ARGUMENT", `Unknown Studio action "${id}". Known actions: ${known.join(", ")}. List them with inspect_studio { scope: "actions" }.`);
|
|
175
175
|
|
package/src/styles/tokens.css
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
--sp-3: 16px;
|
|
64
64
|
|
|
65
65
|
/* Self-hosted UI families with the existing Korean fallbacks retained. */
|
|
66
|
-
--sans: "IBM Plex Sans", "Pretendard", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
66
|
+
--sans: "IBM Plex Sans", "Pretendard", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
67
67
|
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
68
68
|
}
|
|
69
69
|
}
|
package/src/styles.css
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
--grad: var(--primary);
|
|
67
67
|
--grad-soft: var(--primary);
|
|
68
68
|
--display: var(--sans);
|
|
69
|
-
--sans: "IBM Plex Sans", "Pretendard", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
69
|
+
--sans: "IBM Plex Sans", "Pretendard", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
70
70
|
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
71
71
|
--radius: var(--r-1);
|
|
72
72
|
--shadow: 0 1px 2px rgba(0, 0, 0, .4);
|
|
@@ -3,16 +3,16 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
// Closed choices only (analytics USE_CASE_VALUES / TEAM_VALUES): no free text
|
|
4
4
|
// ever leaves the browser from this card.
|
|
5
5
|
const USE_CASES = Object.freeze([
|
|
6
|
-
["animation", "Animation", "애니메이션"],
|
|
7
|
-
["film", "Film / drama", "영화·드라마"],
|
|
8
|
-
["game", "Game", "게임"],
|
|
9
|
-
["ad_mv", "Ad / music video", "광고·뮤비"],
|
|
10
|
-
["personal", "Personal project", "개인 작업"],
|
|
11
|
-
["other", "Something else", "기타"],
|
|
6
|
+
["animation", "Animation", "애니메이션", "动画"],
|
|
7
|
+
["film", "Film / drama", "영화·드라마", "影视剧"],
|
|
8
|
+
["game", "Game", "게임", "游戏"],
|
|
9
|
+
["ad_mv", "Ad / music video", "광고·뮤비", "广告 / MV"],
|
|
10
|
+
["personal", "Personal project", "개인 작업", "个人项目"],
|
|
11
|
+
["other", "Something else", "기타", "其他"],
|
|
12
12
|
]);
|
|
13
13
|
const TEAMS = Object.freeze([
|
|
14
|
-
["team", "With a team or company", "팀·회사에서"],
|
|
15
|
-
["solo", "On my own", "혼자"],
|
|
14
|
+
["team", "With a team or company", "팀·회사에서", "与团队或公司"],
|
|
15
|
+
["solo", "On my own", "혼자", "我自己"],
|
|
16
16
|
]);
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -20,9 +20,9 @@ const TEAMS = Object.freeze([
|
|
|
20
20
|
* what the export is for, then team or solo. Closing it at any point counts as
|
|
21
21
|
* a skip, and the card never comes back on this browser profile.
|
|
22
22
|
*/
|
|
23
|
-
export default function UseCaseQuestion({ open, isKo, onAnswer }) {
|
|
23
|
+
export default function UseCaseQuestion({ open, isKo, isZh, onAnswer }) {
|
|
24
24
|
const [useCase, setUseCase] = useState(null);
|
|
25
|
-
const label = (en,
|
|
25
|
+
const label = (en, korean, chinese) => (isKo ? korean : isZh ? chinese : en);
|
|
26
26
|
useEffect(() => {
|
|
27
27
|
if (!open) setUseCase(null);
|
|
28
28
|
}, [open]);
|
|
@@ -39,28 +39,28 @@ export default function UseCaseQuestion({ open, isKo, onAnswer }) {
|
|
|
39
39
|
}}
|
|
40
40
|
>
|
|
41
41
|
<div className="use-case-ask-head">
|
|
42
|
-
<strong id="use-case-ask-title">{label("Quick question (optional)", "짧은 질문 (선택)")}</strong>
|
|
43
|
-
<button type="button" className="use-case-ask-close" aria-label={label("Close", "닫기")} onClick={close}>
|
|
42
|
+
<strong id="use-case-ask-title">{label("Quick question (optional)", "짧은 질문 (선택)", "快速提问(可选)")}</strong>
|
|
43
|
+
<button type="button" className="use-case-ask-close" aria-label={label("Close", "닫기", "关闭")} onClick={close}>
|
|
44
44
|
×
|
|
45
45
|
</button>
|
|
46
46
|
</div>
|
|
47
47
|
<p className="use-case-ask-prompt">
|
|
48
48
|
{useCase
|
|
49
|
-
? label("Who are you making it with?", "누구와 작업하나요?")
|
|
50
|
-
: label("What are you making with CozyClay?", "CozyClay로 뭘 만들고 있나요?")}
|
|
49
|
+
? label("Who are you making it with?", "누구와 작업하나요?", "你和谁一起做?")
|
|
50
|
+
: label("What are you making with CozyClay?", "CozyClay로 뭘 만들고 있나요?", "你在用 CozyClay 做什么?")}
|
|
51
51
|
</p>
|
|
52
|
-
<div className="use-case-ask-choices" role="group" aria-label={useCase ? label("Team or solo", "팀 또는 혼자") : label("Use case", "용도")}>
|
|
53
|
-
{(useCase ? TEAMS : USE_CASES).map(([value, en, ko]) => (
|
|
52
|
+
<div className="use-case-ask-choices" role="group" aria-label={useCase ? label("Team or solo", "팀 또는 혼자", "团队或个人") : label("Use case", "용도", "用途")}>
|
|
53
|
+
{(useCase ? TEAMS : USE_CASES).map(([value, en, ko, zh]) => (
|
|
54
54
|
<button
|
|
55
55
|
key={value}
|
|
56
56
|
type="button"
|
|
57
57
|
onClick={() => (useCase ? onAnswer(useCase, value) : setUseCase(value))}
|
|
58
58
|
>
|
|
59
|
-
{label(en, ko)}
|
|
59
|
+
{label(en, ko, zh)}
|
|
60
60
|
</button>
|
|
61
61
|
))}
|
|
62
62
|
</div>
|
|
63
|
-
<p className="use-case-ask-note">{label("Anonymous. Only the choice is sent.", "익명이에요. 고른 항목만 전송돼요.")}</p>
|
|
63
|
+
<p className="use-case-ask-note">{label("Anonymous. Only the choice is sent.", "익명이에요. 고른 항목만 전송돼요.", "匿名。只发送所选项目。")}</p>
|
|
64
64
|
</section>
|
|
65
65
|
);
|
|
66
66
|
}
|
|
@@ -89,9 +89,9 @@ function OfflineCard({ probing, onRetry }) {
|
|
|
89
89
|
<FiPower className="agent-offline-icon" size={18} aria-hidden="true" />
|
|
90
90
|
<h3>{ko("Agent server is not running", "에이전트 서버가 실행 중이 아니에요")}</h3>
|
|
91
91
|
<p>{ko(<>Start CozyClay with <code>npx cozyclay</code> (or <code>npm run dev</code> in a checkout) to sign in.</>,
|
|
92
|
-
<>로그인하려면 <code>npx cozyclay</code>(체크아웃에서는 <code>npm run dev</code>)로 CozyClay를
|
|
92
|
+
<>로그인하려면 <code>npx cozyclay</code>(체크아웃에서는 <code>npm run dev</code>)로 CozyClay를 시작하세요.</>, <>使用 <code>npx cozyclay</code> 启动 CozyClay(在代码检出中使用 <code>npm run dev</code>)即可登录。</>)}</p>
|
|
93
93
|
<button type="button" className="agent-ghost-button agent-offline-retry" onClick={onRetry} disabled={probing} aria-busy={probing}>
|
|
94
|
-
<FiRotateCw size={11} aria-hidden="true" /> {probing ? ko("Checking…", "확인 중…") : ko("Retry", "다시 확인")}
|
|
94
|
+
<FiRotateCw size={11} aria-hidden="true" /> {probing ? ko("Checking…", "확인 중…") : ko("Retry", "다시 확인", "重新检查")}
|
|
95
95
|
</button>
|
|
96
96
|
</div>;
|
|
97
97
|
}
|
|
@@ -966,7 +966,7 @@ export default function AgentPanel({
|
|
|
966
966
|
<select className="agent-model-select" aria-label="Model" title="Model" value={model} disabled={!models.length} onChange={(event) => chooseModel(event.target.value)}>
|
|
967
967
|
{modelProviders.length
|
|
968
968
|
? modelProviders.map((provider) => <optgroup key={provider.id} label={provider.label}>
|
|
969
|
-
{provider.models.length
|
|
969
|
+
{provider.error && <option value={`${provider.id}/error`} disabled>{provider.error}</option>}{provider.models.length
|
|
970
970
|
? provider.models.map((entry) => <option key={entry.key} value={entry.key} disabled={!provider.signedIn}>{provider.signedIn ? entry.label : `${entry.label} — add key`}</option>)
|
|
971
971
|
: <option value={`${provider.id}/`} disabled>{provider.signedIn ? "No models" : "No models — add key"}</option>}
|
|
972
972
|
</optgroup>)
|
|
@@ -982,7 +982,7 @@ export default function AgentPanel({
|
|
|
982
982
|
</select>
|
|
983
983
|
)}
|
|
984
984
|
{surface === "studio" && (
|
|
985
|
-
<button type="button" className={`agent-supervisor-toggle agent-tasks-toggle${taskMode ? " is-on" : ""}`} role="switch" aria-checked={taskMode} aria-label={ko("Task mode", "작업 모드")} title={ko(taskMode ? "Task mode is on: the agent answers at once and runs your requests as parallel tasks" : "Task mode is off: one request at a time", taskMode ? "작업 모드 켜짐: 에이전트가 바로 답하고 요청을 병렬 작업으로 돌려요" : "작업 모드 꺼짐: 한 번에 요청 하나")} onClick={toggleTaskMode} disabled={streaming}>
|
|
985
|
+
<button type="button" className={`agent-supervisor-toggle agent-tasks-toggle${taskMode ? " is-on" : ""}`} role="switch" aria-checked={taskMode} aria-label={ko("Task mode", "작업 모드")} title={ko(taskMode ? "Task mode is on: the agent answers at once and runs your requests as parallel tasks" : "Task mode is off: one request at a time", taskMode ? "작업 모드 켜짐: 에이전트가 바로 답하고 요청을 병렬 작업으로 돌려요" : "작업 모드 꺼짐: 한 번에 요청 하나", taskMode ? "任务模式已开启:智能体会立即回答,并将请求作为并行任务运行" : "任务模式已关闭:一次只处理一个请求")} onClick={toggleTaskMode} disabled={streaming}>
|
|
986
986
|
{ko("Tasks", "작업")} {taskMode ? "ON" : "OFF"}
|
|
987
987
|
</button>
|
|
988
988
|
)}
|
|
@@ -24,7 +24,7 @@ export function PlanCard({ plan, live }) {
|
|
|
24
24
|
const total = plan.steps.length, done = plan.steps.filter(step => step.status === "done").length;
|
|
25
25
|
const state = live ? "live" : plan.outcome ?? "done";
|
|
26
26
|
return <div className="agent-row agent-plan-row" data-plan-live={live ? "true" : "false"}>
|
|
27
|
-
<section className="agent-card agent-plan" data-agent-card="plan" data-plan-state={state} aria-label={ko(`Plan, ${done} of ${total} done`, `계획, ${total}단계 중 ${done}단계
|
|
27
|
+
<section className="agent-card agent-plan" data-agent-card="plan" data-plan-state={state} aria-label={ko(`Plan, ${done} of ${total} done`, `계획, ${total}단계 중 ${done}단계 완료`, `计划,已完成 ${done} / ${total}`)}>
|
|
28
28
|
<div className="agent-plan-head">
|
|
29
29
|
<span className="agent-plan-title">{ko("Plan", "계획")}</span>
|
|
30
30
|
<span className="agent-plan-bar" aria-hidden="true"><span className="agent-plan-fill" style={{ "--agent-plan-done": total ? done / total : 0 }} /></span>
|
|
@@ -19,7 +19,7 @@ function Trend({ totals }) {
|
|
|
19
19
|
const { points, first, last } = trendPoints(totals, { width: W, height: H });
|
|
20
20
|
if (!points.length) return null;
|
|
21
21
|
const [lx, ly] = points[points.length - 1];
|
|
22
|
-
const label = ko(`Problems by draft: ${totals.join(", ")}`, `초안별 문제 수: ${totals.join(", ")}`);
|
|
22
|
+
const label = ko(`Problems by draft: ${totals.join(", ")}`, `초안별 문제 수: ${totals.join(", ")}`, `各草稿的问题数:${totals.join(", ")}`);
|
|
23
23
|
return <div className="agent-progress-trend">
|
|
24
24
|
<svg viewBox={`0 0 ${W} ${H}`} role="img" aria-label={label} preserveAspectRatio="none">
|
|
25
25
|
<line className="base" x1={4} y1={H - 4} x2={W - 4} y2={H - 4} />
|
|
@@ -67,17 +67,17 @@ export function AgentProgressCard({ items, since = null, live = false }) {
|
|
|
67
67
|
return <div className="agent-row">
|
|
68
68
|
<div className="agent-card agent-progress-card" data-agent-card="progress" data-drafts={drafts.length} data-installed={latest?.installed ? "true" : "false"} role="status" aria-live="polite">
|
|
69
69
|
{latest && <div className="agent-progress-head">
|
|
70
|
-
<span className="agent-progress-title" title={ko(`${latest.qa.total} frame-level issues`, `프레임 단위 문제 ${latest.qa.total}
|
|
70
|
+
<span className="agent-progress-title" title={ko(`${latest.qa.total} frame-level issues`, `프레임 단위 문제 ${latest.qa.total}건`, `${latest.qa.total} 个帧级问题`)}>{draftLabel(latest)}</span>
|
|
71
71
|
<span className={`agent-progress-chip ${latest.installed ? "installed" : "draft"}`}>{latest.installed ? ko("Installed", "설치됨") : live ? ko("Not installed yet", "아직 설치 전") : ko("Not installed", "설치 안 됨")}</span>
|
|
72
72
|
</div>}
|
|
73
73
|
{latest?.label && <p className="agent-progress-label">{latest.label}</p>}
|
|
74
74
|
{drafts.length > 0 && <section className="agent-progress-section">
|
|
75
|
-
<h4>{ko(`Problems across ${drafts.length} draft${drafts.length === 1 ? "" : "s"}`, `초안 ${drafts.length}개의 문제
|
|
75
|
+
<h4>{ko(`Problems across ${drafts.length} draft${drafts.length === 1 ? "" : "s"}`, `초안 ${drafts.length}개의 문제 수`, `${drafts.length} 个草稿的问题`)}</h4>
|
|
76
76
|
<Trend totals={drafts.map(d => qaProblems(d.qa))} />
|
|
77
77
|
</section>}
|
|
78
78
|
{goals.length > 0 && <section className="agent-progress-section">
|
|
79
79
|
<button type="button" className="agent-progress-fold" aria-expanded={!!shown.goals} onClick={() => toggle("goals")}>
|
|
80
|
-
<h4>{ko("Goals", "목표")}</h4><span>{ko(`${goals.filter(g => g.ok).length} of ${goals.length} met`, `${goals.length}개 중 ${goals.filter(g => g.ok).length}개
|
|
80
|
+
<h4>{ko("Goals", "목표")}</h4><span>{ko(`${goals.filter(g => g.ok).length} of ${goals.length} met`, `${goals.length}개 중 ${goals.filter(g => g.ok).length}개 충족`, `${goals.length} 个目标中已达成 ${goals.filter(g => g.ok).length} 个`)}</span>
|
|
81
81
|
</button>
|
|
82
82
|
{shown.goals && <ul className="agent-progress-goals">
|
|
83
83
|
{goals.map((g, i) => <li key={i} data-goal-ok={g.ok ? "true" : "false"}>
|
|
@@ -45,7 +45,7 @@ function Step({ step, live, isLast, now, toolLabels }) {
|
|
|
45
45
|
</li>;
|
|
46
46
|
}
|
|
47
47
|
const running = step.kind === "compose" || step.status === "running";
|
|
48
|
-
const label = step.kind === "compose" ? ko(`Preparing ${stepLabel(step, toolLabels)}`, `${stepLabel(step, toolLabels)} 준비
|
|
48
|
+
const label = step.kind === "compose" ? ko(`Preparing ${stepLabel(step, toolLabels)}`, `${stepLabel(step, toolLabels)} 준비 중`, `正在准备 ${stepLabel(step, toolLabels)}`) : stepLabel(step, toolLabels);
|
|
49
49
|
const result = running ? (step.progress ? `${scriptNow(step)}${step.progress.summary ? ` — ${step.progress.summary}` : ""}` : "") : stepResult(step);
|
|
50
50
|
const time = running ? now - (step.startedAt ?? now) : step.elapsedMs;
|
|
51
51
|
return <li className={`agent-step ${step.kind}${step.status === "failed" ? " failed" : ""}`} data-step-kind={step.kind} data-tool-name={step.name} data-tool-status={step.kind === "compose" ? "composing" : step.status} data-action={step.action}>
|
|
@@ -28,7 +28,7 @@ function PromptForm({ prompt, onSubmit }) {
|
|
|
28
28
|
<div className="agent-key-controls">
|
|
29
29
|
<input id={inputId} className="agent-key-input" type={ask.type === "secret" ? "password" : "text"} autoComplete="off" spellCheck="false"
|
|
30
30
|
placeholder={ask.placeholder ?? ""} value={value} autoFocus onChange={(event) => setValue(event.target.value)} />
|
|
31
|
-
<button type="submit" className="agent-key-save" disabled={ask.type === "secret" && !value.trim()}>Continue</button>
|
|
31
|
+
<button type="submit" className="agent-key-save" disabled={ask.type === "secret" && !ask.optional && !value.trim()}>Continue</button>
|
|
32
32
|
</div>
|
|
33
33
|
</form>;
|
|
34
34
|
}
|
|
@@ -19,7 +19,7 @@ function useScopeBadges(scopes, titles) {
|
|
|
19
19
|
const paint = () => {
|
|
20
20
|
for (const row of document.querySelectorAll("[data-node-id]")) {
|
|
21
21
|
const title = owner.get(row.getAttribute("data-node-id"));
|
|
22
|
-
if (title) { row.setAttribute("data-task-scope", title); row.setAttribute("title", ko(`In task: ${title}`, `작업 중: ${title}`)); }
|
|
22
|
+
if (title) { row.setAttribute("data-task-scope", title); row.setAttribute("title", ko(`In task: ${title}`, `작업 중: ${title}`, `任务中:${title}`)); }
|
|
23
23
|
else if (row.hasAttribute("data-task-scope")) { row.removeAttribute("data-task-scope"); row.removeAttribute("title"); }
|
|
24
24
|
}
|
|
25
25
|
};
|
|
@@ -31,7 +31,7 @@ export function TaskRows({ steps, items }) {
|
|
|
31
31
|
return <div className="task-rows">{ids.map(id => <TaskRow key={id} task={board.tasks[id]} activity={activity} />)}</div>;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const GROUPS = [["failed", ko("need a look", "확인 필요")], ["running", ko("running", "실행 중")], ["waiting", ko("waiting", "대기")], ["done", ko("done", "완료")]];
|
|
34
|
+
const GROUPS = [["failed", ko("need a look", "확인 필요")], ["running", ko("running", "실행 중", "执行中")], ["waiting", ko("waiting", "대기")], ["done", ko("done", "완료")]];
|
|
35
35
|
|
|
36
36
|
export function TaskStrip() {
|
|
37
37
|
const { board, activity } = useTaskView();
|
|
@@ -204,7 +204,7 @@ export const PANEL_PRESENTATIONS = Object.freeze({
|
|
|
204
204
|
history: true,
|
|
205
205
|
persistWidth: false,
|
|
206
206
|
emptyTitle: ko("Direct the scene", "\uC7A5\uBA74\uC744 \uC5F0\uCD9C\uD558\uC138\uC694"),
|
|
207
|
-
emptyHint: (sceneName) => ko(`Ask for blocking, a camera move, or a motion take in \u201C${sceneName}\u201D.`, `\u201C${sceneName}\u201D\uC5D0\uC11C \uBE14\uB85C\uD0B9, \uCE74\uBA54\uB77C \uC6C0\uC9C1\uC784, \uBAA8\uC158 \uD14C\uC774\uD06C\uB97C \uC694\uCCAD\uD558\uC138\uC694
|
|
207
|
+
emptyHint: (sceneName) => ko(`Ask for blocking, a camera move, or a motion take in \u201C${sceneName}\u201D.`, `\u201C${sceneName}\u201D\uC5D0\uC11C \uBE14\uB85C\uD0B9, \uCE74\uBA54\uB77C \uC6C0\uC9C1\uC784, \uBAA8\uC158 \uD14C\uC774\uD06C\uB97C \uC694\uCCAD\uD558\uC138\uC694.`, `在“${sceneName}”中请求摆位、摄影机运动或动作片段。`),
|
|
208
208
|
composerPlaceholder: ko("Ask the agent to block, frame or animate\u2026", "\uBE14\uB85C\uD0B9\u00B7\uAD6C\uB3C4\u00B7\uBAA8\uC158\uC744 \uC694\uCCAD\uD558\uC138\uC694\u2026"),
|
|
209
209
|
}),
|
|
210
210
|
});
|
|
@@ -66,9 +66,9 @@ export function stepResult(step) {
|
|
|
66
66
|
if (step.name === "script") {
|
|
67
67
|
const calls = Array.isArray(result.calls) ? result.calls : [];
|
|
68
68
|
const refused = calls.filter(call => call?.ok === false);
|
|
69
|
-
const head = ko(`${calls.length} call${calls.length === 1 ? "" : "s"}`, `호출 ${calls.length}
|
|
69
|
+
const head = ko(`${calls.length} call${calls.length === 1 ? "" : "s"}`, `호출 ${calls.length}회`, `调用 ${calls.length} 次`);
|
|
70
70
|
if (result.ok === false) return clip(`${head} · ${result.error?.message ?? ko("failed", "실패")}${result.rollback ? ko(" · its edits were rolled back", " · 편집 되돌림") : ""}`);
|
|
71
|
-
return clip(refused.length ? `${head} · ${ko(`${refused.length} refused`, `${refused.length}회
|
|
71
|
+
return clip(refused.length ? `${head} · ${ko(`${refused.length} refused`, `${refused.length}회 거부`, `${refused.length} 次拒绝`)}: ${refused[0].code ?? refused[0].message ?? ""}` : head);
|
|
72
72
|
}
|
|
73
73
|
if (step.name === "verify_result") return clip(verifySummary(result, step.args));
|
|
74
74
|
if (typeof result.summary === "string" && result.summary) return clip(result.summary.replace(/\.$/, ""));
|
|
@@ -81,7 +81,7 @@ export function scriptNow(step) {
|
|
|
81
81
|
const now = step.progress;
|
|
82
82
|
if (!now) return "";
|
|
83
83
|
const label = now.label ?? (now.action ? actionWords(now.action) : actionWords(now.name ?? "call"));
|
|
84
|
-
return ko(`${label} (call ${now.index})`, `${label} (${now.index}번째 호출)
|
|
84
|
+
return ko(`${label} (call ${now.index})`, `${label} (${now.index}번째 호출)`, `${label}(第 ${now.index} 次调用)`);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/** The reasoning text so far as one line: its latest paragraph, or the one before while the latest has only begun. */
|
|
@@ -157,7 +157,7 @@ export function turnLayout(items, { streaming = false } = {}) {
|
|
|
157
157
|
/** The header of a turn's step list: how many steps, how it ended and how long it took. */
|
|
158
158
|
export function stepsHeader(block, now, formatClock) {
|
|
159
159
|
const count = block.steps.filter(step => step.kind === "tool").length;
|
|
160
|
-
const steps = count ? ` · ${ko(`${count} step${count === 1 ? "" : "s"}`, `${count}
|
|
160
|
+
const steps = count ? ` · ${ko(`${count} step${count === 1 ? "" : "s"}`, `${count}단계`, `${count} 步`)}` : "";
|
|
161
161
|
if (block.live) {
|
|
162
162
|
const started = block.steps[0]?.startedAt;
|
|
163
163
|
return { tone: "busy", text: `${ko("Working", "작업 중")}${steps}${Number.isFinite(started) ? ` · ${formatClock(now - started)}` : ""}` };
|
|
@@ -179,7 +179,7 @@ export function changedLine(ids, context) {
|
|
|
179
179
|
const rest = ids.filter(id => !names.has(id)).length;
|
|
180
180
|
if (!named.length && !rest) return ko("Changed the scene", "장면을 바꿈");
|
|
181
181
|
const shown = named.slice(0, 4).join(", "), more = Math.max(0, named.length - 4) + rest;
|
|
182
|
-
return ko(`Changed ${shown || "the scene"}${more > 0 ? ` and ${more} more` : ""}`, `${shown || "장면"}${more > 0 ? ` 외 ${more}개` : ""}
|
|
182
|
+
return ko(`Changed ${shown || "the scene"}${more > 0 ? ` and ${more} more` : ""}`, `${shown || "장면"}${more > 0 ? ` 외 ${more}개` : ""} 변경`, `修改了 ${shown || "场景"}${more > 0 ? ` 以及另外 ${more} 项` : ""}`);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/** What a stopped turn left behind, as far as its steps tell: their edits stay (one undo entry), or none landed. */
|
|
@@ -45,8 +45,8 @@ export function reduceBoard(board, event) {
|
|
|
45
45
|
return { ...board, after, order: known ? board.order : [...board.order, taskId], tasks: { ...board.tasks, [taskId]: task } };
|
|
46
46
|
};
|
|
47
47
|
const note = (taskId, text) => (board.tasks[taskId] ? patch(taskId, { notes: [...board.tasks[taskId].notes, text].slice(-4) }) : { ...board, after });
|
|
48
|
-
if (event.type === "task.sceneChanged") return note(event.taskId, ko(`The scene changed during a reload: ${event.keys.join(", ")}`, `새로고침 중에 장면이 바뀜: ${event.keys.join(", ")}`));
|
|
49
|
-
if (event.type === "task.userEdit") return note(event.taskId, ko(`You changed ${event.keys.join(", ")}; the task reads it again`, `${event.keys.join(", ")}을(를) 직접 바꿈: 작업이 다시
|
|
48
|
+
if (event.type === "task.sceneChanged") return note(event.taskId, ko(`The scene changed during a reload: ${event.keys.join(", ")}`, `새로고침 중에 장면이 바뀜: ${event.keys.join(", ")}`, `重新加载期间场景发生变化:${event.keys.join(", ")}`));
|
|
49
|
+
if (event.type === "task.userEdit") return note(event.taskId, ko(`You changed ${event.keys.join(", ")}; the task reads it again`, `${event.keys.join(", ")}을(를) 직접 바꿈: 작업이 다시 읽어요`, `你修改了 ${event.keys.join(", ")};任务会重新读取`));
|
|
50
50
|
if (event.type === "task.undone") return board.tasks[event.taskId] ? patch(event.taskId, { undone: true }) : board;
|
|
51
51
|
if (typeof event.type === "string" && event.type.startsWith("task.") && event.taskId && event.status) {
|
|
52
52
|
const { type, at, eventSeq, ...view } = event;
|
|
@@ -63,7 +63,7 @@ export function seedBoard(board, tasks = []) {
|
|
|
63
63
|
/** The line a running card shows: the last tool it started, or the compile it waits for. */
|
|
64
64
|
export function progressLine(frame, labelOf = call => call.name) {
|
|
65
65
|
if (frame?.type === "tool.start") return labelOf(frame);
|
|
66
|
-
if (frame?.type === "error") return ko(`Error: ${frame.message ?? frame.code}`, `오류: ${frame.message ?? frame.code}`);
|
|
66
|
+
if (frame?.type === "error") return ko(`Error: ${frame.message ?? frame.code}`, `오류: ${frame.message ?? frame.code}`, `错误:${frame.message ?? frame.code}`);
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -71,7 +71,7 @@ export function progressLine(frame, labelOf = call => call.name) {
|
|
|
71
71
|
export function taskReason(reason) {
|
|
72
72
|
// Greedy to the last ")": a title may hold parentheses of its own.
|
|
73
73
|
const after = /(?:waits for|held by) task \S+ \((.+)\)/.exec(String(reason ?? ""))?.[1];
|
|
74
|
-
if (after) return ko(`Starts after "${after}"`, `'${after}' 끝나면
|
|
74
|
+
if (after) return ko(`Starts after "${after}"`, `'${after}' 끝나면 시작`, `在“${after}”之后开始`);
|
|
75
75
|
if (/scope is held/.test(String(reason ?? ""))) return ko("Starts when another task frees its part", "다른 작업이 끝나면 시작");
|
|
76
76
|
return reason ?? "";
|
|
77
77
|
}
|
package/tools/loc-baseline.json
CHANGED
package/tools/run-tests.mjs
CHANGED
|
@@ -29,7 +29,7 @@ const NODE_FILES = [
|
|
|
29
29
|
"test/ardy/verify-timeline-coordinates.mjs",
|
|
30
30
|
"test/verify-tokens.mjs", "test/verify-lens-scrub.mjs",
|
|
31
31
|
"test/demo/verify-api-routes.mjs",
|
|
32
|
-
"test/ik/verify-collision-capsules.mjs",
|
|
32
|
+
"test/ik/verify-collision-capsules.mjs", "test/ik/verify-ik-pick.mjs",
|
|
33
33
|
"test/ik/verify-ground.mjs",
|
|
34
34
|
"test/ik/verify-physics-review.mjs",
|
|
35
35
|
"test/ik/verify-physics-support.mjs",
|
|
@@ -43,7 +43,7 @@ const NODE_FILES = [
|
|
|
43
43
|
"test/ik/verify-range-pin-ui.mjs",
|
|
44
44
|
"test/ik/verify-range-pin-object-transform.mjs",
|
|
45
45
|
"test/verify-ik-camera-performance.mjs",
|
|
46
|
-
"test/verify-ik-entry-camera.mjs", "test/verify-viewport-visible-rect.mjs",
|
|
46
|
+
"test/verify-ik-entry-camera.mjs", "test/verify-viewport-visible-rect.mjs", "test/verify-project-open-file.mjs",
|
|
47
47
|
"test/process/verify-lifecycle.mjs",
|
|
48
48
|
"test/process/verify-mcp-package-isolation.mjs",
|
|
49
49
|
"test/process/verify-package-telemetry.mjs",
|
|
@@ -59,7 +59,7 @@ const NODE_FILES = [
|
|
|
59
59
|
"test/verify-agent-runner-errors.mjs",
|
|
60
60
|
"test/verify-agent-steer.mjs",
|
|
61
61
|
"test/verify-pi-tools.mjs",
|
|
62
|
-
"test/verify-agent-providers.mjs", "test/verify-agent-login.mjs",
|
|
62
|
+
"test/verify-agent-providers.mjs", "test/verify-agent-minimax.mjs", "test/verify-agent-login.mjs", "test/verify-agent-openai-compatible.mjs", "test/verify-anthropic-subscription.mjs",
|
|
63
63
|
"test/verify-cliproxy-live-model.mjs",
|
|
64
64
|
"test/verify-schema-to-typebox.mjs",
|
|
65
65
|
"test/verify-agent-sse-golden.mjs",
|
|
@@ -111,7 +111,7 @@ const NODE_FILES = [
|
|
|
111
111
|
"test/verify-image-versions.mjs",
|
|
112
112
|
"test/verify-keyframe-pack.mjs",
|
|
113
113
|
"test/verify-keyframe-pack-request.mjs",
|
|
114
|
-
"test/verify-korean-ui.mjs",
|
|
114
|
+
"test/verify-korean-ui.mjs", "test/verify-chinese-ui.mjs",
|
|
115
115
|
"test/verify-label-tooltips.mjs",
|
|
116
116
|
"test/verify-layout.mjs",
|
|
117
117
|
"test/verify-beginner-screen.mjs",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{c as t,d as n,da as r,f as i,l as a,m as o,o as s,v as c,wi as l}from"./task-board-BqReHzOi.js";import{o as u,r as d,t as f}from"./motion3-compile-dgGhrvPK.js";var p=e(r(),1),m=2e3,h=(e,t)=>new Promise(n=>{let r=setTimeout(n,e);t.addEventListener(`abort`,()=>{clearTimeout(r),n()},{once:!0})});function g(e,t){(0,p.useEffect)(()=>{let n=new Map;for(let[r,i]of Object.entries(e))for(let e of i)n.set(e,t[r]??r);let r=()=>{for(let e of document.querySelectorAll(`[data-node-id]`)){let t=n.get(e.getAttribute(`data-node-id`));t?(e.setAttribute(`data-task-scope`,t),e.setAttribute(`title`,l(`In task: ${t}`,`작업 중: ${t}`))):e.hasAttribute(`data-task-scope`)&&(e.removeAttribute(`data-task-scope`),e.removeAttribute(`title`))}};r();let i=new MutationObserver(r);return i.observe(document.body,{childList:!0,subtree:!0}),()=>{i.disconnect(),n.clear(),r()}},[e,t])}function _({sessionId:e,pulse:r,labelOf:l,onMainNote:_}){let v=(0,p.useMemo)(()=>s(),[]),y=u(),[b,x]=(0,p.useReducer)((e,r)=>r.seed?o(e,r.seed):r.reset?t():n(e,r.event),void 0,t),[S,C]=(0,p.useState)({}),[w,T]=(0,p.useState)(f),E=(0,p.useRef)(0),D=(0,p.useRef)(_);(0,p.useEffect)(()=>{E.current=b.after,D.current=_},[b.after,_]),(0,p.useEffect)(()=>{x({reset:!0}),E.current=0},[e]),(0,p.useEffect)(()=>d(T),[]),(0,p.useEffect)(()=>y.subscribe(e=>{typeof e?.type!=`string`||!e.type.startsWith(`task.`)||(C(t=>i(t,e)),(e.type===`task.userEdit`||e.type===`task.undone`)&&x({event:e}))}),[y]),(0,p.useEffect)(()=>{if(!e)return;let t=new AbortController;return(async()=>{for(;!t.signal.aborted;){try{let{tasks:n}=await v.board(e);x({seed:n}),await v.events(e,E.current,e=>{if(e.type===`main.turn`&&e.turnId){let n=``;v.frames(e.turnId,e=>{e.type===`text.delta`&&(n+=e.text??``),e.type===`tool.start`&&(n=``)},t.signal).then(()=>D.current?.(n),()=>{})}x({event:e})},t.signal)}catch{}await h(m,t.signal)}})(),()=>t.abort()},[v,e,r]);let O=b.order.filter(e=>b.tasks[e]?.status===`running`&&b.tasks[e]?.turnId),k=O.map(e=>`${e}:${b.tasks[e].turnId}`).join();return(0,p.useEffect)(()=>{let e=O.map(e=>{let t=new AbortController,{turnId:n}=b.tasks[e];return v.frames(n,t=>{let n=a(t,l);n&&x({event:{type:`task.progress`,taskId:e,status:`running`,progress:n}})},t.signal).catch(()=>{}),t});return()=>e.forEach(e=>e.abort())},[v,k,l]),g(S,(0,p.useMemo)(()=>Object.fromEntries(b.order.map(e=>[e,b.tasks[e].title])),[b])),(0,p.useEffect)(()=>{c.set({client:v,labelOf:l,undo:async e=>{let t=await y.run(`task.undo`,{taskId:e});if(t?.ok===!1)throw Error(t.message??t.code);x({event:{type:`task.undone`,taskId:e}})}})},[y,v,l]),(0,p.useEffect)(()=>{c.set({board:b,activity:w})},[b,w]),(0,p.useEffect)(()=>()=>c.set({board:t(),open:null}),[e]),null}export{_ as default};
|